Aegis Smart IP Blocker
Smart IP Blocker is a module of Aegis, the security suite for Laravel Nova. It counts the requests of every IP address per minute and bans an IP that sends more than you allow, on the site and in Nova, to slow down brute-force attempts, scrapers and request floods.
🚀 Features
- Per-minute limit: every IP gets a one-minute window of requests; past the limit it is banned.
- Bans for hours: a banned IP gets
429 Too Many Requestswith aRetry-Afterheader for 1 to 720 hours, then it starts over. - Your own blocked page: any Blade view of your application, or the module's own page. Clients that ask for JSON get JSON.
- Exclusions: IP addresses and CIDR subnets, IPv4 and IPv6 (
2001:db8::1and2001:0db8:0:0:0:0:0:1are the same visitor), and headers whose value contains a text (User-AgentcontainsGooglebot). - Lock-out protection: the form presets your own IP in the exclusions, and refuses to switch the blocker on unless your IP stays excluded.
- Bounded memory: optionally count at most N IPs at once; past it the oldest count is dropped, never a ban.
- Cheap on every request: the settings come from the Aegis cache, a request costs two or three cache operations and no database query.
- Dashboard: a line on the Aegis overview, and checks that warn about a cache store that forgets the counts and about spoofable header exclusions.
- Recovery from the console: lift a ban or turn the module off.
📦 Requirements
- PHP 8.4 or higher
- Laravel 12 or 13
- Laravel Nova 5
- Aegis 1.1 or higher (installed with the module)
- A cache store shared by every server (Redis, Memcached, database;
fileon a single server)
📥 Installation
1. Install the package
composer require wobqqq/nova-aegis-smart-ip-blockerThe service provider is discovered automatically.
2. Run the migrations
php artisan migrateThis creates the Aegis settings table if the core is new to the application; the module adds no table of its own.
3. Set up Aegis (once per application)
If Aegis is new to the application, register its tool and define the viewAegis gate as the Aegis README describes. Skip this step if you already use another Aegis module.
4. Turn it on in Nova
Open Aegis → Settings → Smart IP Blocker in Nova, check that your own address is in Excluded IPs, set the limits, switch Enable the Smart IP Blocker on and save.
⚙️ Configuration
Everything is set in the Aegis settings section:
| Setting | Default | Range |
|---|---|---|
| Enable the Smart IP Blocker | off | |
| Requests per minute | 100 |
1 – 10000 |
| Ban duration (hours) | 1 |
1 – 720 |
| Blocked page view | aegis-smart-ip-blocker::blocked |
an existing Blade view |
| Tracked IPs limit | 0 (no limit) |
0 – 10000 |
| Excluded IPs | your IP | up to 150 IPs or subnets |
| Excluded headers | none | up to 150 header / text pairs |
The counts and bans live in the cache store Aegis uses (AEGIS_CACHE_STORE, the default store otherwise), under keys starting with aegis.smart-ip-blocker.v1.. The array and null stores forget them after each request: the Aegis dashboard fails a check when the module runs on one.
A custom view receives $retryAfter (seconds) and $message.
🧰 Recovery commands
php artisan aegis:smart-ip-blocker:remove-ip 203.0.113.7 # lift the ban and reset the request count of an IP
php artisan aegis:smart-ip-blocker:disable # turn the module off, keeping its settings⚠️ Good to know
- Proxies and load balancers: the module counts
$request->ip(). Behind a load balancer, a reverse proxy or a CDN that is the proxy's address unless Laravel's trusted proxies are configured, and every visitor would share one count. Configure them first; if the form shows your proxy's address as your IP, do not exclude it, or nobody is ever counted. - Excluded headers can be spoofed: the client writes its own headers, so anyone who knows the rule can send
User-Agent: Googlebotand bypass the limit. Use them for convenience, and excluded IPs or subnets for anything you rely on. - Shared IPs: offices, mobile carriers and VPNs put many people behind one IP. Leave headroom in the limit, or exclude the subnets you know.
- Nova makes several requests per page: excluding the administrators' IPs keeps a busy session in Nova from being banned.
- The limit is per server only on the
filestore: use a shared store when the application runs on several servers. - A request is counted once even when it passes several middleware groups.
⬆️ Upgrading
See CHANGELOG.md.
🔒 Security
Please report a vulnerability privately, as described in SECURITY.md.
🛠️ Development
The toolchain runs in Docker, the host needs nothing but docker and make. Until the core is on Packagist, Composer installs it from ../nova-aegis (a path repository), so clone nova-aegis next to this repository; the container mounts the parent directory for that. No Nova license is needed: development and CI run on a test double of Nova in stubs/nova (installed as laravel/nova from a path repository, never shipped). Applications still install the real Nova.
make install # composer install
make code.fix # composer normalize, Rector, PHP CS Fixer
make code.check # composer validate/audit, php -l, PHP CS Fixer, Rector, PHPStan (level max)
make test.coverage # Pest with coverage (90 % minimum)
make ready # everything above
make test.nova # optional: the PHP suite on the real Novamake test.nova copies this repository and the core from ../nova-aegis (or AEGIS_CORE) to a temporary directory, installs the real laravel/nova from nova.laravel.com there and runs Pest; it needs your own Nova license in auth.json (gitignored), and NOVA_VERSION=5.9.3 make test.nova picks a release your license may download. The working copy, its vendor/ and composer.lock are left untouched.
GitHub Actions runs the same checks on every pull request. It checks the core's main out next to this repository and needs no Nova license; while the core repository is private, it needs an AEGIS_CORE_TOKEN secret (a token that can read it).