- Jinja 100%
| docs | ||
| inventories/production | ||
| roles | ||
| .gitignore | ||
| ansible.cfg | ||
| README.md | ||
| requirements.yml | ||
| site.yml | ||
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. caddyowns Caddy, ACME state, and proxy config.heyformowns HeyForm, MongoDB, and Valkey.forgejoowns the Forgejo app container.- the host
postgresaccount 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
- HeyForm:
- 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=80by default so the unprivilegedcaddyuser can bind80/443. Setcaddy_enable_low_port_sysctl: falseif you provide those ports through an external firewall, load balancer, or socket/proxy layer instead.
Configure
- Edit
inventories/production/hosts.yml. - Edit
inventories/production/group_vars/all/main.yml. - Replace values in
inventories/production/group_vars/all/vault.yml. - 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
- HeyForm self-hosting: https://docs.heyform.net/open-source/self-hosting
- Forgejo container install: https://forgejo.org/docs/latest/admin/installation-docker/
- Podman Quadlets: https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html
- Borg prune: https://borgbackup.readthedocs.io/en/stable/usage/prune.html