projectsend.org
← All posts

Running ProjectSend behind a reverse proxy

Most reverse proxy problems with ProjectSend come down to two settings: TRUSTED_PROXIES for 419 errors, and buffer sizes for 502 on some pages.

· By ProjectSend Team

A cut-paper collage illustration: a friendly doorkeeper at the front door of a small house holds the door open for a visitor, pointing to an inner room where someone waits with a file; clean morning light.

When you put ProjectSend behind a reverse proxy, two things tend to go wrong: form submissions return a 419 CSRF error, or certain pages return 502. Both have straightforward fixes. The first is almost always TRUSTED_PROXIES. The second, on nginx, is a buffer size setting. This note walks through both, with a quick reference for Traefik, nginx, Caddy, and Nginx Proxy Manager.

TRUSTED_PROXIES and 419 errors

A 419 error means Laravel — the framework ProjectSend runs on — rejected a form submission because the session token did not match. Behind a reverse proxy, this happens when the app cannot read the X-Forwarded-For header correctly, because the proxy’s IP is not listed as trusted. Setting TRUSTED_PROXIES tells the framework to trust forwarded headers from the proxy.

Add it to the environment block in your compose.yaml:

services:
  app:
    environment:
      TRUSTED_PROXIES: "*"

Using "*" trusts all proxies. For most self-hosted setups — where the only traffic reaching the app container comes from your own proxy — this is fine. If you are deploying on a cloud platform with shared load balancers or multiple ingress hops, restrict the value to your proxy’s internal IP or subnet instead.

502 errors on the dashboard and file list

Some nginx setups return 502 on ProjectSend’s dashboard and file list pages. The root cause is proxy_buffer_size being too small: response headers from those pages can overflow the default nginx buffer. The error in the nginx log looks like: upstream sent too big header while reading response header from upstream.

Add these three directives to the location block in your nginx config:

proxy_buffer_size       32k;
proxy_buffers           8 32k;
proxy_busy_buffers_size 64k;

These values are from the Docker guide. The app no longer sends headers that large, but older nginx defaults still trip on some configurations. See the nginx proxy module reference for the full parameter documentation, and issue #1664 for the original report.

Traefik and Caddy do not have an equivalent buffer directive. If you see 502 errors with those proxies, check TRUSTED_PROXIES first, then look at the app container logs.

Quick reference by reverse proxy

  • Traefik: set TRUSTED_PROXIES: "*" in the app service environment. passHostHeader is on by default. See issue #1672 for a working example.
  • nginx: set TRUSTED_PROXIES: "*" and add the three buffer directives above. Also include proxy_set_header Host $host; in your location block if it is not already there.
  • Nginx Proxy Manager: same as nginx. Paste the buffer directives in the Advanced tab of your proxy host.
  • Caddy: set TRUSTED_PROXIES: "*". Caddy’s reverse_proxy directive handles headers automatically; no buffer directives needed.

For more on the full Docker setup, see the Docker guide. For other installation topics, browse the Installation section of this blog.

Checking the logs

When something still is not right after setting both values, start with the app container logs:

docker compose logs -f app
docker compose logs --since 30m app | grep -iE "error|upstream|502"

If you see upstream sent too big header, the buffer setting from the nginx section above is the fix. For other errors, the Laravel application log is inside the container at /var/www/html/storage/logs/laravel.log.

Check that the app itself is responding before debugging the proxy layer:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/up   # straight at the container
curl -s -o /dev/null -w '%{http_code}\n' https://files.example.com/up

A 200 from the first command and a failure from the second means the issue is in the proxy configuration. If neither returns 200, the app itself is not running — check docker compose ps and the container logs.

FAQ

Does Traefik need proxy_buffer_size?

No. Traefik handles its own header buffering and does not expose an equivalent directive. If you see 502 errors with Traefik, check TRUSTED_PROXIES first, then read the app container logs for Laravel errors.

I set TRUSTED_PROXIES but still get 419.

First confirm the value reached the container: docker compose exec app env | grep TRUSTED. If it is set, check that your proxy is forwarding X-Forwarded-For. For multi-container setups, verify that sessions are stored in a persistent backend — file-based or Redis — not in memory.

Can I use Nginx Proxy Manager?

Yes. Nginx Proxy Manager runs standard nginx internally. Set TRUSTED_PROXIES: "*" in the app service environment and paste the three buffer directives in the Advanced tab of your proxy host. The install guide covers web server configuration for the zip install.

What does passHostHeader do in Traefik?

It forwards the Host header from the client request to the upstream. Traefik sets it by default. Without it, ProjectSend would see the proxy’s internal hostname instead of your domain, which affects generated URLs in emails and file-sharing links. See the Traefik load-balancing reference for details.

I am on a zip install, not Docker. Where do I set TRUSTED_PROXIES?

Add TRUSTED_PROXIES=* to your .env file in the ProjectSend root directory — the same directory as config.php. The install guide covers the environment file in the web server configuration section.

ProjectSend Team. Written by the people who build and maintain ProjectSend, the open-source client portal developed in the open since 2011.

Keep reading

ProjectSend is free and open source

It's GPL v2 and built in the open. If something here didn't work for you, or you know a better way to do it, let us know: that's how the docs and the software get better.

Prefer not to run a server? ProjectSend Cloud is the hosted version, run by the same people.