From c637b2783c2568dc8a7ca174f4aa90109736f351 Mon Sep 17 00:00:00 2001 From: Julian Cuni Date: Tue, 23 Jun 2026 19:15:23 +0200 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20Caddy=20reverse=20proxy=20?= =?UTF-8?q?=E2=80=94=20clean=20port-80=20URL,=20server=20internal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operators/admins reach the booth at http:/// (no :3000). Adds a caddy:2-alpine proxy to the prod override that reverse-proxies :80 → server:3000 (the /api/ws WebSocket upgrades pass through natively); the server is now `expose: 3000` (internal, no published port), vision stays internal. The Caddyfile binds `:80` so it matches ANY hostname/IP — works for the booth IP, localhost, AND parksystems.msai.al (pointed at the booth via hosts/DNS on-site; no domain baked into any image). TLS later = swap `:80` for the real hostname + uncomment :443 → Caddy auto-provisions HTTPS. Pairs with the relative-/api SPA fix (77b2acb): together verified end-to-end locally — through Caddy on :80 with Host: parksystems.msai.al, GET / serves the SPA, assets/health 200, and POST /api/auth/login reaches the server (real 401, no CORS/connection error). Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V --- Caddyfile | 13 +++++++++++++ docker-compose.prod.yml | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 Caddyfile diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..9140933 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,13 @@ +# Booth reverse proxy. `:80` matches ANY hostname/IP, so the booth is reachable as +# http:///, http://localhost/, or http://parksystems.msai.al/ (the name pointed +# at the booth's IP via hosts/DNS on-site) — with no domain baked into any image. The SPA +# uses a relative /api base, so everything (HTTP + the /api/ws WebSocket, which Caddy +# upgrades automatically) just flows through to the server container. +# +# TLS later: replace `:80` with the real hostname (e.g. `parksystems.msai.al`), uncomment +# Caddy's :443 in docker-compose.prod.yml, and Caddy auto-provisions HTTPS. For a private +# CA / internal cert, use `tls /path/cert.pem /path/key.pem`. +:80 { + encode gzip + reverse_proxy server:3000 +} diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 7aff09a..ce7656e 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,14 +1,41 @@ # PROD override: pull pinned registry images (no local build), restart always, real -# recognizer, and keep vision INTERNAL (only the server port is published). Use with the -# base file and pin TAG to the branch/SHA you deploy: +# recognizer, and a CADDY reverse proxy in front so operators reach the booth on a clean +# port-80 URL (no :3000) — and a path to real TLS later. Server + vision stay INTERNAL +# (only Caddy publishes a port). Use with the base file and pin TAG to the branch you deploy: # REGISTRY=git.infra.msai.al/mca/parking_solution TAG=main \ # docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d +# See wiki/decisions/container-deployment.md. services: - server: + # Reverse proxy: :80 → server:3000 (WebSocket /api/ws upgrades pass through natively). + # Caddy is a single static binary with a one-line proxy config; swapping http:// for the + # site's real hostname later enables automatic HTTPS. The booth is reached at + # http:/// (the name set via hosts/DNS on-site — NOT baked into any image). + proxy: + image: caddy:2-alpine restart: always ports: - - "3000:3000" + - "80:80" + # - "443:443" # uncomment when moving to TLS (and set a real hostname in Caddyfile) + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + depends_on: + - server + networks: + - parking + logging: + driver: json-file + options: + max-size: "10m" + max-file: "3" + + server: + restart: always + # No published port — only the proxy reaches the server, over the private network. + expose: + - "3000" logging: driver: json-file options: @@ -26,3 +53,7 @@ services: options: max-size: "10m" max-file: "3" + +volumes: + caddy-data: + caddy-config: