HxHippy

Systemd Service Management

Control system services with systemctl, create custom services, and understand systemd.

Last updated: 2024-12-18

Systemd is the init system and service manager for most modern Linux distributions. Master systemctl to control your system.

Service Control

Basic Commands

# Start a service
sudo systemctl start nginx

# Stop a service
sudo systemctl stop nginx

# Restart a service
sudo systemctl restart nginx

# Reload configuration (if supported)
sudo systemctl reload nginx

# Reload or restart (safer)
sudo systemctl reload-or-restart nginx

# Enable at boot
sudo systemctl enable nginx

# Disable at boot
sudo systemctl disable nginx

# Enable and start
sudo systemctl enable --now nginx

# Disable and stop
sudo systemctl disable --now nginx

Service Status

# Check status
systemctl status nginx

# Check if running
systemctl is-active nginx

# Check if enabled
systemctl is-enabled nginx

# Check if failed
systemctl is-failed nginx

# List all services
systemctl list-units --type=service

# List running services
systemctl list-units --type=service --state=running

# List failed services
systemctl --failed

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

Understanding Unit Files

Unit File Locations

/etc/systemd/system/     # Local configuration (highest priority)
/run/systemd/system/     # Runtime units
/lib/systemd/system/     # Distribution-provided units
/usr/lib/systemd/system/ # Package-installed units (RHEL)

Basic Service Unit

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application
After=network.target

[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/start.sh
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Unit Sections

[Unit]

[Unit]
Description=Human-readable description
Documentation=https://example.com/docs
After=network.target postgresql.service
Requires=postgresql.service    # Hard dependency
Wants=redis.service           # Soft dependency

[Service]

[Service]
Type=simple          # Main process stays in foreground
# Type=forking       # Traditional daemon (forks)
# Type=oneshot       # Short-lived task
# Type=notify        # Sends notification when ready

ExecStartPre=/opt/myapp/pre-start.sh
ExecStart=/opt/myapp/start.sh
ExecStartPost=/opt/myapp/post-start.sh
ExecStop=/opt/myapp/stop.sh
ExecReload=/bin/kill -HUP $MAINPID

User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp

Environment="NODE_ENV=production"
EnvironmentFile=/etc/myapp/env

Restart=on-failure
RestartSec=5
TimeoutStartSec=30
TimeoutStopSec=30

[Install]

[Install]
WantedBy=multi-user.target  # Start in multi-user mode
# WantedBy=graphical.target # Start in graphical mode

Creating Custom Services

Simple Web Application

# /etc/systemd/system/webapp.service
[Unit]
Description=Node.js Web Application
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/myapp
ExecStart=/usr/bin/node /var/www/myapp/server.js
Restart=on-failure
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=webapp
Environment=NODE_ENV=production PORT=3000

[Install]
WantedBy=multi-user.target

With Environment File

# /etc/systemd/system/myapp.service
[Unit]
Description=My Application

[Service]
Type=simple
User=appuser
EnvironmentFile=/etc/myapp/.env
ExecStart=/opt/myapp/bin/start
Restart=always

[Install]
WantedBy=multi-user.target
# /etc/myapp/.env
DATABASE_URL=postgresql://localhost/mydb
SECRET_KEY=your-secret-key
DEBUG=false

Enabling the Service

# Reload systemd to read new unit
sudo systemctl daemon-reload

# Enable and start
sudo systemctl enable --now myapp

# Check status
systemctl status myapp

# View logs
journalctl -u myapp -f

Service Security Hardening

[Service]
# User/Group
User=appuser
Group=appgroup
DynamicUser=true  # Allocate user dynamically

# Filesystem restrictions
ProtectSystem=strict           # Mount /usr, /boot read-only
ProtectHome=true              # Hide /home, /root, /run/user
PrivateTmp=true               # Private /tmp
ReadWritePaths=/var/lib/myapp  # Allow write here
ReadOnlyPaths=/etc/myapp       # Read-only access

# Network restrictions
PrivateNetwork=true           # No network access
RestrictAddressFamilies=AF_INET AF_INET6  # IPv4/6 only

# System call restrictions
SystemCallFilter=@system-service  # Whitelist system calls
SystemCallArchitectures=native    # Native arch only

# Other restrictions
NoNewPrivileges=true          # No privilege escalation
ProtectKernelTunables=true    # Protect /proc, /sys
ProtectControlGroups=true     # Protect cgroups

Journalctl (Logs)

# View logs for a service
journalctl -u nginx

# Follow logs (tail -f)
journalctl -u nginx -f

# Since boot
journalctl -u nginx -b

# Last 100 lines
journalctl -u nginx -n 100

# Since time
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2024-01-01 00:00:00"

# Priority (error and above)
journalctl -u nginx -p err

# Output as JSON
journalctl -u nginx -o json

# Disk usage
journalctl --disk-usage

# Clear old logs
sudo journalctl --vacuum-time=7d
sudo journalctl --vacuum-size=500M

System Targets

# List targets
systemctl list-units --type=target

# Get current target
systemctl get-default

# Set default target
sudo systemctl set-default multi-user.target  # Text mode
sudo systemctl set-default graphical.target   # GUI mode

# Change target now
sudo systemctl isolate multi-user.target

# Common targets:
# poweroff.target  - Shutdown
# rescue.target    - Single user / rescue mode
# multi-user.target - Multi-user text mode
# graphical.target - GUI mode
# reboot.target    - Reboot

Analyzing Boot

# Analyze boot time
systemd-analyze

# Blame (time per service)
systemd-analyze blame

# Critical chain (boot path)
systemd-analyze critical-chain

# Plot boot chart
systemd-analyze plot > boot.svg
intermediate System Administration 25 min read

Related Tutorials

systemdsystemctlserviceslinux servicesinit system