โ† Back to Tutorials
29 May 2026ยท5 min read

Manage systemd Services with systemctl: A Guide

Start, stop, enable, and troubleshoot Linux services with systemctl. Plus how to write a custom systemd unit file and read logs with journalctl.

On modern Ubuntu, almost everything that runs in the backgroundโ€”your web server, SSH daemon, database, the cron replacement, even mounting filesystemsโ€”is managed by systemd. The command you use to talk to it is systemctl. Knowing a handful of systemctl verbs is the difference between confidently operating a Linux server and guessing why a service will not start.

This guide is a practical tour of managing services with systemctl on Ubuntu 24.04 LTS: starting and stopping services, enabling them at boot, reading their status, writing your own custom unit file, and reading logs with journalctl. Every command is copy-pasteable and safe to run on a real server.

Prerequisites

  • A machine running Ubuntu 24.04 LTS.
  • A user with sudo privileges.
  • Basic comfort editing files from the terminal.

Understanding units

systemd manages units. A service (a background process) is a unit of type .service; there are also .socket, .timer, .mount, and .target units. When you type systemctl status ssh, systemd assumes the .service suffix. List all loaded service units:

systemctl list-units --type=service

To see every installed unit and whether it starts at boot:

systemctl list-unit-files --type=service

Checking service status

The most-used command. It shows whether a service is running, its main PID, memory use, and the last few log lines:

systemctl status ssh
โ— ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-06-20 09:12:03 UTC; 2h 4min ago
   Main PID: 812 (sshd)
     Memory: 5.2M

Two words matter here. active (running) tells you the current state. enabled tells you it will start at the next boot. Those are independentโ€”a service can be running now but disabled at boot, or vice versa.

For scripting, query just the active state, which sets a useful exit code:

systemctl is-active ssh
systemctl is-enabled ssh

Starting, stopping, and restarting

These change the current runtime state and take effect immediately:

sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx

When you change a service's configuration, prefer reload over restart if the service supports itโ€”reload re-reads config without dropping connections:

sudo systemctl reload nginx

If you are unsure whether a service can reload, reload-or-restart does the right thing:

sudo systemctl reload-or-restart nginx

Enabling and disabling at boot

enable creates the symlinks that make a service start at boot; disable removes them. Neither changes the current state. To do both at once, add --now:

sudo systemctl enable --now nginx
sudo systemctl disable --now nginx

To stop a service from ever being startedโ€”even as a dependency of another unitโ€”mask it. This links it to /dev/null:

sudo systemctl mask nginx
sudo systemctl unmask nginx

Writing a custom systemd unit

Suppose you have a small Python application at /opt/myapp/app.py that you want to run as a managed serviceโ€”restarted automatically if it crashes, started at boot. Create a unit file:

sudo nano /etc/systemd/system/myapp.service

Place your unit definitions under /etc/systemd/system/; that directory is for local admin-defined units and overrides packaged ones. Add:

[Unit]
Description=My Python Application
After=network.target

[Service] Type=simple User=www-data WorkingDirectory=/opt/myapp ExecStart=/usr/bin/python3 /opt/myapp/app.py Restart=on-failure RestartSec=5

[Install] WantedBy=multi-user.target

The three sections do distinct jobs. [Unit] holds metadata and ordering (After=network.target waits for networking). [Service] defines how to run the process: Type=simple means the process started by ExecStart is the service itself; Restart=on-failure auto-restarts it after a non-zero exit. [Install] defines what happens on enableโ€”WantedBy=multi-user.target ties it to normal multi-user boot.

Loading and managing your unit

Whenever you add or edit a unit file, reload the systemd manager so it re-reads the files on disk:

sudo systemctl daemon-reload

Now start and enable your service:

sudo systemctl enable --now myapp.service

Confirm it came up:

systemctl status myapp.service

Reading logs with journalctl

systemd captures the stdout and stderr of every service into the journal. To read a specific service's logs:

journalctl -u myapp.service

The most useful flags in daily operations:

journalctl -u myapp.service -f          # follow live, like tail -f
journalctl -u myapp.service -n 50       # last 50 lines
journalctl -u myapp.service --since '10 min ago'
journalctl -u myapp.service -p err      # only error priority and worse

To see logs from the current boot only:

journalctl -u myapp.service -b

Verification

Prove the auto-restart works. Find the main PID, kill it, then check the service recovers:

systemctl show -p MainPID myapp.service
sudo kill <PID>
systemctl status myapp.service

Within five seconds (RestartSec=5) systemd should restart the process with a new PID, and the journal will record the restart. That confirms both your unit file and the restart policy are correct.

Common pitfalls and troubleshooting

  • Forgetting daemon-reload. After editing a unit file, systemd keeps the old version cached until you run sudo systemctl daemon-reload. If your changes seem ignored, this is usually why.
  • Confusing enabled with active. enable only affects boot; it does not start the service now. Use --now to do both.
  • Wrong Type=. If your program forks into the background, Type=simple makes systemd think it exited. Use Type=forking (with a PIDFile) or, better, run the process in the foreground.
  • Service fails immediately. Run systemctl status and journalctl -xeu myapp.serviceโ€”the -x adds explanatory hints. Common causes are a wrong ExecStart path or a User= that lacks permissions on WorkingDirectory.
  • Editing packaged units directly. Do not edit files under /usr/lib/systemd/system/; package updates overwrite them. Use sudo systemctl edit servicename to create a drop-in override instead.

Conclusion

With start, stop, enable, status, a custom unit file, and journalctl, you can manage the full lifecycle of any service on an Ubuntu server. These same commands work identically across every systemd-based distribution, so the skill transfers everywhere.

Once your services are defined as units, the next step is scheduling recurring workโ€”compare cron and systemd timers in our guide to scheduling jobs with cron on Linux, and put a service behind the internet safely with an Nginx reverse proxy. Keeping dozens of services healthy across a fleet is exactly what a managed platform automates: clouditiv watches unit health, restarts, and resource limits for you as part of its monitoring, so you spend less time reading journalctl at 3 a.m.