Configuring Trusted Proxies
When your application runs behind a load balancer, CDN, or reverse proxy, the web server sees the proxy's IP address instead of the actual visitor's IP. Trusted proxy configuration tells your web server which proxies to trust for forwarding the real client IP.
Why Trusted Proxies Matter
Without proper trusted proxy configuration, your application will:
- Log the proxy's IP address instead of the visitor's real IP
- Have incorrect geolocation data
- Potentially break rate limiting or IP-based security rules
- Show incorrect information in Laravel's
request()->ip()or similar methods
Available Options
Set the TRUSTED_PROXY environment variable to one of the following values:
| Value | Description |
|---|---|
cloudflare (default) | Trusts Cloudflare's IP ranges + local Docker networks using the CF-Connecting-IP header |
sucuri | Trusts Sucuri's IP ranges + local Docker networks using the X-Forwarded-For header |
local | Trusts only private/local network ranges (Docker networks, localhost) using the X-Forwarded-For header |
off | Disables trusted proxy configuration entirely |
off) automatically include Docker's internal network ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). This means if you're behind Cloudflare and running a reverse proxy like Traefik or Caddy in Docker, just use cloudflare — it already trusts both.Quick Start
Using Cloudflare (Default)
If you're using Cloudflare as your CDN/proxy, you don't need to change anything. The default configuration already trusts Cloudflare's IP ranges:
services:
php:
image: serversideup/php:8.5-fpm-nginx
ports:
- "80:8080"
volumes:
- .:/var/www/html
# TRUSTED_PROXY defaults to "cloudflare"
Using Sucuri
If you're using Sucuri as your web application firewall:
services:
php:
image: serversideup/php:8.5-fpm-nginx
ports:
- "80:8080"
volumes:
- .:/var/www/html
environment:
TRUSTED_PROXY: "sucuri"
Local/Docker Networks Only
If you're running behind your own reverse proxy (like Traefik or Caddy) on the same Docker network:
services:
php:
image: serversideup/php:8.5-fpm-nginx
ports:
- "80:8080"
volumes:
- .:/var/www/html
environment:
TRUSTED_PROXY: "local"
Disabling Trusted Proxies
If you want to handle proxy configuration yourself or your application is directly exposed to the internet:
services:
php:
image: serversideup/php:8.5-fpm-nginx
ports:
- "80:8080"
volumes:
- .:/var/www/html
environment:
TRUSTED_PROXY: "off"
Laravel Configuration
While the Docker images handle the web server's trusted proxy configuration, Laravel also needs to know about trusted proxies at the application level.
Laravel includes a TrustProxies middleware that you should configure in your application. For most setups using our images, you can trust all proxies since the web server has already validated them:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: '*');
})
Or if you prefer more control, configure specific headers:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(
at: '*',
headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO
);
})
CF-Connecting-IP header. The HEADER_X_FORWARDED_FOR setting works because Cloudflare also sets this header.How It Works
Cloudflare
When TRUSTED_PROXY=cloudflare:
- Trusts Cloudflare's published IPv4 and IPv6 ranges
- Uses the
CF-Connecting-IPheader to get the real client IP - Includes Docker network ranges for container-to-container communication
Sucuri
When TRUSTED_PROXY=sucuri:
- Trusts Sucuri's WAF IP ranges
- Uses the
X-Forwarded-Forheader to get the real client IP - Includes Docker network ranges for container-to-container communication
Local
When TRUSTED_PROXY=local:
- Trusts only private network ranges (RFC 1918)
- Trusts localhost and IPv6 loopback addresses
- Uses the
X-Forwarded-Forheader - Perfect for setups with your own reverse proxy on the same network
Security Considerations
- Don't trust all IPs: Never set your web server to trust
X-Forwarded-Forfrom any IP address - Keep configurations updated: CDN IP ranges can change over time. Our images are updated regularly, but if security is critical, verify the ranges match your provider's published list
- Use the right option: If you're not using Cloudflare or Sucuri, don't use those options. Use
localif you have your own reverse proxy, oroffif you don't need proxy trust
Troubleshooting
Still seeing proxy IP instead of real IP
- Check your CDN/proxy is in the trusted list: Verify your proxy's IP is within the trusted ranges for your chosen option
- Check the header being used: Different proxies use different headers. Cloudflare uses
CF-Connecting-IP, while most others useX-Forwarded-For - Check Laravel configuration: Remember to also configure Laravel's
TrustProxiesmiddleware
Application works but logs show wrong IP
Your web server might be configured correctly, but your application framework might need separate configuration. See the Laravel Configuration section above.
Need to trust a different proxy provider
If your proxy provider isn't listed, you can create a custom configuration. See Custom Trusted Proxy Configuration below.
Custom Trusted Proxy Configuration
If you're using a proxy provider that isn't included (like AWS ALB, Fastly, or a custom load balancer), you can create your own trusted proxy configuration.
Two Ways to Add Custom Configs
| Method | Best For | How It Works |
|---|---|---|
| Dockerfile (recommended) | Production deployments | Bakes the config into your image |
| Volume mount | Local development | Mount the file at runtime |
The examples below use the Dockerfile approach. To use a volume mount instead, simply replace the COPY instruction with a volume mount in your compose.yml:
volumes:
# Mount syntax: ./local/path:/container/path:ro
- ./docker/trusted-proxy/aws-alb.conf:/etc/nginx/trusted-proxy/aws-alb.conf:ro
| Variation | Config Path |
|---|---|
fpm-nginx | /etc/nginx/trusted-proxy/{name}.conf |
fpm-apache | /etc/apache2/trusted-proxy/{name}.conf |
frankenphp | /etc/frankenphp/trusted-proxy/{name}.caddyfile |
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) so container-to-container communication works correctly.FPM-NGINX Custom Configuration
FROM serversideup/php:8.5-fpm-nginx
# Copy our custom trusted proxy configuration
COPY --chmod=644 docker/trusted-proxy/aws-alb.conf /etc/nginx/trusted-proxy/aws-alb.conf
FPM-Apache Custom Configuration
FROM serversideup/php:8.5-fpm-apache
# Copy our custom trusted proxy configuration
COPY --chmod=644 docker/trusted-proxy/aws-alb.conf /etc/apache2/trusted-proxy/aws-alb.conf
FrankenPHP Custom Configuration
FROM serversideup/php:8.5-frankenphp
# Copy our custom trusted proxy configuration
COPY --chmod=644 docker/trusted-proxy/aws-alb.caddyfile /etc/frankenphp/trusted-proxy/aws-alb.caddyfile