laravel-foundry / trusted-proxies
Laravel trusted proxies configuration for applications behind CDNs, load balancers, or Docker networks. Supports Cloudflare, AWS CloudFront, Fastly, Docker Swarm, and custom proxies.
Package info
github.com/laravel-foundry/trusted-proxies
pkg:composer/laravel-foundry/trusted-proxies
Fund package maintenance!
Requires
- php: >=8.2
- illuminate/http: ^10.0 || ^11.0 || ^12.0
- illuminate/support: ^10.0 || ^11.0 || ^12.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.48
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0 || ^9.0 || ^10.0
- phpunit/phpunit: ^10.0 || ^11.0
This package is not auto-updated.
Last update: 2026-03-07 03:01:02 UTC
README
Laravel Trusted Proxies
Laravel trusted proxies configuration for applications behind CDNs, load balancers, or Docker networks.
Features
- Multiple CDN Support - Cloudflare, AWS CloudFront, Fastly out of the box
- Docker Swarm Ready - Handles Docker ingress networks and overlay networks
- Environment-Based Config - Different settings for dev, staging, production
- Custom Proxy Support - Add your own load balancers or reverse proxies
- Zero Configuration - Works out of the box with sensible defaults
- Laravel Native - Uses Laravel's built-in Request::setTrustedProxies()
Why This Package?
When running Laravel behind proxies (CDN, Docker Swarm, load balancers), Laravel sees the proxy's IP instead of the real client IP. This breaks:
- Rate limiting
- IP-based access control
- Geolocation
- Logging and analytics
- Security features
This package configures Laravel to trust specific proxies and extract the real client IP from headers like X-Forwarded-For and CF-Connecting-IP.
Requirements
- PHP >= 8.2
- Laravel Illuminate/Support ^10.0|^11.0|^12.0
- Laravel Illuminate/HTTP ^10.0|^11.0|^12.0
Installation
1. Install the package
composer require laravel-foundry/trusted-proxies
The package auto-registers via Laravel's service provider discovery.
2. Configure environment variables
Add to your .env file:
# Development (local Docker) TRUSTED_PROXY_PROVIDERS=docker # Staging (Docker + Cloudflare) TRUSTED_PROXY_PROVIDERS=cloudflare,docker # Production (Docker Swarm + Cloudflare) TRUSTED_PROXY_PROVIDERS=cloudflare,docker
That's it! The package will automatically configure trusted proxies on every request.
Configuration
Environment Variables
The package uses environment variables for configuration:
# Comma-separated list of providers TRUSTED_PROXY_PROVIDERS=cloudflare,docker # Custom IP ranges (optional) TRUSTED_PROXY_CUSTOM_RANGES=10.20.0.0/16,192.168.100.5
Available Providers
cloudflare- Cloudflare CDN (includes CF-Connecting-IP header)aws_cloudfront- AWS CloudFront CDNfastly- Fastly CDN (includes Fastly-Client-IP header)docker- Docker networks (bridge, custom, Swarm ingress)
Publish Configuration (Optional)
For advanced customization, publish the config file:
php artisan vendor:publish --tag=trustedproxies-config
This creates config/trustedproxies.php where you can customize settings.
Usage
Basic Usage
After installation, Laravel automatically gets the real client IP:
// Get real client IP (not proxy IP) $clientIp = request()->ip(); // Use in your application Log::info('Request from IP', ['ip' => $clientIp]);
Environment-Specific Configurations
Local Development (.env.development)
# Only trust Docker internal networks
TRUSTED_PROXY_PROVIDERS=docker
Staging (.env.staging)
# Trust Docker + Cloudflare
TRUSTED_PROXY_PROVIDERS=cloudflare,docker
Production with Docker Swarm (.env.production)
# Trust Docker (for Swarm ingress) + Cloudflare
TRUSTED_PROXY_PROVIDERS=cloudflare,docker
Important: Always keep docker enabled in production when using Docker Swarm, because the Swarm ingress network acts as an internal proxy.
Custom Load Balancer
If you have an additional load balancer:
TRUSTED_PROXY_PROVIDERS=cloudflare,docker TRUSTED_PROXY_CUSTOM_RANGES=10.20.0.0/16
Multiple CDN Providers
# Using both Cloudflare and Fastly
TRUSTED_PROXY_PROVIDERS=cloudflare,fastly,docker
Common Use Cases
Rate Limiting
use Illuminate\Support\Facades\RateLimiter; RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->ip()); });
IP Whitelisting
namespace App\Http\Middleware; class IpWhitelist { public function handle($request, $next) { $allowedIps = ['1.2.3.4', '5.6.7.8']; if (!in_array(request()->ip(), $allowedIps)) { abort(403, 'Access denied'); } return $next($request); } }
Logging Real IPs
use Illuminate\Support\Facades\Log; Log::channel('daily')->info('User action', [ 'ip' => request()->ip(), 'user_id' => auth()->id(), 'action' => 'login', ]);
Geolocation
use Illuminate\Support\Facades\Http; $ip = request()->ip(); $location = Http::get("http://ip-api.com/json/{$ip}")->json(); // Use real IP for accurate geolocation
How It Works
Architecture
Internet → CDN (Cloudflare) → Your Server → Docker Swarm Ingress → Container
↓ adds CF-Connecting-IP ↓ adds X-Forwarded-*
Package configures Laravel to:
1. Trust IPs from Cloudflare and Docker networks
2. Read real client IP from CF-Connecting-IP header
3. Fall back to X-Forwarded-For if needed
Technical Details
Request Flow:
- Request arrives at CDN (e.g., Cloudflare)
- CDN adds headers:
CF-Connecting-IP,X-Forwarded-For - Request reaches your server
- If using Docker Swarm, goes through ingress network
- Package configures
Request::setTrustedProxies()with:- CDN IP ranges (Cloudflare, AWS, Fastly)
- Docker network ranges (10.0.0.0/8, 172.16.0.0/12)
- Custom ranges (if configured)
- Laravel extracts real IP from trusted headers
request()->ip()returns real client IP
Provider-Specific Headers:
- Cloudflare: Uses
CF-Connecting-IP(most reliable) - Fastly: Uses
Fastly-Client-IP - Others: Use
X-Forwarded-For(first non-private IP)
Why Trust Docker in Production?
With Docker Swarm, requests flow through the ingress network before reaching your container:
Client → Cloudflare → Your VPS → Swarm Ingress (10.0.x.x) → Container
Without trusting Docker IPs, you'd see the ingress IP (10.0.x.x) instead of the real client IP. Cloudflare sends the real IP in CF-Connecting-IP, but you still need to trust the ingress network to process it correctly.
Troubleshooting
Still seeing proxy IPs?
Check your configuration:
// In tinker or any PHP file $service = app(\LaravelFoundry\TrustedProxies\Service\TrustedProxyService::class); // Check enabled providers $providers = config('trustedproxies.providers'); var_dump($providers); // Check all trusted IPs $trustedIps = $service->getTrustedProxies(); var_dump($trustedIps); // Check current IP var_dump(request()->ip());
Cloudflare not working?
Verify Cloudflare is passing the header:
// Check if header is present var_dump($_SERVER['HTTP_CF_CONNECTING_IP'] ?? 'not set');
Make sure Cloudflare's orange cloud is enabled (proxying traffic).
Docker Swarm issues?
Verify the ingress network:
# Check Docker network docker network inspect ingress # Check your container's networks docker inspect <container-id> | grep -A 20 Networks
Wrong IP being returned?
Enable debug logging:
// In tinker or temporarily in code Log::debug('IP Detection', [ 'request_ip' => request()->ip(), 'remote_addr' => $_SERVER['REMOTE_ADDR'] ?? null, 'cf_connecting_ip' => $_SERVER['HTTP_CF_CONNECTING_IP'] ?? null, 'x_forwarded_for' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? null, 'trusted_proxies' => $service->getTrustedProxies(), ]);
Testing
composer test
More info
See here.
Changelog
Please see CHANGELOG for a detailed list of changes for each release.
We follow Semantic Versioning and use Conventional Commits to automatically generate our changelog.
Release Process
- Major versions (1.0.0 → 2.0.0): Breaking changes
- Minor versions (1.0.0 → 1.1.0): New features, backward compatible
- Patch versions (1.0.0 → 1.0.1): Bug fixes, backward compatible
All releases are automatically created when changes are pushed to the main branch, based on commit message conventions.
Contributing
For your contributions please use:
See CONTRIBUTING for detailed guidelines.