Anatomoy of systemd
Unit File
A typical systemd
unit file for a service consists of three main section:
- [Unit]: Contains metadata and dependencies.
- [Service]: Defines how the service should be managed.
- [Install]: Specifies how the unit is enable or installed.
[Unit]
Description=My Example Service
After=network.target
[Service]
ExecStart=/usr/bin/my-service
Restart=always
[Install]
WantedBy=multi-user.target
Important Directives
ExecStart
: Command to start the service.ExecStop
: Command to stop the service.Restart
: Policy for restarting the service (always
,on-failure
,on-watchdog
,on-abort
orno
).RestartSec
: Time to wait before restarting the service. (RestartSec=5s
)
[Service]
ExecStart=/usr/bin/my-service
ExecStop=/usr/bin/my-service
Restart=on-failure #only restarts when failed
RestartSec=8s #wait until 8 seconds to restart
Defining Dependencies And Order
Requires
: The unit will not start unless the listed unit is active.Wants
: The unit would like the listed unit to be active, but it’s not required.Before
: The unit should be started before the listed unit.After
: The unit should be started after the listed unit.
[Unit]
Description=My Custom Service
Requires=custom.service
After=custom.service
Before=custom.service
Adding Environment Variables
Environment
: Set environment variables directly in the unit file.EnvironmentFile
: Load environment variables from a file.
Environment
- This directive allows yout to set environment variables directly in the unit file.
- You can use it multiple times to set several variables.
[Service]
Environment="VAR1=value1"
Environment="VAR2=value2"
These variables will be available to the process started by the service.
EnvironmentFile
- This directive loads environment variables from an external file.
- The file should contain one variable per line, in the format
VAR=value
.
[Service]
EnvironmentFile=/etc/myapp/env
This is useful for sensitive data or when you want to keep variables outside the unit file.
Example
Let’s create a simple service that prints the envionment variables.
- Script:
usr/loca/bin/env.sh
in executable permissionchmod +x
!#/bin/sh
echo "VAR1 is: ${VAR1:-not set}"
echo "VAR2 is: ${VAR2:-not set}"
- Env:
/usr/myapp/env
VAR1=something1
VAR2=something2
- Create Unit File
[Unit]
Description=Shows environment values
[Service]
ExecStart=/usr/loca/bin/env.sh
#env vars; Environment
Environment="VAR1=something1"
Environment="VAR2=something2"
#env file; EnvironmentFile (use it when handling sensitive data)
EnvironmentFile=/etc/myapp/env
[Install]
WantedBy=multi-user.target
Overriding Existing Services With Drop-In Configuration
You can safely override or extend the configuration of existing services using drop-in files in the unit.service.d
/ directory.
- Using
systemctl edit
:
sudo systemctl edit sshd.service
This creates /etc/systemd/system/sshd.service.d/override.conf
where you can add or override directives.
- Manual Method:
sudo mkdir -p /etc/systemd/system/sshd.service.d
sudo nano /etc/systemd/system/sshd.service.d/custom.conf
As
systemctl edit
creates theoverride.conf
, we can manually createsshd.service.d/
and customizesshd.service.d/custom.conf
. Based on the service, we want to override
Example
- You want to change the restart policy of the
sshd.service
(the SSH daemon) so that it always restarts if it fails, without editing the original unit file. How do you achieve this using systemd drop-in files? Additionally, you want to add a custom environment variable (LOG_LEVEL=DEBUG
) for the service.
- Create drop-in directory and file
sudo systemctl edit sshd.service
# open your default editor and create a file in
# /etc/systemd/system/sshd.service.d/override.conf
- Add your overrides (In the editor, add)
Restart=always
Environment="LOG_LEVEL=DEBUG"
Alternatively, we can use a manual method to accomplish this without systemctl edit
sudo mkdir -p /etc/systemd/system/sshd.service.d/
sudo nano /etc/systemd/system/sshd.service.d/override.conf
#add this in the editor
Restart=always
Environment="LOG_LEVEL=DEBUG"
Finally, reload
and restart the service
sudo systemctl daemon-reload
sudo systemctl restart sshd.service
Verify using systemctl cat sshd.service
Write Your Own Service Unit Files:
- How do you create and configure a
systemd
unit file to run this script as a service, ensuring it start after the network is available and restarts automatically if it fails?
- script =
/usr/loca/bin/myscript.sh
(this simply greets when executed!) - run this as a system service, managed by
systemd
- Write a service in
/etc/systemd/system/script-start.service
:
[Unit]
Description=Service to start the greet script
After=network.target
[Service]
ExecStart=/usr/local/bin/myscript.sh
Restart=Always
[Install]
WantedBy=multi-user.target
[Unit]
Description=Service to start the greet script
- Human readable description
After=network.target
- Specifies that this service should start only after the
network.target
unit is active, ensuring the network is available before your script runs.
- Specifies that this service should start only after the
[Service]
ExecStart=/usr/local/bin/myscript.sh
- The above script will be executed to start the service.
Restart=Always
- Sets the restart policy so that the service will always be restarted if it stops for any reason.
[Install]
WantedBy=multi-user.target
- Specifies that this service should be started when the system reaches the
multi-user.target
state, which is standard state for a multi-user system after reboot. - In simple terms,
systemd
creates a symbolic link so your service start at boot when yousystemctl enable script-start.service
.
- Specifies that this service should be started when the system reaches the
- How do you set environment variables in the systemd unit file, and what directive should you use?
- Variable required by the script
GREETING="Hello, systemd!"
.
!#/bin/sh
echo "$GREETING"
Make sure to give
execute
permission to this script.
[Unit]
Description=Add env variable to service
[Service]
Environment="GREENTING=Hello, World!"
ExecStart=/usr/local/bin/greet.sh
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
reload the services for the new service to take effect.sudo systemctl enable greet.service
to start the service at boot.sudo systemctl start greet.service
to start for the current boot only.