You've rebooted the server and now the site won't come up. systemctl status nginx says active (running), but the browser gives 502 Bad Gateway. The problem usually isn't the restart itself; it's the order in which services were stopped and brought back up. This article is about what happens between reboot and the moment a service actually comes back healthy.
Before restarting the server, look at dependencies, not the service list
Most admins start with systemctl list-units --type=service and see a list with no order to it. What matters is the dependency graph. Run this command:
systemctl list-dependencies --reverse --before nginx.service
The output shows which services must come up before nginx. If PHP-FPM or the database service isn't in this list, you'll have an error window after every restart. To see the actual boot order, systemd-analyze critical-chain nginx.service is more precise than any guess and shows the time of each node in milliseconds.
A point that's rarely noticed: After= only determines order, not dependency. If the database service doesn't come up, nginx with After=mysql.service will still run and the same 502 comes back. To truly enforce it, you also need Requires= or Wants=. The details of these sections are covered in the systemd unit file: sections, restart, and dependencies.
The correct order of stopping services before a server restart
A clean reboot stops services in reverse dependency order. If you're stopping them manually, follow this order:
- Entry layer: nginx or Apache
- Application layer: PHP-FPM, Node, Gunicorn
- Queue and cache: Redis, RabbitMQ
- Database: MySQL or PostgreSQL
Why this order? Because if the database stops first, applications that are still receiving requests generate connection errors and leave traces in the logs that later make it hard to diagnose the real cause. If Redis stops before the application, users' sessions are wiped and everyone gets logged out.
For the database, systemctl stop mysql isn't enough. Run this first:
mysqladmin -u root -p shutdown
This command performs the final flush and closes InnoDB cleanly. The difference between this and the process being killed shows itself on the next boot: longer crash recovery and, in the worst case, inconsistent tables.
This is where they go wrong
A common mistake I've seen a lot: the server admin starts with systemctl restart nginx, then restart php-fpm, and finally doesn't touch the database. The result is that nginx stays active for a few seconds without a backend, and during that window, users get 502 errors. The sign is exactly this: in access.log, a few requests with 502 codes within a two- or three-second window, and then everything is normal. Someone who only looks at the error log goes hunting for an application bug.
The second mistake is more costly: restarting the server at an hour when the backup cron is running. If the database dump is left half-finished, the backup file looks healthy but isn't restorable. Before any restart, check crontab -l and systemctl list-timers.
After boot: a checklist that actually prevents incidents
The fact that uptime shows a small number means the server has booted. Does that mean the services are healthy? No. Run these five items in order:
systemctl --failed— any unit that appears here failed during boot. An empty output means no service is in a failed state.ss -tlnp— check that the expected ports are actually listening. The list of common ports and those that shouldn't be open is in the reference for common service ports.df -handfree -m— if a partition's mount failed after boot, the service runs on an empty path and doesn't see the old data.- A real request:
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' https://example.com— a 200 code and a time under a few hundred milliseconds. journalctl -b -p err --no-pager— errors from this boot only, without old logs.
Take the fourth item seriously. A service that is active (running) can in practice not respond; for example, PHP-FPM may be up but the pool may have been left empty. The only criterion is a real response on the socket.
Server restart or service restart: which to choose
If the problem is in one service, choose to restart that service. A full server reboot is needed for a kernel change, updating system libraries, or when a service is stuck in an unrecoverable state. Their practical difference is in downtime: restarting nginx usually takes under a second, a full reboot takes between 30 and 90 seconds, depending on the number of services and disk speed.
| Method | Approximate downtime | When it's right |
|---|---|---|
systemctl reload nginx | Near zero | Config change without dropping connections |
systemctl restart nginx | Under 1 second | Module change or a stuck worker |
reboot | 30 to 90 seconds | Kernel update, recovery from a broken state |
If the server is on cloud infrastructure and you can take a snapshot before the reboot, do it. On a cloud server, taking this snapshot takes a few seconds, and if the next boot fails for any reason, it's reversible. On a dedicated server without KVM or rescue access, the same thing turns into an hour of downtime.
A trap in automatic restart
In the unit file, Restart=always is tempting. But if the service keeps crashing due to a config error, systemd restarts it in an endless loop and fills up the server logs. The correct combination is:
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=60
That means a maximum of five attempts per minute. After that, systemd gives up and you see it in systemctl --failed, instead of it getting lost in the logs. If your service doesn't come up after a server restart and stays in a failed state, before anything else read journalctl -u service-name -n 50; in ninety percent of cases, the real error is written right there.
When the server doesn't come up after a restart
If SSH doesn't respond and the console shows nothing either, the problem is probably at the mount or fsck stage. In this case you need rescue mode to mount the disk and read the previous boot logs. The process is explained step by step in server reinstall and working with rescue mode. If the server comes up but is slow, the issue is elsewhere and you should follow diagnosing the cause of high server load.
A note about SSH: if you can't connect after a restart but ping responds, check sshd first and then the config. Wrong changes in sshd_config are one of the common reasons for locking yourself out of the server; the important options are listed in SSH configuration: important security options. Always keep another SSH session open before a restart.
Frequently asked questions
What's the difference between reload and restart in systemd?
reload signals the process to re-read the config, without dropping active connections. restart fully kills the process and runs it again. For an nginx config change, reload is always enough; restart is only needed when you've added a new module or a worker is stuck in an abnormal state.
Why doesn't my service come up after a server restart?
Three common causes: a missing Wants= or Requires= in the unit file, a failed mount of a partition, or a config error that was also present in the previous boot but the service had been started manually. With systemctl --failed and journalctl -b -p err, all three can be diagnosed in a few minutes.
Does a server restart erase data?
No, if the partitions mount correctly. Data is only at risk when the database service is closed with a sudden kill or a partition comes up read-only due to an fsck error. That's why, before a reboot, close the database cleanly with mysqladmin shutdown.
How do I know services have really come back healthy after boot?
The output of systemctl --failed should be empty, the ports should be listening with ss -tlnp, and a real request with curl should return a 200 code. The active (running) status alone guarantees nothing.
Before your next restart, run systemd-analyze critical-chain once on your main service and see what actually comes up before it. That one output prevents the next 502 more than any checklist.