--- # arbret's footprint on the edge host - and ONLY that. # # arbret itself (app, worker, Postgres, timers, its backup dump) is deployed by # the arbret owner's own Ansible repo since prd-arbret was merged into vipy on # 2026-10-17. This playbook owns the parts of the shared host that are ours: # the public front door, the tailnet port, and the backup directory contract. # See arbret_handoff.md at the repo root for the division of labour. - name: Publish arbret on the edge host hosts: edge become: yes vars: # Local port the arbret app binds on 127.0.0.1, per the arbret owner. arbret_port: 3100 arbret_domain: arbret.com # Admin port reachable from the tailnet only (ACL in headscale's acl.json.j2). arbret_tailnet_port: 4117 tasks: - name: Publish arbret through Caddy ansible.builtin.include_role: name: caddy_site vars: caddy_site_name: arbret caddy_site_domain: "{{ arbret_domain }}" caddy_site_upstream: "localhost:{{ arbret_port }}" - name: Redirect www to the apex ansible.builtin.include_role: name: caddy_site vars: caddy_site_name: arbret-www caddy_site_domain: "www.{{ arbret_domain }}" caddy_site_body: | redir https://{{ arbret_domain }}{uri} permanent # tailscale0 only. UFW's default-deny applies to the tailnet interface too, # so the headscale ACL alone does not open it - and this must never be # reachable on the public interface. - name: Allow the arbret admin port from the tailnet community.general.ufw: rule: allow interface: tailscale0 direction: in port: "{{ arbret_tailnet_port | string }}" proto: tcp comment: "arbret admin, tailnet only" # The backup contract directory (arbret_handoff.md section 3.3). The arbret # repo creates it identically; creating it here too means small-backups-box # can pull - an empty dir - before arbret's first dump, so one missing # source does not turn the whole pull job red. - name: Ensure the arbret backup directory exists ansible.builtin.file: path: /opt/backups/arbret state: directory owner: root group: backup-pull mode: "0750"