Systemd: Managing Services on Linux
In this tutorial, you'll learn about Systemd: Managing Services on Linux. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Systemd is the init system and service manager used by virtually every modern Linux distribution — responsible for booting the system, managing services, handling logging, and orchestrating the entire lifecycle of processes from power-on to shutdown.
What You'll Learn
- Managing services with systemctl: start, stop, enable, disable, status
- Creating custom service units for your applications
- Viewing logs with journalctl
- Using timers as a modern replacement for cron
- Understanding targets (runlevels)
- Troubleshooting failed services
Why Systemd Matters
Systemd is the foundation of modern Linux administration. Every service on a Linux system — from SSH and Docker to your custom application — is managed by systemd. Understanding systemd means you can deploy, monitor, and troubleshoot services confidently.
Durga Antivirus Pro runs as a systemd service with automatic restart on failure, logging to journald, and a hardened service configuration.
Learning Path
flowchart LR A[Linux Basics] --> B[Process Management] B --> C[Systemd Services
You are here] C --> D[Service Units] D --> E[Timers & Targets] style C fill:#f90,color:#fff
Systemctl Basics
# Service management
sudo systemctl start nginx # Start a service
sudo systemctl stop nginx # Stop a service
sudo systemctl restart nginx # Restart a service
sudo systemctl reload nginx # Reload config without restarting
sudo systemctl status nginx # Show detailed status
# Enable/disable at boot
sudo systemctl enable nginx # Start on boot
sudo systemctl disable nginx # Don't start on boot
sudo systemctl is-enabled nginx # Check if enabled
sudo systemctl enable --now nginx # Enable and start in one command
Expected systemctl status nginx output:
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2026-06-19 10:30:00 UTC
Main PID: 12345 (nginx)
Tasks: 3 (limit: 1137)
Memory: 5.2M
CGroup: /system.slice/nginx.service
├─12345 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
└─12346 nginx: worker process
Creating a Service Unit
Create a service file for your application:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Application Service
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
EnvironmentFile=-/etc/myapp/env.conf
ExecStart=/usr/bin/node /opt/myapp/server.js
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
Key Directives Explained
| Directive | Purpose |
|---|---|
After= |
Ordering — start after these units |
Wants= |
Weak dependency (not required) |
Requires= |
Strong dependency (unit fails if dependency fails) |
Type=simple |
Default — Process forks once |
Type=forking |
Process forks (daemonizes) — wait for PID file |
Type=oneshot |
Runs once and exits (for scripts) |
User=/Group= |
Run as a specific user (security best practice) |
Restart=on-failure |
Auto-restart on crash |
RestartSec=5 |
Wait 5 seconds before restart |
LimitNOFILE= |
Max open file descriptors |
Enable and Start
sudo systemctl daemon-reload # Reload unit files
sudo systemctl enable myapp # Enable at boot
sudo systemctl start myapp # Start now
sudo systemctl status myapp # Verify it's running
Journalctl (Logging)
Systemd collects all service logs via journald:
# View logs for a specific service
sudo journalctl -u myapp
# Follow logs in real time (like tail -f)
sudo journalctl -u myapp -f
# Last 50 lines
sudo journalctl -u myapp -n 50
# Logs for a specific time range
sudo journalctl -u myapp --since "1 hour ago"
sudo journalctl -u myapp --since "2026-06-19" --until "2026-06-20"
# Show only errors
sudo journalctl -u myapp -p err
# Follow all services
sudo journalctl -f
# Show boot logs
sudo journalctl -b
# Show previous boot logs
sudo journalctl -b -1
# Limit output size
sudo journalctl -u myapp --no-pager -n 100
# Export logs to file
sudo journalctl -u myapp > /tmp/myapp.log
Expected journalctl output:
Jun 19 10:30:01 server myapp[12345]: Server started on port 3000
Jun 19 10:30:01 server myapp[12345]: Connecting to database...
Jun 19 10:30:02 server myapp[12345]: Database connected
Systemd Timers
Timers are the systemd equivalent of cron, with better logging and dependency support:
# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backup
# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 2 AM
[Timer]
OnCalendar=daily
Persistent=true # Run if system was off during scheduled time
RandomizedDelaySec=300 # Random delay to avoid thundering herd
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
sudo systemctl list-timers
Expected list-timers output:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-06-20 02:00:00 15h Fri 2026-06-19 02:00:01 23h backup.timer backup.service
Targets (Runlevels)
Targets group services into boot configurations:
| Target | Purpose | Old Runlevel |
|---|---|---|
poweroff.target |
System shutdown | 0 |
rescue.target |
Single-user mode | 1 |
multi-user.target |
Multi-user, no GUI | 3 |
graphical.target |
Multi-user with GUI | 5 |
reboot.target |
Reboot | 6 |
# Check current target
systemctl get-default
# Change default (boot to CLI)
sudo systemctl set-default multi-user.target
# Switch to rescue mode
sudo systemctl rescue
# List all services in a target
systemctl list-dependencies multi-user.target
Troubleshooting Failed Services
# List failed services
systemctl --failed
# Check detailed status
sudo systemctl status failed-service
# View recent logs for a failed service
sudo journalctl -u failed-service -n 50 --no-pager
# Common checks:
# 1. Permission denied → check ExecStart path and User/Group
# 2. Port in use → check if another service is on the same port
# 3. Missing executable → verify binary exists
# 4. Environment variable not set → check Environment directives
# Reset a failed service
sudo systemctl reset-failed failed-service
Common Errors
1. Service Fails with "Permission Denied"
The User= in the service unit doesn't have execute permission on the binary or script. Check ls -l /path/to/binary and sudo -u user /path/to/binary.
2. Service Starts but Immediately Stops
The ExecStart Process exits. For services that should stay running, ensure the Process doesn't fork incorrectly. Check Type= matches your Process behavior.
3. Port Already in Use
Check with sudo ss -tlnp | grep PORT. Stop the conflicting service or change your app's port.
4. Environment Variables Not Set
EnvironmentFile=-/etc/myapp/env.conf (note the - prefix) — the - means "ignore if file doesn't exist." Double-check the path.
5. Service Not Starting at Boot
Run sudo systemctl enable myservice to create the symlink. Verify with systemctl is-enabled myservice.
6. Journalctl Shows No Logs
Ensure StandardOutput=journal and StandardError=journal are set in the service unit.
7. Service Hangs During Stop
Set TimeoutStopSec= in the service unit (default is 90 seconds). Add ExecStop= to send a proper shutdown signal.
Practice Questions
What command checks if a service is running?
sudo systemctl status servicenameWhat directive auto-restarts a service when it crashes?
Restart=on-failurein the[Service]section.How do you view real-time logs for a service?
sudo journalctl -u servicename -fWhat is the difference between
enableandstart?enableconfigures the service to start at boot.startstarts it immediately.What target should services use for non-GUI servers?
multi-user.target— it runs the system without a graphical interface.
Challenge: Create a systemd service for a Python/Node.js web application. Include: (1) a dedicated system user, (2) auto-restart on failure, (3) environment file for configuration, (4) logging to journald, (5) a timer for a companion cleanup script. Test the service starts, stops, restarts, and survives a crash.
FAQ
What's Next
| Tutorial | What You'll Learn |
|---|---|
| Cron Job Scheduling | Alternative task scheduling with cron |
| Linux Administration Basics | Foundational server management |
| Bash Scripting Guide | Writing scripts that run as systemd services |
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-19.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro