Skip to main content
The installer asks which proxy mode to use. The selected mode is stored in harly.config.json, and doctor validates only its expected services.

After reading this

  • You will know the three proxy modes and when to use each
  • You will know which ports each mode publishes
  • You will know how to point an existing reverse proxy at Harly

Available modes

Caddy is never started in external or local mode.

Using an external reverse proxy

If another proxy already owns ports 80 and 443, keep it and select external mode during install. Forward the hostname to 127.0.0.1:3000. Example Nginx server block:
Point your existing certificate management (Certbot, an ACME client, or a load balancer) at the same hostname; Harly does not manage TLS in this mode.
The Nginx block above is a standard reverse-proxy pattern, not a file shipped by Harly. Adapt it to your existing proxy configuration.

Trust your reverse proxy for client IPs

By default, Harly reads the client IP from the rightmost hop in X-Forwarded-For. In external mode that hop is your reverse proxy, not the end user. Workspace IP allowlists, per-IP rate limits, and audit log ipAddress fields will all see the proxy’s address instead of the real client until you tell Harly which peer to trust. Set TRUSTED_PROXY_IPS in .env to the peer address (or comma-separated addresses) that Harly’s container sees when the proxy forwards a request:
When the immediate peer matches one of these values, Harly uses the leftmost address in X-Forwarded-For as the client IP. Your reverse proxy must overwrite X-Forwarded-Peer with an operator-controlled marker that matches the value Harly receives for that proxy, as in the Nginx example above; never pass a client-supplied value through unchanged. If Harly runs behind a container or another network hop, replace 127.0.0.1 with the peer address Harly sees and use the same value in TRUSTED_PROXY_IPS. When the peer does not match, Harly falls back to the rightmost hop so a malicious client cannot spoof its address by injecting the header. Guidelines:
  • Use the address Harly actually receives the connection from, not the public IP of the proxy. Behind Docker with a host-network Nginx, that is typically 127.0.0.1 or the Docker bridge gateway.
  • If several load balancers can each forward directly to Harly, list all of them, comma-separated.
  • Behind a CDN like Cloudflare in front of your own reverse proxy, trust the reverse proxy’s address here and let the CDN handle client IP resolution in your proxy configuration.
  • Leave TRUSTED_PROXY_IPS unset in caddy mode. The bundled Caddy proxy adds exactly one forwarding hop, so the rightmost-hop default already resolves to the real client.
  • After changing the value, restart the app container so the new environment is picked up.

Troubleshooting

doctor reports the wrong services as unhealthy

Symptom: doctor checks for Caddy even though you selected external mode. Cause: harly.config.json still records the previous mode. Solution: re-run the installer’s management menu (npx @harly/cli) and confirm the proxy mode, or edit harly.config.json directly to match your actual topology.

502 from the external proxy

Symptom: the reverse proxy returns a 502 for every request. Cause: Harly is not listening on 127.0.0.1:$HARLY_PORT, or the proxy is forwarding to the wrong port. Solution: confirm docker compose ps shows the app container healthy, then check HARLY_PORT in .env matches the proxy’s upstream port.

Self-hosting overview

VPS requirements and DNS setup.

Operations

Health checks, the scheduler, backups, and upgrades.