Guides: deploy & operate

How to serve TLS

This guide shows you how to put HTTPS in front of DeltaGlider Proxy — either by terminating TLS at the proxy itself or at a reverse proxy in front — and how to avoid the reverse-proxy timeout that breaks large uploads.

S3 clients expect HTTPS. The UI (/_/*) and the S3 API (/) share one listener, so whichever option you pick, route the whole host — no per-path rules.

Option A: terminate TLS at the proxy

If you run the proxy directly on the edge, enable native TLS with your PEM pair:

advanced:
  tls:
    enabled: true
    cert_path: /etc/ssl/certs/proxy.pem
    key_path: /etc/ssl/private/proxy-key.pem

Or via env vars: DGP_TLS_ENABLED=true, DGP_TLS_CERT=..., DGP_TLS_KEY=.... If you omit both paths, the proxy generates a self-signed certificate on startup — fine for testing, not for clients that verify certificates.

When the proxy faces the internet directly, keep DGP_TRUST_PROXY_HEADERS=false (the default). Otherwise clients can spoof X-Forwarded-For and bypass rate limiting.

Option B: terminate TLS at a reverse proxy

If you terminate TLS at Traefik, nginx, or Caddy, bind the proxy to 127.0.0.1:9000 and forward over the loopback.

Traefik (Docker Compose labels):

deltaglider_proxy:
  image: beshultd/deltaglider_proxy:latest
  environment:
    DGP_TRUST_PROXY_HEADERS: "true"
  labels:
    traefik.enable: "true"
    traefik.http.routers.dgp.rule: "Host(`s3.acme.example`)"
    traefik.http.routers.dgp.entrypoints: "websecure"
    traefik.http.routers.dgp.tls.certresolver: "letsencrypt"
    traefik.http.services.dgp.loadbalancer.server.port: "9000"

nginx:

server {
    listen 443 ssl;
    server_name s3.acme.example;
    ssl_certificate /etc/ssl/certs/proxy.pem;
    ssl_certificate_key /etc/ssl/private/proxy-key.pem;
    client_body_timeout 30m;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_read_timeout 30m;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
    }
}

Caddy (automatic TLS):

s3.acme.example {
    reverse_proxy localhost:9000
}

Set two env vars on the proxy when a reverse proxy is in front:

VariableValueWhy
DGP_TRUST_PROXY_HEADERStrueAccept X-Forwarded-For / X-Real-IP for rate limiting and IAM IP conditions. Flip it only when a reverse proxy is genuinely in front — otherwise clients can spoof IPs.
DGP_SECURE_COOKIEStrueAlready the default. Keeps admin session cookies HTTPS-only.

Raise the reverse-proxy read timeout — mandatory for large uploads

If you terminate TLS at a reverse proxy, you must raise its request read-timeout. Most default to 60 seconds; a 16 MB multipart part over a typical home uplink (1–5 MB/s, shared between concurrent parts) takes longer than that, so the reverse proxy closes the upstream connection mid-body and the client sees 502 (Traefik) or 504 (nginx). This bites any object over ~50 MB and every multipart upload.

Reverse proxyDefaultSettingRecommended
Traefik 3.x60 sentryPoints.<name>.transport.respondingTimeouts.readTimeout30m or 0 (no limit)
Caddy 2.x0 (no limit)read_timeout in servers blockleave at default
nginx60 sclient_body_timeout + proxy_read_timeout30m
AWS ALB60 s idle_timeouttarget-group attribute4000 (max)
HAProxy60 s timeout clientglobal / frontend30m

Traefik static config:

entryPoints:
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: "30m"
        writeTimeout: "30m"
        idleTimeout: "180s"

…or as CLI flags on the Traefik container:

command:
  - '--entrypoints.websecure.transport.respondingTimeouts.readTimeout=30m'
  - '--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=30m'

The proxy's own request timeout (DGP_REQUEST_TIMEOUT_SECS) defaults to 300 s and is a separate timer — both must be generous for large uploads to succeed.

Verify

# TLS answers and the health endpoint is reachable
curl -s https://s3.acme.example/_/health

# A signed S3 call works over HTTPS
aws s3 ls --endpoint-url https://s3.acme.example

# Large-upload path survives the timeout (anything > 50 MB)
dd if=/dev/urandom of=/tmp/big.bin bs=1M count=100
aws s3 cp /tmp/big.bin s3://releases/ --endpoint-url https://s3.acme.example

If the large upload fails with 502/504 and the proxy log shows a request finishing at exactly 60 000 ms with status 400, the reverse-proxy timeout is still in effect — see Troubleshooting.