Skip to content

Managing Your Program as a Systemd Daemon

Introduction

Systemd is the standard init system for many Linux distributions, including Raspberry Pi OS. It provides a powerful way to manage services (daemons) on your system, ensuring they start automatically at boot, restart if they fail, and can be controlled using simple commands.

This guide will show you how to configure your custom-built program as a systemd service, allowing it to run reliably as a background process.

Why Use Systemd for Service Management?

Converting your program into a systemd service offers several advantages:

  • Automatic startup during system boot
  • Dependency management to ensure services start in correct order
  • Automatic restart if your program crashes
  • Resource control including memory and CPU limits
  • Standardized logging through journald
  • Simple management with the systemctl command

Step-by-Step Service Configuration

1. Prepare Your Program

Ensure your program: - Is fully built and executable - Has appropriate permissions - Can run without user interaction - Properly handles signals (SIGTERM, SIGINT) for clean shutdown

2. Create a Service Unit File

Create a systemd service definition file:

sudo nano /etc/systemd/system/myprogram.service

3. Configure the Service Definition

Add the following configuration (customize as needed):

[Unit]
Description=My Custom Program Service
After=network.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/myprogram
ExecStart=/home/pi/myprogram/myprogram
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Important fields explained:

  • Description: Human-readable description of your service
  • After: Specifies that this service should start after the specified unit(s)
  • Type: How systemd should manage the service (simple, forking, oneshot, etc.)
  • User: The user account that runs the service
  • WorkingDirectory: The working directory for the process
  • ExecStart: Full path to your executable with any arguments
  • Restart: When the service should be restarted (always, on-failure, on-abnormal, etc.)
  • WantedBy: Defines which target (runlevel equivalent) should include this service

4. Reload Systemd and Enable the Service

After creating the unit file:

1
2
3
4
5
6
7
8
# Reload systemd to recognize the new service
sudo systemctl daemon-reload

# Enable the service to start at boot
sudo systemctl enable myprogram.service

# Start the service now
sudo systemctl start myprogram.service

Managing Your Service

Basic systemctl Commands

# Check service status
sudo systemctl status myprogram.service

# Stop the service
sudo systemctl stop myprogram.service

# Start the service
sudo systemctl start myprogram.service

# Restart the service
sudo systemctl restart myprogram.service

# Reload the service configuration (if supported by your program)
sudo systemctl reload myprogram.service

# Disable automatic start at boot
sudo systemctl disable myprogram.service

Viewing Service Logs

1
2
3
4
5
6
7
8
# View recent logs for your service
journalctl -u myprogram.service

# Follow logs in real-time
journalctl -u myprogram.service -f

# View logs since last boot
journalctl -u myprogram.service -b

Advanced Configuration Options

Environment Variables

If your program needs environment variables:

1
2
3
4
5
[Service]
Environment="VAR1=value1"
Environment="VAR2=value2"
# Or load from a file:
EnvironmentFile=/etc/myprogram/env

Limiting Resources

1
2
3
4
5
[Service]
# Limit CPU usage (10% of one core)
CPUQuota=10%
# Limit memory usage (100MB)
MemoryLimit=100M

Dependencies

1
2
3
4
5
[Unit]
# Start after these services
After=network.target mysql.service
# Require these services to be running
Requires=mysql.service

Troubleshooting

If your service fails to start:

  1. Check the status for error messages:

    systemctl status myprogram.service
    
  2. Check the logs:

    journalctl -u myprogram.service -e
    
  3. Verify your executable runs correctly when launched manually

  4. Check permissions:

    • Your executable needs execute permission (chmod +x)
    • Service file should be 644 (chmod 644 /etc/systemd/system/myprogram.service)
  5. Validate systemd file syntax:

    systemd-analyze verify myprogram.service
    

Example: Python Web Application Service

Here's a complete example for a Python Flask application:

[Unit]
Description=Flask Web Application
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi/mywebapp
ExecStart=/usr/bin/python3 /home/pi/mywebapp/app.py
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
Environment="FLASK_ENV=production"
Environment="PORT=5000"

[Install]
WantedBy=multi-user.target

Conclusion

Converting your program into a systemd service ensures it runs reliably on your Raspberry Pi, automatically starts on boot, and can be easily managed with standard commands. This approach is ideal for home automation projects, servers, IoT applications, and any other software that needs to run continuously in the background.

By leveraging systemd's features for process management, logging, and resource control, you can create robust deployments that recover from failures and provide consistent operation with minimal maintenance.