diff --git a/README.md b/README.md index 08dd16f..8152174 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Create an encrypted Vault file at `group_vars/all/vault.yml` based on `group_var Example: ```bash -ansible-vault create group_vars/all/vault.yml +uv run ansible-vault create group_vars/all/vault.yml ``` ## Usage @@ -49,19 +49,30 @@ Update the inventory and variables first, especially: Run a syntax check: ```bash -ansible-playbook --syntax-check site.yml +uv run ansible-playbook --syntax-check site.yml ``` Run the playbook: ```bash -ansible-playbook site.yml --ask-vault-pass +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. -- If you enable `certbot_manage_certificates`, run the playbook a second time after the first successful issuance so nginx can switch to the live certificates automatically. +- 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 diff --git a/group_vars/all/main.yml b/group_vars/all/main.yml index 193e536..5c21208 100644 --- a/group_vars/all/main.yml +++ b/group_vars/all/main.yml @@ -63,7 +63,7 @@ certbot_packages: - certbot - python3-certbot-nginx certbot_email: admin@twirre.io -certbot_manage_certificates: false +certbot_manage_certificates: true certbot_certificates: - name: twirre.io domains: @@ -71,21 +71,21 @@ certbot_certificates: - name: twirre.me domains: - twirre.me - - name: git.twirre.io - domains: - - git.twirre.io - - name: lagrange.meulenbelt.nl - domains: - - lagrange.meulenbelt.nl - - name: map.twirre.io - domains: - - map.twirre.io - - name: chat.twirre.io - domains: - - chat.twirre.io - - name: overleaf.twirre.io - domains: - - overleaf.twirre.io + # - name: git.twirre.io + # domains: + # - git.twirre.io + # - name: lagrange.meulenbelt.nl + # domains: + # - lagrange.meulenbelt.nl + # - name: map.twirre.io + # domains: + # - map.twirre.io + # - name: chat.twirre.io + # domains: + # - chat.twirre.io + # - name: overleaf.twirre.io + # domains: + # - overleaf.twirre.io - name: mail.twirre.io domains: - mail.twirre.io diff --git a/inventory/hosts.yml b/inventory/hosts.yml index bed6d42..2d4b90a 100644 --- a/inventory/hosts.yml +++ b/inventory/hosts.yml @@ -4,5 +4,5 @@ all: twirre_servers: hosts: suno.twirre.dev: - ansible_host: 203.0.113.10 + ansible_host: 185.232.69.99 ansible_user: root diff --git a/roles/backupagent/templates/backupagent-sshd-match.conf.j2 b/roles/backupagent/templates/backupagent-sshd-match.conf.j2 index 59fb754..fce837b 100644 --- a/roles/backupagent/templates/backupagent-sshd-match.conf.j2 +++ b/roles/backupagent/templates/backupagent-sshd-match.conf.j2 @@ -10,6 +10,5 @@ Match User {{ backupagent.name }} AllowStreamLocalForwarding no PermitTunnel no GatewayPorts no - PermitUserEnvironment no PermitUserRC no PermitOpen none diff --git a/roles/mailserver/tasks/main.yml b/roles/mailserver/tasks/main.yml index b402e03..93e1306 100644 --- a/roles/mailserver/tasks/main.yml +++ b/roles/mailserver/tasks/main.yml @@ -65,6 +65,12 @@ daemon_reload: true when: mailserver_unit.changed +- name: Check whether live mailserver certificate exists + ansible.builtin.stat: + path: "{{ mailserver.tls_root_path }}/live/{{ mailserver.hostname }}/fullchain.pem" + register: mailserver_live_certificate + when: mailserver.env.SSL_TYPE | default('') == 'letsencrypt' + - name: Enable mailserver compose stack ansible.builtin.service: name: mailserver-compose @@ -75,3 +81,6 @@ else 'started' }} enabled: true + when: >- + mailserver.env.SSL_TYPE | default('') != 'letsencrypt' + or mailserver_live_certificate.stat.exists | default(false) diff --git a/site.yml b/site.yml index 3768d60..98eddcb 100644 --- a/site.yml +++ b/site.yml @@ -49,11 +49,11 @@ when: wireguard_enabled | bool - role: gitea when: gitea_enabled | bool - - role: mailserver - when: mailserver_enabled | bool - role: bun_app when: bun_enabled | bool - role: nginx when: nginx_enabled | bool - role: certbot when: certbot_enabled | bool + - role: mailserver + when: mailserver_enabled | bool diff --git a/uv.lock b/uv.lock index c29c938..511d92a 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,10 @@ version = 1 revision = 3 requires-python = ">=3.14" +[options] +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. +exclude-newer-span = "P1W" + [[package]] name = "ansible-core" version = "2.20.4"