A system administrator managing a modest VPS hosting static sites behind Caddy decided to stop manually watching logs filled with brute-force attempts against SSH and automated scans for common sensitive files.
The server regularly received requests for wp-admin, .env, phpmyadmin, and backup configuration files even though no WordPress instance was present. At the same time, systemd-journal recorded repeated OpenSSH messages such as “Invalid user admin” and “Invalid user oracle”.
Although Fail2ban is widely used, the administrator found its configuration of jails, filters, and actions too cumbersome for web-related blocking and preferred a single binary with minimal dependencies.
How the custom solution works
The resulting tool, called Bouncer, first performs a controlled crawl of the site using a breadth-first queue limited by depth and total page count. It extracts internal links from HTML, records all discovered paths, and allows additional routes such as API endpoints to be added manually in the configuration.
When new entries appear in the Caddy access log showing a 404 response, the path is checked against the discovered list. Five unknown paths within a sliding time window trigger addition of the source IP to an nftables set that drops traffic before it reaches listening ports. Direct requests to files such as /.env result in immediate blocking without waiting for the threshold.
For SSH, the program parses journal entries and treats an “Invalid user” message as an immediate ban because legitimate users do not attempt non-existent accounts. Failed password attempts for existing users are counted within a time window instead.
- The tool never replays old log files on startup, processing only new lines from the moment it begins.
- Each site maintains its own path list and log source, allowing multiple Caddy virtual hosts to be protected by one process.
- An installation script places the binary, generates a systemd unit, populates a whitelist with the administrator’s current IP, and inserts the required nftables drop rule in the correct chain order.
After switching from a previous prototype named CaddyBan, the administrator reported significantly cleaner logs and fewer manual reviews of connection attempts.


