Set up HTTPS
LawFive speaks plain HTTP on port 3000. Something in front of it holds the certificate. LawFive doesn’t manage certificates itself.
Your server has this same guide built in, with your domain filled in, under Settings → Server → HTTPS. It also tells you when it’s set up correctly.
Choose a method
Section titled “Choose a method”| Method | Best for | The trade-off |
|---|---|---|
| Caddy | The simplest with your own domain. It gets and renews the certificate itself. | Ports 80 and 443 must reach this machine, and nothing else may be using them. |
| Traefik | A machine that already runs Traefik. | Names must match your Traefik setup. |
| nginx and Certbot | A machine that already runs nginx, outside Docker. | nginx and Certbot are yours to keep updated. |
| Cloudflare Tunnel | A server at home: no open ports, behind any router. | The domain must be on Cloudflare, it can see the traffic, and uploads are limited to 100 MB on its free plan. |
| Tailscale Funnel | No domain of your own: you get a free .ts.net address. |
Funnel must be allowed in your tailnet, and the address has Tailscale’s name in it. |
The examples use lawfive.example.com. Replace it with your own domain.
-
Point your domain at this machine’s public address in DNS. If it’s behind a router, forward ports 80 and 443 to it.
-
Add Caddy beside the server, in a new file next to
compose.yaml:compose.override.yaml services:caddy:image: caddy:2restart: unless-stoppedcommand: caddy reverse-proxy --from lawfive.example.com --to server:3000ports:- "80:80"- "443:443"- "443:443/udp"volumes:- caddy-data:/datavolumes:caddy-data:
Traefik
Section titled “Traefik”-
Point your domain at your Traefik machine in DNS.
-
Give the server Traefik’s labels and network, in a new file next to
compose.yaml. The network, entry point and certificate resolver must use the names in your Traefik setup.compose.override.yaml services:server:labels:- traefik.enable=true- traefik.http.routers.lawfive.rule=Host(`lawfive.example.com`)- traefik.http.routers.lawfive.entrypoints=websecure- traefik.http.routers.lawfive.tls.certresolver=letsencrypt- traefik.http.services.lawfive.loadbalancer.server.port=3000networks:- default- traefiknetworks:traefik:external: true -
Optional: while the server restarts after an update, Traefik has no route to it and answers 404. To have it answer 503 (try again) instead, add this file to the folder Traefik’s file provider reads. It’s used only while the server’s own route is gone.
lawfive-restarting.yml http:routers:lawfive-restarting:rule: "Host(`lawfive.example.com`)"priority: 1entryPoints: [websecure]tls: {}service: lawfive-restartingservices:lawfive-restarting:loadBalancer:servers: []
nginx and Certbot
Section titled “nginx and Certbot”-
Point your domain at this machine’s public address in DNS. If it’s behind a router, forward ports 80 and 443 to it.
-
Add a site to nginx. The size limit allows restoring a large export, and turning buffering off lets one download as it’s made.
/etc/nginx/conf.d/lawfive.example.com.conf server {listen 80;server_name lawfive.example.com;client_max_body_size 2g;location / {proxy_pass http://127.0.0.1:3000;proxy_set_header Host $host;proxy_set_header X-Forwarded-For $remote_addr;proxy_set_header X-Forwarded-Proto $scheme;proxy_buffering off;}} -
Get the certificate. Certbot adds it to that site, and renews it by itself once installed.
Terminal window sudo certbot --nginx -d lawfive.example.com
Cloudflare Tunnel
Section titled “Cloudflare Tunnel”-
In Cloudflare’s Zero Trust dashboard, make a tunnel under Networks, and copy its token. Add a public hostname of your domain, with the service
http://server:3000. -
Run the tunnel beside the server, in a new file next to
compose.yaml:compose.override.yaml services:cloudflared:image: cloudflare/cloudflared:latestrestart: unless-stoppedcommand: tunnel runenvironment:TUNNEL_TOKEN: ${CLOUDFLARE_TUNNEL_TOKEN} -
Add these to
.env. The first makes limits on wrong passwords count each visitor rather than Cloudflare..env TRUSTED_IP_HEADER=CF-Connecting-IPCLOUDFLARE_TUNNEL_TOKEN=the-token-from-cloudflare
Tailscale Funnel
Section titled “Tailscale Funnel”-
Install Tailscale on this machine and sign in, then share the server. It prints your address.
Terminal window tailscale funnel --bg 3000 -
Finish up, using the address it printed, such as
https://your-machine.your-tailnet.ts.net.
Finish up
Section titled “Finish up”-
Tell LawFive its new address, keep port 3000 to this machine, and let it believe the proxy about who’s visiting, in
.env:.env PUBLIC_URL=https://lawfive.example.comPORT=127.0.0.1:3000TRUSTED_PROXIES=privateprivatebelieves any proxy on a private network or this machine, which is where each method above runs. WithoutTRUSTED_PROXIES, everyone counts as the proxy’s one address, so they share one limit on wrong passwords. To be stricter, list your proxy’s network instead, such as172.18.0.0/16. -
Start it all again:
Terminal window docker compose up -d -
Open your new address and sign in again. Settings → Server → HTTPS says when it’s right.
Phones and watches linked to the old address need signing in or linking again.
Behind more than one proxy
Section titled “Behind more than one proxy”TRUSTED_PROXIES lists the proxies LawFive believes about the visitor’s address: addresses, ranges such as 172.18.0.0/16, or private. It’s empty by default, so a server reached directly can’t be fooled. Settings → Server → Visitors’ addresses shows the address the server sees you at; if that’s your proxy’s, the setting is missing.
If another proxy such as Cloudflare sits in front of your reverse proxy, set TRUSTED_IP_HEADER to the header it puts the visitor’s address in, as well as TRUSTED_PROXIES. For Cloudflare, that’s CF-Connecting-IP. Without it, limits on wrong passwords count everyone arriving through that proxy together.
That header is only as good as the path to your server. If your reverse proxy can also be reached directly, not just through Cloudflare, anyone can send it with any address and dodge those limits. Either reach the server only through a Cloudflare Tunnel (above), or let your reverse proxy take that host’s traffic only from Cloudflare’s addresses. In Traefik that’s an ipAllowList middleware on the router, with the ranges from cloudflare.com/ips-v4 and /ips-v6.
If phones should reach the API at a different address from the website, set API_URL. Most servers leave it unset.