Run Caddy as a rootless Podman Quadlet
Replaces the docker_container role with Quadlet systemd user units under ~/.config/containers/systemd, and moves state from /var/lib/caddy to ~/podman-data/caddy. Caddy is now the base unit and no longer lists its upstream networks. Each service registers itself by writing its own <name>.network unit plus a drop-in into caddy.container.d/, so adding or removing a service never means editing the Caddy playbook. Drop-ins are used rather than blockinfile because this playbook re-templates caddy.container on every run, which would wipe appended blocks. The play runs as the connecting user instead of using become: the rootless units belong to it, so the connection's PAM session is what makes systemctl --user work without setting XDG_RUNTIME_DIR. podman_user and the data directory are derived from facts, so the play fails loudly if that resolves to root. Two things that bit us and are worth keeping: - The privileged-port sysctl is applied inline with sysctl -w, not via a handler. Handlers only run at the end of the play, by which point Caddy has already failed to bind 80/443. - The Caddyfile is seeded with a minimal valid config. Caddy exits 1 with a bare "EOF" on an empty config file, so touching it into existence made the service crash-loop.
This commit is contained in:
1 parent
21f848340e
commit
060173db5e
8 files changed
+708
-79
No files matched your search
+45
-3
@@ -1,5 +1,47 @@
|
||||
---
|
||||
caddy_name: caddy
|
||||
caddy_image: caddy:alpine
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rootless Podman / Quadlet
|
||||
# ---------------------------------------------------------------------------
|
||||
# The container user is derived from the connection: this play carries no
|
||||
# become, so the modules run as — and the Quadlet units belong to — whoever
|
||||
# Ansible connects as. Requires gather_facts (set explicitly in playbook.yml).
|
||||
#
|
||||
# To use a different user you would have to reintroduce become_user, which is
|
||||
# exactly what this design avoids; the podman role fails loudly if the resolved
|
||||
# user is root.
|
||||
podman_user: "{{ ansible_facts['user_id'] }}"
|
||||
|
||||
host_directory: caddy
|
||||
# State and config live in the user's home, not /var/lib. Taken from the
|
||||
# user_dir fact, so this is correct even for users whose home is not
|
||||
# /home/<name>.
|
||||
podman_data_dir: "{{ ansible_facts['user_dir'] }}/podman-data"
|
||||
quadlet_dir: "{{ ansible_facts['user_dir'] }}/.config/containers/systemd"
|
||||
|
||||
# Rootless containers cannot publish ports below 1024 without this sysctl.
|
||||
# Caddy needs 80/443, so patching it down to 80 is the standard trade.
|
||||
podman_unprivileged_port_start: 80
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Caddy
|
||||
# ---------------------------------------------------------------------------
|
||||
caddy_name: caddy
|
||||
caddy_unit: "{{ caddy_name }}.service"
|
||||
|
||||
# Fully qualified on purpose: rootless Podman resolves short names against
|
||||
# unqualified-search-registries, and there is no TTY to answer a prompt when
|
||||
# the systemd unit starts.
|
||||
caddy_image: docker.io/library/caddy:latest
|
||||
|
||||
host_directory: "{{ podman_data_dir }}/caddy"
|
||||
caddyfile_path: "{{ host_directory }}/conf/Caddyfile"
|
||||
|
||||
# Quadlet drop-in directory for the Caddy unit. Services register themselves
|
||||
# here; see the "How services register themselves" section of readme.md.
|
||||
# Caddy itself never lists its upstream networks.
|
||||
caddy_dropin_dir: "{{ quadlet_dir }}/{{ caddy_name }}.container.d"
|
||||
|
||||
# Host ports. 443/udp is HTTP/3 (QUIC).
|
||||
caddy_ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "443:443/udp"
|
||||
Reference in new issue
Block a user