Skip to content

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.target so it starts with your user session.
  • Managed with systemctl --user ….

Common patterns

Long‑running daemon (most common case)

  • Type=simple
  • ExecStart=/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 in ExecStart is 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 that fork() 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= and RestartSec= control restarts.
  • User= / Group= (system units) drop privileges to that account.
  • NoNewPrivileges= and ProtectSystem= / ProtectHome= / PrivateTmp= etc. tighten security; add these gradually and test.

[Install]

  • WantedBy=multi-user.target for typical system daemons.
  • WantedBy=graphical.target if it’s only relevant when a graphical session is up.
  • WantedBy=default.target for 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 xautolock tied 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.target will want NAME.service (one instance per user session).

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