unitdore

A door you open and close for container units.

Unitdore bridges your container runtime (Podman, Docker) and systemd. It discovers running containers and podman-compose stacks, stores them in a config file, and generates + manages systemd .service units for each one.

Install

Arch Linux (AUR)

yay -S unitdore

Debian / Ubuntu

Download the .deb from the releases page and install:

sudo dpkg -i unitdore_*.deb

CentOS / AlmaLinux / Rocky Linux

Download the .rpm from the releases page and install:

sudo rpm -i unitdore-*.rpm
# or with dnf:
sudo dnf install unitdore-*.rpm

From source

make build
sudo make install

Or manually:

go build -o unitdore .
sudo cp unitdore /usr/local/bin/

Usage

Discover running containers

sudo unitdore syncup

Queries Podman and Docker for running containers, adds new ones to the config, and reconciles any that have disappeared (marking them disabled).

  • Podman first; Docker only for names Podman doesn't have
  • podman-compose containers → one kind: stack unit per project; existing member units disabled (part of stack <project>)
  • Root: root's containers + rootless Podman containers of each user in users:
  • Normal user: own Podman containers, config ~/.config/unitdore/units.yaml, user units only

Edit the config

sudo unitdore edit

Opens /etc/unitdore/units.yaml in $EDITOR (falls back to vi).

Install systemd unit files

sudo unitdore install

Generates .service files for all enabled units and writes them to systemd. Use --dry-run to preview without writing.

sudo unitdore install --dry-run

Enable and start units

sudo unitdore active

Runs systemctl enable --now for all installed, enabled units in startup order.

Check status

sudo unitdore status

Prints a summary table:

NAME       RUNTIME   USER    ENABLED   INSTALLED   STATE             REASON
nginx      podman    root    yes       yes         active
myapp      docker    hein    yes       yes         active
oldthing   podman    hein    no        no          —                 container not found

Config file

Location: /etc/unitdore/units.yaml

prefix: ""                   # optional: prepended to all service names, e.g. "prod-"
suffix: ""                   # optional: appended to all service names, e.g. "-svc"
users: [hein]                # root only: rootless users scanned by syncup

units:
  - name: nginx
    runtime: podman          # podman | docker
    user: ""                 # empty = root/system unit
    command: ""              # optional: override ExecStart entirely
    order: 1                 # startup order (lower = earlier)
    delay: 0s                # delay after previous order group
    enabled: true
    disabled_reason: ""      # auto-set by syncup reconciliation

  - name: myapp
    runtime: docker
    user: hein               # rootless: generates user unit for this user
    order: 2
    delay: 5s
    enabled: true

  - name: shop               # = compose project name
    kind: stack              # container (default) | stack
    runtime: podman
    user: hein
    project: shop
    working_dir: /srv/shop   # from compose labels (refreshed by syncup)
    compose_files: [compose.yaml]
    compose_bin: /usr/bin/podman-compose
    order: 3
    enabled: true

Stacks (podman-compose)

Condition Unit
compose_bin, working_dir, compose_files exist podman-compose -p <proj> -f <files> up / stop, Type=simple
any missing podman pod start/stop pod_<proj>, Type=oneshot
compose missing and no pod syncup disables: stack not found

Users

Run as Config Discovers Units
root /etc/unitdore/units.yaml root + users: (Podman only for users) system + user units
user ~/.config/unitdore/units.yaml own Podman own user units

User units need linger to start at boot: sudo loginctl enable-linger <user> (install warns).

Prefix and suffix

Set prefix and/or suffix to namespace your service files:

prefix: prod-
suffix: ""

Generates: unitdore-prod-nginx.service, unitdore-prod-myapp.service, etc. Prefix/suffix apply to the service file name only — container names are unchanged.

Unnamed containers

If a container has no name, syncup uses its short container ID (first 12 chars) as the unit name. You can rename it later with unitdore edit.

Generated unit files

See docs/generated-units.md for full examples covering:

  • System units (root)
  • User units (rootless)
  • Docker vs Podman
  • Custom commands
  • Compose stacks (compose + pod fallback)
  • Prefix/suffix naming
  • Startup ordering
  • Unnamed containers (short ID fallback)

Quick example:

# /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

Flags

--config string   path to units config file (default "/etc/unitdore/units.yaml"; non-root: ~/.config/unitdore/units.yaml)

Requirements

  • Go 1.21+
  • systemd
  • Podman and/or Docker (only what you have installed is used)
  • podman-compose for compose-mode stacks (pod fallback without it)
  • Root for system units; the relevant user for rootless units
S
Description
A door you open and close for container units. Manages systemd units for Podman/Docker containers.
Readme MIT
306 KiB
v1.0.0
Latest
2026-10-12 20:03:16 +00:00
Languages
Go 96.3%
Shell 2.2%
Makefile 1.5%