abdulhadii777 / laravel-ip-guard
Middleware to restrict application usage from blacklisted IPs with whitelist overrides.
Requires
- php: ^8.4
- illuminate/contracts: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
README
A powerful Laravel middleware package for IP-based access control with whitelist and blacklist support. Protect your application by allowing or blocking specific IP addresses with dynamic database management and a flexible priority system.
Current Version: v0.1.1
Features
- Dynamic Database Management: Add/remove IPs without code changes
- Priority-Based Access Control: Blacklist takes highest priority over whitelist
- Environment Toggle: Enable/disable IP restrictions via environment variable
- Whitelist Support: Allow only specific IPs
- Blacklist Support: Block specific IPs (including
*
for all IPs) - Exact IP Matching: Support for exact IP addresses only
- Soft Toggle Control: Enable/disable IPs without deleting records
- Artisan Commands: Full CLI management interface
- Facade Support: Easy programmatic access
- Proxy Support: Works behind load balancers and proxies
- Fallback Support: Falls back to config if database unavailable
- Custom Error Responses: JSON or plain text error responses
- Laravel Integration: Seamless integration with Laravel middleware
Support us
We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.
We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.
Installation
You can install the package via composer:
composer require abdulhadii777/laravel-ip-guard
The package will automatically register itself. You can publish the config file and migration with:
php artisan vendor:publish --provider="Ahs\LaravelIpGuard\LaravelIpGuardServiceProvider" --tag="config" php artisan vendor:publish --provider="Ahs\LaravelIpGuard\LaravelIpGuardServiceProvider" --tag="migrations"
Or use the package's publish commands:
php artisan vendor:publish --tag="ip-guard-config" php artisan vendor:publish --tag="ip-guard-migrations"
Then run the migration:
php artisan migrate
Configuration
After publishing the config file, you can configure the package in config/ip-guard.php
. The package now uses database-driven IP management by default, with config as fallback:
return [ /* |-------------------------------------------------------------------------- | Enable/Disable IP Guard |-------------------------------------------------------------------------- | Set to false to disable IP restrictions entirely. | You can also use IP_GUARD_ENABLED environment variable. */ 'enabled' => env('IP_GUARD_ENABLED', true), /* |-------------------------------------------------------------------------- | IP Lists (Fallback Configuration) |-------------------------------------------------------------------------- | These are used as fallback when database is unavailable. | Use '*' to match all IPs. Supports exact IPs only. | | Priority order: | 1. Blacklist (highest priority) - if IP matches, block access | - '*' in blacklist blocks ALL IPs regardless of whitelist | 2. Whitelist - if IP matches, allow access (only if not blacklisted) | 3. null/empty - no restrictions (only if not blacklisted) | | Example: blacklist=['*'] + whitelist=['1.2.3.4'] = NO ACCESS (all blocked) */ 'whitelist' => null, // Fallback whitelist (use database for dynamic management) 'blacklist' => null, // Fallback blacklist (use database for dynamic management) /* |-------------------------------------------------------------------------- | Client IP Resolution |-------------------------------------------------------------------------- | Set the header to use for client IP when behind a proxy/load balancer. | Set to null to use Laravel's default IP detection. */ 'ip_header' => 'X-Forwarded-For', // or 'X-Real-IP', 'CF-Connecting-IP', etc. /* |-------------------------------------------------------------------------- | Error Response |-------------------------------------------------------------------------- | Configure the response when access is denied. */ 'error' => [ 'status' => 403, 'message' => 'Access denied from your IP address.', 'json' => true, // Return JSON response if true, plain text if false ], ];
Database Management
The package now uses database-driven IP management by default. IPs are stored in the ip_guards
table with the following structure:
id
: Primary keyip_address
: The IP address (exact match only)type
: Either 'whitelist' or 'blacklist'description
: Optional description for the IPis_active
: Boolean flag to enable/disable the IPcreated_at
/updated_at
: Timestamps
Database Schema
CREATE TABLE ip_guards ( id BIGINT PRIMARY KEY AUTO_INCREMENT, ip_address VARCHAR(255) NOT NULL, type ENUM('whitelist', 'blacklist') NOT NULL, description TEXT NULL, is_active BOOLEAN DEFAULT TRUE, created_at TIMESTAMP NULL, updated_at TIMESTAMP NULL, INDEX idx_ip_type (ip_address, type), INDEX idx_type_active (type, is_active), UNIQUE KEY unique_ip_type (ip_address, type) );
Usage
Dynamic IP Management
Via Facade
use Ahs\LaravelIpGuard\Facades\LaravelIpGuard; // Add IPs to whitelist LaravelIpGuard::addToWhitelist('192.168.1.100', 'Office IP'); LaravelIpGuard::addToWhitelist('203.0.113.10', 'Admin IP'); // Add IPs to blacklist LaravelIpGuard::addToBlacklist('10.0.0.50', 'Blocked IP'); LaravelIpGuard::addToBlacklist('*', 'Block all IPs'); // Check IP status $isWhitelisted = LaravelIpGuard::isWhitelisted('192.168.1.100'); $isBlacklisted = LaravelIpGuard::isBlacklisted('10.0.0.50'); // Get IP lists $whitelistIps = LaravelIpGuard::getWhitelistIps(); $blacklistIps = LaravelIpGuard::getBlacklistIps(); // Remove IPs LaravelIpGuard::removeFromWhitelist('192.168.1.100'); LaravelIpGuard::removeFromBlacklist('10.0.0.50'); // Bulk operations $ips = ['192.168.1.101', '192.168.1.102', '192.168.1.103']; LaravelIpGuard::bulkAddToWhitelist($ips, 'Office Network'); // Get statistics $stats = LaravelIpGuard::getStats(); // Returns: ['whitelist_count' => 5, 'blacklist_count' => 2, 'total_count' => 7]
Via Artisan Commands
# Add IPs php artisan ip-guard:manage add whitelist 192.168.1.100 --description="Office IP" php artisan ip-guard:manage add blacklist 10.0.0.50 --description="Blocked IP" # List IPs php artisan ip-guard:manage list # List all IPs php artisan ip-guard:manage list whitelist # List whitelist only php artisan ip-guard:manage list blacklist # List blacklist only # Remove IPs php artisan ip-guard:manage remove whitelist 192.168.1.100 php artisan ip-guard:manage remove blacklist 10.0.0.50 # Toggle IP status (enable/disable without deleting) php artisan ip-guard:manage toggle --id=1 # Clear IPs php artisan ip-guard:manage clear whitelist # Clear all whitelist IPs php artisan ip-guard:manage clear blacklist # Clear all blacklist IPs php artisan ip-guard:manage clear # Clear all IPs # Show statistics php artisan ip-guard:manage stats
Via Model
use Ahs\LaravelIpGuard\Models\IpGuard; // Direct model usage IpGuard::addToWhitelist('192.168.1.100', 'Office IP'); IpGuard::addToBlacklist('10.0.0.50', 'Blocked IP'); // Query IPs $whitelistIps = IpGuard::whitelist()->active()->get(); $blacklistIps = IpGuard::blacklist()->active()->get(); // Toggle IP status $ip = IpGuard::find(1); $ip->toggleActive(); // Toggle between active/inactive // Check if IP is in list $isWhitelisted = IpGuard::isWhitelisted('192.168.1.100'); $isBlacklisted = IpGuard::isBlacklisted('10.0.0.50');
Basic Middleware Usage
Apply the middleware to routes in your routes/web.php
or routes/api.php
:
// Apply to specific routes Route::get('/admin', function () { return view('admin'); })->middleware('ip.guard'); // Apply to route groups Route::middleware(['ip.guard'])->group(function () { Route::get('/dashboard', 'DashboardController@index'); Route::get('/profile', 'ProfileController@index'); }); // Apply to controllers Route::get('/admin', 'AdminController@index')->middleware('ip.guard');
Global Middleware
Add the middleware globally in app/Http/Kernel.php
:
protected $middleware = [ // ... other middleware \Ahs\LaravelIpGuard\Middleware\IpGuard::class, ];
Controller Middleware
Apply in your controller constructor:
class AdminController extends Controller { public function __construct() { $this->middleware('ip.guard'); } }
IP Matching Rules
The package supports exact IP matching only:
Exact IP Matching
'whitelist' => ['203.0.113.10', '198.51.100.20']
Block All IPs
'blacklist' => ['*'] // Block all IPs (useful with whitelist)
Priority Rules
The middleware follows this priority order:
- Environment Check: If
IP_GUARD_ENABLED=false
, all IPs are allowed (no restrictions) - Blacklist Check (Highest Priority): If the client IP matches any blacklist rule, access is denied
*
in blacklist blocks ALL IPs regardless of whitelist
- Whitelist Check: If whitelist is configured and IP matches, access is allowed
- Whitelist Enforcement: If whitelist is configured but IP doesn't match, access is denied
- Default: If whitelist is null/empty and IP is not blacklisted, access is allowed
Examples:
Scenario 1: Blacklist with *
'blacklist' => ['*'], 'whitelist' => ['1.2.3.4', '5.6.7.8'] // Result: NO ACCESS (all IPs blocked by blacklist)
Scenario 2: Normal priority
'blacklist' => ['192.168.1.100'], 'whitelist' => ['1.2.3.4', '5.6.7.8'] // Result: Only 1.2.3.4 and 5.6.7.8 allowed, 192.168.1.100 blocked, others blocked
Scenario 3: No restrictions
'blacklist' => null, 'whitelist' => null // Result: ALL ACCESS (no restrictions)
Scenario 4: Disabled
IP_GUARD_ENABLED=false // Result: ALL ACCESS (IP guard disabled)
Proxy and Load Balancer Support
When your application is behind a proxy or load balancer, configure the ip_header
option:
'ip_header' => 'X-Forwarded-For', // Most common // or 'ip_header' => 'X-Real-IP', // Nginx // or 'ip_header' => 'CF-Connecting-IP', // Cloudflare
Make sure your Laravel application trusts the proxy by configuring TrustProxies
middleware.
Error Responses
JSON Response (default)
{ "message": "Access denied from your IP address." }
Plain Text Response
Access denied from your IP address.
Configure the response format in the config:
'error' => [ 'status' => 403, 'message' => 'Custom access denied message', 'json' => false, // Use plain text instead of JSON ],
Advanced Examples
Admin Panel Protection
// Via Artisan Commands php artisan ip-guard:manage add whitelist 203.0.113.10 --description="Admin Office" php artisan ip-guard:manage add whitelist 198.51.100.20 --description="Admin Home" php artisan ip-guard:manage add blacklist "*" --description="Block all others" // Via Facade LaravelIpGuard::addToWhitelist('203.0.113.10', 'Admin Office'); LaravelIpGuard::addToWhitelist('198.51.100.20', 'Admin Home'); LaravelIpGuard::addToBlacklist('*', 'Block all others');
Environment-Based Control
# .env IP_GUARD_ENABLED=true # Enable IP restrictions # IP_GUARD_ENABLED=false # Disable IP restrictions entirely
Mixed Blacklist and Whitelist
// Via Artisan Commands php artisan ip-guard:manage add blacklist 192.168.1.100 --description="Problematic IP" php artisan ip-guard:manage add blacklist 10.0.1.50 --description="Blocked IP" php artisan ip-guard:manage add whitelist 203.0.113.10 --description="Trusted IP" php artisan ip-guard:manage add whitelist 198.51.100.20 --description="Trusted IP" // Via Facade LaravelIpGuard::addToBlacklist('192.168.1.100', 'Problematic IP'); LaravelIpGuard::addToBlacklist('10.0.1.50', 'Blocked IP'); LaravelIpGuard::addToWhitelist('203.0.113.10', 'Trusted IP'); LaravelIpGuard::addToWhitelist('198.51.100.20', 'Trusted IP'); // Result: Only whitelisted IPs allowed, except blacklisted ones
Block Specific IPs
// Via Artisan Commands php artisan ip-guard:manage add blacklist 1.2.3.4 --description="Blocked IP" php artisan ip-guard:manage add blacklist 5.6.7.8 --description="Blocked IP" // Via Facade LaravelIpGuard::addToBlacklist('1.2.3.4', 'Blocked IP'); LaravelIpGuard::addToBlacklist('5.6.7.8', 'Blocked IP');
Development Environment
// Via Artisan Commands php artisan ip-guard:manage add whitelist 127.0.0.1 --description="Localhost" php artisan ip-guard:manage add whitelist 192.168.1.100 --description="Dev IP" php artisan ip-guard:manage add whitelist 10.0.0.50 --description="Local IP" // Via Facade LaravelIpGuard::addToWhitelist('127.0.0.1', 'Localhost'); LaravelIpGuard::addToWhitelist('192.168.1.100', 'Dev IP'); LaravelIpGuard::addToWhitelist('10.0.0.50', 'Local IP');
Temporary IP Management
// Temporarily disable an IP without deleting $ip = IpGuard::find(1); $ip->toggleActive(); // Disable // Later... $ip->toggleActive(); // Re-enable // Or via command php artisan ip-guard:manage toggle --id=1
Testing
The package includes comprehensive tests using Pest 4 with MySQL database testing.
Prerequisites
- MySQL Database: Ensure MySQL is running and accessible
- Test Database: Create a test database (or run the setup script)
# Create test database mysql -u root -p < tests/setup-test-db.sql
Running Tests
# Run all tests composer test # Run tests with coverage composer test -- --coverage # Run specific test file ./vendor/bin/pest tests/Unit/Models/IpGuardTest.php # Run tests with verbose output ./vendor/bin/pest --verbose
Test Structure
The test suite includes:
-
Unit Tests (
tests/Unit/
):Models/IpGuardTest.php
- Model functionality and scopesServices/LaravelIpGuardTest.php
- Service class methods
-
Feature Tests (
tests/Feature/
):Middleware/IpGuardTest.php
- Middleware behavior and IP matchingCommands/IpGuardCommandTest.php
- Artisan command functionalityIntegration/IpGuardIntegrationTest.php
- End-to-end workflows
Test Configuration
Tests use MySQL database with the following configuration:
- Database:
laravel_ip_guard_test
- Host:
127.0.0.1
- Port:
3306
- Username:
root
(configurable) - Password: Empty (configurable)
Test Coverage
The test suite covers:
- ✅ Model creation, updates, and deletion
- ✅ Database scopes and relationships
- ✅ Service facade methods
- ✅ Middleware IP matching logic
- ✅ Priority system (blacklist > whitelist)
- ✅ Artisan command functionality
- ✅ Error handling and validation
- ✅ Custom headers and configuration
- ✅ Fallback to config when database unavailable
- ✅ Integration workflows
- ✅ Bulk operations
- ✅ Statistics and reporting
Custom Test Configuration
You can customize test database settings in phpunit.xml.dist
:
<php> <env name="DB_CONNECTION" value="mysql"/> <env name="DB_DATABASE" value="your_test_database"/> <env name="DB_USERNAME" value="your_username"/> <env name="DB_PASSWORD" value="your_password"/> <env name="DB_HOST" value="127.0.0.1"/> <env name="DB_PORT" value="3306"/> </php>
Security Considerations
- Always test your IP rules in a staging environment
- Consider using both whitelist and blacklist for maximum security
- Regularly review and update your IP lists
- Monitor access logs for blocked attempts
- Use HTTPS to prevent IP spoofing
Troubleshooting
Common Issues
- Middleware not working: Ensure the middleware is properly registered and applied
- Wrong IP detected: Check your
ip_header
configuration and proxy setup - Blocked legitimate users: Review your whitelist/blacklist rules and priority order
- IP guard not working: Check if
IP_GUARD_ENABLED
is set totrue
in your environment - All IPs blocked: Check if
*
is in your blacklist (this blocks all IPs) - Whitelist not working: Remember blacklist takes priority - check if IP is blacklisted first
- Invalid IP format: Ensure all IPs in your lists are valid IPv4 or IPv6 addresses
- Database connection issues: Check if migration has been run and database is accessible
- IP not found in database: Use
php artisan ip-guard:manage list
to check if IP exists - Inactive IPs: Check if IP is disabled using
php artisan ip-guard:manage toggle --id=X
Debug Mode
Enable Laravel's debug mode to see detailed error messages:
// config/app.php 'debug' => true,
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.