Files
unitdore/docs/generated-units.md
T
warkanum f0827fcdd7 feat: podman-compose stack units and root/user execution scopes
- syncup: podman first, docker only as fallback (podman wins on name clash;
  existing docker units found in podman switch to podman)
- syncup: group podman-compose containers into one `kind: stack` unit per
  project (project, working_dir, compose_files, compose_bin from labels);
  disable existing member units ("part of stack <project>")
- generator: compose mode (podman-compose up/stop, WorkingDirectory) with
  pod start/stop fallback when compose binary/dir/files are missing
- reconcile: stacks disabled with "stack not found" when neither compose
  files nor pod exist
- root: scan root + rootless users listed in `users:` (podman only)
- non-root: config ~/.config/unitdore/units.yaml, own user units only
- sysuser package: runuser with XDG_RUNTIME_DIR/DBUS env, home/linger lookup
- install: warn when linger is not enabled for user units
- testdata/stack: podman-compose test stack and captured podman ps fixture
- docs: README, generated-units, man page, AGENTS, PLAN
2026-10-12 19:05:51 +02:00

6.7 KiB

Generated Systemd Unit Files

Unitdore generates .service files from your units.yaml config. This document shows every combination with annotated examples.


System Unit (root, no user)

Config:

units:
  - name: nginx
    runtime: podman
    order: 1
    enabled: true

Written to: /etc/systemd/system/unitdore-nginx.service

# /etc/systemd/system/unitdore-nginx.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: nginx (podman)
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a nginx
ExecStop=/usr/bin/podman stop nginx
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Notes:

  • After=network.target ensures the network is up before starting
  • WantedBy=multi-user.target means it starts in normal boot runlevel
  • Restart=on-failure restarts the container if it exits unexpectedly

System Unit (Docker)

Config:

units:
  - name: redis
    runtime: docker
    order: 1
    enabled: true

Written to: /etc/systemd/system/unitdore-redis.service

# /etc/systemd/system/unitdore-redis.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: redis (docker)
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/docker start redis
ExecStop=/usr/bin/docker stop redis
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Notes:

  • Docker uses docker start <name> (no -a flag needed)

User Unit (rootless container)

Config:

units:
  - name: myapp
    runtime: podman
    user: hein
    order: 2
    enabled: true

Written to: /home/hein/.config/systemd/user/unitdore-myapp.service

# ~/.config/systemd/user/unitdore-myapp.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: myapp (podman)
After=default.target

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a myapp
ExecStop=/usr/bin/podman stop myapp
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target

Notes:

  • User units use After=default.target and WantedBy=default.target
  • The file is written to the user's own systemd directory
  • Unitdore calls runuser -u hein -- systemctl --user for enable/start/status

Custom Command

Config:

units:
  - name: myscript
    runtime: podman
    command: /opt/myapp/start.sh
    order: 3
    enabled: true

Written to: /etc/systemd/system/unitdore-myscript.service

# /etc/systemd/system/unitdore-myscript.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: myscript (podman)
After=network.target

[Service]
Type=simple
ExecStart=/opt/myapp/start.sh
ExecStop=
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Notes:

  • When command is set, it is used verbatim as ExecStart
  • ExecStop is left empty — systemd will send SIGTERM to the process group

With Prefix and Suffix

Config:

prefix: prod-
suffix: -svc

units:
  - name: nginx
    runtime: podman
    order: 1
    enabled: true
  - name: api
    runtime: docker
    order: 2
    enabled: true

Written to:

  • /etc/systemd/system/unitdore-prod-nginx-svc.service
  • /etc/systemd/system/unitdore-prod-api-svc.service
# /etc/systemd/system/unitdore-prod-nginx-svc.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: nginx (podman)
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/podman start -a nginx
ExecStop=/usr/bin/podman stop nginx
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Notes:

  • prefix and suffix apply to the service file name only — the container name stays unchanged
  • Useful for distinguishing environments (prod-, staging-) or roles (-web, -worker)

Container Named by Short ID

If a container has no name (e.g. started with docker run without --name), unitdore uses its short container ID (first 12 characters) as the unit name.

Example: Container ID a3f2c1b9e4d7 with no name →

Config entry added by syncup:

units:
  - name: a3f2c1b9e4d7
    runtime: docker
    order: 1
    enabled: true

Written to: /etc/systemd/system/unitdore-a3f2c1b9e4d7.service

Tip: After syncup, use unitdore edit to give it a proper name before running install.


Startup Ordering Example

Config:

units:
  - name: postgres
    runtime: podman
    order: 1
    enabled: true

  - name: redis
    runtime: podman
    order: 1         # same order = starts in parallel
    enabled: true

  - name: api
    runtime: podman
    order: 2         # waits until order 1 group is started
    enabled: true

  - name: nginx
    runtime: podman
    order: 3
    enabled: true

unitdore active starts units in ascending order value, lowest first. Units with the same order are started together (parallel).


Disabled Unit

Config:

units:
  - name: oldthing
    runtime: podman
    order: 1
    enabled: false
    disabled_reason: container not found
  • unitdore install will remove the .service file if it exists
  • unitdore active will skip disabled units
  • unitdore status shows the reason in the REASON column

Stack Unit (podman-compose, compose mode)

Used when compose_bin, working_dir and all compose_files exist.

- name: shop
  kind: stack
  runtime: podman
  project: shop
  working_dir: /srv/shop
  compose_files: [compose.yaml]
  compose_bin: /usr/bin/podman-compose
  enabled: true
# /etc/systemd/system/unitdore-shop.service
# Generated by unitdore — do not edit manually

[Unit]
Description=Unitdore: shop (podman-compose stack)
After=network.target

[Service]
Type=simple
WorkingDirectory=/srv/shop
ExecStart=/usr/bin/podman-compose -p shop -f compose.yaml up
ExecStop=-/usr/bin/podman-compose -p shop -f compose.yaml stop

[Install]
WantedBy=multi-user.target

Stack Unit (pod fallback)

Used when the compose binary, working dir or a compose file is missing. Requires pod pod_<project>.

[Unit]
Description=Unitdore: shop (podman pod)
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/podman pod start pod_shop
ExecStop=-/usr/bin/podman pod stop pod_shop

Quick Reference: Service File Locations

Scenario Path
System unit (root) /etc/systemd/system/unitdore-<name>.service
User unit /home/<user>/.config/systemd/user/unitdore-<name>.service
With prefix prod- /etc/systemd/system/unitdore-prod-<name>.service
With suffix -svc /etc/systemd/system/unitdore-<name>-svc.service
With both /etc/systemd/system/unitdore-prod-<name>-svc.service