Skip to content

Reverse Proxy

A reverse proxy terminates TLS and forwards requests to Presswerk and Keycloak. Both services need their own domain or subdomain.

ServiceInternalExternal (example)
Applicationhttp://localhost:8080https://reports.your-domain.com
Keycloakhttp://localhost:8081https://auth.your-domain.com

Keycloak is already configured with KC_PROXY_HEADERS=xforwarded to trust X-Forwarded-* headers.

server {
listen 443 ssl http2;
server_name reports.your-domain.com;
ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;
client_max_body_size 50m;
location / {
proxy_pass http://localhost:8080;
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;
}
}
server {
listen 443 ssl http2;
server_name auth.your-domain.com;
ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;
location / {
proxy_pass http://localhost:8081;
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;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
server_name reports.your-domain.com auth.your-domain.com;
return 301 https://$host$request_uri;
}

Add Traefik as a Docker service and label the application containers:

services:
traefik:
image: traefik:v3
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=admin@your-domain.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- letsencrypt_data:/letsencrypt
app:
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`reports.your-domain.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=8080"
keycloak:
labels:
- "traefik.enable=true"
- "traefik.http.routers.keycloak.rule=Host(`auth.your-domain.com`)"
- "traefik.http.routers.keycloak.entrypoints=websecure"
- "traefik.http.routers.keycloak.tls.certresolver=letsencrypt"
- "traefik.http.services.keycloak.loadbalancer.server.port=8080"
reports.your-domain.com {
reverse_proxy localhost:8080
}
auth.your-domain.com {
reverse_proxy localhost:8081
}

Caddy handles TLS automatically with Let’s Encrypt.

frontend https
bind *:443 ssl crt /etc/haproxy/certs/
mode http
acl is_app hdr(host) -i reports.your-domain.com
acl is_auth hdr(host) -i auth.your-domain.com
use_backend app if is_app
use_backend keycloak if is_auth
backend app
mode http
option forwardfor
http-request set-header X-Forwarded-Proto https
server presswerk 127.0.0.1:8080 check
backend keycloak
mode http
option forwardfor
http-request set-header X-Forwarded-Proto https
server keycloak 127.0.0.1:8081 check

The following headers must be forwarded for Keycloak and Presswerk to work correctly behind a proxy:

HeaderRequired ByPurpose
HostBothOriginal hostname for URL generation
X-Forwarded-ForBothClient IP address
X-Forwarded-ProtoBothOriginal protocol (http/https)
X-Real-IPApplicationClient IP for logging