Skip to content

systemd

Systemd User Environment

User-based systemd units may fail over SSH or sudo as generally a full systemd environment is not configured automatically with a non-local login.

# Export required user systemd unit environment variables.
export XDG_RUNTIME_DIR="/run/user/$(id -u)"
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"

# Enable service lingering for user.
loginctl enable-linger {USER}

~/.profile

0644 {USER}:{USER}

if [ -z "$XDG_RUNTIME_DIR" ]; then
    export XDG_RUNTIME_DIR="/run/user/$(id -u)"
    export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"
fi
# Alternatively use machinectl to spawn a fully isolated (systemd/dbus session)
# interactive shell on a given machine. Use this after SSH/sudo.
sudo machinectl shell {USER}@.host

Cron Replacement

Actively migrate cronjobs to systemd timers. They are much more flexible and provide consistency on systemd systems. These may also be deployed per-user.

job.service

0644 root:root

# Service executes the commands or script from original cronjob.
[Unit]
Description=Cronjob service example.
Requires=cron_example.timer
After=network.target
Wants=network.target

[Service]
Type=simple
ExecStart=/bin/bash -c '/usr/bin/tar -cvJf /srv/test.tar.xz" "/opt/test"'
WorkingDirectory=/opt/test
User=test_user
Group=test_user

[Install]
WantedBy=multi-user.target

job.timer

0644 root:root

# Timer acts as the scheduler allowing for fine-grained scheduling of job.
[Unit]
Description=cron_example.service timer.
Requires=cron_example.service

[Timer]
OnBootSec=1d

[Install]
WantedBy=timers.target
systemctl daemon-reload
systemctl enable job.service job.timer
systemctl start job.timer

Analyze Boot Time

Don't rabbit hole. Usually slow boot times are from connected drives and devices.

systemd-analyze plot > plot.svg

Service Security Exposure

Generate exposure threat ratings for current system services.

systemd-analyze security

.NET / Mono applications

Applications based on .NET and Mono require special handling for restarting services.

Use KillMode=control-group

KillMode=none is explicitly deprecated and will eventually be removed.

KillMode=process allows child forks to escape control group (cgroup) and remain running even while their service is considered stopped and assumed to not consume any resources.

For .NET / Mono apps that spawn sub-processes or handle in-app updates, using mixed or control-group keeps systemd's state machine tracking things correctly.

Use Restart=always

Combine with RestartSec and TimeoutStopSec to gracefully shutdown a running application, killing sub-processes after the timeout.

KillMode=control-group
Restart=always
RestartSec=5
TimeoutStopSec=20

Reference1