Systemd Service Cheat Sheet
Rich minimal service template
[Unit]
Description=My Example Service
Documentation=https://example.com/docs
# What must be up before we start (ordering only)
After=network-online.target
# What we logically belong to (pulls in if that target starts us)
Wants=network-online.target
[Service]
# Basic behavior
Type=simple # simple | exec | notify | forking | oneshot | idle
ExecStart=/usr/bin/my-app --flag1 --flag2
# ExecStartPre=/usr/bin/env echo "About to start my-app"
# ExecStartPost=/usr/bin/env echo "my-app started"
# ExecStop=/usr/bin/pkill my-app
# ExecReload=/bin/kill -HUP $MAINPID
# Runtime user/group (system unit)
User=myuser # omit for root, or change to a dedicated service user
Group=myuser
# Working directory, environment
WorkingDirectory=/var/lib/my-app
Environment="ENVIRONMENT=production" "LOG_LEVEL=info"
# EnvironmentFile=-/etc/my-app/my-app.env # "-" means optional
# Restart behavior
Restart=on-failure # no | on-success | on-failure | on-abnormal | on-watchdog | always
RestartSec=5s
# Resource limits / hardening (pick what fits)
# Nice=5
# LimitNOFILE=65535
# NoNewPrivileges=yes
# ProtectSystem=full # or strict
# ProtectHome=true
# PrivateTmp=true
# PrivateDevices=true
# RestrictSUIDSGID=true
# CapabilityBoundingSet=
# AmbientCapabilities=
# ReadWritePaths=/var/lib/my-app
# ReadOnlyPaths=/usr/share/my-app
[Install]
WantedBy=multi-user.target # or graphical.target for GUI-ish system services User service variant
Same idea, but simplified and placed in ~/.config/systemd/user/my-app.service:
[Unit]
Description=My Example User Service
After=network-online.target
[Service]
Type=simple
ExecStart=/home/you/.local/bin/my-app --flag
WorkingDirectory=/home/you
Restart=on-failure
RestartSec=5s
# User=/ Group=/ hardening options are generally not needed or are limited for user units
[Install]
WantedBy=default.target Key differences:
- No
User=/Group=(it is your user). WantedBy=default.targetso it starts with your user session.- Managed with
systemctl --user ….
Common patterns
Long‑running daemon (most common case)
Type=simpleExecStart=/path/to/binary ...Restart=on-failure
This is what you use for servers, sync tools, custom scripts that should always be up.
One‑shot task at boot / login
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/my-once-task.sh
RemainAfterExit=yes # so "active" status doesn’t vanish immediately Use WantedBy=multi-user.target (system) or default.target (user) to run once each boot/login.
Service with pre/post hooks
[Service]
Type=simple
ExecStartPre=/usr/bin/install -d -m 0750 /var/lib/my-app
ExecStart=/usr/bin/my-app
ExecStartPost=/usr/bin/logger "my-app is now running"
ExecStop=/usr/bin/pkill my-app You can chain multiple ExecStartPre lines; they run in order.
Quick reference: important directives
[Unit]
Description=human‑readable description.Documentation=URLs or man pages.After=ordering (start after these units).Requires=hard dependency: if this fails/stops, your service stops.Wants=soft dependency: try to start, but don’t fail if missing.
[Service] basics
Type=simple: process inExecStartis the service (default).exec: like simple but waits until the process actually execs.notify: service not “ready” until it sends a notification (used by some daemons).forking: legacy daemons thatfork()into background.oneshot: run once and exit.idle: start after others have settled.
ExecStart=main command (absolute path recommended).WorkingDirectory=set current directory.Environment=inline env vars.EnvironmentFile=load env vars from a file.
[Service] reliability and hardening
Restart=andRestartSec=control restarts.User=/Group=(system units) drop privileges to that account.NoNewPrivileges=andProtectSystem=/ProtectHome=/PrivateTmp=etc. tighten security; add these gradually and test.
[Install]
WantedBy=multi-user.targetfor typical system daemons.WantedBy=graphical.targetif it’s only relevant when a graphical session is up.WantedBy=default.targetfor user services.
Workflow reminder (system vs user)
System unit:
sudo cp my-app.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl start my-app.service
sudo systemctl enable my-app.service User unit:
mkdir -p ~/.config/systemd/user
cp my-app.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user start my-app.service
systemctl --user enable my-app.service Global user services (same user unit for all users)
Where to put the unit
- Location for the template (available to all users):
/etc/systemd/user/xautolock.service
- Each user still gets their own instance, but you define the service once at the system level.
Example xautolock.service in /etc/systemd/user/:
[Unit]
Description=Auto-lock screen on inactivity (xautolock)
After=graphical-session.target
PartOf=graphical-session.target
[Service]
Type=simple
Environment=DISPLAY=:0
ExecStart=/usr/bin/xautolock
-time 10 -detectsleep -locker 'i3lock -n'
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target Notes you can keep in the sheet:
- This is a user unit, just installed globally instead of in
~/.config/systemd/user/. - Each logged‑in user runs their own
xautolocktied to their session. - Adjust
DISPLAY, locker command, and timeouts to your setup.
Enabling for all users (global enable)
Once the file exists in /etc/systemd/user/:
# Reload user unit templates
sudo systemctl daemon-reload
# Enable for all users (adds wants/links in their user trees)
sudo systemctl --global enable xautolock.service In your cheat sheet, you can phrase it like:
- Make a user service globally enabled
- Put unit in:
/etc/systemd/user/NAME.service - Run:
sudo systemctl --global enable NAME.service - Effect: every user’s
default.targetwill wantNAME.service(one instance per user session).
- Put unit in:
Per-user override / disable
Useful lines to add:
- To disable just for one user (without touching others):
systemctl --user disable xautolock.service - To inspect what’s enabled for your user:
systemctl --user list-unit-files | grep enabled