Self-host
Reverse proxy and HTTPS
Serve Dezfil at your own domain over HTTPS, with Caddy or nginx in front of it.
Put Caddy or nginx in front of Dezfil to serve it at your own domain over HTTPS. The proxy holds the certificate and passes each request to Dezfil, which serves plain HTTP on port 3000.
- You need: Dezfil running in Docker as Install sets it up, on port 3000 of
127.0.0.1only. - A domain: a domain or subdomain of its own, such as
maps.example.com, whose DNS record points at the server. Dezfil serves from the root of its address, not from a path such asexample.com/maps/. - The proxy: Caddy, or nginx and certbot, installed on the same server, with ports 80 and 443 open to the internet.
1. Set up the proxy
Section titled “1. Set up the proxy”Caddy
Put this site in /etc/caddy/Caddyfile, in place of the example site:
<YOUR_DOMAIN> { reverse_proxy 127.0.0.1:3000 { header_up -Forwarded header_up -X-Forwarded-Port }}<YOUR_DOMAIN>is your domain, such asmaps.example.com. Caddy gets a certificate for it by itself and sends plain HTTP visitors to HTTPS.reverse_proxy 127.0.0.1:3000passes every request to Dezfil, with the visitor’s address, host and scheme in forwarding headers.- The two
header_uplines drop forwarding headers that Caddy would otherwise pass on from the visitor unchanged. Dezfil takes what a trusted proxy sends as true.
Load the new file:
sudo systemctl reload caddyCaddy passes uploads and the assistant’s answers through as they arrive, and sets no time limit on an answer, so the site needs nothing more.
nginx
Save this file as /etc/nginx/conf.d/dezfil.conf:
server { listen 80; listen [::]:80; server_name <YOUR_DOMAIN>;
client_max_body_size 0; proxy_read_timeout 3600s; proxy_buffering off; proxy_request_buffering off;
location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Port $server_port; proxy_set_header Forwarded ""; }}- The two
listenlines take visitors over IPv4 and IPv6. On a server without IPv6, leave outlisten [::]:80;. client_max_body_size 0leaves the size of an upload to Dezfil’s Largest upload, 5,120 MB by default (Limits). Without it, nginx refuses anything over 1 MB.proxy_read_timeout 3600swaits up to an hour for an answer, as long as Dezfil’s Data processing time limit allows an import by default.- The two buffering lines pass uploads and the assistant’s answers through as they arrive.
- The
proxy_set_headerlines send the visitor’s address, host, scheme and port, and drop aForwardedheader a visitor could add. - Dezfil uses no WebSockets, so the block needs no
Upgradeheaders.
Check the file:
sudo nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successfulLoad it, then get a certificate with certbot and its nginx plugin:
sudo systemctl reload nginxsudo certbot --nginx --redirect -d <YOUR_DOMAIN>--nginxgets a certificate from Let’s Encrypt and adds HTTPS to the server block above.--redirectsends plain HTTP visitors to HTTPS.
2. Trust the proxy
Section titled “2. Trust the proxy”Dezfil reads the visitor’s address and scheme from the proxy’s headers only when the connection comes from an address you trust.
With the proxy on the server and Dezfil in Docker, Dezfil sees the proxy’s requests arrive from the gateway of the container’s network. Print it:
docker inspect --format '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' dezfil172.17.0.1With Docker Compose the address differs, such as 172.18.0.1. If Dezfil runs on the server itself, outside Docker, the address is 127.0.0.1.
Start Dezfil again with that address in DEZFIL_TRUSTED_PROXIES:
Docker
Use your image and variables in the command, as Set a variable lists them, DEZFIL_SECRET_KEY too if you set one:
docker rm -f dezfildocker run -d --name dezfil -p 127.0.0.1:3000:3000 -v dezfil-data:/data \ -e DEZFIL_TRUSTED_PROXIES=<PROXY_ADDRESS> \ ghcr.io/dezfil/dezfilThe dezfil-data volume keeps your data.
Docker Compose
Add the variable to the service in your compose.yaml:
services: dezfil: environment: DEZFIL_TRUSTED_PROXIES: "<PROXY_ADDRESS>"Then run docker compose up -d. Compose replaces the container and keeps the volume.
From a trusted address, Dezfil reads:
- The visitor’s address: from
X-Forwarded-FororForwarded, the nearest address that is not trusted. Dezfil counts failed sign-ins and requests to published maps per address. - The scheme, host and port: from
X-Forwarded-Proto,X-Forwarded-HostandX-Forwarded-Port. Dezfil checks that each change a browser makes comes from its own pages at that address, and builds the sign-in links Users hands out with it. - HTTPS: when the scheme is
https, Dezfil marks its session cookie as secure, so the browser sends it only over HTTPS.
From any other address, Dezfil drops these headers and uses the connection itself: the proxy’s address and plain HTTP. Sign-in through your domain then fails, and all visitors share one address’s limits.
3. Check it
Section titled “3. Check it”curl https://<YOUR_DOMAIN>/api/health{"status":"ready"}- Open
https://<YOUR_DOMAIN>and sign in with your Email and Password. You should see Home. - As an admin, open Settings › System. In the Server settings card, you should see the Trusted proxies row with your proxy’s address and the Source Environment.
Trusted proxies
Section titled “Trusted proxies”Set DEZFIL_TRUSTED_PROXIES to the address Dezfil sees your proxy’s requests arrive from, and have the proxy send the visitor’s address, host and scheme, as steps 1 and 2 do.
Session cookie name needs no change behind a proxy: it follows the port Dezfil listens on, not the one visitors use.
| Setting | Variable | Settings key | Default | Values | What it does | Changes |
|---|---|---|---|---|---|---|
| Trusted proxies | DEZFIL_TRUSTED_PROXIES | unset | IP addresses or CIDR networks, separated by commas or spaces; a host name stops the server at start | The proxies whose forwarded visitor address, host, scheme and port Dezfil accepts. | By variable, after a restart | |
| Session cookie name | DEZFIL_SESSION_COOKIE | port-based | ASCII letters, digits and !#$%&'*+-.^_`|~; any other value stops the server at start | Browser session cookie name, derived from the listening port unless overridden. | By variable, after a restart |
Troubleshooting
Section titled “Troubleshooting”Sign-in fails with “This request must come from the same instance.”
Section titled “Sign-in fails with “This request must come from the same instance.””Dezfil reads its own address differently from your browser, most often http where the browser has https.
Run the docker inspect command of step 2 again: DEZFIL_TRUSTED_PROXIES must hold the address it prints. Then check that the proxy sends the headers of step 1.
Sign-in links from Users point at 127.0.0.1:3000
Section titled “Sign-in links from Users point at 127.0.0.1:3000”nginx sends its own upstream address as the host, and Dezfil builds the links Users hands out from it. Add the proxy_set_header Host and X-Forwarded-Host lines of step 1, then reload nginx. A link made while you opened Dezfil at another address, such as http://localhost:3000 over SSH, carries that address: make it again from your domain.
Pages show {"error":{"code":"invalid_request","message":"Invalid request provenance."}}
Section titled “Pages show {"error":{"code":"invalid_request","message":"Invalid request provenance."}}”A trusted proxy sent forwarding headers that disagree, such as a Forwarded header beside different X-Forwarded-* values, or an X-Forwarded-Port that differs from the port the host names. Drop Forwarded at the proxy as step 1 does, and let one proxy set the X-Forwarded-* headers.
Dezfil stops or restarts right after it starts
Section titled “Dezfil stops or restarts right after it starts”docker logs dezfil shows Error: Invalid ingress address or Error: Invalid trusted proxy network. DEZFIL_TRUSTED_PROXIES takes IP addresses and networks such as 172.17.0.0/16, separated by commas. A host name is refused.
Uploads over 1 MB fail behind nginx
Section titled “Uploads over 1 MB fail behind nginx”nginx refuses larger requests unless told otherwise. Add client_max_body_size 0; to the server block, then reload nginx.
Long imports or queries fail after a minute behind nginx
Section titled “Long imports or queries fail after a minute behind nginx”nginx answers 504 Gateway Time-out when Dezfil takes over 60 seconds to answer. Add proxy_read_timeout 3600s;, then reload nginx.
The assistant’s answer arrives in bursts behind nginx
Section titled “The assistant’s answer arrives in bursts behind nginx”nginx holds the answer back until its buffers fill. Add proxy_buffering off;, then reload nginx.
Next steps
Section titled “Next steps”- Docker Compose: a Compose file for a lasting instance.
- Configuration: set other variables, and see the values in effect.
- Users: invite people once the instance answers at your domain.
- What leaves the instance: every outside request your instance can make.
7439201b