# 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)** ```bash yay -S unitdore ``` **Debian / Ubuntu** Download the `.deb` from the [releases page](https://git.warky.dev/wdevs/unitdore/releases) and install: ```bash sudo dpkg -i unitdore_*.deb ``` **CentOS / AlmaLinux / Rocky Linux** Download the `.rpm` from the [releases page](https://git.warky.dev/wdevs/unitdore/releases) and install: ```bash sudo rpm -i unitdore-*.rpm # or with dnf: sudo dnf install unitdore-*.rpm ``` **From source** ```bash make build sudo make install ``` Or manually: ```bash go build -o unitdore . sudo cp unitdore /usr/local/bin/ ``` ## Usage ### Discover running containers ```bash 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 `) - 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 ```bash sudo unitdore edit ``` Opens `/etc/unitdore/units.yaml` in `$EDITOR` (falls back to `vi`). ### Install systemd unit files ```bash sudo unitdore install ``` Generates `.service` files for all enabled units and writes them to systemd. Use `--dry-run` to preview without writing. ```bash sudo unitdore install --dry-run ``` ### Enable and start units ```bash sudo unitdore active ``` Runs `systemctl enable --now` for all installed, enabled units in startup order. ### Check status ```bash 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` ```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 -f up` / `stop`, `Type=simple` | | any missing | `podman pod start/stop pod_`, `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 ` (`install` warns). ### Prefix and suffix Set `prefix` and/or `suffix` to namespace your service files: ```yaml 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](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: ```ini # /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