systemd & Service Management
systemd is the init system and service manager for Ubuntu 26.04, responsible for bootstrapping the system, managing services, and daemons. Mastering systemd is an essential skill for Ubuntu system administration.
systemctl Basics
Managing Service State
# Start a service
sudo systemctl start nginx
# Stop a service
sudo systemctl stop nginx
# Restart a service
sudo systemctl restart nginx
# Reload configuration (without interrupting the service)
sudo systemctl reload nginx
# Reload if supported, otherwise restart
sudo systemctl reload-or-restart nginx
# Check service status
systemctl status nginxBoot Service Management
# Enable a service at boot
sudo systemctl enable nginx
# Disable a service at boot
sudo systemctl disable nginx
# Enable and start immediately
sudo systemctl enable --now nginx
# Prevent a service from being started (including manually)
sudo systemctl mask nginx
# Remove the mask
sudo systemctl unmask nginxViewing Service Information
# List all running services
systemctl list-units --type=service --state=running
# List all installed services
systemctl list-unit-files --type=service
# List failed services
systemctl list-units --failed
# View a service's dependencies
systemctl list-dependencies nginx
# View detailed service properties
systemctl show nginx
# Check if a service is active
systemctl is-active nginx
# Check if a service is enabled at boot
systemctl is-enabled nginxService Unit Files
Unit File Locations
systemd service unit files are stored in the following locations, in order of priority (highest to lowest):
| Path | Description |
|---|---|
/etc/systemd/system/ | Custom admin configurations, highest priority |
/run/systemd/system/ | Runtime-generated unit files |
/lib/systemd/system/ | Default unit files installed by packages |
Viewing Unit Files
# View a service's unit file contents
systemctl cat nginx.service
# View the unit file path
systemctl show -p FragmentPath nginx.service
# Edit a unit file (creates an override)
sudo systemctl edit nginx.service
# Edit the full unit file
sudo systemctl edit --full nginx.serviceUnit File Structure
A typical service unit file has three sections:
[Unit]
Description=Service description
Documentation=https://example.com/docs
After=network.target
Wants=network-online.target
Requires=postgresql.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/myapp
ExecStartPre=/opt/myapp/pre-start.sh
ExecStart=/opt/myapp/start.sh
ExecStop=/opt/myapp/stop.sh
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
Environment=NODE_ENV=production
EnvironmentFile=/opt/myapp/.env
[Install]
WantedBy=multi-user.targetCommon Service Types
| Type | Description |
|---|---|
simple | Default; the process started by ExecStart is the main process |
forking | The service forks a child process; startup is considered complete when the parent exits |
oneshot | One-time task; considered complete when the process exits |
notify | The service notifies systemd via sd_notify when startup is complete |
idle | Similar to simple, but waits for other tasks to finish before starting |
Restart Policies
| Option | Description |
|---|---|
no | Do not restart automatically (default) |
on-success | Restart on normal exit |
on-failure | Restart on abnormal exit |
on-abnormal | Restart when killed by signal or timeout |
on-abort | Restart when killed by an uncaught signal |
always | Always restart regardless of exit reason |
Creating Custom Services
Example: Node.js Application Service
Create a unit file:
sudo nano /etc/systemd/system/myapp.serviceAdd the following content:
[Unit]
Description=My Node.js Application
After=network.target
[Service]
Type=simple
User=nodeapp
Group=nodeapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp
Environment=NODE_ENV=production PORT=3000
# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/myapp/data
PrivateTmp=yes
[Install]
WantedBy=multi-user.targetEnable and start the service:
# Reload systemd configuration
sudo systemctl daemon-reload
# Start the service
sudo systemctl enable --now myapp.service
# Check status
systemctl status myapp.service
# View logs
journalctl -u myapp.service -fExample: Python Application Service
[Unit]
Description=Python Flask Application
After=network.target
[Service]
Type=simple
User=flask
Group=flask
WorkingDirectory=/opt/flask-app
ExecStart=/opt/flask-app/venv/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
Restart=always
RestartSec=5
Environment=FLASK_ENV=production
[Install]
WantedBy=multi-user.targetExample: Service with Watchdog
[Unit]
Description=Critical Service with Watchdog
After=network.target
[Service]
Type=notify
ExecStart=/opt/critical/run.sh
WatchdogSec=30
Restart=on-failure
RestartSec=5
# Auto-restart on failure, up to 5 attempts
StartLimitIntervalSec=300
StartLimitBurst=5
[Install]
WantedBy=multi-user.targetUsing Overrides to Modify Existing Services
It is not recommended to directly modify files in /lib/systemd/system/. Instead, use overrides:
# Create an override file
sudo systemctl edit nginx.serviceThis opens an editor where you can add configuration overrides:
[Service]
# Add memory limit
MemoryMax=512M
# Change restart policy
Restart=always
RestartSec=3The override file is saved to /etc/systemd/system/nginx.service.d/override.conf.
# View the merged full configuration
systemctl cat nginx.service
# Reload configuration
sudo systemctl daemon-reload
sudo systemctl restart nginxSystem Management Commands
# View boot time
systemd-analyze
# View boot time per service (sorted)
systemd-analyze blame
# View the boot critical chain
systemd-analyze critical-chain
# View the current default target
systemctl get-default
# Set the default target
sudo systemctl set-default multi-user.target # Command-line mode
sudo systemctl set-default graphical.target # Graphical mode
# Shutdown and reboot
sudo systemctl poweroff
sudo systemctl reboot
# Suspend and hibernate
sudo systemctl suspend
sudo systemctl hibernateResource Limits
You can set resource limits in service unit files:
[Service]
# CPU limit
CPUQuota=50%
# Memory limit
MemoryMax=1G
MemoryHigh=800M
# I/O limit
IOWeight=100
IOReadBandwidthMax=/dev/sda 10M
# Process count limit
TasksMax=100
# File descriptor limit
LimitNOFILE=65535Troubleshooting
# View the reason a service failed
systemctl status myapp.service
journalctl -u myapp.service --no-pager -n 50
# Validate unit file syntax
systemd-analyze verify /etc/systemd/system/myapp.service
# View systemd's own logs
journalctl -b _PID=1
# Reset the failure count
sudo systemctl reset-failed myapp.serviceRelated Articles
- journalctl Log Queries — Using journalctl to view and filter systemd service logs
- Scheduled Tasks (cron) — Setting up periodic scheduled tasks with cron and systemd timers
Last updated on