Manage Linux Services with systemctl
The eight commands that cover 95% of what you'll ever do with services on a Linux VPS — start, stop, restart, enable on boot, check status, and tail the log of any unit on the system.
systemd is the boot and service manager on every mainstream Linux distribution today — Ubuntu, Debian, AlmaLinux, Rocky, Fedora, and most others. systemctl is the one command that talks to it. Whether you need to restart nginx after a config change, see why your app died at 3 AM, or make sure your service comes back after a reboot, this guide covers the moves you'll reach for daily.
The seven verbs you actually use
# Check the current state sudo systemctl status nginx # Start a service now (this boot only) sudo systemctl start nginx # Stop it now sudo systemctl stop nginx # Restart — full stop + start, drops any open connections sudo systemctl restart nginx # Reload — re-read config without dropping connections (when the service supports it) sudo systemctl reload nginx # Enable so it starts automatically on boot sudo systemctl enable nginx # Disable autostart sudo systemctl disable nginx # Combo: enable + start in one shot sudo systemctl enable --now nginx
restart vs reload
reload is what you want after a config change — it tells the running process to re-read its files without dropping open connections. restart kills the process and starts a fresh one, which drops every in-flight request. Most server software supports reload (nginx, apache, sshd, postfix); some doesn't (most simple Python apps). When in doubt, check systemctl status for a 'Drop-In: reload' hint.
1Read the status of a service properly
systemctl status is the single highest-value command in this article. It tells you whether the service is running, when it was last started, and prints the last ten lines of its log — usually enough to diagnose any problem.
# Full status with recent log lines sudo systemctl status nginx # Just the one-word state (active, inactive, failed) systemctl is-active nginx # Will it autostart on boot? systemctl is-enabled nginx
Reading the output
Look for three things: Active: should say active (running); Main PID: the process ID; and the log lines at the bottom. A red failed state at the top with a Python or nginx error in the log block tells you exactly what to fix.
2List every service on the box
# Every running service systemctl list-units --type=service --state=running # Every service that failed since last boot systemctl list-units --type=service --state=failed # Every service installed (even ones that have never run) systemctl list-unit-files --type=service # Just the enabled ones (will start on boot) systemctl list-unit-files --type=service --state=enabled
3Tail a service's log with journalctl
systemd captures every line a service writes to stdout/stderr and stores it in the systemd journal. journalctl reads it. You'll use this every time something breaks.
# Last 100 lines for nginx sudo journalctl -u nginx -n 100 # Tail live (like tail -f) sudo journalctl -u nginx -f # Since the last boot only sudo journalctl -u nginx -b # Since a specific time sudo journalctl -u nginx --since "1 hour ago" sudo journalctl -u nginx --since "2026-05-21 09:00" --until "2026-05-21 10:00" # Only error and worse (priority levels: 0=emerg ... 7=debug) sudo journalctl -u nginx -p err
4Inspect a unit file before editing anything
Every service is described by a .service file. Before you change behaviour, read what's already there — the right tool prints the merged result of the main file plus every drop-in override.
# Show the unit as systemd actually sees it (all overrides merged) systemctl cat nginx # Find the file paths involved systemctl show nginx -p FragmentPath -p DropInPaths
5Override a setting without breaking package updates
Editing the file in /lib/systemd/system/ directly is a bad idea: package updates will overwrite your changes silently. The right way is a drop-in override, which systemctl edit creates for you.
# Open the override editor for nginx sudo systemctl edit nginx # In the editor, write only the lines you want to change. Example: # [Service] # Restart=on-failure # RestartSec=5s # # Save and exit. The drop-in lands in: # /etc/systemd/system/nginx.service.d/override.conf # Reload systemd to pick up the change sudo systemctl daemon-reload sudo systemctl restart nginx
How drop-in overrides work
systemd reads the main unit file first, then layers every *.conf file from /etc/systemd/system/.service.d/ on top. Your override wins, the package's file stays untouched, and package upgrades don't fight your changes.
6Write your own unit file
When you ship a Python app, Node service, or any long-running binary, giving it a proper unit file means systemd starts it on boot, restarts it if it crashes, and captures its logs in the journal.
[Unit] Description=My Application After=network-online.target Wants=network-online.target [Service] Type=simple User=deploy Group=deploy WorkingDirectory=/opt/myapp Environment="NODE_ENV=production" EnvironmentFile=/opt/myapp/.env ExecStart=/usr/bin/node /opt/myapp/server.js Restart=on-failure RestartSec=5s # Modest hardening defaults NoNewPrivileges=true PrivateTmp=true ProtectSystem=full [Install] WantedBy=multi-user.target
# Tell systemd a new unit exists sudo systemctl daemon-reload # Start it now and enable on boot sudo systemctl enable --now myapp # Verify sudo systemctl status myapp sudo journalctl -u myapp -f
7Mask a unit when you need it gone permanently
Sometimes another package keeps starting a service you don't want — exim4 sneaks back after every apt-get on Debian, for instance. disable only stops the next reboot autostart; mask prevents it from ever starting, even manually.
sudo systemctl mask postfix # Trying to start it now silently fails — exactly what we want sudo systemctl start postfix # errors out # When you change your mind sudo systemctl unmask postfix
Schedule jobs without cron, with systemd timers
systemd can replace cron entirely. Timer units have advantages over crontabs: logs go through the journal, missed runs can be caught up on boot, and you can depend on other units running first.
[Unit] Description=Daily backup [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh
[Unit] Description=Run backup daily at 02:30 [Timer] OnCalendar=*-*-* 02:30:00 Persistent=true # run missed jobs after a reboot [Install] WantedBy=timers.target
sudo systemctl daemon-reload sudo systemctl enable --now backup.timer # See when your timers will next fire systemctl list-timers
Frequently asked questions
What's the difference between systemd and systemctl?
systemctl is a command-line client that sends requests to it. Same way Docker has dockerd (daemon) and docker (client).My service runs fine when I start it manually but won't start on boot. Why?
sudo systemctl enable — without enable, the unit doesn't autostart. Second, your unit depends on something not ready at boot (network, a database, a mounted volume). Add After= and Wants= for the resources you need, like After=network-online.target.A service keeps crashing and respawning. How do I find out why?
sudo systemctl status myapp for the latest exit reason, then sudo journalctl -u myapp -n 200 --no-pager for the full log. Most crashes leave a stack trace or error message in the last 50 lines. If the app spams logs and rotates them too fast, slow the restarts with RestartSec=30s so you can read.Can I undo a systemctl edit override?
sudo systemctl revert removes every drop-in override for that unit and goes back to the package-provided defaults.Are timers really better than cron?
Need help wiring up a service?
Our managed support team writes and audits systemd units as part of every managed VPS plan — including hardening flags, dependency ordering, and log forwarding.
Deploy a VPS Open a Ticket