Manages one Caddyfile entry per subdomain (URL -> IP:Port, plus optional
HTTP Basic Auth) and applies changes with a hot-reload through the Caddy
admin API, so an edit is live in ~0.3s with no restart and no certificate
churn.
Safety properties:
- every change is validated by the real Caddy binary before it is written
- a rejected reload restores the previous Caddyfile
- site blocks containing directives cadprox does not model are preserved
byte-for-byte, shown read-only, and never rewritten
- the Caddyfile is the only source of state, so a hand-edited file cannot
silently diverge from what the UI shows
- password hashes never leave the server; the session cookie is HttpOnly
and SameSite=Strict, and mutating requests need a custom header
app.py is a single standard-library file. The image is built on caddy:2.11.4
so validation, adaptation and hashing use the same binary that serves
traffic, which is why basic-auth hashes are bcrypt: Caddy's argon2id hashes
load fine but its basic-auth provider only verifies bcrypt.
Tests: 28 unit tests (Caddy-backed ones skip without the binary) and a 32
assertion end-to-end script that runs against a throwaway Caddy.
24 lines
702 B
Docker
24 lines
702 B
Docker
# cadprox reuses the official Caddy image so that validation, config adaptation
|
|
# and password hashing are performed by the exact same binary that will serve
|
|
# the traffic. A different Caddy build could accept a config the live instance
|
|
# then rejects.
|
|
FROM caddy:2.11.4
|
|
|
|
# The caddy image ships no Python, and app.py is standard library only.
|
|
# The base is Alpine, so it is apk rather than apt.
|
|
RUN apk add --no-cache python3
|
|
|
|
WORKDIR /app
|
|
COPY app.py /app/app.py
|
|
|
|
ENV CADPROX_CADDYFILE=/caddy/Caddyfile \
|
|
CADPROX_CADDY_ADMIN=http://127.0.0.1:2019 \
|
|
CADPROX_DATA=/data \
|
|
CADPROX_PORT=8090 \
|
|
PYTHONUNBUFFERED=1
|
|
|
|
EXPOSE 8090
|
|
VOLUME ["/data"]
|
|
|
|
ENTRYPOINT ["python3", "-u", "/app/app.py"]
|