#!/usr/bin/env sh # # Erzeugt die Konfiguration des Tunnel-Gateways beim Start und startet Caddy. # # Warum erzeugt statt fest hinterlegt: die Namen stehen in der .env und sind je # Installation andere, und zu jedem gehört ein eigenes Zertifikat. Caddy startet # NICHT, wenn eine in `tls` genannte Datei fehlt — ein noch nicht ausgestelltes # Zertifikat für www. nähme damit den Tunnel-Zugang zur Konsole mit, und das ist # der Weg, auf dem sich ein ausgesperrter Betreiber zurückholt. Deshalb wird # jeder Name einzeln geprüft und ausgelassen, wenn sein Zertifikat fehlt. # # Die Zertifikate sind die, die der öffentliche Caddy ohnehin erneuert. Ein # Zertifikat hängt am NAMEN, nicht an der Adresse, die ihn ausliefert. set -eu HUB="${VPN_HUB_ADDRESS:-10.66.0.1}" HEALTH="${VPN_HEALTH_PORT:-8081}" CERT_DIR="${VPN_CERT_DIR:-/certs}" OUT="${VPN_CONFIG_OUT:-/tmp/vpn.Caddyfile}" # Die Zertifikate, die dieser Lauf wirklich geladen hat. Der Update-Agent # ueberwacht sie und startet den Gateway nach einer Erneuerung neu — Caddys # `tls` liest die Datei EINMAL beim Start, und ohne Neustart liefe der Tunnel # danach mit einem abgelaufenen Zertifikat weiter, ausgerechnet fuer die # einzigen Leute, die die Konsole noch erreichen. CERT_LIST="${VPN_CERT_LIST:-/tmp/vpn-certs.list}" : > "$CERT_LIST" { echo '{' echo ' admin off' echo ' auto_https off' echo '}' } > "$OUT" # Der Konsolenname ZUERST, und getrennt von der Liste: er ist der einzige, ohne # den der Gateway keinen Zweck hat. emit_site() { name="$1" # `-print -quit`, nicht `| head -1`: eine Pipe, aus der head aussteigt, # waehrend find noch schreibt, liefert SIGPIPE — install-agent.sh hat sich # daran schon einmal selbst beendet. `|| true`, damit ein leeres Ergebnis # unter `set -e` kein Abbruch ist. crt="$(find "$CERT_DIR" -name "${name}.crt" -print -quit 2>/dev/null || true)" if [ -z "$crt" ] || [ ! -f "${crt%.crt}.key" ]; then echo " ausgelassen: $name — kein Zertifikat unter $CERT_DIR" >&2 return 0 fi { echo "" echo "https://${name}:443 {" echo " bind ${HUB}" echo " tls ${crt} ${crt%.crt}.key" echo " reverse_proxy app:80 {" echo " header_up X-Forwarded-For {remote_host}" echo " header_up X-Forwarded-Proto https" echo " header_up Host {host}" echo " }" echo "}" } >> "$OUT" echo "$crt" >> "$CERT_LIST" } # `if`, nicht `[ … ] && …`. Bei leerem Wert gibt die AND-OR-Liste 1 zurueck, und # genau diese Konstruktion hat install-agent.sh unter `set -e` schon einmal # beendet — dort als letzte Anweisung einer Funktion. Hier waere sie geprueft # unschaedlich, aber die Regel steht im Repo und eine Ausnahme davon muesste man # jedem Nachfolger erklaeren. if [ -n "${VPN_INTERNAL_HOST:-}" ]; then emit_site "$VPN_INTERNAL_HOST" fi # Portal, Website und Statusseite. files. steht hier nie drin: dort holt ein # Server im Rettungssystem sein Archiv, und der ist nicht im Tunnel. echo "${VPN_TUNNEL_HOSTS:-}" | tr ',' '\n' | while read -r host; do [ -n "$host" ] || continue emit_site "$host" done # Der Gesundheits-Port, ohne TLS und ohne Namen. Daran hängt VPN_READY und damit, # ob ausgegebene Client-Konfigurationen den Resolver überhaupt nennen — er darf # deshalb von keinem Zertifikat abhängen. { echo "" echo "http://${HUB}:${HEALTH} {" echo " bind ${HUB}" echo " respond /healthz 204" echo " respond 404" echo "}" } >> "$OUT" # Nur rendern, für den Test: er prüft, was das Skript AUSLÄSST, und braucht # dafür kein laufendes Caddy. if [ -n "${VPN_RENDER_ONLY:-}" ]; then exit 0 fi exec caddy run --config "$OUT" --adapter caddyfile