146 lines
6.1 KiB
Caddyfile
146 lines
6.1 KiB
Caddyfile
{
|
|
servers {
|
|
# Address-based rules and QUIC early data do not mix: a decision taken
|
|
# on 0-RTT data can answer 425, and some browsers do not retry — an
|
|
# intermittent lockout from the console, which is the worst kind.
|
|
protocols h1 h2
|
|
}
|
|
# Replace: this address receives the certificate-expiry notices for THIS
|
|
# installation. Left as the copied original, they reach whoever wrote the
|
|
# file instead of whoever runs the server.
|
|
email you@example.com
|
|
}
|
|
|
|
# Reference reverse-proxy configuration.
|
|
#
|
|
# Copy to /etc/caddy/Caddyfile, replace the hostnames, then:
|
|
# sudo bash deploy/install-agent.sh
|
|
# which replaces the console's allowlist line with an import generated from the
|
|
# list the owner keeps in the console itself.
|
|
#
|
|
# The rule this file exists to enforce: only the marketing site, the customer
|
|
# portal and the status page are public. The console and the websocket endpoint
|
|
# must not merely refuse — they must be indistinguishable from a hostname that
|
|
# serves nothing at all. An empty 404 is itself information: it says something
|
|
# terminates TLS here and chose not to answer.
|
|
|
|
|
|
|
|
# ── Customer portal ──────────────────────────────────────────────────────────
|
|
app.example.com {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
|
|
# ── Stripe webhook, and nothing else ─────────────────────────────────────────
|
|
# The application answers the whole site on every hostname, so without this the
|
|
# login and registration pages are served here too. Narrowed to the one request
|
|
# this hostname exists for; everything else never reaches PHP.
|
|
api.example.com {
|
|
@webhook {
|
|
method POST
|
|
path /webhooks/stripe
|
|
}
|
|
handle @webhook {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
handle {
|
|
respond 404
|
|
}
|
|
}
|
|
|
|
# ── Websockets (Reverb) ──────────────────────────────────────────────────────
|
|
ws.example.com {
|
|
# Only an actual websocket upgrade. A browser opening this name has no
|
|
# business here, and answering it — even with a 404 — advertises that
|
|
# something is listening.
|
|
@websocket {
|
|
header Connection *Upgrade*
|
|
header Upgrade websocket
|
|
}
|
|
handle @websocket {
|
|
reverse_proxy 127.0.0.1:8081
|
|
}
|
|
handle {
|
|
abort
|
|
}
|
|
}
|
|
|
|
# ── Operator console ─────────────────────────────────────────────────────────
|
|
# The network-level lock. The hostname checks inside the application are
|
|
# defence in depth — a Host header is chosen by the caller, so they cannot
|
|
# decide WHO gets through. This can.
|
|
#
|
|
# 10.66.0.0/24 is the WireGuard subnet. 62.178.50.33 is temporary, so the first
|
|
# VPN access can be created at all; it comes out once that is done.
|
|
admin.example.com {
|
|
import /etc/caddy/clupilot-console-allow.conf
|
|
handle @allowed {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
# Nothing at all for anyone else. An empty 404 still says "something
|
|
# terminates TLS here and chose not to answer" — which is itself the
|
|
# information worth hiding. Closing the connection is what a host that does
|
|
# not serve this name looks like.
|
|
handle {
|
|
abort
|
|
}
|
|
}
|
|
www.example.com {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
|
|
status.example.com {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
|
|
# ── Von der Konsole verwaltete Hostnamen ─────────────────────────────────────
|
|
# Erzeugt von `clupilot-host-step apply-proxy-hosts` aus der Liste, die der
|
|
# Betreiber in der Konsole pflegt. Damit lässt sich ein Name hinzufügen, ohne
|
|
# sich auf den Server zu melden — der Handgriff, der `files.clupilot.com`
|
|
# gekostet hat.
|
|
#
|
|
# BEIDES setzt `sudo bash deploy/install-agent.sh` selbst — die Datei und die
|
|
# Import-Zeile unten. Von Hand eintragen muss man nichts, und man sollte es auch
|
|
# nicht: die Datei MUSS existieren, bevor irgendetwas sie importiert, denn ein
|
|
# Import ins Leere macht die GANZE Proxy-Konfiguration ungültig und nimmt die
|
|
# öffentliche Website mit. Eine Anleitung wird in der falschen Reihenfolge
|
|
# befolgt, ein Skript nicht.
|
|
#
|
|
# Der Installer prüft nach dem Eintragen mit `caddy validate` und nimmt die
|
|
# Zeile wieder heraus, wenn Caddy sie ablehnt.
|
|
#
|
|
# EIN NAME GEHÖRT AN EINE STELLE. Steht ein Hostname schon von Hand in dieser
|
|
# Datei, lässt die Erzeugung ihn aus — zwei Blöcke für denselben Namen lehnt
|
|
# Caddy ab, und zwar die ganze Konfiguration.
|
|
import /etc/caddy/clupilot-proxy-hosts.conf
|
|
|
|
# ── Dateien zum Herunterladen ────────────────────────────────────────────────
|
|
# FILES_HOST aus der .env. Zwei Dinge liegen hier, und beide müssen von überall
|
|
# erreichbar sein:
|
|
#
|
|
# - Rechtsdokumente (AGB, AV, TOM). Ihre Adressen stehen in Verträgen und auf
|
|
# Rechnungen und müssen Jahre halten.
|
|
# - Das Bootstrap-Archiv für die Host-Übernahme. Es wird von einem Server im
|
|
# RETTUNGSSYSTEM geholt — einer Maschine ohne Tunnel, mit einer öffentlichen
|
|
# Adresse, die in keiner Freigabeliste steht. Genau deshalb steht hier KEIN
|
|
# `import clupilot-console-allow.conf`: die Sperre der Konsole wäre hier die
|
|
# Sperre gegen den einzigen, der es braucht.
|
|
#
|
|
# Der Schutz sitzt in der Anwendung, nicht im Proxy: ohne gültigen Einmal-Code
|
|
# antwortet das Archiv mit 404, und die Dokumente sind ohnehin öffentlich.
|
|
#
|
|
# Auch KEIN `http://… { abort }` wie bei admin und ws weiter unten. Dieser Name
|
|
# soll bekannt sein — und ein abgewürgtes Port 80 nimmt der ACME-Prüfung den
|
|
# Weg, wenn Caddys eigener Handler einmal nicht als Erster drankommt.
|
|
files.example.com {
|
|
reverse_proxy 127.0.0.1:8080
|
|
}
|
|
|
|
# Plain HTTP for the two hidden names. Without this Caddy answers port 80 with
|
|
# an automatic redirect to https, which announces that both hostnames are
|
|
# served here — the one thing this file exists to avoid. The ACME challenge is
|
|
# unaffected: Caddy's own challenge handler runs ahead of these routes.
|
|
http://admin.example.com, http://ws.example.com {
|
|
abort
|
|
}
|