How to Use systemd: Services, Timers, and Logs Explained

6 min read
Intermediate Linux systemd Services Sysadmin

systemd is the init system and service manager on almost every modern Linux distribution — Ubuntu, Debian, Fedora, CentOS, Arch, and more. If you administer a Linux server, you interact with systemd every day whether you realize it or not.

Every time you run systemctl start nginx or journalctl -f, you are using systemd. This guide covers everything you need to know — from basic service management to creating your own unit files and replacing cron jobs with systemd timers.

What is systemd?

systemd is the first process that runs when Linux boots (PID 1). It is responsible for:

  • Starting and stopping services (nginx, sshd, docker, etc.)
  • Managing dependencies (start database before web server)
  • Logging (journald replaces syslog)
  • Scheduling tasks (timers as cron alternative)
  • Mounting filesystems
  • Managing network, DNS, time sync, and more

Before systemd, Linux used SysV init scripts — shell scripts in /etc/init.d/ that were fragile and inconsistent. systemd replaced this with a unified, declarative system.

Managing Services

Basic Commands

# Start a service
sudo systemctl start nginx

# Stop a service
sudo systemctl stop nginx

# Restart (stop then start)
sudo systemctl restart nginx

# Reload config without restarting (if supported)
sudo systemctl reload nginx

# Check status
systemctl status nginx

# Enable (start on boot)
sudo systemctl enable nginx

# Disable (don't start on boot)
sudo systemctl disable nginx

# Enable and start in one command
sudo systemctl enable --now nginx

Check Service Status

$ systemctl status nginx
● nginx.service - A high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
     Active: active (running) since Tue 2026-04-01 10:30:00 CDT
    Process: 1234 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
   Main PID: 1235 (nginx)
      Tasks: 5 (limit: 18838)
     Memory: 12.4M
        CPU: 234ms
     CGroup: /system.slice/nginx.service
             ├─1235 "nginx: master process /usr/sbin/nginx"
             └─1236 "nginx: worker process"

Key things to look at:

  • Active: active (running) means it is working. failed means it crashed.
  • Loaded: enabled means it starts on boot
  • Main PID: The process ID
  • Memory/CPU: Resource usage

List All Services

# All loaded services
systemctl list-units --type=service

# All services (including inactive)
systemctl list-units --type=service --all

# Only failed services
systemctl list-units --type=service --state=failed

# Check if a specific service is active
systemctl is-active nginx

# Check if enabled on boot
systemctl is-enabled nginx

Creating Custom Services

When you write your own application or script that needs to run as a service, you create a unit file.

Unit File Location

  • /etc/systemd/system/ — your custom services go here
  • /lib/systemd/system/ — package-installed services (don't edit these)

Basic Service Unit File

Create /etc/systemd/system/myapp.service:

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

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/server.py
Restart=always
RestartSec=5
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

Then activate it:

sudo systemctl daemon-reload    # Reload unit files
sudo systemctl enable --now myapp   # Enable and start
systemctl status myapp          # Verify

Section Breakdown

[Unit] — Metadata and dependencies

Directive Purpose
Description Human-readable name
After Start after these units
Requires Hard dependency — if it fails, this fails too
Wants Soft dependency — start if available

[Service] — How to run it

Directive Purpose
Type simple (default), forking, oneshot, notify
ExecStart Command to run
ExecStartPre Command to run before starting
ExecReload Command for systemctl reload
Restart always, on-failure, no
RestartSec Seconds to wait before restart
User / Group Run as this user
WorkingDirectory Set the working directory
Environment Set environment variables
EnvironmentFile Load env vars from a file

[Install] — When to start

Directive Purpose
WantedBy=multi-user.target Start in normal multi-user mode (most services)
WantedBy=graphical.target Start when GUI is ready

Real Example: Node.js App

[Unit]
Description=SamNet API Server
After=network.target

[Service]
Type=simple
User=samnet
WorkingDirectory=/opt/samnet-api
ExecStart=/usr/bin/node /opt/samnet-api/index.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
Environment=PORT=3000
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target

Real Example: Python with Virtual Environment

[Unit]
Description=Flask Web App
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/flask-app
ExecStart=/opt/flask-app/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 app:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Journalctl — Reading Logs

systemd's logging system is called journald. It replaces traditional log files with a structured, indexed journal.

Basic Usage

# All logs (paged)
journalctl

# Follow logs in real time (like tail -f)
journalctl -f

# Logs for a specific service
journalctl -u nginx

# Follow a specific service
journalctl -u nginx -f

# Last 50 lines
journalctl -u nginx -n 50

# Logs since last boot
journalctl -b

# Logs from previous boot
journalctl -b -1

Filtering by Time

# Since a specific time
journalctl --since "2026-04-01 10:00:00"

# Last hour
journalctl --since "1 hour ago"

# Last 24 hours
journalctl --since "yesterday"

# Time range
journalctl --since "2026-04-01" --until "2026-04-02"

Filtering by Priority

# Only errors and worse
journalctl -p err

# Warnings and worse
journalctl -p warning

# Priority levels: emerg, alert, crit, err, warning, notice, info, debug

Output Formats

# JSON output (great for parsing)
journalctl -u nginx -o json-pretty

# Short (default, syslog-like)
journalctl -u nginx -o short

# Verbose (all fields)
journalctl -u nginx -o verbose

Disk Usage

# How much space journals use
journalctl --disk-usage

# Clean up old logs (keep last 1GB)
sudo journalctl --vacuum-size=1G

# Keep only last 30 days
sudo journalctl --vacuum-time=30d

systemd Timers (Cron Alternative)

systemd timers are a modern alternative to cron. They offer better logging, dependency management, and can trigger on events (not just time).

Creating a Timer

You need two files: a service unit (what to run) and a timer unit (when to run it).

Step 1: Create the service/etc/systemd/system/backup.service:

[Unit]
Description=Daily Backup

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh

Step 2: Create the timer/etc/systemd/system/backup.timer:

[Unit]
Description=Run backup daily at 2 AM

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target

Step 3: Enable the timer (not the service):

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

Timer Syntax

# Every day at midnight
OnCalendar=daily

# Every day at 3:30 AM
OnCalendar=*-*-* 03:30:00

# Every Monday at 6 AM
OnCalendar=Mon *-*-* 06:00:00

# Every 15 minutes
OnCalendar=*:0/15

# First of every month
OnCalendar=*-*-01 00:00:00

List Active Timers

systemctl list-timers --all

Timer vs Cron

Feature Cron systemd Timer
Logging Manual (redirect to file) Automatic (journalctl)
Missed runs Lost forever Persistent=true catches up
Dependencies None Full systemd dependency system
Resource control None CPU/memory limits via cgroups
Randomized delay No RandomizedDelaySec
Setup One line Two files

For more cron syntax examples, check our Cron Job Examples guide or use the Cron Expression Generator.

Useful systemd Commands Cheat Sheet

# Reload all unit files after changes
sudo systemctl daemon-reload

# See all failed units
systemctl --failed

# See boot time breakdown
systemd-analyze

# See which services slow down boot
systemd-analyze blame

# Kill a service and all its children
sudo systemctl kill nginx

# Mask a service (prevent starting entirely)
sudo systemctl mask nginx

# Unmask
sudo systemctl unmask nginx

# See all dependencies of a service
systemctl list-dependencies nginx

# Edit a service's override (safe way to customize)
sudo systemctl edit nginx

Related Tools

Use our Chmod Calculator to set correct permissions on your service scripts and unit files.