Extract init-neutral unit resolution into service/, add initsys.Init with systemd, openrc and runit backends, selected by 'init:' config or autodetect. OpenRC and runit are root only; rootless units run as system services as that user. Add docs and generated examples for all three.
13 KiB
Generated Unit Files (systemd, OpenRC, runit)
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.targetensures the network is up before startingWantedBy=multi-user.targetmeans it starts in normal boot runlevelRestart=on-failurerestarts 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-aflag 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.targetandWantedBy=default.target - The file is written to the user's own systemd directory
- Unitdore calls
runuser -u hein -- systemctl --userfor 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
commandis set, it is used verbatim asExecStart ExecStopis 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:
prefixandsuffixapply 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 installwill remove the.servicefile if it existsunitdore activewill skip disabled unitsunitdore statusshows 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
Config Behind the Init System Examples
init: systemd # systemd | openrc | runit
units:
- {name: nginx, runtime: podman, order: 1, enabled: true}
- {name: redis, runtime: docker, order: 2, enabled: true, restart: true, restart_sec: 5, restart_retries: 3}
- {name: myapp, runtime: podman, user: alice, order: 3, enabled: true}
- {name: backup, runtime: script, script: /opt/scripts/backup.sh, stop_script: /opt/scripts/stop.sh, shell: /bin/sh, working_dir: /opt/scripts, order: 4, enabled: true}
- {name: agent, runtime: exec, executable: /opt/agent/bin/agent, args: [--config, /etc/agent.toml], service_type: oneshot, order: 5, enabled: true}
- {name: shop, runtime: podman, kind: stack, project: shop, order: 6, enabled: true}
Script and Executable Units (systemd)
script runs <shell> <script> (default shell /bin/bash); exec runs the binary directly.
# /etc/systemd/system/unitdore-backup.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: backup (sh script)
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/scripts
ExecStart=/bin/sh /opt/scripts/backup.sh
ExecStop=-/bin/sh /opt/scripts/stop.sh
[Install]
WantedBy=multi-user.target
# /etc/systemd/system/unitdore-agent.service
# Generated by unitdore — do not edit manually
[Unit]
Description=Unitdore: agent (executable)
After=network.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/opt/agent/bin/agent --config /etc/agent.toml
ExecStop=
[Install]
WantedBy=multi-user.target
OpenRC
Root only. Files in /etc/init.d/. Rootless user: units run as a system service via command_user.
nginx
#!/sbin/openrc-run
# /etc/init.d/unitdore-nginx
# Generated by unitdore — do not edit manually
description="Unitdore: nginx (podman)"
command_background=yes
pidfile="/run/${RC_SVCNAME}.pid"
command="/usr/bin/podman"
command_args="start -a nginx"
depend() {
need net
}
stop_pre() {
/usr/bin/podman stop nginx || true
}
redis
#!/sbin/openrc-run
# /etc/init.d/unitdore-redis
# Generated by unitdore — do not edit manually
description="Unitdore: redis (docker)"
supervisor=supervise-daemon
respawn_delay=5
respawn_max=3
command="/usr/bin/docker"
command_args="start -a redis"
depend() {
need net
need docker
}
stop_pre() {
/usr/bin/docker stop redis || true
}
myapp
#!/sbin/openrc-run
# /etc/init.d/unitdore-myapp
# Generated by unitdore — do not edit manually
description="Unitdore: myapp (podman)"
export HOME=/home/alice
export XDG_RUNTIME_DIR=/run/user/1000
command_background=yes
pidfile="/run/${RC_SVCNAME}.pid"
command="/usr/bin/podman"
command_args="start -a myapp"
command_user="alice"
depend() {
need net
}
start_pre() {
checkpath -d -m 0700 -o alice /run/user/1000
}
stop_pre() {
su -m -s /bin/sh -c '/usr/bin/podman stop myapp' alice || true
}
backup
#!/sbin/openrc-run
# /etc/init.d/unitdore-backup
# Generated by unitdore — do not edit manually
description="Unitdore: backup (sh script)"
command_background=yes
pidfile="/run/${RC_SVCNAME}.pid"
command="/bin/sh"
command_args="/opt/scripts/backup.sh"
directory="/opt/scripts"
depend() {
need net
}
stop_pre() {
/bin/sh /opt/scripts/stop.sh || true
}
agent
#!/sbin/openrc-run
# /etc/init.d/unitdore-agent
# Generated by unitdore — do not edit manually
description="Unitdore: agent (executable)"
start() {
ebegin "Starting $RC_SVCNAME"
/opt/agent/bin/agent --config /etc/agent.toml
eend $?
}
depend() {
need net
}
shop
#!/sbin/openrc-run
# /etc/init.d/unitdore-shop
# Generated by unitdore — do not edit manually
description="Unitdore: shop (podman pod)"
start() {
ebegin "Starting $RC_SVCNAME"
/usr/bin/podman pod start pod_shop
eend $?
}
stop() {
ebegin "Stopping $RC_SVCNAME"
/usr/bin/podman pod stop pod_shop
eend $?
}
depend() {
need net
}
runit
Root only. Each unit is /etc/sv/unitdore-<name>/{run,finish} symlinked into the service dir. Install adds a down file (no autostart until started/enabled). Both files are shown per unit.
nginx
# ===== /etc/sv/unitdore-nginx/run =====
#!/bin/sh
# unitdore-nginx — generated by unitdore, do not edit manually
exec 2>&1
exec /usr/bin/podman start -a nginx
# ===== /etc/sv/unitdore-nginx/finish =====
#!/bin/sh
# unitdore-nginx — generated by unitdore, do not edit manually
/usr/bin/podman stop nginx || true
exec sv down .
redis
# ===== /etc/sv/unitdore-redis/run =====
#!/bin/sh
# unitdore-redis — generated by unitdore, do not edit manually
exec 2>&1
exec /usr/bin/docker start -a redis
# ===== /etc/sv/unitdore-redis/finish =====
#!/bin/sh
# unitdore-redis — generated by unitdore, do not edit manually
/usr/bin/docker stop redis || true
[ "$1" = 0 ] && exec sv down .
sleep 5
myapp
# ===== /etc/sv/unitdore-myapp/run =====
#!/bin/sh
# unitdore-myapp — generated by unitdore, do not edit manually
exec 2>&1
[ -d /run/user/1000 ] || install -d -m 0700 -o alice /run/user/1000
export HOME=/home/alice
export XDG_RUNTIME_DIR=/run/user/1000
exec chpst -u alice /usr/bin/podman start -a myapp
# ===== /etc/sv/unitdore-myapp/finish =====
#!/bin/sh
# unitdore-myapp — generated by unitdore, do not edit manually
chpst -u alice /usr/bin/podman stop myapp || true
exec sv down .
backup
# ===== /etc/sv/unitdore-backup/run =====
#!/bin/sh
# unitdore-backup — generated by unitdore, do not edit manually
exec 2>&1
cd /opt/scripts || exit 1
exec /bin/sh /opt/scripts/backup.sh
# ===== /etc/sv/unitdore-backup/finish =====
#!/bin/sh
# unitdore-backup — generated by unitdore, do not edit manually
cd /opt/scripts 2>/dev/null
/bin/sh /opt/scripts/stop.sh || true
exec sv down .
agent
# ===== /etc/sv/unitdore-agent/run =====
#!/bin/sh
# unitdore-agent — generated by unitdore, do not edit manually
exec 2>&1
/opt/agent/bin/agent --config /etc/agent.toml || exit 1
exec tail -f /dev/null
# ===== /etc/sv/unitdore-agent/finish =====
#!/bin/sh
# unitdore-agent — generated by unitdore, do not edit manually
exec sv down .
shop
# ===== /etc/sv/unitdore-shop/run =====
#!/bin/sh
# unitdore-shop — generated by unitdore, do not edit manually
exec 2>&1
/usr/bin/podman pod start pod_shop || exit 1
exec tail -f /dev/null
# ===== /etc/sv/unitdore-shop/finish =====
#!/bin/sh
# unitdore-shop — generated by unitdore, do not edit manually
/usr/bin/podman pod stop pod_shop || true
exec sv down .
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 |
| OpenRC | /etc/init.d/unitdore-<name> |
| runit | /etc/sv/unitdore-<name>/ (+ symlink in /var/service or /etc/service) |