Ansible deployment for CariConnect Bremen (Django container on gierz-services, Caddy route on gierz-gateway). Slots into the prototypes/* drop-in hook in main infra.
Find a file
Paul Gierz 2f2cd59769
All checks were successful
Deploy CariConnect Bremen / deploy (push) Successful in 1m35s
caddy: redirect www.cariconnect.de to the bare domain
DNS now has a www CNAME pointing at cariconnect.de. Caddy auto-issues
TLS for it too and 301s to the canonical bare-domain URL rather than
serving the site twice under two hostnames.
2026-09-04 12:16:08 +02:00
.forgejo/workflows ci: add forgejo-runner role so cariconnect-de runs its own CI 2026-09-04 11:52:10 +02:00
inventory fix: vault password newline mismatch between local/CI paths 2026-09-04 11:52:18 +02:00
playbooks ci: add forgejo-runner role so cariconnect-de runs its own CI 2026-09-04 11:52:10 +02:00
roles caddy: redirect www.cariconnect.de to the bare domain 2026-09-04 12:16:08 +02:00
.gitignore Use .vault_pass.sh pattern from main infra 2026-05-11 14:57:59 +02:00
.vault_pass.sh fix: vault password newline mismatch between local/CI paths 2026-09-04 11:52:18 +02:00
ansible.cfg Use .vault_pass.sh pattern from main infra 2026-05-11 14:57:59 +02:00
README.md deploy: retarget CariConnect to the cariconnect.de VPS 2026-09-04 11:52:01 +02:00
requirements.yml deploy: retarget CariConnect to the cariconnect.de VPS 2026-09-04 11:52:01 +02:00

CariConnect Bremen — deployment

Ansible repo for deploying the CariConnect Bremen Django site (cariconnect/web) onto its own VPS at https://cariconnect.de.

What this repo owns

  • The cariconnect_web Ansible role — installs podman, caddy and firewalld on cariconnect-de, builds the container image with podman from code.gierz.xyz/cariconnect/web, renders a Quadlet container unit, renders the Caddyfile, brings both services up.
  • The CI workflow that re-runs the playbook on push to main, executed by an act_runner with SSH access to the VPS.

There is no separate gateway host — Caddy and the container run on the same box, so the role owns the whole stack top to bottom.

First-time run (manual, before CI is set up)

git clone https://code.gierz.xyz/cariconnect/infra.git
cd infra
ansible-galaxy collection install -r requirements.yml

# One-time: stash the vault password in `pass` so .vault_pass.sh finds it.
pass insert ansible/cariconnect-infra/vault-password

ansible-playbook -K playbooks/deploy.yml

In CI, .vault_pass.sh reads $ANSIBLE_VAULT_PASSWORD instead of touching pass; the Forgejo Actions workflow sets that env var from the ANSIBLE_VAULT_PASSWORD repo secret.

Vault entries needed

inventory/group_vars/all/vault.yml (encrypted with ansible-vault):

vault_cariconnect_web_secret_key: "..."         # Django SECRET_KEY (50+ chars)
vault_cariconnect_web_deploy_token: "..."       # Forgejo PAT, read:repository scope only

Generate the secret key with python -c "import secrets; print(secrets.token_urlsafe(50))".

URL layout, recap

browser  →  cariconnect.de (Caddy, automatic TLS via Let's Encrypt)
         →  127.0.0.1:8000 (Quadlet cariconnect-bremen, loopback only)
         →  gunicorn → Django