Securing a Caddy Server with a Custom Fail2Ban Filter

Hey everyone,

I was looking through my server logs recently and noticed a lot of the usual background noise of the internet: bots scanning for .env files, probing for WordPress admin panels, and other common attack vectors. Since I use Caddy as my web server and reverse proxy, I decided it was time to set up Fail2Ban to automatically block these bad actors.


Creating a Custom Fail2Ban Filter for Caddy

The first step was to create a new filter specifically for Caddy's JSON-formatted logs. This filter uses a few regular expressions to catch the most common offenders.

Here's the filter, which I saved as /etc/fail2ban/filter.d/caddy-json.conf:

[Definition]
# Matches the Unix epoch timestamp in Caddy's JSON logs.
datepattern = LongEpoch

# Multiple failregex lines are treated as OR.
failregex =
    # Matches common authentication failures.
    ^.*"remote_ip":\s*"<HOST>".*"status":\s*(401|403).*$

    # Matches scanners probing for common vulnerabilities/files (resulting in 404).
    ^.*"remote_ip":\s*"<HOST>".*"uri":\s*".*(?:/\.git|/\.env|/wp-admin|/wp-login\.php|/xmlrpc\.php).*".*"status":\s*404.*$

    # Matches common malicious user agents.
    ^.*"remote_ip":\s*"<HOST>".*"User-Agent":\s*\[\s*"(?i:sqlmap|nmap|nikto|wpscan|masscan)".*].*$

ignoreregex =

This filter looks for three main things:

  1. HTTP 401 (Unauthorized) or 403 (Forbidden) responses.
  2. HTTP 404 (Not Found) errors for common exploit paths like /wp-admin or .env.
  3. Requests from known malicious user agents like sqlmap or nmap.

Enabling the New Jail

With the filter in place, the next step was to enable a new "jail" to use it. I added the following to my /etc/fail2ban/jail.local file:

[caddy-json]
enabled   = true
filter    = caddy-json
port      = http,https
logpath   = /var/log/caddy/*.log

This configuration tells Fail2Ban to enable the caddy-json jail, use our new filter, monitor all Caddy log files, and block offenders on the http and https ports. My default settings will ban an IP for one hour after three offenses, with an exponential backoff for repeat offenders.


Testing the Filter

Before letting it run wild, I used the fail2ban-regex utility to test the filter against my actual Caddy access log. As you can see, it found plenty of malicious requests to block.

caddy_regex_test.png

My previous attempts at this were sometimes a bit too aggressive, but based on these test results, I'm hopeful this setup will significantly slow down the automated scanning without blocking legitimate users.

As always,
Michael Garcia a.k.a. TheCrazyGM

0.13804099 BEE
2 comments

Harden the shell GM!

!PAKX
!PIMP
!PIZZA

0.00022319 BEE

View or trade PAKX tokens.

@ecoinstant, PAKX has voted the post by @thecrazygm. (1/2 calls)



Use !PAKX command if you hold enough balance to call for a @pakx vote on worthy posts! More details available on PAKX Blog.

0.00021871 BEE

PIZZA!

$PIZZA slices delivered:
@ecoinstant(1/20) tipped @thecrazygm

Come get MOONed!

0.00021433 BEE