No description
Find a file
Christopher 4e3f207016 init
2026-05-06 19:52:47 +02:00
docs init 2026-05-06 19:52:47 +02:00
inventories/production init 2026-05-06 19:52:47 +02:00
roles init 2026-05-06 19:52:47 +02:00
.gitignore init 2026-05-06 19:52:47 +02:00
ansible.cfg init 2026-05-06 19:52:47 +02:00
README.md init 2026-05-06 19:52:47 +02:00
requirements.yml init 2026-05-06 19:52:47 +02:00
site.yml init 2026-05-06 19:52:47 +02:00

AutoDeployMisc

Ansible playbook for deploying HeyForm and Forgejo to a single Ubuntu 26.04 LTS server with rootless Podman Quadlets, Caddy TLS, and Borg backups.

Architecture

  • Caddy runs as a rootless Quadlet and binds public 80/443.
  • HeyForm, MongoDB, Valkey, and Forgejo run as rootless Quadlets under separate host users.
  • PostgreSQL runs as a native Ubuntu system service bound to 127.0.0.1.
  • caddy owns Caddy, ACME state, and proxy config.
  • heyform owns HeyForm, MongoDB, and Valkey.
  • forgejo owns the Forgejo app container.
  • the host postgres account owns shared PostgreSQL data.
  • Caddy proxies HTTPS traffic to rootless app ports on localhost:
    • HeyForm: 127.0.0.1:9513
    • Forgejo: 127.0.0.1:3000
  • Forgejo reaches host PostgreSQL through rootless pasta host-loopback forwarding to 127.0.0.1:5432.
  • Forgejo SSH is exposed on port 2222.
  • Borg runs from a root-owned systemd timer, creates logical database dumps, temporarily switches to each service user for Podman dumps/volume exports, and archives the combined staging tree to a remote Borg repository.
  • Rootless Caddy uses net.ipv4.ip_unprivileged_port_start=80 by default so the unprivileged caddy user can bind 80/443. Set caddy_enable_low_port_sysctl: false if you provide those ports through an external firewall, load balancer, or socket/proxy layer instead.

Configure

  1. Edit inventories/production/hosts.yml.
  2. Edit inventories/production/group_vars/all/main.yml.
  3. Replace values in inventories/production/group_vars/all/vault.yml.
  4. Encrypt the Vault file:
ansible-vault encrypt inventories/production/group_vars/all/vault.yml

Useful secret generation commands:

openssl rand -hex 32
openssl rand -base64 48

With borg_ssh_key_mode: generate, the playbook creates /root/.ssh/autodeploy_borg_ed25519 on the server. Add the corresponding .pub key to the remote Borg account before enabling scheduled backups. For a single deployment pass, provide vault_borg_ssh_private_key instead.

Deploy

ansible-galaxy collection install -r requirements.yml
ansible-playbook --syntax-check site.yml --ask-vault-pass
ansible-playbook site.yml --ask-vault-pass

Older revisions used KeyDB for HeyForm. This revision replaces it with Valkey, stops and removes the old heyform-keydb user units during deploy, and leaves the old heyform-keydb Podman volume in place for manual migration or cleanup.

The playbook intentionally fails while any required value still contains CHANGE_ME.

SMTP is configured per service. Keep heyform_smtp_enabled and forgejo_smtp_enabled false until the matching *_smtp_* values and Vault passwords are set. For port 587, the defaults use HeyForm heyform_smtp_secure: false and Forgejo forgejo_smtp_protocol: smtp+starttls; for port 465, use HeyForm heyform_smtp_secure: true and Forgejo forgejo_smtp_protocol: smtps.

To add another PostgreSQL-backed service later, give it its own rootless host user, add a postgres_databases entry with a separate owner/password, and have the app container reach Postgres through host-loopback forwarding like Forgejo.

Operations

Check services:

sudo -u caddy env HOME=/home/caddy XDG_RUNTIME_DIR=/run/user/$(id -u caddy) DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u caddy)/bus systemctl --user status caddy.service
sudo -u heyform env HOME=/home/heyform XDG_RUNTIME_DIR=/run/user/$(id -u heyform) DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u heyform)/bus systemctl --user status heyform.service
sudo -u forgejo env HOME=/home/forgejo XDG_RUNTIME_DIR=/run/user/$(id -u forgejo) DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u forgejo)/bus systemctl --user status forgejo.service
sudo systemctl status postgresql.service

Run a backup manually:

sudo systemctl start autodeploy-borg-backup.service
sudo journalctl -u autodeploy-borg-backup.service -n 100 --no-pager

List Borg archives:

sudo bash -lc 'set -a; source /etc/autodeploy/borg/borg.env; borg list'

Forgejo admin bootstrap is disabled by default. To create an admin during deployment, set forgejo_admin_create: true and configure the admin vars before running the playbook.

HeyForm registration is disabled by default. Temporarily set heyform_disable_registration: false if you need a bootstrap signup window.

Restore

See docs/restore.md.

Upstream References