Using a Reverse Proxy¶
A reverse proxy sits in front of PhotoPrism to terminate TLS, serve your public hostname, and apply its own request filtering. Pick your server from the list for a working configuration: Traefik, Caddy 2, NGINX, Apache 2.4, SWAG, or HAProxy.
The settings below apply whichever one you use, so they are worth getting right before you start on a specific configuration.
Getting Support
Reverse proxies are easy to misconfigure, and we cannot provide individual support for proxy-related problems such as failed uploads, connection errors, broken thumbnails, or video playback issues. Please ask your proxy's community for help, or consider Traefik if you prefer a simpler setup.
Public Site URL¶
Set the public Site URL to the external https:// address
your users open, so that links, shared albums, and redirects point at the right host. A Site URL
that still refers to an internal address or port is the most common cause of links that work for
you and not for anyone else.
TLS Termination¶
Let the proxy manage certificates and keep PhotoPrism's own TLS disabled with
PHOTOPRISM_DISABLE_TLS, so the two do not both try to serve
HTTPS. Expose only ports 80 and 443 to the internet and keep PhotoPrism's own port, 2342 by default,
private.
Client Addresses¶
When a proxy forwards a request, PhotoPrism sees the connection coming from the proxy rather than
from the browser. PHOTOPRISM_TRUSTED_PROXY determines which
hosts it accepts forwarded client information from, so that rate limits and logs are attributed to
the browser that sent the request.
The default covers the address range Docker uses for its internal networks, which is where a proxy running alongside PhotoPrism normally connects from. If yours connects from a different address, set this to that address or range, for example:
- a proxy on another host: its IP address, e.g.
192.168.1.10; - a proxy on the same host while PhotoPrism runs without Docker or with host networking, so the
proxy connects to
localhost:127.0.0.1, ::1.
Keep a value configured whenever a proxy is in front of PhotoPrism: with none, every request appears to come from the proxy, so a rate limit reached by one person can affect everyone behind it.
Forwarding Headers¶
The proxy must add the address it received the request from to the X-Forwarded-For header, and
PhotoPrism reads that header only from the addresses listed above:
- Traefik and Caddy add it automatically.
- NGINX:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;, as in our example. Setting onlyX-Real-IPis not enough. - HAProxy:
option forwardfor, as in our example. - Apache adds it by default; do not set
ProxyAddHeaders Off.
Only list addresses whose connections all pass through such a proxy. Tools that forward connections
without adding the header, such as TCP tunnels, port forwarders, and TLS passthrough routers, should
not connect from a listed address. If one runs on the same host or in the same Docker network as
your proxy, set PHOTOPRISM_TRUSTED_PROXY to the proxy's own address only.
Without a Proxy¶
If clients connect to PhotoPrism directly, no forwarded headers are needed. Set
PHOTOPRISM_TRUSTED_PROXY: "" so that none are accepted, and PhotoPrism uses the address of each
connection.
If PhotoPrism runs in Docker and is reachable over IPv6 without a proxy, also
enable IPv6 on its Docker network (enable_ipv6: true),
so that it sees the client's real IPv6 address. Docker then publishes the port over IPv6 with its own
firewall rules, as it already does for IPv4, so check which ports your host firewall and router
expose afterwards.
WebSocket Connections¶
PhotoPrism uses a WebSocket to push live updates to the user interface, such as indexing and import
progress. Your proxy must forward the Upgrade and Connection headers for that connection to
succeed. Without it the app still loads, but it stops reflecting what the server is doing until the
page is reloaded.
Uploads & Timeouts¶
Proxies usually cap the size of a request body and the time a response may take, and both defaults are lower than a photo library needs. Raise the body-size limit so large uploads are not rejected, and the read timeout so long-running requests are not cut off mid-operation. The exact directives differ per server and are covered in each guide.