One hostname a charger can be told about and actually reach
Charger control needs TLS, and the stack speaks plain HTTP, so the README said "terminate TLS in a reverse proxy" and left the operator to work out which four settings have to agree. This adds the proxy: a Caddy overlay that fronts the Web App BFF — which already carries /api/ and /ocpp/ — so browsers and chargers arrive at the same name and the certificate is issued on first boot. The four settings are derived from DV_DOMAIN, since one value getting typed right is better odds than four: OCPP_PUBLIC_URL, OCPP_REQUIRE_TLS back on, CORS, and TRUST_FORWARDED_PROTO on the Web App. That last one is the non-obvious one — without it the BFF overwrites Caddy's X-Forwarded-Proto with its own plaintext hop and the API Server rejects the charger it just told to connect over wss. The README's OCPP section was stale besides: it still sent chargers to the API Server port alone, from before the BFF carried that path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9f5c8dc49a
commit
e9a82a1cca
5 files changed
+141
-9
No files matched your search
@@ -0,0 +1,61 @@
|
||||
name: drivervault
|
||||
|
||||
# TLS overlay — put a public hostname and a real certificate in front of the
|
||||
# stack. Layer it on top of either base file:
|
||||
#
|
||||
# docker compose -f docker-compose.prod.yml -f docker-compose.tls.yml up -d
|
||||
#
|
||||
# What it changes:
|
||||
# • Caddy terminates TLS on :443 and proxies everything to the Web App BFF,
|
||||
# which already carries /api/ and /ocpp/ through to the API Server. One
|
||||
# hostname serves browsers and chargers alike.
|
||||
# • The charger endpoint the panel hands out becomes wss://$DV_DOMAIN/ocpp/…,
|
||||
# so OCPP_REQUIRE_TLS goes back on and the control token stops crossing the
|
||||
# network in the clear.
|
||||
#
|
||||
# Requirements, none of which this file can arrange for you:
|
||||
# • DV_DOMAIN resolves to this host from the public internet, and ports 80 and
|
||||
# 443 reach it (Caddy needs :80 for the ACME challenge, and keeps it for the
|
||||
# redirect afterwards).
|
||||
# • The charger can resolve DV_DOMAIN too. On a LAN behind NAT that usually
|
||||
# means hairpin NAT or a split-DNS entry pointing the name at 10.2.1.10 —
|
||||
# otherwise the charger looks up a public address it cannot route to.
|
||||
|
||||
services:
|
||||
caddy:
|
||||
image: "${CADDY_IMAGE:-caddy:2-alpine}"
|
||||
container_name: drivervault-caddy
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
web-app:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DV_DOMAIN: "${DV_DOMAIN:?set DV_DOMAIN in .env}"
|
||||
# Let's Encrypt sends expiry warnings here if renewal ever stops working.
|
||||
DV_ACME_EMAIL: "${DV_ACME_EMAIL:?set DV_ACME_EMAIL in .env}"
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||
# Certificates live here. Keep the volume: wiping it re-issues on next
|
||||
# boot and Let's Encrypt rate-limits that.
|
||||
- caddy_data:/data
|
||||
- caddy_config:/config
|
||||
|
||||
api-server:
|
||||
environment:
|
||||
# Derived from the one hostname, so there is a single thing to set.
|
||||
OCPP_REQUIRE_TLS: "true"
|
||||
OCPP_PUBLIC_URL: "wss://${DV_DOMAIN}"
|
||||
CORS_ALLOW_ORIGINS: "https://${DV_DOMAIN}"
|
||||
|
||||
web-app:
|
||||
environment:
|
||||
# Caddy terminates TLS and says so in X-Forwarded-Proto. Believe it —
|
||||
# that header is now set by the proxy in front, not by whoever dialed in.
|
||||
TRUST_FORWARDED_PROTO: "true"
|
||||
|
||||
volumes:
|
||||
caddy_data:
|
||||
caddy_config:
|
||||
Reference in new issue
Block a user