myscode/laravel-any-trusted-proxies

Easily configurable any popular, custom or niche proxy providers for Laravel. Dynamic trusted proxies middleware with Cloudflare, Fastly, AWS CloudFront, Gcore, Bunny CDN, CDNvideo, Megafon and custom IP providers.

Maintainers

Package info

github.com/myscode/laravel-any-trusted-proxies

pkg:composer/myscode/laravel-any-trusted-proxies

Transparency log

Statistics

Installs: 5

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.2 2026-08-02 12:39 UTC

This package is auto-updated.

Last update: 2026-08-02 12:40:21 UTC


README

Latest Version License Tests PHP

Easily configurable any popular, custom, or niche proxy providers for Laravel.

A Laravel package for dynamic loading of trusted proxy IPs from multiple CDN and proxy providers: Cloudflare, Fastly, AWS CloudFront, Gcore, Bunny CDN, CDNvideo, Megafon β€” and any custom provider you add.

πŸ“– Русская вСрсия

Table of Contents

Features

  • Pick any providers β€” enable only the ones you need via a single .env variable
  • 7 built-in providers: Cloudflare, Fastly, AWS CloudFront, Gcore, Bunny CDN, CDNvideo, Megafon
  • Custom provider support β€” add your own or niche providers via the IpProvider interface
  • HTTP retries via Http::retry with configurable attempts and delay
  • Safe cache refresh: if any provider fails, the existing cache is preserved β€” partial results are never saved
  • Middleware that injects trusted proxy IPs at runtime β€” replaces the stock TrustProxies middleware
  • Artisan command for manual/scheduled cache refresh
  • CIDR and plain IP support β€” transparently works with both formats

Requirements

Dependency Version
PHP >= 8.1
Laravel 10.x or 11.x
Composer >= 2.0

Installation

composer require myscode/laravel-any-trusted-proxies

The package uses Laravel auto-discovery β€” the ServiceProvider is registered automatically.

Quick Start

  1. Add to your .env the providers you want to enable:
TRUSTED_PROXIES=cloudflare,fastly
  1. Register the middleware in bootstrap/app.php (Laravel 11+):
->withMiddleware(function (Middleware $middleware) {
    $middleware->replace(
        \Illuminate\Http\Middleware\TrustProxies::class,
        \Myscode\AnyTrustedProxies\Http\Middleware\TrustProxies::class
    );
})
  1. Done! The trusted proxy IPs will be fetched, cached, and applied automatically.

If TRUSTED_PROXIES is left empty, no providers are loaded β€” the middleware will have an empty proxy list.

Publishing Configuration

php artisan vendor:publish --tag=trusted-proxy-config

After publishing, the file will be placed at config/trusted-proxy.php. You can add custom providers, change TTL, or tweak retry settings.

Middleware Setup

The package provides its own middleware Myscode\AnyTrustedProxies\Http\Middleware\TrustProxies that replaces the stock Illuminate\Http\Middleware\TrustProxies.

Laravel 11+

In bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->replace(
        \Illuminate\Http\Middleware\TrustProxies::class,
        \Myscode\AnyTrustedProxies\Http\Middleware\TrustProxies::class
    );
})

Laravel 10

In app/Http/Kernel.php:

protected $middleware = [
    // ...
    \Myscode\AnyTrustedProxies\Http\Middleware\TrustProxies::class,
];

Configuration

Environment Variables

All configuration can be done through .env:

# Comma-separated list of providers to enable (leave empty to disable all)
TRUSTED_PROXIES=cloudflare,fastly,aws_cloudfront

# Cache key (optional, default: trusted_proxy_ips)
TRUSTED_PROXY_CACHE_KEY=trusted_proxy_ips

# Cache TTL in seconds (optional, default: 604800 = 7 days)
TRUSTED_PROXY_TTL=604800

# HTTP retry attempts (optional, default: 3)
TRUSTED_PROXY_RETRY_TIMES=3

# HTTP retry delay in ms (optional, default: 200)
TRUSTED_PROXY_RETRY_SLEEP=200

Options Reference

Option Type .env Variable Description Default
cache_key string TRUSTED_PROXY_CACHE_KEY Cache key for storing IPs trusted_proxy_ips
ttl int TRUSTED_PROXY_TTL Cache lifetime in seconds 604800 (7 days)
retry.times int TRUSTED_PROXY_RETRY_TIMES Number of HTTP retry attempts 3
retry.sleep int TRUSTED_PROXY_RETRY_SLEEP Delay between retries (ms) 200
enabled array TRUSTED_PROXIES Comma-separated provider names to enable []
providers array β€” Map of all available providers (name β†’ class) all built-in
headers int β€” Bitmask of trusted forwarded headers HEADER_X_FORWARDED_ALL

The headers value is a bitmask from Illuminate\Http\Request:

Constant Value Description
HEADER_X_FORWARDED_FOR 0b00000010 Client IP
HEADER_X_FORWARDED_HOST 0b00000100 Host
HEADER_X_FORWARDED_PORT 0b00001000 Port
HEADER_X_FORWARDED_PROTO 0b00010000 Protocol (http/https)
HEADER_X_FORWARDED_ALL 0b11111110 All headers

Available Providers

Provider .env Key Class Response Type Data Source
Cloudflare cloudflare CloudflareIpProvider Plain text cloudflare.com/ips-v4 + ips-v6
Fastly fastly FastlyIpProvider JSON api.fastly.com/public-ip-list
AWS CloudFront aws_cloudfront AwsCloudFrontIpProvider JSON ip-ranges.amazonaws.com/ip-ranges.json
Gcore gcore GcoreIpProvider JSON api.gcore.com/cdn/public_ips_list
Bunny CDN bunny BunnyIpProvider JSON api.bunny.net/system/edgeserverlist
CDNvideo cdnvideo CdnvideoIpProvider JSON api.cdnvideo.ru/app/nodes/v2/ip2origin
Megafon megafon MegafonIpProvider JSON api.lk.cdn.megafon.ru/cdn/public_ips_list

IP Address Formats

The package does not validate or transform IP addresses on its own β€” it passes them "as is" to Laravel's standard middleware. Verification happens at the framework level via Symfony's IpUtils::checkIp().

Both formats are supported:

Format Example How it is checked
CIDR 173.245.48.0/20 Subnet membership check
Plain IPv4 192.168.1.1 Exact match (equivalent to /32)
Plain IPv6 2400:cb00::1 Exact match (equivalent to /128)

Cache Safety

  • On refresh/load, the list is cached only if all enabled providers succeed
  • If any provider fails, the existing cache is used (if available), so the application never loses its trusted proxies
  • Partial results on failure are never saved β€” this prevents a scenario where a single failed provider removes its IPs from the trusted list
  • All IPs are deduplicated across providers

Available Commands

any-trustedproxy:reload

Force-refreshes the trusted proxy list from all enabled providers:

php artisan any-trustedproxy:reload

Output:

Trusted proxies refreshed. Count: 42

Exit codes:

  • 0 (SUCCESS) β€” refresh completed successfully

Scheduler Setup

In routes/console.php:

use Illuminate\Support\Facades\Schedule;

Schedule::command('any-trustedproxy:reload')->weekly();
// or: ->daily(), ->twiceDaily(), ->everySixHours()

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  .env                        β”‚
β”‚        TRUSTED_PROXIES=cloudflare,fastly     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ServiceProvider                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Read enabled[] from config           β”‚  β”‚
β”‚  β”‚  Filter providers map by enabled      β”‚  β”‚
β”‚  β”‚  Instantiate only selected providers  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               HTTP Request                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                 β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Middleware: TrustProxies                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  $this->proxies = TrustedProxy::load()β”‚  β”‚
β”‚  β”‚  $this->headers = config(...)         β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Facade: TrustedProxy                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  IpCacheManager                       β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚  Cache::get(cache_key)          β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  β”œβ”€β”€ hit  β†’ return cached       β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  └── miss β†’ fetchFromProviders  β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  IpProvider[] (only enabled)                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚Cloudflareβ”‚ β”‚  Fastly  β”‚ β”‚   Gcore    β”‚  β”‚
β”‚  β”‚ getIps() β”‚ β”‚ getIps() β”‚ β”‚  getIps()  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                     β”‚                        β”‚
β”‚              array_merge +                   β”‚
β”‚              array_unique                    β”‚
β”‚                     β–Ό                        β”‚
β”‚              Cache::put()                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

Component Purpose
IpProvider (interface) Contract for all providers: getIps(): array
FetchesWithRetry (trait) HTTP requests with retries: getJsonWithRetry() and getTextLinesWithRetry()
IpCacheManager Orchestration: collects IPs from providers, caching, fail-safe logic
TrustProxies (middleware) Replaces stock middleware β€” injects proxies at runtime
TrustedProxy (facade) Convenient access to IpCacheManager
TrustedProxyServiceProvider Laravel registration: singleton, TRUSTED_PROXIES filtering, command, config
ReloadProxiesCommand Artisan command for forced cache refresh

Adding a Custom Provider

Implement the IpProvider interface and optionally use the FetchesWithRetry trait:

<?php

namespace App\TrustedProxies;

use Myscode\AnyTrustedProxies\Contracts\IpProvider;
use Myscode\AnyTrustedProxies\Services\Concerns\FetchesWithRetry;

class MyCdnProvider implements IpProvider
{
    use FetchesWithRetry;

    public function getIps(): array
    {
        // Option 1: JSON API
        $data = $this->getJsonWithRetry('https://api.mycdn.com/public-ips');
        return collect($data['ip_ranges'] ?? [])
            ->pluck('subnet')
            ->filter()
            ->values()
            ->all();

        // Option 2: Plain text (one IP per line)
        // return $this->getTextLinesWithRetry('https://mycdn.com/ips.txt');

        // Option 3: Static list
        // return ['10.0.0.0/8', '172.16.0.0/12'];
    }
}

Register it in config/trusted-proxy.php and .env:

// config/trusted-proxy.php
'providers' => [
    // ...built-in providers...
    'my_cdn' => \App\TrustedProxies\MyCdnProvider::class,
],
# .env
TRUSTED_PROXIES=cloudflare,fastly,my_cdn

Implementation Guidelines

  • getIps() must return a flat array of strings β€” CIDR (10.0.0.0/8) or plain IP (192.168.1.1)
  • Do not throw exceptions β€” IpCacheManager catches \Throwable and logs the error without breaking other providers
  • Use the FetchesWithRetry trait for automatic retries according to your retry settings
  • Filter out empty values β€” use array_filter on the result

Testing

composer install
composer test
composer test-coverage   # with coverage

Tests use Orchestra Testbench. HTTP requests are mocked via Http::fake().

License

MIT License β€” see LICENSE.