Put Caddy in front
HTTPS, a reverse proxy, and a configuration file you can read before your coffee gets cold. Caddy is annoyingly good at this.
Keep the Python listener private
These deployment chapters use the notebook at the site root, including its static files. Use a host with Caddy installed and your app dependencies in a virtualenv. First run the backend on IPv4 loopback:
# Run from the repository root with the notebook dependencies installed.
weft example_app.asgi:app --host 127.0.0.1 --port 8000 \
--lifespan on --forwarded-allow-ips 127.0.0.1Accept forwarded headers only from the loopback proxy. That gives the notebook the external HTTPS scheme for cookie flags and same-origin checks, and the actual client address for its rate limiter. Use your supervisor to keep this process running; the operations chapter includes systemd.
Give your domain a Caddyfile
Replace notes.example.com with your domain. Point its DNS records at this host and make ports 80 and 443 reachable. Keep Caddy’s certificate storage writable and persistent. With those prerequisites, automatic HTTPS handles certificate issuance, renewal, and HTTP redirects.
notes.example.com {
request_body {
max_size 1MB
}
encode zstd gzip
reverse_proxy 127.0.0.1:8000
}request_body caps uploads at about one megabyte. reverse_proxy preserves the request path and forwards the Host and proxy headers. The notebook still sees /api/notes, which is fortunate because that’s where we put it.
Validate, reload, and check
Save the site configuration in the Caddyfile used by your installation, commonly /etc/caddy/Caddyfile. Validate it before applying it:
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl reload caddy
curl -i https://notes.example.com/api/healthUse the Caddy CLI reload workflow if your installation isn’t managed by systemd. Expect JSON 200 from health. Visit the site, log in, and check that the refresh cookie has Secure under HTTPS. A green health check cannot inspect your cookies on your behalf.
Try the proxy locally
For an HTTP-only local smoke check, replace the domain line with http://localhost:8080, save as Caddyfile.local, and run:
caddy run --config Caddyfile.local --adapter caddyfileOpen http://localhost:8080/. This explicitly disables automatic HTTPS for that local site. Use the domain configuration for public HTTPS.
Keep the responsibilities obvious
Caddy terminates TLS and limits request bodies. Weft runs the ASGI app. The notebook handles its database lifecycle and authorization. You still need a shared rate-limit strategy if you want one limit across workers; this Caddyfile does not add one.
Choose whether compression belongs in Caddy or an application middleware layer. For streams, check proxy timeouts and disconnect behavior with a real client. For a separate frontend build, use explicit static and API routing while preserving the API prefix.
