deploy: record the relay as actually deployed

Quadlets captured from the live units on bob, with the real immutable tags
(0.1.44-ge06652a) rather than a placeholder, plus the hanzalova vhost that
mounts the relay on /relay-api/ of the existing name.

Verified end to end: /relay-api/health returns ok through the prefix, the
relay's nested /v1 routes answer 401 rather than 404 (so the strip reaches
them and they are genuinely protected), the remote's own /v1 is unaffected,
and the served SPA bundle now carries the origin-relative /relay-api base.

The vhost is committed because it is half the design: the relay only works
on a path because nginx strips the prefix, and a future kanban.l4ir.net
needs exactly this location block and nothing else.
This commit is contained in:
rob thijssen
2026-07-21 18:10:25 +03:00
parent e06652a57a
commit d7c912c7f4
3 changed files with 77 additions and 2 deletions

View File

@@ -0,0 +1,75 @@
# Mesh-only vhost for vibe-kanban, fronted by the hanzalova edge proxy (office site).
# Cert: internal `lair` CA, minted from the operator box and renewed by
# step@kanban.timer (architecture internal-tls.md — dot-free instance label).
# Whole-app reverse proxy to the vibe-kanban remote-server on bob, which serves
# both its API and the built SPA. Mirrors the hermes.internal vhost pattern.
# ln -sf ../sites-available/kanban.internal.conf /etc/nginx/sites-enabled/
#
# TLS terminates here, not in the app: upstream's compose puts Caddy in front for
# Let's Encrypt, which we drop entirely — this is a mesh-only name on the internal
# CA. remote-server is told SERVER_PUBLIC_BASE_URL=https://kanban.internal so the
# links it generates match what the client actually reached.
#
# Electric streams shape updates over long-lived HTTP; the long read timeout and
# disabled buffering below are what keep those from being cut or batched.
# The relay is a separate service on the same host. It is mounted on a PATH of
# this vhost rather than given its own name: every relay URL on both sides is
# composed as {base}/v1/..., and the relay has no notion of its own public
# address, so a prefix is invisible to it. Same-origin also means no CORS and no
# second certificate -- and a future kanban.l4ir.net inherits the relay by
# copying the location block below.
upstream kanban_relay_up {
server bob.hanzalova.internal:27181;
keepalive 16;
}
upstream kanban_up {
server bob.hanzalova.internal:27180;
keepalive 16;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name kanban.internal;
ssl_certificate /etc/nginx/tls/cert/kanban.internal.pem;
ssl_certificate_key /etc/nginx/tls/key/kanban.internal.pem;
ssl_protocols TLSv1.3;
ssl_trusted_certificate /etc/pki/ca-trust/source/anchors/root-internal.pem;
client_max_body_size 100m;
# Electric shape subscriptions are long-poll/streaming; don't cut them short.
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
# Trailing slash on proxy_pass strips /relay-api/, so the relay sees the
# /v1/... routes it nests. Must precede location / .
location /relay-api/ {
proxy_pass http://kanban_relay_up/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# The relay control channel is a long-lived websocket.
proxy_buffering off;
}
location / {
proxy_pass http://kanban_up;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Sync streams must reach the browser as they arrive, not in buffers.
proxy_buffering off;
}
}

View File

@@ -27,7 +27,7 @@ Wants=network-online.target
Requires=vibe-kanban-db.service
[Container]
Image=git.lair.cafe/lair/vibe-kanban-relay:REPLACE_WITH_IMMUTABLE_TAG
Image=git.lair.cafe/lair/vibe-kanban-relay:0.1.44-ge06652a
ContainerName=vibe-kanban-relay
Network=vibe-kanban.network
# Published to the LAN so the hanzalova edge proxy can reach it; the browser and

View File

@@ -23,7 +23,7 @@ Wants=network-online.target
Requires=vibe-kanban-db.service
[Container]
Image=git.lair.cafe/lair/vibe-kanban-remote:0.1.44-gccff6fc
Image=git.lair.cafe/lair/vibe-kanban-remote:0.1.44-ge06652a
ContainerName=vibe-kanban
Network=vibe-kanban.network
PublishPort=27180:8081