Run programs at startup (Linux) by Systemd Service - GitMasterNikanjam/C_WiKi GitHub Wiki

Systemd is a powerful and versatile system and service manager for Linux operating systems. Using systemd to manage services provides better control over the startup process, including dependency management, monitoring, and logging. Here's a more detailed guide on creating and managing systemd services:

Steps to Create and Manage a Systemd Service

1. Create a Script or Program

Prepare the script or program you want to run at startup. Ensure it has the necessary execute permissions.

Example script (/usr/local/bin/myscript.sh):

#!/bin/bash
echo "My script is running" >> /var/log/myscript.log

Make it executable:

sudo chmod +x /usr/local/bin/myscript.sh

2. Create a Systemd Service Unit File

Create a service unit file in /etc/systemd/system/. The filename should have a .service extension.

Example service unit file (/etc/systemd/system/myscript.service):

[Unit]
Description=My Custom Script
After=network.target

[Service]
ExecStart=/usr/local/bin/myscript.sh
Restart=on-failure
User=myuser
Group=mygroup

[Install]
WantedBy=multi-user.target

Explanation:

  • [Unit]
    • Description: A brief description of the service.
    • After: Defines the ordering of service startup. network.target ensures the network is up before starting the service.
  • [Service]
    • ExecStart: The command to run the script or program.
    • Restart: Defines the restart behavior. on-failure restarts the service only if it fails.
    • User and Group: Specifies the user and group under which the service will run.
  • [Install]
    • WantedBy: Specifies the target that this service should be started under. multi-user.target is common for most user services.

3. Reload systemd Daemon

Reload the systemd manager configuration to apply the new service:

sudo systemctl daemon-reload

4. Enable the Service

Enable the service to start on boot:

sudo systemctl enable myscript.service

5. Start the Service

Start the service immediately:

sudo systemctl start myscript.service

6. Check the Service Status

Verify that the service is running correctly:

sudo systemctl status myscript.service

Advanced Systemd Service Configuration

Environment Variables

To set environment variables for your service, use the Environment directive in the [Service] section:

[Service]
Environment="VAR_NAME=value"
Environment="PATH=/usr/local/bin:/usr/bin"

Logging

By default, systemd logs the service output to the journal. You can view these logs using:

journalctl -u myscript.service

Dependencies

You can specify dependencies to ensure services start in the correct order:

[Unit]
Requires=other.service
After=other.service

Timeout and Restart

Customize the timeout and restart behavior:

[Service]
TimeoutStartSec=30
Restart=always
RestartSec=5

Conclusion

Using systemd to manage startup programs is a robust solution for ensuring your applications run correctly and efficiently. It offers extensive features for dependency management, logging, and service monitoring, making it the preferred choice for managing system and user services on modern Linux distributions.


Example:

To run a C++ executable file named main at startup using systemd, ensuring it starts after the network is up and runs with elevated permissions (using sudo), follow these steps:

Step 1: Place the Executable

Ensure your main executable is placed in a directory with appropriate permissions. For this example, we will place it in /usr/local/bin.

sudo cp /path/to/main /usr/local/bin/main
sudo chmod +x /usr/local/bin/main

Step 2: Create a Systemd Service Unit File

Create a service unit file in /etc/systemd/system/. The filename should have a .service extension. We'll name it main.service.

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

Step 3: Edit the Service Unit File

Add the following content to the main.service file:

[Unit]
Description=Run C++ executable at startup
After=network.target

[Service]
ExecStart=sudo /usr/local/bin/main
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

Explanation:

  • [Unit]

    • Description: A brief description of the service.
    • After: Ensures the network is up before starting the service (network.target).
  • [Service]

    • ExecStart: The command to run the main executable with sudo.
    • Restart: Defines the restart behavior. on-failure restarts the service only if it fails.
    • User and Group: Specifies the root user and group since sudo is used. Directly using User=root runs the command with root privileges.
  • [Install]

    • WantedBy: Specifies the target that this service should be started under. multi-user.target is common for most user services.

Step 4: Reload systemd Daemon

Reload the systemd manager configuration to apply the new service:

sudo systemctl daemon-reload

Step 5: Enable the Service

Enable the service to start on boot:

sudo systemctl enable main.service

Step 6: Start the Service

Start the service immediately:

sudo systemctl start main.service

Step 7: Check the Service Status

Verify that the service is running correctly:

sudo systemctl status main.service

Viewing Logs

To view the logs generated by the service, use:

journalctl -u main.service

By following these steps, your C++ executable main will run at startup with root privileges, ensuring that it starts after the network is available.


Systemd provides various restart options that control how and when a service should be restarted. These options can be specified in the [Service] section of the service unit file. Here’s a detailed explanation of the different restart options available:

Restart Options

  1. no

    • Description: The service will not be restarted under any circumstances.
    • Use Case: When the service should run only once and should not be restarted even if it fails.
    • Example:
      Restart=no
  2. on-success

    • Description: The service will be restarted only if it exits with a successful exit status (i.e., exit code 0).
    • Use Case: Rarely used, as successful completion typically does not require a restart.
    • Example:
      Restart=on-success
  3. on-failure

    • Description: The service will be restarted if it exits with a non-zero exit status, is terminated by a signal, or times out.
    • Use Case: For services that should be restarted if they fail unexpectedly.
    • Example:
      Restart=on-failure
  4. on-abnormal

    • Description: The service will be restarted if it is terminated by a signal (not via the usual exit status codes).
    • Use Case: For services that should be restarted if they are killed or crash due to a signal.
    • Example:
      Restart=on-abnormal
  5. on-abort

    • Description: The service will be restarted only if it is terminated by a signal from the system (usually SIGABRT).
    • Use Case: For debugging or handling specific abnormal terminations.
    • Example:
      Restart=on-abort
  6. on-watchdog

    • Description: The service will be restarted if the watchdog timeout is triggered.
    • Use Case: Used with watchdog-enabled services that require monitoring and restart upon failure to signal within a defined interval.
    • Example:
      Restart=on-watchdog
  7. always

    • Description: The service will be restarted regardless of how it exits (whether it exits successfully or fails).
    • Use Case: For services that need to run continuously and be restarted under any condition.
    • Example:
      Restart=always

Additional Restart Settings

In addition to the Restart option, systemd provides several other settings to fine-tune the restart behavior:

  1. RestartSec

    • Description: Specifies the delay between restart attempts.
    • Example: A 5-second delay before restarting:
      RestartSec=5
  2. StartLimitInterval and StartLimitBurst

    • Description: These options control the rate limiting of service restarts.
    • Use Case: To prevent a service from entering a restart loop.
    • Example: Allow up to 5 restarts within a 10-minute interval:
      StartLimitInterval=10min
      StartLimitBurst=5
  3. TimeoutStartSec

    • Description: Specifies the maximum time to wait for the service to start.
    • Example: A 30-second timeout:
      TimeoutStartSec=30
  4. TimeoutStopSec

    • Description: Specifies the maximum time to wait for the service to stop.
    • Example: A 30-second timeout:
      TimeoutStopSec=30

Example Service Unit File

Here’s an example systemd service unit file for running the main executable, with restart options configured to restart on failure and a 10-second delay between restarts:

[Unit]
Description=Run C++ executable at startup
After=network.target

[Service]
ExecStart=sudo /usr/local/bin/main
Restart=on-failure
RestartSec=10
User=root
Group=root

[Install]
WantedBy=multi-user.target

In this example:

  • The service will be restarted if it fails (Restart=on-failure).
  • There will be a 10-second delay before attempting to restart the service (RestartSec=10).

Conclusion

Using the various restart options provided by systemd, you can control the behavior of your services in detail, ensuring they are resilient and can recover from different types of failures automatically. This is particularly useful for critical services that need to maintain high availability.


To capture and manage the output of your program's printf statements (or other output to standard output and error), you can use systemd's logging capabilities, as well as direct logging to specific files if needed. Here’s a detailed guide on how to set this up:

Logging Program Output with Systemd

  1. Ensure your program uses standard output (stdout) and standard error (stderr) for its printf and error messages. In a typical C++ program, you might use std::cout and std::cerr for logging.

  2. Create a systemd service unit file for your executable. You can direct the output to various destinations such as the system journal, a specific file, or even syslog.

Example Program

Here’s a simple C++ program (main.cpp) that logs messages:

#include <iostream>
#include <chrono>
#include <thread>

int main() {
    while (true) {
        std::cout << "This is a log message to stdout" << std::endl;
        std::cerr << "This is a log message to stderr" << std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(5));
    }
    return 0;
}

Compile the program:

g++ main.cpp -o /usr/local/bin/main

Systemd Service Unit File

Create the service unit file /etc/systemd/system/main.service:

[Unit]
Description=Run C++ executable at startup
After=network.target

[Service]
ExecStart=/usr/local/bin/main
StandardOutput=journal
StandardError=journal
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

Explanation

  • StandardOutput=journal: Directs standard output to the systemd journal.
  • StandardError=journal: Directs standard error to the systemd journal.

Steps to Apply the Configuration

  1. Reload the systemd daemon to apply the new service:

    sudo systemctl daemon-reload
  2. Enable the service to start on boot:

    sudo systemctl enable main.service
  3. Start the service immediately:

    sudo systemctl start main.service
  4. Check the service status to ensure it is running:

    sudo systemctl status main.service

Viewing Logs

Use journalctl to view the logs captured by systemd:

journalctl -u main.service

This command shows all logs for the main.service. You can filter by time or other criteria as needed.

Logging to a Specific File

If you prefer to log to a specific file instead of the systemd journal, you can modify the StandardOutput and StandardError directives.

Example Service Unit File to Log to a Specific File:

[Unit]
Description=Run C++ executable at startup
After=network.target

[Service]
ExecStart=/usr/local/bin/main
StandardOutput=file:/var/log/main.log
StandardError=file:/var/log/main_error.log
Restart=on-failure
User=root
Group=root

[Install]
WantedBy=multi-user.target

Ensure Log Files Are Writable

Make sure the log files and their directories are writable by the service user (root in this case):

sudo touch /var/log/main.log /var/log/main_error.log
sudo chown root:root /var/log/main.log /var/log/main_error.log
sudo chmod 644 /var/log/main.log /var/log/main_error.log

Log Rotation

To manage log file sizes, use logrotate.

  1. Create a logrotate configuration file for your logs in /etc/logrotate.d/.

Example logrotate configuration (/etc/logrotate.d/main):

/var/log/main.log /var/log/main_error.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    create 0644 root root
    postrotate
        systemctl reload main.service > /dev/null 2>&1 || true
    endscript
}

Conclusion

By configuring systemd to capture the standard output and error of your program, you can ensure that all printf statements and other logging output are managed effectively. You can choose to send logs to the system journal or specific files, depending on your needs. Using tools like journalctl and logrotate, you can easily monitor and manage these logs.

⚠️ **GitHub.com Fallback** ⚠️