Reverse Proxy Configuration
This guide covers configuring the three most common reverse proxies for use with Briefen.
Before you start
Two settings must be correct for every setup:
1 — Raise timeouts to 310 seconds
Summarizing a long article with a local Ollama model can take 2–3 minutes. Every reverse proxy ships with a default timeout of 60 seconds. That default will kill the connection mid-request, returning a network error to the browser even though the summary completed fine on the backend. Set all proxy timeouts to 310 s — 10 seconds more than Briefen’s own Ollama client timeout.
2 — Enable forwarded-header trust
Set SERVER_FORWARD_HEADERS_STRATEGY=FRAMEWORK in Briefen’s environment so Spring Boot reads the X-Forwarded-Proto and X-Forwarded-Host headers that the proxy sends. Without this, any server-generated redirect (e.g. after login) uses http:// even on an HTTPS deployment.
# docker-compose.sample.yml → environment:
SERVER_FORWARD_HEADERS_STRATEGY: FRAMEWORK
Nginx
Minimal HTTPS config
server {
listen 443 ssl;
server_name briefen.example.com;
ssl_certificate /etc/ssl/certs/briefen.crt;
ssl_certificate_key /etc/ssl/private/briefen.key;
location / {
proxy_pass http://127.0.0.1:8080;
# ── Required: raise timeouts for long Ollama requests ──────────────
proxy_read_timeout 310s;
proxy_send_timeout 310s;
proxy_connect_timeout 10s;
# ── Required: forward original host/scheme to Spring Boot ──────────
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# ── Recommended: buffer settings for streaming responses ───────────
proxy_buffering off;
proxy_request_buffering off;
}
}
# Redirect HTTP → HTTPS
server {
listen 80;
server_name briefen.example.com;
return 301 https://$host$request_uri;
}
Nginx Proxy Manager (NPM)
If you use Nginx Proxy Manager, open the proxy host → Edit → Advanced and paste into the Custom Nginx Configuration box:
proxy_read_timeout 310s;
proxy_send_timeout 310s;
proxy_connect_timeout 10s;
proxy_buffering off;
NPM already sets the X-Forwarded-* headers automatically — no extra configuration needed.
Sub-path deployment with Nginx
If Briefen is built locally with a sub-path (APP_BASE_PATH=/briefen/), configure the proxy to pass the prefix to the app:
location /briefen/ {
proxy_pass http://127.0.0.1:8080/briefen/;
proxy_read_timeout 310s;
proxy_send_timeout 310s;
proxy_connect_timeout 10s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Set SERVER_CONTEXT_PATH=/briefen/ in the Briefen environment to match.
If you want the proxy to strip the prefix before forwarding (so Briefen sees
/), useproxy_pass http://127.0.0.1:8080/;(trailing slash) and leaveSERVER_CONTEXT_PATHunset.
Caddy
Caddy automatically provisions and renews TLS certificates via Let’s Encrypt and has no default proxy timeout, so no explicit timeout configuration is required.
Minimal HTTPS config
briefen.example.com {
reverse_proxy localhost:8080
}
That’s it. Caddy handles TLS, sets X-Forwarded-* headers, and has no timeout by default.
With explicit header passthrough (optional)
briefen.example.com {
reverse_proxy localhost:8080 {
header_up X-Real-IP {remote_host}
}
}
Sub-path deployment with Caddy
myserver.example.com {
handle_path /briefen/* {
rewrite * /briefen{uri}
reverse_proxy localhost:8080
}
}
Set SERVER_CONTEXT_PATH=/briefen/ and build the image with APP_BASE_PATH=/briefen/.
Traefik
Docker Compose label-based config
Add these labels to the Briefen service in your compose file:
services:
app:
image: ghcr.io/lucaslra/briefen:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.briefen.rule=Host(`briefen.example.com`)"
- "traefik.http.routers.briefen.entrypoints=websecure"
- "traefik.http.routers.briefen.tls.certresolver=letsencrypt"
- "traefik.http.services.briefen.loadbalancer.server.port=8080"
Note: Traefik does not support per-service response timeouts via labels. Timeout configuration is set globally in the static config — see below.
Add to your Traefik static configuration (traefik.yml or traefik.toml):
# traefik.yml
serversTransport:
respondingTimeouts:
readTimeout: 310s
writeTimeout: 310s
idleTimeout: 310s
Or with environment variables if you run Traefik in Docker:
environment:
- TRAEFIK_SERVERSTRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT=310s
- TRAEFIK_SERVERSTRANSPORT_RESPONDINGTIMEOUTS_WRITETIMEOUT=310s
Note: Traefik’s default
readTimeoutfor backend responses is 0 (unlimited), so if you are not seeing timeouts you may already be fine. Check your static config to be sure.
Sub-path deployment with Traefik
labels:
- "traefik.http.routers.briefen.rule=Host(`myserver.example.com`) && PathPrefix(`/briefen`)"
- "traefik.http.middlewares.briefen-strip.stripPrefix.prefixes=/briefen"
- "traefik.http.routers.briefen.middlewares=briefen-strip"
Using stripPrefix means the proxy removes /briefen before forwarding — leave SERVER_CONTEXT_PATH unset in this case (the app sees all requests at /).
Protecting the Ollama port
Regardless of which proxy you use, ensure the Ollama API port (11434) is never exposed to the network. Ollama has no authentication. The default docker-compose.sample.yml binds it to 127.0.0.1:11434 — do not change this.
# Correct — loopback only
ports:
- "127.0.0.1:11434:11434"
# WRONG — exposed to all interfaces
ports:
- "11434:11434"
Binding Briefen to localhost
When a reverse proxy runs on the same host as Briefen, you can restrict Briefen to only accept connections from localhost, preventing direct access that would bypass the proxy:
# docker-compose.sample.yml → environment:
SERVER_BIND_ADDRESS: 127.0.0.1
Then in the proxy, use proxy_pass http://127.0.0.1:8080 (or equivalent). The Briefen port no longer needs to be published to the host at all — remove or replace the ports: entry with a network-only reference.