Reverse proxy
A reverse proxy sits in front of Frameleaf and passes requests on to it. It’s the usual way to serve Frameleaf over HTTPS on your own domain, such as https://photos.example.com, and it can handle certificates, load balancing and access control for you.
If you’d rather not run one, Frameleaf Cloud remote access gives you HTTPS and a stable address without opening ports. See Remote access for all the options.
What every proxy needs
Section titled “What every proxy needs”- Forward all headers, and set
Host,X-Real-IP,X-Forwarded-ProtoandX-Forwarded-Forto the right values. - Allow large uploads. Videos can be many gigabytes.
- Long timeouts. Large uploads fail if the proxy gives up after a minute.
- WebSockets. The web app uses them for live updates.
- Serve Frameleaf at the root of a domain or subdomain. Frameleaf can’t be served on a sub-path such as
https://example.com/photos.
Then tell Frameleaf to trust the proxy, so it sees each visitor’s real address. Add the proxy’s IP to FRAMELEAF_TRUSTED_PROXIES in .env, comma-separated if there are several, and run docker compose up -d. See Environment variables.
Finally, set Public server URL to your new address in Settings, then Frameleaf Cloud, then Remote access, so shared links and emails use it. It doesn’t need a Frameleaf Cloud link. If you use your own sign-in provider, add the new address to its redirect URIs.
Replace <public_url> with your domain and <backend_url> with the address of the Frameleaf server.
server { server_name <public_url>;
# allow large file uploads client_max_body_size 50000M;
# don't buffer uploads, to save memory on the proxy and keep uploads fast proxy_request_buffering off;
# a larger body buffer avoids limiting upload speed client_body_buffer_size 1024k;
# headers 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;
# websockets proxy_http_version 1.1; proxy_redirect off;
# timeouts proxy_read_timeout 600s; proxy_send_timeout 600s; send_timeout 600s;
location / { proxy_pass http://<backend_url>:2283; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
# useful with the Let's Encrypt http-01 challenge # location = /.well-known/immich { # proxy_pass http://<backend_url>:2283; # }}Caddy sets up HTTPS for you automatically:
photos.example.com { reverse_proxy http://<backend_url>:2283}Apache
Section titled “Apache”<VirtualHost *:80> ServerName <public_url> ProxyRequests Off # timeout in seconds ProxyPass / http://127.0.0.1:2283/ timeout=600 upgrade=websocket ProxyPassReverse / http://127.0.0.1:2283/ ProxyPreserveHost On</VirtualHost>Traefik
Section titled “Traefik”This example is for Traefik version 3. The most important part is raising the entry point’s timeouts. The default of 60 seconds stops video uploads after a minute with error 499; this raises it to 10 minutes, which is usually enough.
In traefik.yaml:
entryPoints: websecure: address: :443 # add this section transport: respondingTimeouts: readTimeout: 600s idleTimeout: 600sThen add labels to the server in Frameleaf’s docker-compose.yml:
services: immich-server: labels: traefik.enable: true traefik.http.routers.frameleaf.entrypoints: websecure traefik.http.routers.frameleaf.rule: Host(`photos.example.com`) traefik.http.services.frameleaf.loadbalancer.server.port: 2283Traefik needs to reach the network Frameleaf runs on, usually by adding Traefik’s network to the immich-server service.