Skip to Content
DeploymentReverse Proxy

Reverse Proxy

For production deployments, place PicPeak behind a reverse proxy for SSL termination and routing.

Routing schema

PathServicePortDescription
/api/*Backend3001All API endpoints
/photos/*Backend3001Protected photo files
/thumbnails/*Backend3001Protected thumbnail files
/uploads/*Backend3001Upload files
/* (everything else)Frontend3000React SPA (including /admin/*, /gallery/*)

The /admin/* routes are served by the frontend (React SPA), not the backend. The backend only handles /api/admin/* requests.

Create /etc/nginx/sites-available/picpeak:

server { listen 80; server_name your-domain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem; # Backend: API endpoints location /api/ { proxy_pass http://localhost:3001; 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; } # Backend: Protected media files location ~ ^/(photos|thumbnails|uploads)/ { proxy_pass http://localhost:3001; 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; } # Frontend: Everything else (React SPA) location / { proxy_pass http://localhost:3000; 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; } }

Enable the site:

sudo ln -s /etc/nginx/sites-available/picpeak /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx

For video uploads, increase the body size limit:

client_max_body_size 10G; proxy_read_timeout 3600; proxy_send_timeout 3600;

Mixed HTTPS + LAN HTTP access

Some self-hosted setups want two working entry points to the same PicPeak instance:

  • Public HTTPS via the reverse proxy on a domain (https://photos.example.com)
  • Direct HTTP on the LAN for admin access (http://192.168.1.50:3001)

With the default COOKIE_SECURE setting, only one of these works at a time — the Secure cookie flag either blocks LAN HTTP (when true) or weakens HTTPS cookies (when false).

Set COOKIE_SECURE=auto in your .env to make PicPeak decide per request:

# .env COOKIE_SECURE=auto

In this mode the backend reads req.secure from Express. The flag is set to true when the request arrived over HTTPS (either directly or via a trusted proxy forwarding X-Forwarded-Proto: https) and false otherwise. The end result: both public HTTPS login and LAN HTTP login work with correctly-flagged cookies.

The Nginx, Traefik, and Caddy configurations shown above already forward X-Forwarded-Proto correctly. PicPeak’s Express trust proxy is preset to loopback, linklocal, uniquelocal, which covers Docker networks and private-network proxies out of the box.

See Environment Variables → Authentication cookies for the full reference.

Last updated on