systemctl is the primary interface to systemd for managing units, checking status, and querying the system state.
# Start / stop / restart / reload systemctl start nginx systemctl stop nginx systemctl restart nginx systemctl reload nginx # sends SIGHUP (if supported) # Enable / disable at boot systemctl enable nginx systemctl disable nginx systemctl enable --now nginx # enable + start immediately # Mask / unmask (prevent any start) systemctl mask nginx systemctl unmask nginx # Status and logs systemctl status nginx # state, PID, recent journal output systemctl is-active nginx systemctl is-enabled nginx systemctl is-failed nginx # List units systemctl list-units --type=service systemctl list-units --failed systemctl list-unit-files --type=service # Reload systemd configuration (after editing unit files) systemctl daemon-reload
Service units define how systemd starts and supervises a process. They live in /etc/systemd/system/ (admin) or /lib/systemd/system/ (packages). Drop-in overrides go in /etc/systemd/system/name.service.d/*.conf.
Full annotated service unit
[Unit] Description=My Application After=network.target postgresql.service # ordering Requires=postgresql.service # hard dependency Wants=redis.service # soft dependency [Service] Type=simple # simple|forking|notify|oneshot|idle User=myapp Group=myapp WorkingDirectory=/opt/myapp Environment=APP_ENV=production EnvironmentFile=/etc/myapp/env ExecStartPre=/opt/myapp/bin/migrate ExecStart=/opt/myapp/bin/server --port 8080 ExecReload=/bin/kill -HUP $MAINPID ExecStop=/bin/kill -TERM $MAINPID Restart=on-failure # always|on-failure|on-abnormal|no RestartSec=5s StartLimitBurst=3 StartLimitIntervalSec=30s # Resource limits LimitNOFILE=65536 MemoryMax=1G CPUQuota=200% # 200% = 2 full CPUs # Sandboxing PrivateTmp=yes # isolated /tmp ProtectSystem=strict # read-only /usr /boot /etc ProtectHome=yes # no access to /home /root NoNewPrivileges=yes # prevent privilege escalation ReadWritePaths=/var/lib/myapp [Install] WantedBy=multi-user.target
Service types
| Type | Behaviour |
|---|---|
| simple | ExecStart process is the main service. systemd considers it started immediately. |
| forking | ExecStart forks and exits. Parent exit = service started. Use PIDFile= to track main process. |
| notify | Process calls sd_notify(READY=1) when ready. Most reliable — systemd knows exactly when started. |
| oneshot | Short-lived task. systemd waits for it to exit before considering it done. Use RemainAfterExit=yes if appropriate. |
| dbus | Service is ready when it acquires a D-Bus name. Use BusName=. |
Override a vendor unit (drop-in)
# Create a drop-in to override a specific setting systemctl edit nginx # opens editor, creates drop-in automatically # Or manually: mkdir -p /etc/systemd/system/nginx.service.d/ cat > /etc/systemd/system/nginx.service.d/override.conf <<'EOF' [Service] LimitNOFILE=65536 EOF systemctl daemon-reload systemctl restart nginx
Targets group units and define system states. They replace SysV runlevels. The default target determines what gets started at boot.
Common targets
| Target | SysV equiv | Description |
|---|---|---|
| poweroff.target | 0 | System shutdown |
| rescue.target | 1 | Single-user mode, minimal services, root shell |
| multi-user.target | 3 | Multi-user, no GUI — typical server default |
| graphical.target | 5 | Multi-user with GUI |
| reboot.target | 6 | Reboot |
| emergency.target | — | Minimal shell, root filesystem read-only |
| network.target | — | Network configured (not necessarily up) |
| network-online.target | — | Network fully online — use Wants= sparingly |
# Show current target systemctl get-default # Change default target systemctl set-default multi-user.target # Switch to a target immediately (without reboot) systemctl isolate rescue.target # Reboot / shutdown systemctl reboot systemctl poweroff systemctl suspend
Systemd timers replace cron. Each timer activates a corresponding .service unit. They support monotonic (relative to boot/last run) and realtime (calendar-based) schedules, missed run tracking, and can be inspected with systemctl.
Timer unit types
# /etc/systemd/system/backup.timer [Unit] Description=Daily backup timer [Timer] # Realtime (calendar) — run every day at 02:30 OnCalendar=*-*-* 02:30:00 # Catch up if system was off when scheduled Persistent=true # Monotonic — run 15 minutes after boot, then every hour # OnBootSec=15min # OnUnitActiveSec=1h # Random spread to avoid thundering herd RandomizedDelaySec=5min Unit=backup.service [Install] WantedBy=timers.target
# List all timers with next/last trigger systemctl list-timers --all # Enable and start timer systemctl enable --now backup.timer # Test the timer's service immediately systemctl start backup.service # OnCalendar examples # hourly → *-*-* *:00:00 # daily → *-*-* 00:00:00 # weekly → Mon *-*-* 00:00:00 # Mon..Fri 09:00 → Mon..Fri *-*-* 09:00:00 # Verify calendar expression systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
Socket activation starts a service on-demand when the first connection arrives. systemd holds the socket open; the service inherits it on start via file descriptor 3 (or via sd_listen_fds()). This enables parallelised boot and zero-downtime restarts.
# /etc/systemd/system/myapp.socket [Unit] Description=My App Socket [Socket] ListenStream=8080 # TCP port # ListenStream=/run/myapp.sock # Unix socket Accept=no # one instance handles all connections # Accept=yes # fork a new instance per connection [Install] WantedBy=sockets.target --- # /etc/systemd/system/myapp.service [Unit] Description=My App [Service] ExecStart=/opt/myapp/bin/server # Service receives the socket on fd 3 via sd_listen_fds()
# Enable socket (not the service — it starts on demand) systemctl enable --now myapp.socket # Zero-downtime restart: systemd keeps socket open systemctl restart myapp.service # new process inherits socket
journald collects logs from kernel, systemd units, and any process writing to stdout/stderr. Logs are stored in a structured binary format and queried with journalctl.
journalctl filtering
# Follow logs for a service (like tail -f) journalctl -fu nginx # Last 100 lines journalctl -n 100 -u nginx # Since a time / between times journalctl -u nginx --since "2026-05-13 10:00" --until "2026-05-13 11:00" journalctl -u nginx --since "1 hour ago" # By priority (0=emerg .. 7=debug) journalctl -p err # err and above journalctl -p warning..err # Kernel messages (like dmesg) journalctl -k journalctl -k --since "today" # By PID or UID journalctl _PID=1234 journalctl _UID=1000 # JSON output for structured processing journalctl -u nginx -o json | jq .MESSAGE # Show disk usage journalctl --disk-usage # Vacuum old logs journalctl --vacuum-time=30d journalctl --vacuum-size=500M
Persistent journal configuration
# /etc/systemd/journald.conf [Journal] Storage=persistent # auto|volatile|persistent|none Compress=yes SystemMaxUse=2G SystemKeepFree=500M MaxRetentionSec=1month ForwardToSyslog=no # set yes to also forward to rsyslog
mkdir -p /var/log/journal && systemctl restart systemd-journald. Without this, logs are lost on reboot.Every systemd service runs in its own cgroup slice. This provides isolation, resource limits, and accurate accounting per service.
# Show cgroup tree systemd-cgls # Live resource usage per service systemd-cgtop # Set resource limits at runtime (transient, lost on restart) systemctl set-property nginx.service MemoryMax=512M systemctl set-property nginx.service CPUQuota=50% # Make permanent (writes to override file) systemctl set-property --runtime=false nginx.service MemoryMax=512M # Available service resource properties # MemoryMax=, MemoryHigh=, MemorySwapMax= # CPUQuota=, CPUWeight= # IOWeight=, IOReadBandwidthMax=, IOWriteBandwidthMax= # TasksMax= # LimitNOFILE=, LimitNPROC=
# Total boot time summary systemd-analyze # Time per unit (slowest first) systemd-analyze blame # Show critical chain (longest path) systemd-analyze critical-chain # SVG timeline of all units systemd-analyze plot > boot.svg # Check unit file syntax systemd-analyze verify /etc/systemd/system/myapp.service # Security score for a service systemd-analyze security nginx.service # Show unit dependencies systemctl list-dependencies nginx systemctl list-dependencies --reverse nginx # what depends on it
systemctl
systemctl enable --now svcsystemctl restart svcsystemctl daemon-reloadsystemctl list-units --failed
journalctl
journalctl -fu svcjournalctl -p err --since todayjournalctl -k — kerneljournalctl --vacuum-time=30d
Service unit keys
Type=notify — most reliableRestart=on-failurePrivateTmp=yesNoNewPrivileges=yes
Timers
OnCalendar=dailyPersistent=truesystemctl list-timerssystemd-analyze calendar "..."
Boot debug
systemd-analyze blamesystemd-analyze critical-chainsystemd-analyze security svcsystemd-analyze verify unit
cgroups
systemd-cglssystemd-cgtopsystemctl set-property svc MemoryMax=1Gsystemctl set-property svc CPUQuota=50%