From c4a64259266ba7981c037212fab9ecacd12fe5be Mon Sep 17 00:00:00 2001 From: Amritanshu Date: Sun, 6 Sep 2026 14:21:59 +0530 Subject: [PATCH] Caddy: adopt dual-role snippet (PB api+admin on main host), relative PB file urls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - www host: /_* and /api/* proxy to pocketbase :8090, everything else to the TanStack app; redir /_ /_/ for the admin path - cms host unchanged: redir / -> /_/ - migration: legacy per-host marker blocks are removed before the new combined block is installed - cms.ts: PB file urls are now same-origin relative (/api/files/...) — browsers could never load the old 127.0.0.1:8090 urls; validated the rendered Caddyfile with caddy:2 --- ansible/roles/caddy/tasks/main.yaml | 14 +------------- ansible/roles/caddy/tasks/snippet.yaml | 20 +++++++++++++++----- ansible/roles/caddy/templates/snippet.j2 | 24 +++++++++++++++++++----- ansible/vars/default.yml | 8 +------- src/lib/cms.ts | 4 +++- 5 files changed, 39 insertions(+), 31 deletions(-) diff --git a/ansible/roles/caddy/tasks/main.yaml b/ansible/roles/caddy/tasks/main.yaml index e56c48c..1a89bb6 100644 --- a/ansible/roles/caddy/tasks/main.yaml +++ b/ansible/roles/caddy/tasks/main.yaml @@ -1,15 +1,3 @@ --- -- name: Read current Caddyfile - ansible.builtin.slurp: - path: "{{ caddyfile_path }}" - register: caddyfile_raw - -- name: Decode Caddyfile content - set_fact: - caddyfile_content: "{{ caddyfile_raw['content'] | b64decode }}" - -- name: Add Caddy snippets for each published host +- name: Install mozimo Caddy snippet (web + cms) ansible.builtin.include_tasks: snippet.yaml - loop: "{{ caddy_hosts }}" - loop_control: - loop_var: snippet diff --git a/ansible/roles/caddy/tasks/snippet.yaml b/ansible/roles/caddy/tasks/snippet.yaml index 7014afc..3ff69bb 100644 --- a/ansible/roles/caddy/tasks/snippet.yaml +++ b/ansible/roles/caddy/tasks/snippet.yaml @@ -1,12 +1,22 @@ --- -- name: Build Caddy snippet block for {{ snippet.host }} +- name: Read snippet from template ansible.builtin.set_fact: - snippet_block: "{{ lookup('ansible.builtin.template', 'snippet.j2') }}" + caddy_snippet_block: "{{ lookup('ansible.builtin.template', 'snippet.j2') }}" -- name: Install snippet block for {{ snippet.host }} +# migrate away from the older per-host marker blocks (pre dual-role snippet) +- name: Remove legacy per-host snippet blocks ansible.builtin.blockinfile: path: "{{ caddyfile_path }}" - marker: "# {mark} Ansible managed Caddy snippet for {{ snippet.host }}" - block: "{{ snippet_block }}" + marker: "# {mark} Ansible managed Caddy snippet for {{ item }}" + state: absent + loop: + - "{{ www_host }}" + - "{{ cms_host }}" + +- name: Install mozimo Caddy snippet (web + cms) + ansible.builtin.blockinfile: + path: "{{ caddyfile_path }}" + marker: "# {mark} Ansible managed Caddy snippet (mozimo web + cms)" + block: "{{ caddy_snippet_block }}" insertafter: EOF notify: "Reload Caddy" diff --git a/ansible/roles/caddy/templates/snippet.j2 b/ansible/roles/caddy/templates/snippet.j2 index f8c9cfa..13af9de 100644 --- a/ansible/roles/caddy/templates/snippet.j2 +++ b/ansible/roles/caddy/templates/snippet.j2 @@ -1,6 +1,20 @@ -{{ snippet.host }} { -{% if snippet.pb_root | default(false) %} - redir / /_/ -{% endif %} - reverse_proxy {{ snippet.upstream }} +{{ www_host }} { + # PocketBase Admin UI and REST API (files included) + redir /_ /_/ + handle /_/* { + reverse_proxy {{ docker_container }}:{{ cms_port }} + } + handle /api/* { + reverse_proxy {{ docker_container }}:{{ cms_port }} + } + + # TanStack Start frontend + handle { + reverse_proxy {{ docker_container }}:{{ www_port }} + } +} + +{{ cms_host }} { + redir / /_/ + reverse_proxy {{ docker_container }}:{{ cms_port }} } diff --git a/ansible/vars/default.yml b/ansible/vars/default.yml index 34afd0b..ee2c11f 100644 --- a/ansible/vars/default.yml +++ b/ansible/vars/default.yml @@ -20,13 +20,7 @@ docker_network: "{{ title }}_net" docker_image: "{{ registry }}/{{ title }}:{{ image_tag | default(tag) }}" docker_container: "{{ title }}-staging" -# hosts Caddy publishes on this box: web (SSR) + pocketbase (cms) -caddy_hosts: - - host: "{{ www_host }}" - upstream: "{{ docker_container }}:{{ www_port }}" - - host: "{{ cms_host }}" - upstream: "{{ docker_container }}:{{ cms_port }}" - pb_root: true # dashboard at / (Caddy redirs / -> /_/) +# caddy publishes www (SSR + /api/* + /_/* -> pocketbase) and cms (admin) caddy_container: caddy caddyfile_path: /var/lib/caddy/conf/Caddyfile diff --git a/src/lib/cms.ts b/src/lib/cms.ts index 812e566..6ee91d5 100644 --- a/src/lib/cms.ts +++ b/src/lib/cms.ts @@ -63,9 +63,11 @@ async function pbList( } } +// same-origin relative url: caddy routes /api/* to pocketbase on every +// public host, so browsers can load cms-uploaded files directly const fileUrl = (r: PbRecord, filename: unknown) => typeof filename === "string" && filename - ? `${PB_URL}/api/files/${r.collectionId}/${r.id}/${filename}` + ? `/api/files/${r.collectionId}/${r.id}/${filename}` : null; const str = (v: unknown) => (typeof v === "string" ? v.trim() : "");