Laravel IP firewall — whitelist, blacklist, and attack blocking.
Fork of antonioribeiro/firewall (originally published as pragmarx/firewall), modernized for PHP 8.1+ and Laravel 10–13.
| Laravel | PHP |
|---|---|
| 10 | 8.1, 8.2 |
| 11 | 8.2, 8.3 |
| 12 | 8.2, 8.3, 8.4 |
| 13 | 8.3, 8.4 |
The cell list is kept in docker/matrix.txt (single source of truth for local Docker runs) and mirrored in .forgejo/workflows/tests.yml.
Run the full matrix or a single cell locally via Docker:
make test-all # full matrix
make test-matrix PHP=8.2 LARAVEL=11 # single cellCells run inside pre-built thecodingmachine/php CLI images, pinned by digest in docker/digests.txt for reproducibility. The repository is mounted read-only and copied to a scratch directory inside the container, so composer require cannot mutate the host composer.json or vendor/.
Refreshing image digests. Update docker/digests.txt when adding a new PHP version or pulling in upstream base-image changes. The refresh command is documented in the header of that file; after running it, commit the updated digests alongside any matrix changes.
composer require magentron/laravel-firewallThe service provider and Firewall facade are auto-discovered via extra.laravel in composer.json.
php artisan vendor:publish --tag=firewall-configThis writes config/firewall.php to your application.
php artisan vendor:publish --tag=firewall-migrations
php artisan migrateSet firewall.use_database = true in the config to persist IP lists in the database. When false (default), lists are kept in config arrays only.
Three named middleware aliases are registered automatically:
| Alias | Behaviour |
|---|---|
fw-block-blacklisted |
Returns 403 for blacklisted IPs; lets others through |
fw-only-whitelisted |
Returns 403 for non-whitelisted IPs; lets whitelisted through |
fw-block-attacks |
Returns 403 when attack-blocker threshold is exceeded |
// Apply to a single route
Route::get('/admin', AdminController::class)->middleware('fw-only-whitelisted');
// Apply to a route group
Route::middleware(['fw-block-blacklisted'])->group(function () {
Route::get('/api/public', PublicApiController::class);
});
// Stack multiple middleware
Route::middleware(['fw-block-blacklisted', 'fw-block-attacks'])->group(function () {
Route::post('/api/sensitive', SensitiveController::class);
});use Firewall; // or use PragmaRX\Firewall\Vendor\Laravel\Facade as Firewall;
// Add to lists
Firewall::blacklist('1.2.3.4');
Firewall::whitelist('1.2.3.4');
// Force move between lists (overrides existing entry)
Firewall::blacklist('1.2.3.4', force: true);
// Query lists
Firewall::isBlacklisted('1.2.3.4'); // bool
Firewall::isWhitelisted('1.2.3.4'); // bool
Firewall::whichList('1.2.3.4'); // 'blacklist'|'whitelist'|null
// Remove / clear
Firewall::remove('1.2.3.4');
Firewall::clear();
// Attack detection
Firewall::isBeingAttacked('1.2.3.4'); // bool
Firewall::responseToAttack(); // Response|RedirectResponse|null
// Misc
Firewall::all(); // Collection of all stored IPs
Firewall::report(); // alias of all()
Firewall::find('1.2.3.4'); // Eloquent model|null
Firewall::ipIsValid('...'); // bool
Firewall::getMessages(); // Collection<string>127.0.0.1
192.168.17.0/24
127.0.0.1/255.255.255.255
10.0.0.1-10.0.0.255
172.17.*.*
country:br
host:example.com
/path/to/iplist.txt (file containing IPs, one per line)
| Command | Description |
|---|---|
firewall:whitelist <ip> |
Add IP to whitelist |
firewall:blacklist <ip> |
Add IP to blacklist |
firewall:remove <ip> |
Remove IP from all lists |
firewall:clear |
Remove all IPs from lists |
firewall:list |
Display all stored IPs |
firewall:updategeoip |
Download/update GeoLite2 database |
firewall:cache:clear |
Flush the firewall in-memory cache |
This fork delegates IP resolution entirely to Laravel's Request::getClientIp(). That method honors Symfony's Request::$trustedProxies, which Laravel configures via the TrustProxies middleware.
If your application runs behind Cloudflare, an AWS ALB, or any other reverse proxy, configure TrustProxies once and IP detection works automatically — no package-specific configuration needed.
Cloudflare example — add Cloudflare's published IP ranges to App\Http\Middleware\TrustProxies:
protected $proxies = [
'103.21.244.0/22',
'103.22.200.0/22',
// ... full list from https://www.cloudflare.com/ips/
];
protected $headers = Request::HEADER_X_FORWARDED_FOR;See Laravel's trusted proxy documentation for details.
Migrating from
pragmarx/firewall: The previous version readHTTP_CF_CONNECTING_IPandHTTP_X_FORWARDED_FORheaders directly, bypassing Laravel's proxy trust list. This was a spoofing risk. The new behavior is safer: configureTrustProxiesand the right IP will be detected.
Country-based filtering (country:us, country:br, etc.) requires a MaxMind GeoLite2-Country database.
Set the environment variable and run the Artisan command:
FIREWALL_MAXMIND_LICENSE_KEY=your_key_here php artisan firewall:updategeoipOr add to .env:
FIREWALL_MAXMIND_LICENSE_KEY=your_key_here
A free license key can be obtained from MaxMind.
Download GeoLite2-Country.mmdb from MaxMind and place it at the path configured in firewall.geoip_database_path (defaults to <package>/src/config/geoip/GeoLite2-Country.mmdb).
When no database file exists, country lookups return null silently. Country filtering is skipped and no exception is thrown. Users who don't need country features are unaffected.
magentron/laravel-firewall is a true drop-in replacement: it reuses the
PragmaRX\Firewall PHP namespace and declares a Composer replace for
pragmarx/firewall, so Composer's dependency resolver will accept this
package wherever pragmarx/firewall is required. Existing code that
imports PragmaRX\Firewall\... classes continues to work without
modification.
Config file keys and defaults, middleware aliases
(fw-only-whitelisted, fw-block-blacklisted, fw-block-attacks),
the Firewall facade, Artisan command signatures, the database table
schema, and the AttackDetected event class are all unchanged.
-
Remove
pragmarx/firewalland install this fork:composer remove pragmarx/firewall composer require magentron/laravel-firewall
-
If you published the config previously, re-publish or manually verify it — config keys are identical, so the existing file will work.
-
Review the behavioural changes in
changelog.md— in particular, the trusted-proxy IP resolution hardening (see below) may require configuring Laravel'sTrustProxiesmiddleware if you run behind Cloudflare, AWS ALB, or similar.
BSD-3-Clause
Original work Copyright (c) 2014, Antonio Carlos Ribeiro
Fork modifications Copyright (c) 2026, Jeroen D. a.k.a. Magentron