systemd Cheat Sheet: systemctl, journalctl, Services, and Timers

4 min read
Intermediate systemd Linux Services systemctl Cheat Sheet

Quick Answer: systemctl start nginx starts a service. systemctl enable nginx starts it on boot. systemctl status nginx shows status. journalctl -u nginx -f follows its logs. systemctl restart nginx restarts it.

systemctl — Service Management

Basic Commands

# Start / Stop / Restart
systemctl start nginx
systemctl stop nginx
systemctl restart nginx          # Stop then start
systemctl reload nginx           # Reload config without restart (if supported)
systemctl reload-or-restart nginx

# Enable / Disable (boot behavior)
systemctl enable nginx           # Start on boot
systemctl disable nginx          # Don't start on boot
systemctl enable --now nginx     # Enable AND start immediately

# Status
systemctl status nginx
systemctl is-active nginx        # Just "active" or "inactive"
systemctl is-enabled nginx       # "enabled" or "disabled"
systemctl is-failed nginx        # "failed" or not

List Services

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

# Running services only
systemctl list-units --type=service --state=running

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

# All installed service files
systemctl list-unit-files --type=service

# Enabled services
systemctl list-unit-files --type=service --state=enabled

Service Dependencies

# What depends on this service
systemctl list-dependencies nginx

# What this service depends on
systemctl list-dependencies nginx --reverse

# Show service properties
systemctl show nginx
systemctl show nginx -p MainPID
systemctl show nginx -p ActiveState

journalctl — Log Management

Basic Log Viewing

# All logs
journalctl

# Follow (live tail)
journalctl -f

# Specific service
journalctl -u nginx
journalctl -u nginx -f           # Follow

# Last N lines
journalctl -u nginx -n 50

# Since specific time
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2026-04-06 10:00"
journalctl --since "yesterday"
journalctl --since "2 days ago" --until "1 day ago"

# Current boot only
journalctl -b
journalctl -b -1                 # Previous boot

# Kernel messages
journalctl -k
journalctl -k -b                 # Kernel messages from current boot

Filtering and Output

# By priority (error and above)
journalctl -p err
journalctl -p warning
# Levels: emerg, alert, crit, err, warning, notice, info, debug

# Specific PID
journalctl _PID=1234

# Specific executable
journalctl _COMM=sshd

# JSON output
journalctl -u nginx -o json-pretty -n 5

# Short output (default, most readable)
journalctl -u nginx -o short-iso

# Search/grep
journalctl -u nginx | grep "error"
journalctl -u nginx -g "error|failed"    # Built-in grep (systemd 245+)

Log Maintenance

# Disk usage
journalctl --disk-usage

# Clean logs older than 2 weeks
journalctl --vacuum-time=2weeks

# Clean logs to fit in 500MB
journalctl --vacuum-size=500M

# Rotate logs now
journalctl --rotate

# Permanent limits (edit /etc/systemd/journald.conf)
# SystemMaxUse=500M
# SystemMaxFileSize=50M
# MaxRetentionSec=2weeks
systemctl restart systemd-journald

Creating Custom Services

Basic Service 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=/opt/myapp/start.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Then:

systemctl daemon-reload          # Load new service file
systemctl enable --now myapp     # Enable and start

Service Types

Type Behavior
simple Default. Process started by ExecStart is the main process
exec Like simple, but systemd waits for exec() to complete
forking Process forks, parent exits. Use with daemons that daemonize themselves
oneshot Process exits after running. Good for scripts
notify Process signals systemd when ready (requires sd_notify)

Service with Environment Variables

[Service]
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=/opt/myapp/.env
ExecStart=/usr/bin/node /opt/myapp/server.js

Service with Logging

[Service]
ExecStart=/opt/myapp/start.sh
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

View logs: journalctl -u myapp -f

Node.js / Python App Service

# Node.js
[Unit]
Description=Node.js API
After=network.target

[Service]
Type=simple
User=node
WorkingDirectory=/opt/api
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3
Environment=NODE_ENV=production
Environment=PORT=3000

[Install]
WantedBy=multi-user.target
# Python (with venv)
[Unit]
Description=Python Web App
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/webapp
ExecStart=/opt/webapp/venv/bin/python app.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Docker Container as Service

[Unit]
Description=My Docker Container
After=docker.service
Requires=docker.service

[Service]
Type=simple
Restart=always
RestartSec=5
ExecStartPre=-/usr/bin/docker stop myapp
ExecStartPre=-/usr/bin/docker rm myapp
ExecStart=/usr/bin/docker run --name myapp -p 8080:80 myimage:latest
ExecStop=/usr/bin/docker stop myapp

[Install]
WantedBy=multi-user.target

Timers (Cron Replacement)

Timer + Service Pair

Create /etc/systemd/system/backup.timer:

[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=daily
# Or specific: OnCalendar=*-*-* 02:00:00 (2 AM daily)
Persistent=true
RandomizedDelaySec=300

[Install]
WantedBy=timers.target

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

[Unit]
Description=Run backup

[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
systemctl daemon-reload
systemctl enable --now backup.timer

Timer Schedules

OnCalendar When
minutely Every minute
hourly Every hour
daily Every day at midnight
weekly Every Monday at midnight
monthly First day of month
--* 02:30:00 Daily at 2:30 AM
Mon --* 09:00:00 Every Monday at 9 AM
--01 00:00:00 First of every month
*:0/15 Every 15 minutes
# Validate a timer expression
systemd-analyze calendar "Mon *-*-* 09:00:00"

# List active timers
systemctl list-timers
systemctl list-timers --all

# Run timer manually (triggers the service)
systemctl start backup.service

System Commands

# Reboot
systemctl reboot

# Shutdown
systemctl poweroff

# Suspend
systemctl suspend

# Analyze boot time
systemd-analyze
systemd-analyze blame            # Time per service
systemd-analyze critical-chain   # Critical path

# Show system state
systemctl is-system-running

# Reload all unit files (after editing)
systemctl daemon-reload

Troubleshooting

# Service won't start? Check logs:
journalctl -u myapp -n 30 --no-pager

# Check service file syntax:
systemd-analyze verify /etc/systemd/system/myapp.service

# See full service properties:
systemctl show myapp

# Reset failed state:
systemctl reset-failed myapp

# Check what's blocking boot:
systemd-analyze critical-chain

# Emergency mode:
systemctl isolate emergency.target

# Default boot target:
systemctl get-default
systemctl set-default multi-user.target    # CLI only (no GUI)
systemctl set-default graphical.target     # With GUI

See Also