Skip to content

Run Dew behind a reverse proxy

Dew serves HTTPS itself, so it doesn’t need a reverse proxy. If you already run one, or your network requires one, this guide sets it up so large uploads stay fast, Let’s Encrypt keeps working where it can, and Dew’s logs show each visitor’s real address.

You need:

  • A running Dew server (see Get started with Dew)
  • Access to your proxy’s configuration and to Dew’s compose.yaml
  • Your domain’s DNS record and your router’s port 443 pointing at the proxy, not at Dew

If you control the router, the simplest setup is no proxy at all: forward public port 443 straight to Dew. Dew then sees every visitor’s address and Let’s Encrypt works with no extra settings.

1. Choose how the proxy passes traffic to Dew

Section titled “1. Choose how the proxy passes traffic to Dew”

Traffic reaches Dew in one of three ways, and the choice decides who holds the public certificate.

Setup Public certificate Visitor addresses in Dew Let’s Encrypt in Dew
Port forward (router or firewall NAT, no proxy) Dew’s Real visitor addresses Works when the public port is 443
Passthrough (the proxy forwards the encrypted connection by hostname) Dew’s The proxy’s address for everyone Works when the public port is 443
Terminating (the proxy decrypts, then connects to Dew over HTTPS) The proxy’s Real visitor addresses, once you trust the proxy Not available: the proxy manages the certificate

Choose passthrough when you want Dew to keep managing its certificate and don’t need per-visitor addresses. Choose terminating when the proxy already manages certificates for your sites, or when a WAF or application gateway must inspect traffic.

Dew doesn’t support the PROXY protocol, so in passthrough mode Dew’s logs and rate limits see the proxy’s address for every visitor.

Dew listens on one HTTPS port, 443 by default. Behind a proxy, pick a free internal port such as 8443 and make it reachable only by the proxy. Ports are set in Dew’s compose.yaml: the port Dew listens on as DEW_HTTPS_PORT, and the port visitors use as DEW_PUBLIC_HTTPS_PORT.

On Synology, skip this step. Dew uses the NAS’s own network and already listens on port 8843, so the upstream is 127.0.0.1:8843. Use it wherever the examples below show 127.0.0.1:8443, and block port 8843 for other machines in the DSM firewall.

  1. In compose.yaml, add these lines to the environment: list of the dew service (add environment: if it isn’t there yet):

          - DEW_HTTPS_PORT=8443
          - DEW_PUBLIC_HTTPS_PORT=443

    DEW_PUBLIC_HTTPS_PORT is the port visitors use, usually 443. Dew uses it in every link and email it sends, and for its reachability check and Let’s Encrypt.

  2. Change the ports: lines of the dew service to match where your proxy runs:

    • Proxy container on the same host: delete the ports: section, so Dew publishes no port on the host. Attach the proxy container to Dew’s network, dew_default, and use dew:8443 as the upstream.
    • Proxy on the same host, outside Docker (a local nginx, for example): publish the port on the loopback address only, - "127.0.0.1:8443:8443". The upstream is 127.0.0.1:8443.
    • Proxy on another machine (a WAF, Azure Application Gateway, F5, an nginx on another server): publish the port, - "8443:8443", and firewall the host so only the proxy can reach it. The upstream is <dew-host>:8443.
  3. Run docker compose up -d in the folder that holds compose.yaml. docker compose restart doesn’t apply changed settings.

Every proxy in front of Dew needs these settings:

  • Pass the original hostname to Dew. Dew answers only for the domains you added, and returns “not found” for anything else.
  • Turn off buffering of both uploads and downloads. A proxy that collects each upload before passing it on halves upload speed and stops upload speed limits from working. A proxy that collects downloads makes them sit at 0 bytes, then jump.
  • No body-size limit, or one above your largest allowed upload.
  • Long idle timeouts. Dew has no request time limit, because a large upload or download can take hours. In nginx, proxy_read_timeout and proxy_send_timeout are the longest pause allowed between data, not the whole transfer, so 1h covers any transfer.
  • HTTP/1.1 to browsers, not HTTP/2. Browsers upload to Dew over several connections at once, which HTTP/2 merges into one. Measured browser uploads are about half as fast through a proxy with HTTP/2 turned on.
  • HTTPS all the way to Dew. Dew only accepts HTTPS, and its upstream accepts HTTP/1.1 only. A proxy that offers only HTTP/2 to its upstream fails to connect.

Dew doesn’t use WebSockets, so no upgrade settings are needed, and it always serves HTTPS, so it doesn’t need X-Forwarded-Proto.

The examples below assume Dew listens on 127.0.0.1:8443 and your domain is files.example.com.

server {
    listen 443 ssl;
    http2 off;                         # nginx 1.25.1 or later; see below for older versions
    server_name files.example.com;

    ssl_certificate     /etc/nginx/certs/files.example.com.crt;
    ssl_certificate_key /etc/nginx/certs/files.example.com.key;

    client_max_body_size 0;            # Dew enforces its own upload limits

    location / {
        proxy_pass https://127.0.0.1:8443;
        proxy_ssl_server_name on;
        proxy_ssl_name $host;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_read_timeout 1h;
        proxy_send_timeout 1h;
    }
}

On nginx older than 1.25.1, delete the http2 off; line and remove http2 from every port 443 listen line, so listen 443 ssl http2; becomes listen 443 ssl;. That older setting applies to every site on the port, so on a shared nginx that needs HTTP/2 for other sites, use passthrough instead.

With a terminating proxy, Dew can’t get a Let’s Encrypt certificate. When you add the domain in Dew, import a certificate in the certificate step (the one your proxy uses works).

stream {
    map $ssl_preread_server_name $dew_upstream {
        files.example.com 127.0.0.1:8443;
        default           127.0.0.1:8444;   # your other HTTPS sites
    }
    server {
        listen 443;
        ssl_preread on;
        proxy_pass $dew_upstream;
    }
}

Only one listener can own port 443, so on an nginx that also serves other sites, move their listen 443 ssl lines to an internal port such as 127.0.0.1:8444. The default line above sends every other hostname there.

Skip step 4: a passthrough proxy can’t tell Dew the visitor’s address.

{
    servers :443 {
        protocols h1
    }
}

files.example.com {
    reverse_proxy https://127.0.0.1:8443 {
        header_up Host {host}
        transport http {
            tls_server_name files.example.com
        }
        flush_interval -1
    }
}

protocols h1 turns off HTTP/2 and HTTP/3 for every site on port 443. Standard Caddy can’t pass connections through by hostname, so on a Caddy that serves other sites, either accept HTTP/1.1 for them or put nginx, HAProxy or Traefik in passthrough mode in front.

Caddy checks the certificate on Dew’s own port. If it isn’t publicly trusted, add tls_trust_pool file /path/to/dew-certificate.pem to the transport block, or for a test setup only, tls_insecure_skip_verify.

frontend fe_tls
    bind :443
    mode tcp
    tcp-request inspect-delay 5s
    tcp-request content accept if { req_ssl_hello_type 1 }
    default_backend be_dew

backend be_dew
    mode tcp
    server dew 127.0.0.1:8443
tcp:
  routers:
    dew:
      rule: "HostSNI(`files.example.com`)"
      entryPoints: [websecure]
      service: dew
      tls:
        passthrough: true
  services:
    dew:
      loadBalancer:
        servers:
          - address: "127.0.0.1:8443"

For a terminating Traefik, use an HTTP router pointing at https://127.0.0.1:8443 with serversTransport.serverName: files.example.com, and complete step 4 with Traefik’s address.

Cloudflare’s proxy terminates HTTPS, so treat it like a terminating proxy and set DEW_TRUSTED_PROXIES to Cloudflare’s IP ranges. Two Cloudflare settings affect uploads:

  • Request body buffering: keep it at Standard (the default) or None, not Full.
  • Upload size per request: Cloudflare caps each request at 100 MB on Free, 200 MB on Pro and 500 MB on Business. Dew uploads in pieces of 16 MB, so this is only a concern with S3 storage and files over about 150 GB, where pieces grow (32 MB at 300 GB, over 100 MB at 1 TB). If your uploads are that large, raise the limit with Cloudflare or use a DNS-only record for Dew.

A terminating proxy tells Dew each visitor’s address in a forwarding header, and Dew only reads it from proxies you trust. Until then, audit logs, rate limits and upload speed limits see the proxy’s address for everyone.

  1. Open https://files.example.com through the proxy, then open System → System. On the System tab, Dew shows Reverse proxy detected at the address the proxy connects from. The domain wizard’s proxy step shows the same notice after its check.

    System → System, System tab, Server details card; Reverse proxy showing Not trusted and the Reverse proxy detected notice with Trust this proxy outlined

  2. Select Trust this proxy. It applies at once, with no restart. A proxy container on a Docker network is trusted with its whole network, so it stays trusted when the container is recreated with a new address. A proxy anywhere else is trusted by its exact address.

If the notice adds “Only trust it if this server’s port can’t be reached from the internet except through this proxy”, the proxy reaches Dew through Docker’s gateway, which also passes on visitors who connect to Dew’s port directly. Trust it only when Dew’s port is closed to the internet, for example published on 127.0.0.1 or blocked in the firewall.

To stop trusting a proxy, select Remove next to it under Reverse proxy.

Use DEW_TRUSTED_PROXIES instead of the button for Cloudflare (its addresses are public, so Dew never offers the button), when Dew has its own address on your network (a macvlan or ipvlan network, such as Unraid’s br0), or to trust the proxy before first setup. When it is set, proxies trusted with the button are ignored.

  1. In compose.yaml, add this line to the environment: list of the dew service (add environment: if it isn’t there yet). Separate several addresses or ranges with commas:

          - DEW_TRUSTED_PROXIES=10.0.0.5,172.16.0.0/12
  2. Run docker compose up -d. On Synology, stop the dew project in Container Manager, add the line to the project’s YAML, then build the project again.

  1. Open https://files.example.com: Dew loads with no certificate warning.
  2. Open System → System. On the System tab, Reverse proxy shows Trusted with your proxy’s network or address, Configured when set with DEW_TRUSTED_PROXIES (terminating proxies), or None detected (passthrough and port forward).
  3. Sign in from another network, then open the Access logs tab: your request shows your own address, not the proxy’s.
  4. Upload a large file and watch the speed: it should match an upload without the proxy. A speed of about half points to HTTP/2 or buffering in the proxy.
What you see What to do
Reverse proxy shows Not trusted on the System tab of System → System Dew receives forwarding headers from a proxy it doesn’t trust. Select Trust this proxy under it. If a proxy is already listed as trusted, it isn’t the one connecting: remove it, then trust the detected address.
Reverse proxy shows None detected although a terminating proxy is in front Dew checks the first requests after it starts. Restart the container with docker compose restart, open Dew through the proxy, then reload System → System.
Every visitor has the same address in the logs Terminating proxy: complete step 4. Passthrough proxy: expected; use a port forward if you need visitor addresses.
Dew answers “not found” through the proxy The proxy isn’t passing the original hostname. In nginx, add proxy_set_header Host $host;.
Browser uploads are about half as fast as expected The proxy uses HTTP/2 towards browsers. Turn it off as shown in step 3.
Downloads sit at 0 bytes, then jump The proxy is collecting downloads first. In nginx, set proxy_buffering off;. In Caddy, flush_interval -1.
Large uploads stop partway The proxy’s timeout or body-size limit is too low. See step 3.
The proxy can’t connect to Dew Point the proxy at https://, not http://, and make sure it offers HTTP/1.1 to Dew.
The domain wizard says “Let’s Encrypt needs this server on port 443 from the internet.” DEW_PUBLIC_HTTPS_PORT is set to a port other than 443. Set it to 443 or remove it, and run docker compose up -d. Let’s Encrypt also needs visitors to reach Dew itself on port 443, through a port forward or passthrough. With a terminating proxy, import a certificate instead.
Links in emails include the wrong port Set DEW_PUBLIC_HTTPS_PORT to the port visitors use and run docker compose up -d.

For more detail, open System → System and the Error logs tab. Each failed request has a reference such as REF-a3f8b2c1 that you can quote when you contact support at support@getdew.io.