Serve over HTTPS
A production deployment needs TLS. Outside development mode the session cookie is
marked Secure, and a browser does not send it over plain HTTP, so without TLS nobody
can stay signed in. Sift ships an overlay, docker-compose.tls.yml, that makes the
console’s nginx serve HTTPS with a certificate you supply. You can instead put your own
TLS front end in front of Sift.
Sift does not issue or renew certificates. That is your PKI’s job.
Before you start
Section titled “Before you start”You need, in PEM form:
| File | Contents |
|---|---|
tls.crt | The certificate’s full chain, leaf first. |
tls.key | The private key, unencrypted. |
Put both in ./tls beside docker-compose.yml, or in the directory SIFT_TLS_DIR
names. nginx mounts the directory read-only and does not start without both files.
To try the overlay with a throwaway self-signed certificate:
mkdir -p tls && openssl req -x509 -newkey rsa:2048 -nodes -days 30 \ -subj "/CN=localhost" -keyout tls/tls.key -out tls/tls.crtTurn on the overlay
Section titled “Turn on the overlay”-
Place
tls.crtandtls.keyas above. -
Add the overlay to the compose files in
.env, so everymakeanddocker composecommand uses it:Terminal window COMPOSE_FILE=docker-compose.yml:docker-compose.tls.yml -
Apply it:
Terminal window make up
To use the overlay for one command instead, name both files:
docker compose -f docker-compose.yml -f docker-compose.tls.yml up -dCOMPOSE_FILE replaces Compose’s default file list. If you also use a
docker-compose.override.yml, it is read only when COMPOSE_FILE names it too.
What changes
Section titled “What changes”| Without the overlay | With the overlay | |
|---|---|---|
SIFT_HTTPS_PORT (443) | not published | The console, the API and these docs over HTTPS. |
SIFT_WEB_PORT (8080) | The console and the API over HTTP. | A 301 redirect to https://<host>/, and nothing else. |
| Protocols | TLS 1.2 and 1.3, HTTP/2, session tickets off. | |
Strict-Transport-Security | never sent | max-age=31536000 on every HTTPS response. |
The redirect names no port, so it lands on 443. If you publish HTTPS on another port
with SIFT_HTTPS_PORT, give people the full https://host:port/ address.
Every response, over either listener, also carries X-Content-Type-Options: nosniff,
X-Frame-Options: DENY and Referrer-Policy: no-referrer. HSTS leaves out
includeSubDomains and preload, which would commit every host under your domain to
HTTPS; that is your decision to make.
Renew the certificate
Section titled “Renew the certificate”Replace tls.crt and tls.key in place, then restart the web container so nginx reads
them:
docker compose restart sift-webNothing else needs restarting.
Behind a load balancer
Section titled “Behind a load balancer”Sift’s login throttle limits failed sign-ins per client address. It takes the address
from X-Forwarded-For, counting SIFT_TRUSTED_PROXY_HOPS entries from the right: the
address the outermost proxy you trust recorded, never what the client wrote.
| Your setup | SIFT_TRUSTED_PROXY_HOPS |
|---|---|
| Clients reach Sift’s nginx directly | 1 (the default) |
A load balancer or TLS terminator in front of Sift’s nginx also appends to X-Forwarded-For | 2 |
| Nothing proxies the API | 0 |
Set too low, every client shares the load balancer’s budget. Set too high, a client can choose its own address again. The count is sound only while the API cannot be reached around those proxies, which is one reason the stack never publishes the API’s own port.
Your own TLS front end
Section titled “Your own TLS front end”You can terminate TLS at a proxy or load balancer of your own and leave the overlay off.
Point it at SIFT_WEB_PORT, set SIFT_TRUSTED_PROXY_HOPS=2 if it appends to
X-Forwarded-For, and keep the plain port reachable only from that proxy. The proxy must
not buffer text/event-stream responses, and its read timeout should allow for slow
answers: Sift’s own nginx waits up to 300 seconds for the API, and up to 900 seconds under
/api/v1/copilot/, where a request can wait on a model. The assistant’s message stream sends
a keepalive every 15 seconds while it waits.