ac40364f65
Previously Element Call used call.element.io for the frontend JS while routing media through a local LiveKit SFU. This adds the self-hosted Element Call frontend so no requests go to Element's CDN at all. Changes: - docker-compose.yml: add element-call service (ghcr.io/element-hq/element-call) under the element-call profile, port 8083:8080. No config required — the app reads the Matrix homeserver from URL params passed by Element Web, and gets the livekit_service_url from the homeserver's .well-known/matrix/client. - caddy/Caddyfile: add call.example.test:443 virtual host for local dev. - deploy.sh: add CALL_DOMAIN variable (call.example.test / call.<domain>), prompt for call subdomain in production mode, write CALL_DOMAIN to .env, update element_call.url from call.element.io to the self-hosted CALL_DOMAIN in all three places (element/config.json generator and both Caddyfile inline JSON strings), add Caddy blocks for CALL_DOMAIN in local and production Caddyfile generation, add CALL_DOMAIN to /etc/hosts hint, update summary output. - README.md: rewrite to reflect actual project state — deploy.sh workflow, all optional components, correct architecture diagram, bridge setup, ports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
290 lines
9.2 KiB
Caddyfile
290 lines
9.2 KiB
Caddyfile
# Local Development Caddyfile for Matrix Stack
|
|
# Uses self-signed certificates for local HTTPS testing
|
|
# Auto-generated by deploy.sh — do not edit manually
|
|
{
|
|
# Use local CA for self-signed certificates
|
|
local_certs
|
|
# Enable admin API
|
|
admin 0.0.0.0:2019
|
|
}
|
|
|
|
# =========================
|
|
# Matrix Homeserver (Synapse)
|
|
# =========================
|
|
matrix.example.test:443 {
|
|
# TLS with self-signed cert
|
|
tls internal
|
|
|
|
# Well-known client endpoint
|
|
# IMPORTANT: The respond body must stay on a single line. If you edit this file manually
|
|
# and your editor wraps the JSON, Caddy will refuse to start with "invalid control character".
|
|
@wk path /.well-known/matrix/client
|
|
handle @wk {
|
|
header Content-Type application/json
|
|
header Access-Control-Allow-Origin "*"
|
|
respond `{"m.homeserver":{"base_url":"https://matrix.example.test"},"m.authentication":{"issuer":"https://auth.example.test/"},"org.matrix.msc4143.rtc_foci":[{"type":"livekit","livekit_service_url":"https://rtc.example.test/livekit/jwt"}]}` 200
|
|
}
|
|
|
|
# Well-known server endpoint (federation)
|
|
@wk_server path /.well-known/matrix/server
|
|
handle @wk_server {
|
|
header Content-Type application/json
|
|
respond `{"m.server":"matrix.example.test:443"}` 200
|
|
}
|
|
|
|
# Rendezvous endpoints for QR code login (MSC4108)
|
|
@rendezvous path_regexp rendezvous ^/_matrix/client/(unstable|v1)/org\.matrix\.(msc3886|msc4108)/rendezvous.*$
|
|
handle @rendezvous {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept, If-Match, If-None-Match"
|
|
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
|
encode {
|
|
}
|
|
reverse_proxy synapse:8008 {
|
|
header_down -Access-Control-Allow-Origin
|
|
header_down -Access-Control-Allow-Methods
|
|
header_down -Access-Control-Allow-Headers
|
|
header_down -Vary
|
|
}
|
|
}
|
|
|
|
# Client versions endpoint with CORS
|
|
@versions path /_matrix/client/versions
|
|
handle @versions {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
|
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
|
reverse_proxy synapse:8008 {
|
|
header_down -Access-Control-Allow-Origin
|
|
header_down -Access-Control-Allow-Methods
|
|
header_down -Access-Control-Allow-Headers
|
|
header_down -Vary
|
|
}
|
|
}
|
|
|
|
# CORS preflight for auth metadata
|
|
@auth_preflight {
|
|
method OPTIONS
|
|
path /_matrix/client/unstable/org.matrix.msc2965/auth_metadata
|
|
}
|
|
handle @auth_preflight {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
|
header Access-Control-Max-Age "86400"
|
|
respond 204
|
|
}
|
|
|
|
# CORS preflight for all Matrix API
|
|
@preflight {
|
|
method OPTIONS
|
|
path_regexp matrix ^/_matrix/.*$
|
|
}
|
|
handle @preflight {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
|
header Access-Control-Max-Age "86400"
|
|
respond 204
|
|
}
|
|
|
|
# MAS compat endpoints (login/logout/refresh) with CORS
|
|
@compat path \
|
|
/_matrix/client/v3/login* \
|
|
/_matrix/client/v3/logout* \
|
|
/_matrix/client/v3/refresh* \
|
|
/_matrix/client/r0/login* \
|
|
/_matrix/client/r0/logout* \
|
|
/_matrix/client/r0/refresh*
|
|
handle @compat {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
|
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
|
reverse_proxy mas:8080 {
|
|
header_down -Access-Control-Allow-Origin
|
|
header_down -Access-Control-Allow-Methods
|
|
header_down -Access-Control-Allow-Headers
|
|
header_down -Vary
|
|
}
|
|
}
|
|
|
|
# Everything else under /_matrix → Synapse with CORS
|
|
@matrix_rest path_regexp matrix ^/_matrix/.*$
|
|
handle @matrix_rest {
|
|
header Access-Control-Allow-Origin "*"
|
|
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
|
|
header Vary "Origin, Access-Control-Request-Method, Access-Control-Request-Headers"
|
|
reverse_proxy synapse:8008 {
|
|
header_down -Access-Control-Allow-Origin
|
|
header_down -Access-Control-Allow-Methods
|
|
header_down -Access-Control-Allow-Headers
|
|
header_down -Vary
|
|
}
|
|
}
|
|
|
|
# Default: everything else → Synapse
|
|
handle {
|
|
reverse_proxy synapse:8008
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Matrix Authentication Service (MAS)
|
|
# =========================
|
|
auth.example.test:443 {
|
|
tls internal
|
|
|
|
# OIDC Discovery
|
|
@disco path /.well-known/openid-configuration
|
|
handle @disco {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# Dynamic Client Registration: CORS preflight
|
|
@reg_opts {
|
|
method OPTIONS
|
|
path /oauth2/registration
|
|
}
|
|
handle @reg_opts {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "POST, OPTIONS"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
respond 204
|
|
}
|
|
|
|
# Dynamic Client Registration (POST)
|
|
@reg path /oauth2/registration
|
|
route @reg {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "POST, OPTIONS"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# JWKS preflight
|
|
@jwks_opts {
|
|
method OPTIONS
|
|
path /oauth2/keys.json
|
|
}
|
|
handle @jwks_opts {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
respond 204
|
|
}
|
|
|
|
# Map keys.json → /oauth2/jwks (MAS naming)
|
|
@jwksjson path /oauth2/keys.json
|
|
route @jwksjson {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "GET, OPTIONS"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
uri replace /oauth2/keys.json /oauth2/jwks
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# Generic OAuth2 endpoints
|
|
@oauth path /oauth2/*
|
|
route @oauth {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Methods "GET, OPTIONS, POST"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# Account portal
|
|
handle_path /account/* {
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# Authelia endpoints (proxy to authelia)
|
|
handle_path /authelia/* {
|
|
reverse_proxy authelia:9091
|
|
}
|
|
|
|
# Fallback: everything else to MAS
|
|
handle {
|
|
reverse_proxy mas:8080
|
|
}
|
|
|
|
# Add CORS on error responses
|
|
handle_errors {
|
|
header ?Access-Control-Allow-Origin "*"
|
|
header ?Access-Control-Allow-Headers "*"
|
|
header ?Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Authelia SSO
|
|
# =========================
|
|
authelia.example.test:443 {
|
|
tls internal
|
|
|
|
reverse_proxy authelia:9091
|
|
}
|
|
|
|
# =========================
|
|
# Element Web Client
|
|
# =========================
|
|
element.example.test:443 {
|
|
tls internal
|
|
|
|
# Serve config.json with proper settings
|
|
# IMPORTANT: respond body must stay on a single line — see well-known note above.
|
|
@cfg path /config.json
|
|
handle @cfg {
|
|
header Content-Type application/json
|
|
header Cache-Control no-store
|
|
respond `{"default_server_config":{"m.homeserver":{"base_url":"https://matrix.example.test","server_name":"matrix.example.test"}},"default_server_name":"matrix.example.test","disable_custom_urls":false,"disable_guests":true,"features":{"feature_oidc_aware_navigation":true,"feature_element_call_video_rooms":true},"element_call":{"url":"https://call.element.io","participant_limit":8,"brand":"Element Call"}}` 200
|
|
}
|
|
|
|
# Everything else to Element container
|
|
handle {
|
|
reverse_proxy element:80
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Element Admin
|
|
# =========================
|
|
admin.example.test:443 {
|
|
tls internal
|
|
|
|
handle {
|
|
reverse_proxy element-admin:8080
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Element Call (LiveKit)
|
|
# =========================
|
|
rtc.example.test:443 {
|
|
tls internal
|
|
|
|
handle_path /livekit/jwt* {
|
|
reverse_proxy lk-jwt-service:8080
|
|
}
|
|
|
|
handle_path /livekit/sfu* {
|
|
reverse_proxy livekit:7880
|
|
}
|
|
}
|
|
|
|
# =========================
|
|
# Element Call Frontend
|
|
# =========================
|
|
call.example.test:443 {
|
|
tls internal
|
|
|
|
reverse_proxy element-call:8080
|
|
}
|