Proxy
Put Caddy or nginx in front of the server to hold the TLS certificate.
The daemon terminates no TLS. A team that runs a server already runs a proxy, and a certificate lifecycle inside the daemon is a product of its own. The proxy holds the certificate, speaks TLS to the browser, and speaks plain HTTP to the daemon on the private interface.
The proxy does three things:
- Forward the WebSocket upgrade of
/api/v1/ws,/api/v1/channels/{id}/dictateand/api/v1/calls/{id}/listen. Without it the Product App loads and then shows nothing live. - Set
X-Forwarded-Prototo the scheme the browser used. The Session cookie carriesSecureonly where the daemon is told the browser spoke TLS. - Set
X-Forwarded-Forto the browser's address. The sign-in rate limit counts against it, so without it one person who forgets a password locks out everybody behind the proxy.
A browser can write both headers, so the daemon reads them from the Trusted
Proxy and from no other address. It takes the last entry of
X-Forwarded-For, which is the entry the proxy wrote, so a proxy that
appends and a proxy that replaces read the same. In the compose deployment
the Trusted Proxy is 127.0.0.1, where the proxy is and where no browser
can be.
Caddy
pagis.example.net {
reverse_proxy 10.0.1.7:4400
}Caddy gets and renews the certificate, sets X-Forwarded-Proto, appends to
X-Forwarded-For, and passes a WebSocket upgrade through with no
configuration. deploy/Caddyfile is the same block for the compose
deployment, with the admin API of Caddy off (The shape).
nginx
server {
listen 443 ssl;
server_name pagis.example.net;
ssl_certificate /etc/letsencrypt/live/pagis.example.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pagis.example.net/privkey.pem;
location / {
proxy_pass http://10.0.1.7:4400;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# The WebSocket upgrade of /api/v1/ws and of the two media sockets.
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# A run streams for minutes and a socket stays open for hours.
proxy_read_timeout 1h;
proxy_send_timeout 1h;
proxy_buffering off;
}
client_max_body_size 50m; # the artifact upload cap
}
# Connection: upgrade only where the request asked for one.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}