I liked Nginx Proxy Manager, but I wanted a WAF in the same place
If you self-host anything, there is a good chance it sits behind Nginx Proxy Manager (NPM). Add a domain, pick a container, click Let's Encrypt, done. I used it for exactly that reason. Then you open the logs of anythin

If you self-host anything, there is a good chance it sits behind Nginx Proxy Manager (NPM). Add a domain, pick a container, click Let's Encrypt, done. I used it for exactly that reason.
Then you open the logs of anything exposed to the internet and see this, every day:
GET /.env
GET /wp-config.php
GET /../../etc/passwd
GET /?id=1 UNION SELECT password FROM users
You don't run WordPress and you don't have a .env in your web root, but the scanners don't care. At some point I wanted three things: see what is actually hitting my services, block the obvious junk, and keep some control when traffic spikes.
The usual answer
The common setups are:
- NPM + CrowdSec (or fail2ban) to ban bad IPs from the logs.
- A WAF container in front of or behind NPM: SafeLine, BunkerWeb, ModSecurityβ¦
All good tools. But you end up with more containers, more config screens, and when a request is blocked you jump between three places to find out why. I wanted the proxy and the protection in one simple console, the way NPM feels. So I built Corvus.
What Corvus is
A self-hosted gateway that works like NPM and adds a layer that watches, blocks and controls traffic. It is not an NPM fork; it is written from scratch on OpenResty, Go and React. Apache-2.0, no paid tier.
- Proxy hosts, Let's Encrypt with auto-renewal (DNS challenge for wildcards), redirections, TCP/UDP streams
- Known attack patterns (SQL injection, path traversal, scannersβ¦) blocked as soon as you add a host
- Automatic bans for IPs that keep trying
- Security rules on IP, country, path, header and User-Agent, a browser challenge, and an automatic "under attack" mode
- An access queue (waiting room) that lets people in up to a capacity during a rush
- A live traffic monitor and alerts to Slack, Discord, Teams, Telegram and others
- Import from NPM, and every config change is versioned with rollback
Install
services:
corvus:
image: ghcr.io/corvus-gateway/gateway:latest
restart: unless-stopped
ports:
- '80:80'
- '443:443'
- '9443:9443'
volumes:
- ./data:/data
docker compose up -d
docker compose logs corvus | grep setup_token
There is no default password. The first start prints a one-time setup token so that only the server owner can create the admin account. Open https://<server>:9443 (self-signed certificate at first, so expect a browser warning), enter the token and create your account. If you'd rather pick the token yourself, set CORVUS_SETUP_TOKEN (12+ characters).
On TrueNAS SCALE, Corvus is also in the Community apps catalog: search for "Corvus" under Apps.
What you get without writing a single rule
Go to Proxy hosts β Add, enter the domain and the target (say shop-web:80), choose Let's Encrypt, save. Same as NPM so far.
The difference is that protection is already on:
-
Exploit path blocking is enabled by default. All four requests from the top of this post are stopped before they reach your app. I checked them against a test stack:
403,403,400,403, while normal requests return200. - Automatic bans are on too: an IP with more than 20 detections in 10 minutes is banned for 15 minutes, and the ban doubles on every repeat (up to 7 days by default).
- Every request lands in the traffic monitor, so you can see per host which paths were hit and what was blocked.
When you want more
All optional:
-
Security rules, e.g. "
/adminonly from my office IP" or "block these countries". Tip: start a rule in Log mode, see what it would catch, then switch to Block. - Browser challenge: a short proof-of-work in the browser, no third-party service. Useful when bots pile in.
- Under attack mode: when requests per second or the block ratio pass a threshold, every visitor gets the challenge automatically.
- Access queue: for a launch or a limited drop, let in only as many people as your server can handle and queue the rest in order.
Coming from NPM
Import from NPM brings over proxy hosts, redirections, streams, certificates and access lists. It only reads NPM's files and database, so if you don't like Corvus you can simply go back.
Honest limitations
- It is young (1.1.x). Bugs reported as issues get fixed quickly.
- Auto-bans work per IP, so people behind the same company or carrier NAT can be banned together. Put networks you know into the exception list.
- No single gateway can stop a DDoS that saturates your uplink. For that, put a CDN such as Cloudflare in front; Corvus still sees the real visitor IPs behind it.
Feedback welcome
I built Corvus with heavy help from an AI coding assistant; the design, verification and testing I do myself, change by change. If you try it, I'd love to hear what was annoying during install or use, and what you'd need.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.

