Calendars: Caddy Reverse Proxy¶
The Calendars pre-built frontend image serves only static files. It doesn't include API reverse proxy rules. You must mount a custom Caddyfile to proxy:
/api/v1.0/*→ Django backend/caldav/*→ Django backend (which adds auth and proxies to CalDAV server)/rsvp/*→ Django backend (RSVP page for email invitation links)
Custom Caddyfile¶
{
auto_https off
admin off
}
:8080 {
root * /srv
header X-Frame-Options DENY
route {
# API reverse proxy to backend
reverse_proxy /api/v1.0/* 172.29.0.30:8000 {
header_up Host {host}
header_up X-Forwarded-Proto https
}
# CalDAV proxy through Django (adds X-LS-User + API key)
reverse_proxy /caldav/* 172.29.0.30:8000 {
header_up Host {host}
header_up X-Forwarded-Proto https
}
# RSVP endpoint (handles accept/maybe/decline links)
reverse_proxy /rsvp/* 172.29.0.30:8000 {
header_up Host {host}
header_up X-Forwarded-Proto https
}
try_files {path} {path}.html /index.html
file_server
}
handle_errors {
rewrite * /404.html
file_server
}
}
Why Three Proxies?¶
/api/v1.0/*— standard REST API calls from the frontend JS/caldav/*— CalDAV protocol requests (PROPFIND, MKCALENDAR, REPORT). MUST go through Django, not directly to CalDAV. Django addsX-LS-Userheader and API key authentication/rsvp/*— RSVP confirmation pages linked from invitation emails. Django serves the HTML page and processes accept/decline actions
Critical: CalDAV Must Go Through Django¶
The CalDAV PHP server uses ApiKeyAuthBackend which requires an API key header. Direct browser requests don't have this — they only have session cookies. Proxying through Django solves this:
If you proxy /caldav/* directly to the CalDAV server:
1. CalDAV returns 401 (no API key)
2. Frontend JS sees 401 → triggers full re-authentication
3. Infinite redirect loop
Port¶
Caddy listens on 8080, not 3000. This is what the original Caddyfile in the image uses. The Traefik label must match.