Files
mozimo.in/ansible/files/Caddyfile.j2
T
tanshu d04314ab1c Deploy with rootless podman + Quadlet on emily
Retargets the build and the playbook off rootful Docker on monoco, following the
conventions already in place on emily's other services: Quadlet units in
~/.config/containers/systemd, per-service data in ~/podman-data, and a shared
Caddy that every service registers itself with — a network drop-in plus a
marked block in its Caddyfile. Nothing is published on the host; Caddy reaches
the containers by name over mozimo_net.

- Makefile: podman build + push instead of docker buildx, PLATFORMS=linux/arm64
  (both hosts are aarch64). podman has no built-in QEMU the way buildx's builder
  image does, so a foreign-platform failure now points at qemu-user-static.
- deploy.sh: pass COMMIT= to make, which the Makefile actually reads; it was
  passing TAG=, so the tag silently came from `git rev-parse` instead.
- ansible: hosts emily, become false, XDG_RUNTIME_DIR for rootless podman and
  systemctl --user. Docker modules become Quadlet templates with user-service
  handlers, and the network role now ships mozimo.network plus the Caddy drop-in
  rather than calling docker_network.
- UserNS=keep-id maps the container's uid 1000 (node) and root (vince) onto the
  host user, so PocketBase and Vince write host-owned files instead of
  subuid-owned ones; the play asserts the pinned uid still matches the host.
- ansible/README.md: the unit layout, the service-registration convention, and
  the monoco -> emily migration (PocketBase 23 MB + Vince 119 MB, DNS cutover,
  rollback).

Verified by a check-mode rehearsal against emily (13 ok / 8 changed / 0 failed)
and a disposable Quadlet unit on that host proving the uid mapping, the
EnvironmentFile and the isolated network. The real build and cutover have not
been run.
2026-10-16 10:11:39 +05:30

48 lines
1.6 KiB
Caddyfile

# Canonical origin. Everything the site emits — og:url, robots.txt, the
# sitemap, the GA4 property, vince_site_domain — already says mozimo.in, so
# the apex serves and www is permanently redirected here (below).
#
# Upstreams are container names on {{ network_quadlet }}.network: Caddy
# resolves them through podman's DNS because it has joined that network.
{{ apex_host }} {
# PocketBase Admin UI and REST API (files included)
redir /_ /_/
handle /_/* {
reverse_proxy {{ app_container }}:{{ cms_port }}
}
handle /api/* {
reverse_proxy {{ app_container }}:{{ cms_port }}
}
# First-party analytics (Vince) — the tracker script and event endpoint
# are proxied same-origin with the /stats prefix stripped (vince serves
# /js/script.js and /api/event), so they survive ad blockers and never
# touch a third-party domain.
handle_path /stats/* {
reverse_proxy {{ vince_container }}:{{ vince_port }}
}
# TanStack Start frontend
handle {
reverse_proxy {{ app_container }}:{{ www_port }}
}
}
# www is a permanent (301) redirect to the canonical apex origin, so the same
# page is never served from two hosts. {uri} carries the path and query string.
{{ www_host }} {
redir https://{{ apex_host }}{uri} permanent
}
{{ cms_host }} {
redir / /_/
reverse_proxy {{ app_container }}:{{ cms_port }}
}
# Vince analytics dashboard (login-protected). DNS for this host must point
# at this server; the tracker script itself stays on the canonical apex host
# at /stats/* — this is only for humans reading the dashboard.
{{ stats_host }} {
reverse_proxy {{ vince_container }}:{{ vince_port }}
}