updated multica deployment

This commit is contained in:
rblundon committed 2026-10-20 14:23:27 -05:00
1 parent 39e2b87941
commit b1ce761291
4 files changed
+80 -16

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
--- ---
# Single-origin layout: one hostname, Caddy routes /health, /ws, /api/daemon/ws to the backend # Single-origin layout: one hostname, Caddy routes /health, /ws, /api/daemon/ws to the backend
multica_layout: single multica_layout: single
multica_domain: muppet-vision.wdw-labs.cloud multica_domain: multica.wdw-labs.cloud
# TLS: acme_http | cloudflare_dns | internal # TLS: acme_http | cloudflare_dns | internal
caddy_tls_mode: cloudflare_dns caddy_tls_mode: cloudflare_dns
@@ -53,6 +53,11 @@ caddy_version: "2"
caddy_tls_mode: acme_http caddy_tls_mode: acme_http
caddy_acme_email: "" caddy_acme_email: ""
caddy_cloudflare_api_token: "{{ vault_cloudflare_api_token | default('') }}" caddy_cloudflare_api_token: "{{ vault_cloudflare_api_token | default('') }}"
# cloudflare_dns only: resolvers Caddy uses for the DNS-01 propagation check. Needed with split-horizon/local DNS,
# where the host resolver returns internal nameserver names that can't be resolved. [] = use the host resolver.
caddy_dns_resolvers:
- 1.1.1.1
- 1.0.0.1
# Rebuild the custom image on every run (cloudflare_dns only) # Rebuild the custom image on every run (cloudflare_dns only)
caddy_force_rebuild: false caddy_force_rebuild: false
@@ -61,6 +61,16 @@
label: "{{ item.key }}" label: "{{ item.key }}"
no_log: "{{ multica_no_log }}" no_log: "{{ multica_no_log }}"
# .env.example ships a DATABASE_URL with the default password embedded. POSTGRES_PASSWORD alone does not
# change it, so keep the URL's password in step (no-op if the line is absent or already matches).
- name: Sync password inside DATABASE_URL
ansible.builtin.replace:
path: "{{ multica_install_dir }}/.env"
regexp: '^(DATABASE_URL=[a-z]+://[^:/@]+:)[^@]*(@.*)$'
replace: '\g<1>{{ multica_postgres_password }}\g<2>'
mode: "0600"
no_log: "{{ multica_no_log }}"
# Compose re-reads .env and recreates containers whose config changed (equivalent of `up -d`). # Compose re-reads .env and recreates containers whose config changed (equivalent of `up -d`).
- name: Start / update Multica stack - name: Start / update Multica stack
community.docker.docker_compose_v2: community.docker.docker_compose_v2:
@@ -73,6 +83,55 @@
recreate: auto recreate: auto
register: _multica_up register: _multica_up
# Postgres only reads POSTGRES_PASSWORD when the data volume is first initialised. If the volume pre-dates this
# run (or the vault value changed), the DB user keeps the old password and the backend can't log in.
# Test over TCP (the local socket is trust-auth and proves nothing) and repair via the socket if needed.
- name: Wait for Postgres to accept connections
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "postgres", "pg_isready", "-U", "{{ multica_postgres_user }}", "-d", "{{ multica_postgres_db }}"]
chdir: "{{ multica_install_dir }}"
register: _multica_pg_ready
until: _multica_pg_ready.rc == 0
retries: 24
delay: 5
changed_when: false
- name: Test database login with the configured password (over TCP)
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "-e", "PGPASSWORD", "postgres", "sh", "-c",
"psql -h \"$(hostname -i | cut -d' ' -f1)\" -U {{ multica_postgres_user }} -d {{ multica_postgres_db }} -tAc 'select 1'"]
chdir: "{{ multica_install_dir }}"
environment:
PGPASSWORD: "{{ multica_postgres_password }}"
register: _multica_pg_auth
changed_when: false
failed_when:
- _multica_pg_auth.rc != 0
- "'password authentication failed' not in _multica_pg_auth.stderr"
no_log: "{{ multica_no_log }}"
- name: Reset database user password to match .env
when: _multica_pg_auth.rc != 0
block:
- name: ALTER USER via local socket (password passed on stdin)
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"exec", "-T", "postgres", "psql", "-v", "ON_ERROR_STOP=1",
"-U", "{{ multica_postgres_user }}", "-d", "{{ multica_postgres_db }}"]
chdir: "{{ multica_install_dir }}"
stdin: "ALTER USER {{ multica_postgres_user }} PASSWORD '{{ multica_postgres_password }}';"
changed_when: true
no_log: "{{ multica_no_log }}"
- name: Restart backend so it reconnects
ansible.builtin.command:
argv: ["docker", "compose", "-p", "{{ multica_compose_project }}", "-f", "{{ _multica_compose_file }}",
"restart", "backend"]
chdir: "{{ multica_install_dir }}"
changed_when: true
- name: Wait for backend /readyz (db + migrations ok) - name: Wait for backend /readyz (db + migrations ok)
ansible.builtin.uri: ansible.builtin.uri:
url: "http://127.0.0.1:{{ _multica_backend_port }}/readyz" url: "http://127.0.0.1:{{ _multica_backend_port }}/readyz"
@@ -1,4 +1,16 @@
# Managed by Ansible (multica_docker) - local changes will be overwritten # Managed by Ansible (multica_docker) - local changes will be overwritten
{% macro tls_block() %}
{% if caddy_tls_mode == 'internal' %}
tls internal
{% elif caddy_tls_mode == 'cloudflare_dns' %}
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
{% if caddy_dns_resolvers | length > 0 %}
resolvers {{ caddy_dns_resolvers | join(' ') }}
{% endif %}
}
{% endif %}
{% endmacro %}
{ {
{% if caddy_acme_email | length > 0 %} {% if caddy_acme_email | length > 0 %}
email {{ caddy_acme_email }} email {{ caddy_acme_email }}
@@ -9,17 +21,11 @@
{% if caddy_https_port | int != 443 %} {% if caddy_https_port | int != 443 %}
https_port {{ caddy_https_port }} https_port {{ caddy_https_port }}
{% endif %} {% endif %}
{% if caddy_tls_mode == 'cloudflare_dns' %}
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
{% endif %}
} }
{% if multica_layout == 'single' %} {% if multica_layout == 'single' %}
{{ multica_domain }} { {{ multica_domain }} {
{% if caddy_tls_mode == 'internal' %} {{ tls_block() }} # CLI reachability probe: `multica setup` GETs <server-url>/health and needs a 200
tls internal
{% endif %}
# CLI reachability probe: `multica setup` GETs <server-url>/health and needs a 200
handle /health { handle /health {
reverse_proxy 127.0.0.1:{{ _multica_backend_port }} reverse_proxy 127.0.0.1:{{ _multica_backend_port }}
} }
@@ -45,10 +51,7 @@
} }
{% else %} {% else %}
{{ multica_app_domain }} { {{ multica_app_domain }} {
{% if caddy_tls_mode == 'internal' %} {{ tls_block() }} # Hand browser WebSockets straight to the backend
tls internal
{% endif %}
# Hand browser WebSockets straight to the backend
@ws path /ws /ws/* @ws path /ws /ws/*
handle @ws { handle @ws {
reverse_proxy 127.0.0.1:{{ _multica_backend_port }} { reverse_proxy 127.0.0.1:{{ _multica_backend_port }} {
@@ -63,10 +66,7 @@
} }
{{ multica_api_domain }} { {{ multica_api_domain }} {
{% if caddy_tls_mode == 'internal' %} {{ tls_block() }} reverse_proxy 127.0.0.1:{{ _multica_backend_port }} {
tls internal
{% endif %}
reverse_proxy 127.0.0.1:{{ _multica_backend_port }} {
flush_interval -1 flush_interval -1
} }
} }