# {{ container_name }} — rootless Podman Quadlet unit. # Managed by Ansible (menu-admin/roles/menu-app). Do not edit by hand. # # This unit joins {{ network_name }}.network, which is created by # roles/register — the same include that attaches the shared Caddy unit to it, # so Caddy can resolve {{ container_name }} by name. [Unit] Description=Menu app for {{ host }} ({{ site }}) After=network-online.target Wants=network-online.target [Container] ContainerName={{ container_name }} Image={{ image }} # keep-id maps the image's own account — `node`, uid/gid {{ app_uid }} — onto # {{ podman_user }}, which keeps every file the app writes owned by # {{ podman_user }} on the host: plain tar/rsync backups, no subuids, no # `podman unshare`. scripts/provision-site-env.sh writes site.env with the same # mapping rather than --user, which under rootless Podman would have produced a # subuid-owned file the app could not read. UserNS=keep-id:uid={{ app_uid }},gid={{ app_gid }} Environment=MENU_ROOT=/data Environment=MENU_SITE_CONFIG=/app/config/{{ site }}.site.json Environment=SECURE_COOKIES=true Environment=LOG_LEVEL=info Environment=PORT={{ site_port }} # Everything the app writes: data/ (originals, drafts, published, site.json, # sections.json) and site.env. The Site's own config is baked into the image and # read from /app. Volume={{ host_directory }}:/data Network={{ network_name }}.network # No PublishPort on purpose: Caddy reaches the app over {{ network_name }}_net, # so nothing is exposed on the host. # podman builds an OCI image by default and drops the Dockerfile's HEALTHCHECK # instruction, so the same check is declared here and the play gates on it with # `podman healthcheck run`. wget is busybox's; see vars/default.yml for why the # command must not contain quotes. HealthCmd={{ health_cmd }} HealthInterval=30s HealthTimeout=5s HealthRetries=3 HealthStartPeriod=30s [Service] Restart=always # The app validates its data directory before it serves and refuses to boot on a # fatal integrity problem, so a first start over copied data can take a moment. TimeoutStartSec=120 [Install] WantedBy=default.target