Skip to main content

Reverse Proxy and Client IP Hardening

When Headendarr is behind a reverse proxy, client IP addresses can be forwarded using headers such as X-Forwarded-For.

By default, Headendarr does not trust these headers from arbitrary clients.

Trusted Proxy Header Settings

VariableDescriptionDefaultExample
TIC_TRUST_PROXY_HEADERSTrust forwarded IP headers only when requests come from trusted proxy CIDRs.falsetrue
TIC_TRUSTED_PROXY_CIDRSComma-separated proxy CIDRs allowed to provide forwarded headers.empty172.18.0.0/16,10.0.0.0/8,127.0.0.1/32
TIC_AUTH_COOKIE_SECUREMarks auth/OIDC cookies as Secure (HTTPS-only in browsers).falsetrue
warning

Do not enable TIC_TRUST_PROXY_HEADERS=true without setting TIC_TRUSTED_PROXY_CIDRS. If you do, clients can spoof audit/login IP addresses by sending forged forwarding headers.

Docker Compose Example

environment:
- TIC_TRUST_PROXY_HEADERS=true
- TIC_TRUSTED_PROXY_CIDRS=172.18.0.0/16,10.0.0.0/8,127.0.0.1/32
- TIC_AUTH_COOKIE_SECURE=true

Use TIC_AUTH_COOKIE_SECURE=true when browser access is HTTPS (for example behind a TLS reverse proxy). Keep it false for direct plain-HTTP LAN deployments.

Reverse Proxy Examples

Use these as starting points. Keep your proxy and Headendarr on private network paths.

Nginx

location / {
proxy_pass http://headendarr:9985;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}

Caddy

headendarr.example.com {
reverse_proxy headendarr:9985 {
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
header_up X-Real-IP {remote_host}
}
}

Traefik (Docker labels)

labels:
- traefik.enable=true
- traefik.http.routers.headendarr.rule=Host(`headendarr.example.com`)
- traefik.http.services.headendarr.loadbalancer.server.port=9985

Traefik forwards client IP information automatically when configured as the entrypoint.

Auth Rate Limiting (In-memory)

Headendarr can throttle repeated authentication requests to reduce brute-force login attempts.

This limiter is kept in process memory:

  • It applies immediately while the app is running.
  • Counters reset when the container/app restarts.
VariableDescriptionDefaultExample
TIC_AUTH_RATE_LIMIT_ENABLEDEnables auth endpoint rate limiting.truetrue
TIC_AUTH_LOGIN_IP_WINDOW_SECONDSSliding window length for failed login attempts per IP.600600
TIC_AUTH_LOGIN_IP_MAX_ATTEMPTSMaximum failed login attempts per IP within the IP window.1010
TIC_AUTH_LOGIN_USER_WINDOW_SECONDSSliding window length for failed login attempts per username.600600
TIC_AUTH_LOGIN_USER_MAX_ATTEMPTSMaximum failed login attempts per username within the username window.55
TIC_AUTH_LOGIN_COOLDOWN_BASE_SECONDSBase cooldown after repeated login failures.22
TIC_AUTH_LOGIN_COOLDOWN_MAX_SECONDSMaximum cooldown cap after repeated failures.6060
TIC_AUTH_OIDC_START_IP_WINDOW_SECONDSSliding window length for OIDC start requests per IP.600600
TIC_AUTH_OIDC_START_IP_MAX_ATTEMPTSMaximum OIDC start requests per IP in the start window.6060
TIC_AUTH_OIDC_CALLBACK_IP_WINDOW_SECONDSSliding window length for OIDC callback requests per IP.600600
TIC_AUTH_OIDC_CALLBACK_IP_MAX_ATTEMPTSMaximum OIDC callback requests per IP in the callback window.6060

What These Settings Do

  • TIC_AUTH_LOGIN_IP_*:

    • Limits failed local-login attempts from the same IP address.
    • Default: up to 10 failed attempts per 600 seconds (10 minutes).
  • TIC_AUTH_LOGIN_USER_*:

    • Limits failed local-login attempts against the same username from the same source IP.
    • Default: up to 5 failed attempts per 600 seconds (10 minutes).
  • TIC_AUTH_LOGIN_COOLDOWN_*:

    • Adds temporary lockout backoff after repeated failures.
    • Backoff increases with continued failures and is capped by TIC_AUTH_LOGIN_COOLDOWN_MAX_SECONDS.
  • TIC_AUTH_OIDC_START_IP_* and TIC_AUTH_OIDC_CALLBACK_IP_*:

    • Limit repeated OIDC start/callback requests per source IP.

If you are unsure, keep the defaults shown above.

If your users frequently share a single public IP (for example through CGNAT or VPN), consider slightly increasing IP thresholds while keeping username thresholds strict.

How Throttling Appears

When a limit is exceeded, Headendarr returns:

  • HTTP status 429 Too Many Requests
  • a Retry-After header with the wait time in seconds