diff --git a/countdown.html b/countdown.html new file mode 100644 index 0000000..16c77f5 --- /dev/null +++ b/countdown.html @@ -0,0 +1,354 @@ + + + + + + Countdown – Heilige Mutter Teresa Chemnitz + + + + + + + + +
+
Bald gehen wir online
+
+ +
+
--Tage
+
--Stunden
+
--Minuten
+
--Sekunden
+
+ + + + diff --git a/infra/README.md b/infra/README.md index 5a40cca..3046561 100644 --- a/infra/README.md +++ b/infra/README.md @@ -257,36 +257,50 @@ The Forgejo Actions workflow (`.forgejo/workflows/deploy.yml`) triggers on push ## Countdown Static Site (Caddy) -`deploy-countdown.yml` provisions a **fresh standalone VPS** that serves only the -static `countdown.html` (repo root). It installs Caddy, uploads the page, and lets -Caddy obtain + auto-renew the TLS certificate for `hl-mutter-teresa-chemnitz.de` -and `www.hl-mutter-teresa-chemnitz.de`. +The static `countdown.html` (repo root) is served by the **existing test VPS** +Caddy alongside the app reverse-proxies — no separate box. The domains live in +`countdown_domains` in `inventory/test.yml`: + +```yaml +countdown_domains: + - hl-mutter-teresa-chemnitz.de + - www.hl-mutter-teresa-chemnitz.de +``` + +When this var is set, the `caddy` role uploads `countdown.html` to +`/var/www/countdown/index.html` and renders a Caddyfile block that serves it for +all listed names (`chemnitz_live` defaults to `false` = countdown). Caddy obtains +and auto-renews TLS automatically — point each domain's DNS A/AAAA record at the +VPS first so the ACME challenge resolves. `setup.yml` provisions it as part of the +normal server setup. + +### Go live: countdown → staging app + +`switch-to-staging.yml` re-renders the Caddyfile so the chemnitz domains +`reverse_proxy` to the staging app (port 3001) instead of serving the static +page, then validates and reloads Caddy: ```bash cd infra/ansible -# 1. Point the inventory at the VPS and confirm the domains -# edit inventory/countdown/hosts.yml -> ansible_host, countdown_domain, countdown_aliases +# Switch the domains to the live staging app: +ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --ask-vault-pass -# 2. Make sure DNS A/AAAA records for both names point at the VPS first -# (Caddy's ACME challenge needs them resolving), then run with the root -# password (--ask-pass needs `sshpass` installed locally): -ansible-playbook playbooks/deploy-countdown.yml -i inventory/countdown/hosts.yml --ask-pass +# Revert to the countdown page: +ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --ask-vault-pass -e chemnitz_live=false ``` -> Authenticating with the root password? Install `sshpass` first -> (`brew install hudochenkov/sshpass/sshpass` on macOS, `apt install sshpass` on -> Debian/Ubuntu). Once you've added an SSH key to the box you can drop -> `--ask-pass` and set `ansible_ssh_private_key_file` in the inventory instead. +The playbook is idempotent, so you can run it ahead of time to dry-run the +cutover and flip it back. It reuses the TLS cert Caddy already holds from +countdown mode (same domains), so there's no re-issue at switch time. -**What it does:** - -1. Installs Caddy + ufw (allows 22/80/443) -2. Uploads `countdown.html` to `/var/www/countdown/index.html` -3. Deploys a Caddyfile serving both domains; Caddy handles HTTPS automatically - -**Re-running** is the normal way to publish content changes — it re-uploads the -HTML and reloads Caddy. The certificate is managed entirely by Caddy. +> After go-live, set `chemnitz_live: true` in `inventory/test.yml` so a later full +> `setup.yml` run keeps the domains pointed at the app instead of reverting to the +> countdown page. +> +> Note: the staging image is built with `NEXT_PUBLIC_SERVER_URL` set to its +> `skick.app` domain, so canonical URLs/sitemap still point there. If +> `hl-mutter-teresa-chemnitz.de` should be canonical, rebuild staging with that URL. --- diff --git a/infra/ansible/inventory/test.yml b/infra/ansible/inventory/test.yml index 42877c8..929217e 100644 --- a/infra/ansible/inventory/test.yml +++ b/infra/ansible/inventory/test.yml @@ -33,6 +33,16 @@ all: - domain: git.skick.app proxy_port: 3003 + # Chemnitz domains: served by Caddy as the static countdown page until go-live. + # The setup/caddy role renders them in countdown mode (chemnitz_live defaults + # to false). Run playbooks/switch-to-staging.yml to flip them to the staging + # app (port 3001) and reload Caddy. Point DNS at this VPS first so Caddy can + # obtain TLS for each name. + countdown_domains: + - hl-mutter-teresa-chemnitz.de + - www.hl-mutter-teresa-chemnitz.de + countdown_live_port: 3001 # staging app port the domains proxy to once live + # Forgejo forgejo_domain: git.skick.app forgejo_container_name: forgejo diff --git a/infra/ansible/playbooks/switch-to-staging.yml b/infra/ansible/playbooks/switch-to-staging.yml new file mode 100644 index 0000000..4ccb77d --- /dev/null +++ b/infra/ansible/playbooks/switch-to-staging.yml @@ -0,0 +1,47 @@ +--- +# Flip the chemnitz domains (countdown_domains) from the static countdown page +# to the live staging app, then validate + reload Caddy. +# +# ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --ask-vault-pass +# +# Re-runnable and idempotent — run it to go live, or to dry-run the cutover. +# To revert to the countdown page: +# ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --ask-vault-pass -e chemnitz_live=false +- name: Switch chemnitz domains between countdown and the staging app + hosts: all + become: true + + vars: + chemnitz_live: true + + tasks: + - name: Fail early if the chemnitz domains are not configured + ansible.builtin.assert: + that: + - countdown_domains is defined + - countdown_domains | length > 0 + fail_msg: "countdown_domains must be set in the inventory before switching." + + - name: Render Caddyfile ({{ 'staging app' if chemnitz_live | bool else 'countdown page' }}) + ansible.builtin.template: + src: "{{ playbook_dir }}/../roles/caddy/templates/Caddyfile.j2" + dest: /etc/caddy/Caddyfile + mode: "0644" + register: caddyfile_result + + - name: Validate Caddyfile + ansible.builtin.command: caddy validate --adapter caddyfile --config /etc/caddy/Caddyfile + changed_when: false + + - name: Reload Caddy + ansible.builtin.systemd: + name: caddy + state: reloaded + when: caddyfile_result is changed + + - name: Report active mode + ansible.builtin.debug: + msg: >- + chemnitz domains now serving + {{ 'the staging app (port ' ~ (countdown_live_port | default(3001)) ~ ')' + if chemnitz_live | bool else 'the countdown page' }}. diff --git a/infra/ansible/roles/caddy/tasks/main.yml b/infra/ansible/roles/caddy/tasks/main.yml index 0c6972c..08223c7 100644 --- a/infra/ansible/roles/caddy/tasks/main.yml +++ b/infra/ansible/roles/caddy/tasks/main.yml @@ -24,6 +24,24 @@ state: present update_cache: true +- name: Create countdown web root + ansible.builtin.file: + path: /var/www/countdown + state: directory + owner: caddy + group: caddy + mode: "0755" + when: countdown_domains is defined and countdown_domains | length > 0 + +- name: Upload countdown page + ansible.builtin.copy: + src: "{{ playbook_dir }}/../../../countdown.html" + dest: /var/www/countdown/index.html + owner: caddy + group: caddy + mode: "0644" + when: countdown_domains is defined and countdown_domains | length > 0 + - name: Deploy Caddyfile ansible.builtin.template: src: Caddyfile.j2 diff --git a/infra/ansible/roles/caddy/templates/Caddyfile.j2 b/infra/ansible/roles/caddy/templates/Caddyfile.j2 index 94cf12f..a7f2379 100644 --- a/infra/ansible/roles/caddy/templates/Caddyfile.j2 +++ b/infra/ansible/roles/caddy/templates/Caddyfile.j2 @@ -4,3 +4,14 @@ } {% endfor %} +{% if countdown_domains is defined and countdown_domains | length > 0 %} +{{ countdown_domains | join(', ') }} { +{% if chemnitz_live | default(false) | bool %} + reverse_proxy localhost:{{ countdown_live_port | default(3001) }} +{% else %} + root * /var/www/countdown + file_server +{% endif %} +} + +{% endif %} diff --git a/launch.md b/launch.md new file mode 100644 index 0000000..e10fe12 --- /dev/null +++ b/launch.md @@ -0,0 +1,13 @@ +# Launch countdown + +## Switch to live + +```bash +cd infra/ansible && ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --vault-password-file /home/benno/.config/chemnitz-vault-pass -e chemnitz_live=true +``` + +## Switch to countdown + +```bash +cd infra/ansible && ansible-playbook playbooks/switch-to-staging.yml -i inventory/test.yml --vault-password-file /home/benno/.config/chemnitz-vault-pass -e chemnitz_live=false +``` \ No newline at end of file