Systemd Service Management: Modern Init System for CentOS/RHEL

Tyler Maginnis | February 18, 2024

systemdCentOSRHELservicesinitsystem management

Need Professional CentOS/RHEL Support?

Get expert assistance with your centos/rhel support implementation and management. Tyler on Tech Louisville provides priority support for Louisville businesses.

Same-day service available for Louisville area

Systemd Service Management: Modern Init System for CentOS/RHEL

Systemd is the modern init system and service manager for CentOS/RHEL. This guide covers service management, unit file creation, system targets, timers, and advanced systemd features.

Systemd Fundamentals

Basic Service Management

Essential systemctl commands:

# Check service status
systemctl status nginx
systemctl status sshd.service

# Start/stop services
systemctl start httpd
systemctl stop mariadb

# Enable/disable services
systemctl enable nginx
systemctl disable firewalld

# Restart/reload services
systemctl restart httpd
systemctl reload nginx

# Check if service is active
systemctl is-active sshd
systemctl is-enabled nginx

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

Service Dependencies

Manage service relationships:

# Show service dependencies
systemctl list-dependencies nginx
systemctl list-dependencies --all httpd

# Show reverse dependencies
systemctl list-dependencies --reverse sshd

# Show service requirements
systemctl show nginx -p Requires
systemctl show httpd -p Wants -p After -p Before

Unit File Configuration

Creating Custom Service Units

Create systemd service files:

# Basic service unit file
cat > /etc/systemd/system/myapp.service <<EOF
[Unit]
Description=My Application Service
Documentation=https://docs.example.com
After=network.target
Wants=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStartPre=/usr/bin/test -f /opt/myapp/config.yml
ExecStart=/usr/bin/myapp --config /opt/myapp/config.yml
ExecReload=/bin/kill -HUP \$MAINPID
ExecStop=/bin/kill -TERM \$MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=myapp

[Install]
WantedBy=multi-user.target
EOF

# Reload systemd configuration
systemctl daemon-reload

# Enable and start service
systemctl enable --now myapp.service

Advanced Service Types

Configure different service types:

# Forking service
cat > /etc/systemd/system/legacy-app.service <<EOF
[Unit]
Description=Legacy Forking Application
After=network.target

[Service]
Type=forking
PIDFile=/var/run/legacy-app.pid
ExecStart=/usr/sbin/legacy-app --daemon
ExecStop=/usr/sbin/legacy-app --stop
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

# Oneshot service
cat > /etc/systemd/system/backup.service <<EOF
[Unit]
Description=System Backup
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
RemainAfterExit=yes
StandardOutput=journal

[Install]
WantedBy=multi-user.target
EOF

# Notify service
cat > /etc/systemd/system/advanced-app.service <<EOF
[Unit]
Description=Advanced Application with Notification
After=network-online.target

[Service]
Type=notify
NotifyAccess=main
ExecStart=/usr/bin/advanced-app
WatchdogSec=30
Restart=on-failure
RestartPreventExitStatus=SIGTERM

[Install]
WantedBy=multi-user.target
EOF

System Targets

Managing System States

Work with systemd targets:

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

# Get default target
systemctl get-default

# Set default target
systemctl set-default multi-user.target
systemctl set-default graphical.target

# Switch to target
systemctl isolate multi-user.target
systemctl isolate rescue.target

# Create custom target
cat > /etc/systemd/system/maintenance.target <<EOF
[Unit]
Description=Maintenance Mode
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
EOF

Boot Targets

Configure boot behavior:

# Emergency mode
systemctl emergency

# Rescue mode
systemctl rescue

# Reboot to specific target
systemctl reboot --boot-loader-entry=maintenance

# Configure target dependencies
systemctl add-wants multi-user.target myapp.service
systemctl add-requires graphical.target display-manager.service

Systemd Timers

Creating Timer Units

Schedule tasks with timers:

# Create timer unit
cat > /etc/systemd/system/backup.timer <<EOF
[Unit]
Description=Daily Backup Timer
Requires=backup.service

[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true

[Install]
WantedBy=timers.target
EOF

# Complex timer schedules
cat > /etc/systemd/system/maintenance.timer <<EOF
[Unit]
Description=System Maintenance Timer

[Timer]
OnBootSec=10min
OnUnitActiveSec=1w
OnCalendar=Mon *-*-* 02:00:00
RandomizedDelaySec=30min

[Install]
WantedBy=timers.target
EOF

# Enable timer
systemctl enable --now backup.timer

# List active timers
systemctl list-timers --all

Timer Examples

Real-world timer configurations:

# Hourly job
cat > /etc/systemd/system/hourly-task.timer <<EOF
[Unit]
Description=Hourly Task

[Timer]
OnCalendar=hourly
Persistent=true

[Install]
WantedBy=timers.target
EOF

# Custom schedule
cat > /etc/systemd/system/custom-schedule.timer <<EOF
[Unit]
Description=Custom Schedule Timer

[Timer]
# Run at 2:30 AM every Monday and Thursday
OnCalendar=Mon,Thu *-*-* 02:30:00
# Run every 6 hours
OnUnitActiveSec=6h
# Run 15 minutes after boot
OnBootSec=15min

[Install]
WantedBy=timers.target
EOF

Resource Control

CPU and Memory Limits

Control service resources:

# Set resource limits in service file
cat > /etc/systemd/system/resource-limited.service <<EOF
[Unit]
Description=Resource Limited Service

[Service]
Type=simple
ExecStart=/usr/bin/app
# CPU limits
CPUQuota=50%
CPUWeight=50
# Memory limits
MemoryLimit=512M
MemoryMax=1G
# IO limits
IOWeight=10
BlockIOWeight=10

[Install]
WantedBy=multi-user.target
EOF

# Runtime resource control
systemctl set-property nginx.service CPUQuota=25%
systemctl set-property httpd.service MemoryLimit=1G

# Show resource usage
systemd-cgtop
systemctl status nginx.service | grep -E "Memory:|CPU:"

Cgroup Management

Advanced cgroup configuration:

# Configure cgroup hierarchy
cat >> /etc/systemd/system/myapp.service <<EOF
[Service]
Slice=myapp.slice
Delegate=yes
TasksMax=100
EOF

# Create custom slice
cat > /etc/systemd/system/myapp.slice <<EOF
[Unit]
Description=My Application Slice
Before=slices.target

[Slice]
CPUQuota=200%
MemoryMax=4G
IOWeight=100
EOF

Security Features

Service Sandboxing

Implement security restrictions:

# Secure service configuration
cat > /etc/systemd/system/secure-app.service <<EOF
[Unit]
Description=Secure Application

[Service]
Type=simple
ExecStart=/usr/bin/secure-app
User=appuser
Group=appgroup

# Filesystem protection
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/secure-app
TemporaryFileSystem=/var:ro

# Network isolation
PrivateNetwork=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6

# System call filtering
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

# Capability restrictions
NoNewPrivileges=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# Device access
PrivateDevices=yes
DevicePolicy=closed

[Install]
WantedBy=multi-user.target
EOF

Dynamic Users

Use dynamic user allocation:

# Service with dynamic user
cat > /etc/systemd/system/dynamic-app.service <<EOF
[Unit]
Description=Application with Dynamic User

[Service]
Type=simple
ExecStart=/usr/bin/app
DynamicUser=yes
StateDirectory=app
CacheDirectory=app
LogsDirectory=app
ConfigurationDirectory=app

[Install]
WantedBy=multi-user.target
EOF

Logging and Debugging

Journal Management

Work with systemd journal:

# View service logs
journalctl -u nginx.service
journalctl -u sshd -f

# Time-based filtering
journalctl --since "2023-01-01" --until "2023-12-31"
journalctl --since "1 hour ago"
journalctl --since today

# Priority filtering
journalctl -p err
journalctl -p warning..err

# Boot logs
journalctl -b
journalctl -b -1  # Previous boot
journalctl --list-boots

# Export logs
journalctl -u nginx --output=json > nginx-logs.json
journalctl -u httpd --output=export | systemd-journal-remote -o /tmp/httpd.journal

Debug Service Issues

Troubleshoot service problems:

# Enable debug logging
systemctl edit myapp.service
# Add under [Service]:
# Environment="SYSTEMD_LOG_LEVEL=debug"

# Analyze service startup
systemd-analyze verify myapp.service
systemd-analyze security myapp.service

# Check service environment
systemctl show-environment
systemctl show myapp.service --property=Environment

# Debug boot issues
systemd-analyze
systemd-analyze blame
systemd-analyze critical-chain
systemd-analyze plot > boot.svg

Advanced Features

Socket Activation

Implement on-demand service startup:

# Create socket unit
cat > /etc/systemd/system/myapp.socket <<EOF
[Unit]
Description=My App Socket

[Socket]
ListenStream=8080
Accept=no

[Install]
WantedBy=sockets.target
EOF

# Modify service for socket activation
cat >> /etc/systemd/system/myapp.service <<EOF
[Unit]
Requires=myapp.socket
After=myapp.socket

[Service]
StandardInput=socket
StandardOutput=socket
EOF

Path Monitoring

Monitor filesystem changes:

# Create path unit
cat > /etc/systemd/system/monitor-uploads.path <<EOF
[Unit]
Description=Monitor Upload Directory

[Path]
PathChanged=/var/uploads
MakeDirectory=yes
DirectoryMode=0755

[Install]
WantedBy=multi-user.target
EOF

# Associated service
cat > /etc/systemd/system/monitor-uploads.service <<EOF
[Unit]
Description=Process Uploaded Files

[Service]
Type=oneshot
ExecStart=/usr/local/bin/process-uploads.sh
EOF

Template Units

Creating Service Templates

Build reusable service templates:

# Template service file
cat > /etc/systemd/system/webapp@.service <<EOF
[Unit]
Description=Web Application %i
After=network.target

[Service]
Type=simple
User=webapp-%i
Group=webapp-%i
WorkingDirectory=/var/www/%i
ExecStart=/usr/bin/webapp --instance %i --port %i
Restart=always

[Install]
WantedBy=multi-user.target
EOF

# Use template instances
systemctl enable webapp@8081.service
systemctl enable webapp@8082.service
systemctl start webapp@8081.service

System Maintenance

Service Migration

Migrate from SysV init scripts:

# Convert init script to systemd
cat > /etc/systemd/system/legacy.service <<EOF
[Unit]
Description=Legacy Service
After=network.target

[Service]
Type=forking
ExecStart=/etc/init.d/legacy start
ExecStop=/etc/init.d/legacy stop
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

# Disable old init script
chkconfig legacy off
systemctl enable legacy.service

Systemd Housekeeping

Maintain systemd health:

# Clean up journal
journalctl --vacuum-time=1M
journalctl --vacuum-size=500M

# Remove failed units
systemctl reset-failed

# Reload all unit files
systemctl daemon-reexec

# Check for masked units
systemctl list-unit-files --state=masked

# Find broken symlinks
find /etc/systemd/system -xtype l -print

Best Practices

Service Design Guidelines

  1. Use appropriate service types
  2. Implement proper dependencies
  3. Configure restart policies
  4. Set resource limits
  5. Enable security features
  6. Use template units for similar services
  7. Document unit files thoroughly

Monitoring Script

#!/bin/bash
# Systemd service monitoring

echo "=== Systemd Service Health Check ==="

# Failed services
failed=$(systemctl list-units --failed --no-legend | wc -l)
echo "Failed services: $failed"

if [ $failed -gt 0 ]; then
    systemctl list-units --failed
fi

# Services in degraded state
degraded=$(systemctl is-system-running)
echo "System state: $degraded"

# High resource usage
echo -e "\nTop 5 CPU consuming services:"
systemd-cgtop -n 1 -b | head -n 6

# Recent service failures
echo -e "\nRecent service failures:"
journalctl -p err -since "1 hour ago" --no-pager | grep -E "Failed|Error" | tail -5

Conclusion

Systemd provides powerful service management capabilities for CentOS/RHEL systems. Master unit files, timers, resource control, and security features to build robust and efficient system services. Regular monitoring and proper configuration ensure reliable service operation in production environments.