Twirre Meulenbelt b44ff6f808 as deployed
2026-06-28 08:43:43 +02:00
2026-06-28 08:43:43 +02:00
2026-06-28 08:43:43 +02:00
2026-06-28 08:43:43 +02:00
2026-04-22 12:22:58 +02:00
2026-04-15 12:49:04 +02:00
2026-04-15 12:49:04 +02:00
2026-06-28 08:43:43 +02:00
2026-06-28 08:43:43 +02:00
2026-06-28 08:43:43 +02:00

Ansible Domo

Going for an Esperanto naming theme.

Portable Ansible provisioning for Twirre infrastructure. The current layout uses Ubuntu 24.04 package names, /srv for deployed services, /etc for config, and systemd-managed apps, so it will not work on Debian without adjustment.

What this provisions

  • Base host packages, timezone, and static content roots
  • SSH admin users with key-based login
  • A dedicated backupagent user for rsync-based backups with restricted SSH settings and passwordless sudo /usr/bin/rsync
  • Docker from distro packages
  • Bun installed to /opt/bun with /usr/local/bin/bun
  • Two Bun app services: twirre.io and twirre.me
  • Gitea and Docker Mailserver as Compose stacks under /srv
  • nginx virtual hosts for the retained public domains
  • apt-based certbot with ACME webroot support
  • WireGuard with wg-quick@wg0 enabled at boot
  • fail2ban with the audit-derived SSH jail settings

Layout

  • site.yml: top-level playbook
  • inventory/hosts.yml: example inventory
  • group_vars/all/main.yml: shared variables and service declarations
  • group_vars/all/vault.example.yml: secrets shape to move into an encrypted Vault file
  • roles/: reusable server roles

Secrets

Create an encrypted Vault file at group_vars/all/vault.yml based on group_vars/all/vault.example.yml. The playbook will use Vault variables when present and otherwise fall back to safe placeholders for syntax checking.

Example:

uv run ansible-vault create group_vars/all/vault.yml

Usage

Update the inventory and variables first, especially:

  • inventory/hosts.yml
  • group_vars/all/main.yml
  • group_vars/all/vault.yml
  • repository URLs and domains for the Bun apps
  • backupagent.authorized_keys

Run a syntax check:

uv run ansible-playbook --syntax-check site.yml

Run the playbook:

uv run ansible-playbook site.yml --ask-vault-pass

Result

  • twirre.io: Bun source checkout in /srv/twirre/twirre.io; runtime config in /etc/twirre-io/app.env; data in /var/lib/twirre-io/app.sqlite3, public files in /var/lib/twirre-io/files, and hidden files in /var/lib/twirre-io/hfiles; systemd unit twirre_io.service.
  • twirre.me: Bun source checkout in /srv/twirre/twirre.me; runtime config in /etc/twirre-me/app.env; data directory reserved at /var/lib/twirre-me; systemd unit twirre_me.service.
  • Gitea: Docker Compose stack in /srv/gitea/compose.yaml; persistent application data in /srv/gitea/data; systemd unit gitea-compose.service; public HTTP behind nginx at git.twirre.io, SSH on port 2222.
  • Mailserver: Docker Compose stack in /srv/mail/compose.yaml with environment in /srv/mail/mailserver.env; mail data, state, logs, and docker-mailserver config under /srv/mail/docker-data/dms/; Let's Encrypt certificates mounted from /etc/letsencrypt; systemd unit mailserver-compose.service.
  • lagrange.meulenbelt.nl: static placeholder site rooted at /srv/lagrange.
  • map.twirre.io, chat.twirre.io, and overleaf.twirre.io: nginx reverse proxies only; no source code or data is stored on this host for these services.
  • Shared web infrastructure: nginx site configs in /etc/nginx/sites-available/ with enabled symlinks in /etc/nginx/sites-enabled/; ACME webroot in /var/www/letsencrypt; certificates in /etc/letsencrypt.

Notes

  • nginx falls back to snakeoil certificates until a matching ACME certificate already exists on disk.
  • A run with certbot_manage_certificates: true requests certificates during that playbook run. If DNS and HTTP reachability are correct, issuance happens immediately.
  • mailserver starts only after its live Let's Encrypt certificate exists on disk, so the same run that issues mail.twirre.io can also bring up Docker Mailserver.
  • ACME issuance is disabled by default through certbot_manage_certificates: false so the first provisioning run can complete before DNS and public reachability are finalized.

Manual post-provisioning steps

  • Set up ACME DNS records for the domains and enable certbot_manage_certificates: true before the next playbook run.
  • Restore backups for Gitea and Mailserver data.

Future plans

  • Encryption for non-boot files with LUKS (/home, /srv, /var/lib/).
Description
Ansible stuff for Twirre, by Twirre.
Readme 107 KiB
Languages
Jinja 100%