Linux and open source
Diagnose a failed Linux service with systemd
nginx won't start on a fresh server. Find the real cause with systemctl, journalctl and ss, then fix it so it survives a reboot.
- Beginner
- About 20 minutes (plus 15 for the real VM)
- Command line
- Simulation + real-world
- Published 26 October 2026
The scenario
You installed nginx, but the site won't load and the service shows as failed. The configuration test passes, so something else is in the way. The same four commands solve most service failures.
At a glance
Before you start
- Able to type commands in a Linux terminal
- For the real-world part, an Ubuntu or Debian virtual machine you can break (not a production server)
Tools
systemctljournalctlssnginx -tcurl
You'll be able to
You can go from "the service failed" to the exact cause using status, logs and listening ports, and make a fix that persists after a reboot.
Try it
Browser simulation. Runs entirely in your browser. Nothing connects to real systems.
Get nginx running and answering on port 80, in a way that survives a reboot.
This simulation needs JavaScript. Here is a short sample of how a session goes:
$ systemctl status nginx
× nginx.service - A high performance web server and a reverse proxy server
Active: failed (Result: exit-code)
$ journalctl -u nginx -n 20 --no-pager
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
$ sudo ss -tlnp
LISTEN 0 511 *:80 *:* users:(("apache2",pid=812,fd=4),...)
$ sudo systemctl disable --now apache2
Removed "/etc/systemd/system/multi-user.target.wants/apache2.service".
$ sudo systemctl restart nginx && curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)The four commands that solve most service failures
| Question | Command |
|---|---|
| What state is the service in? | systemctl status nginx |
| What did it say when it failed? | journalctl -u nginx -n 20 --no-pager |
| Is the configuration valid? | sudo nginx -t |
| Who is using the port? | sudo ss -tlnp |
Work through them in that order in the simulation above. The goal tracker at the top turns green when nginx is serving on port 80 and the fix will survive a reboot.
What’s actually going on
The journal tells you bind() to 0.0.0.0:80 failed (98: Address already in use). Only one program can listen on a given port, and ss shows that apache2 already holds port 80. Installing both web servers is an easy accident: they both default to port 80, and whichever starts first wins.
Two clues worth noticing:
curl -I http://localhoststill returns200 OK, but theServer:header says Apache. “The site responds” and “the right service responds” are different things.- Without
sudo,sshides process names. Plenty of troubleshooting dead ends come from running a command without the privileges it needs.
Fixing it properly
You have two reasonable choices:
-
You don’t need Apache: stop it now and stop it starting at boot.
sudo systemctl disable --now apache2 sudo systemctl restart nginx -
You need both: move one of them to another port. For nginx, change the
listen 80lines in/etc/nginx/sites-enabled/default(for example tolisten 8080), then runsudo nginx -tandsudo systemctl reload nginx.
systemctl stop alone only fixes things until the next reboot. That’s why the simulation’s goal needs Apache disabled, not just stopped.
Reproduce it on a real VM
On a disposable Ubuntu or Debian VM:
sudo apt update
sudo apt install -y apache2 # starts and takes port 80
sudo apt install -y nginx # installs, then fails to start
systemctl status nginx
journalctl -u nginx -n 20 --no-pager
sudo ss -tlnp
apt may report that it couldn’t configure the nginx package, because its install script tries to start the service. That’s expected here. After you fix the port clash, run sudo dpkg --configure -a so apt can finish the job.
Fix it with either option above, then confirm:
systemctl status nginx
curl -I http://localhost # look for "Server: nginx"
To clean up afterwards: sudo apt purge -y apache2 nginx && sudo apt autoremove -y.
Expected result
nginx shows active (running), curl -I http://localhost returns a Server: nginx header, and systemctl is-enabled apache2 says disabled, so the fix survives a reboot.
Further reading
- systemctl manual (freedesktop.org)
- journalctl manual (freedesktop.org)
- ss manual (man7.org)
Key lessons
- Status, logs, a configuration test and the list of listening ports answer most service failures.
- Only one program can listen on a port. "Address already in use" means: find out who owns it.
- Stopping a service fixes things until the next reboot. Disabling it makes the fix stick.
Keep going
Trace a request from your laptop to a website
Follow one web request hop by hop, and learn the one command that tests each stage.