Documentation menu
Reverse proxy & mTLS
MoliSync trusts identity headers only from configured proxy CIDRs. The proxy must verify the client certificate, strip any inbound identity headers and then set fresh values.
Trust order
- Terminate TLS and request a client certificate.
- Verify the certificate chain and, where applicable, revocation.
- Remove inbound
X-Client-*headers. - Set the verified result, fingerprint and subject from the proxy's own variables.
- Forward WebSocket upgrades and disable request and response buffering.
Nginx example
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_request_buffering off;
proxy_buffering off;
proxy_set_header X-Client-Verify $ssl_client_verify;
proxy_set_header X-Client-DN $ssl_client_s_dn;
# nginx has no SHA-256 variable: $ssl_client_fingerprint is SHA-1 (40 hex) and
# the server rejects it with invalid_client_fingerprint. Forward the whole
# certificate instead and let the server hash it.
proxy_set_header X-Client-Fingerprint "";
proxy_set_header X-Client-Cert $ssl_client_escaped_cert;
Server side: set MOLISYNC_PROXY_CERT_HEADER=X-Client-Cert, and mount the same CA bundle into
the container to enable MOLISYNC_PROXY_CLIENT_CA_FILE (optional, strongly recommended: the server
then verifies the chain instead of trusting the header).
proxy_set_header X-Client-Fingerprint ""; blanks the digest header. Blanking it without
forwarding X-Client-Cert leaves the server with no identity for pinning: P2P falls back to the
relay and the client shows "经服务端中继传输".
Proxies that can compute SHA-256 do not need cert_header; Caddy, for example, exposes it as
{http.request.tls.client.fingerprint}.
Map the headers
Tell the control plane which header names it should read:
| Variable | Value in the example |
|---|---|
MOLISYNC_PROXY_VERIFY_HEADER | X-Client-Verify |
MOLISYNC_PROXY_FINGERPRINT_HEADER | X-Client-Fingerprint |
MOLISYNC_PROXY_CERT_HEADER | X-Client-Cert (optional, whole certificate) |
MOLISYNC_PROXY_CLIENT_CA_FILE | CA path (optional, verifies the certificate header) |
MOLISYNC_PROXY_DN_HEADER | X-Client-DN |
Network boundary
Only the proxy and the control plane should join molisync-internal (subnet 172.28.0.0/24 in the example). Keep MOLISYNC_PROXY_TRUSTED_CIDRS as narrow as that network allows.
Anyone who can reach the service on the trusted network can forge identity headers. Never expose the Go service directly to the public internet, and never let clients join that network.
Checklist
- Client certificate verification enabled and tested with a trusted certificate.
- Inbound
X-Client-*headers stripped at the edge. MOLISYNC_PROXY_TRUSTED_CIDRSmatches only the proxy network.- WebSocket upgrade and streaming (no buffering) verified.
- Health check still points at the real listen port.