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:
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
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
andGroup
: 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.
-
Reload the systemd manager configuration to apply the new service:
sudo systemctl daemon-reload
Enable the service to start on boot:
sudo systemctl enable myscript.service
Start the service immediately:
sudo systemctl start myscript.service
Verify that the service is running correctly:
sudo systemctl status myscript.service
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"
By default, systemd logs the service output to the journal. You can view these logs using:
journalctl -u myscript.service
You can specify dependencies to ensure services start in the correct order:
[Unit]
Requires=other.service
After=other.service
Customize the timeout and restart behavior:
[Service]
TimeoutStartSec=30
Restart=always
RestartSec=5
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.
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:
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
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
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
-
[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 themain
executable withsudo
. -
Restart
: Defines the restart behavior.on-failure
restarts the service only if it fails. -
User
andGroup
: Specifies theroot
user and group sincesudo
is used. Directly usingUser=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.
-
Reload the systemd manager configuration to apply the new service:
sudo systemctl daemon-reload
Enable the service to start on boot:
sudo systemctl enable main.service
Start the service immediately:
sudo systemctl start main.service
Verify that the service is running correctly:
sudo systemctl status main.service
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:
-
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
-
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
-
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
-
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
-
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
-
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
-
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
In addition to the Restart
option, systemd provides several other settings to fine-tune the restart behavior:
-
RestartSec
- Description: Specifies the delay between restart attempts.
-
Example: A 5-second delay before restarting:
RestartSec=5
-
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
-
TimeoutStartSec
- Description: Specifies the maximum time to wait for the service to start.
-
Example: A 30-second timeout:
TimeoutStartSec=30
-
TimeoutStopSec
- Description: Specifies the maximum time to wait for the service to stop.
-
Example: A 30-second timeout:
TimeoutStopSec=30
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
).
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:
-
Ensure your program uses standard output (
stdout
) and standard error (stderr
) for itsprintf
and error messages. In a typical C++ program, you might usestd::cout
andstd::cerr
for logging. -
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.
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
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
- StandardOutput=journal: Directs standard output to the systemd journal.
- StandardError=journal: Directs standard error to the systemd journal.
-
Reload the systemd daemon to apply the new service:
sudo systemctl daemon-reload
-
Enable the service to start on boot:
sudo systemctl enable main.service
-
Start the service immediately:
sudo systemctl start main.service
-
Check the service status to ensure it is running:
sudo systemctl status main.service
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.
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
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
To manage log file sizes, use logrotate
.
-
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
}
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.