How to block all countries except for one in Caddyfile or (preferred) use fail2ban?

1. Caddy version (caddy version):

Caddy V2.1.1

2. How I run Caddy:

I run Caddy with the Caddyfile in /etc/caddy and enabling systemd service

a. System environment:

Caddy is installed on a raspberry pi 4 running raspbian buster. Kernel 4.19.118-v7l+ Systemd version 241

b. Command:

sudo systemctl enable caddy.service

c. Service/unit/compose file:


ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile


d. My complete Caddyfile or JSON config:


log {
        output file /media/ramdisk/acces.log {
                roll_size 50MiB
                roll_keep 5
                roll_keep_for 48h

ipfilter / {
        rule allow
        database /home/pi/ipfilter/testdata/Geolite.mmdb
        country DE

3. The problem I’m having:

I use Caddy as a reverse proxy for my Jellyfin media server.

So I want to block repeat offenders trying to access port 443 and 80 using Fail2ban or only allow IP addresses from a certain country. Problem with fail2ban is that there is no Fail2ban module and I don’t have a clue how what the failregex should be.
Using the above Caddyfile gives me an error. The Caddyfile without the ipfilter part runs good.

4. Error messages and/or full log output:

[I] [pi@raspberrypi ~ ]$ sudo systemctl status caddy.service
● caddy.service - Caddy
Loaded: loaded (/lib/systemd/system/caddy.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Thu 2020-07-09 09:31:23 CEST; 23s ago
Docs: Welcome — Caddy Documentation
Process: 6490 ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile (code=exited, status=1/FAILURE)
Main PID: 6490 (code=exited, status=1/FAILURE)

Jul 09 09:31:23 raspberrypi caddy[6490]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Jul 09 09:31:23 raspberrypi caddy[6490]: HOME=/var/lib/caddy
Jul 09 09:31:23 raspberrypi caddy[6490]: LOGNAME=caddy
Jul 09 09:31:23 raspberrypi caddy[6490]: USER=caddy
Jul 09 09:31:23 raspberrypi caddy[6490]: INVOCATION_ID=fc08e61e021441e382590d299acc5886
Jul 09 09:31:23 raspberrypi caddy[6490]: JOURNAL_STREAM=8:39470
Jul 09 09:31:23 raspberrypi caddy[6490]: {“level”:“info”,“ts”:1594279883.6053421,“msg”:“using provided configuration”,“config_file”:"/etc/caddy/Caddyfile",“config_adapter”:""}
Jul 09 09:31:23 raspberrypi caddy[6490]: run: adapting config using caddyfile: /etc/caddy/Caddyfile:13: unrecognized directive: ipfilter
Jul 09 09:31:23 raspberrypi systemd[1]: caddy.service: Main process exited, code=exited, status=1/FAILURE
Jul 09 09:31:23 raspberrypi systemd[1]: caddy.service: Failed with result ‘exit-code’.

5. What I already tried:

I tried the above Caddyfile but the directive ipfilter isn’t recognized so I’m guessing this filter is appropriate for Caddy V1? I found that syntax here: ipfilter/ at master · pyed/ipfilter · GitHub
I did clone GitHub - pyed/ipfilter: ipfilter is a middleware for Caddy that blocks or allows requests based on the client's IP

I’ve looked through the Caddy V2 documentation all I can find is blocking specific IP’s or IP ranges. I did found something related to GeoIP blocking here but I don’t understand how to use it to block all countries but one.


So correct me if I’m wrong but do I have to do a custom build of Caddy using xcaddy?
something like: xcaddy build \ --with GitHub - pyed/ipfilter: ipfilter is a middleware for Caddy that blocks or allows requests based on the client's IP

Would the ipfilter plugin work then??

6. Links to relevant resources:

The ipfilter plugin only works with Caddy v1. You can find the list of plugins supported for Caddy v2 below; I don’t think there’s an equivalent plugin for v2 yet. Caddy v2 does have remote_ip request matching which you could use to block or allow specific IP ranges if you know what they are, without using an ipfilter module.

I don’t know enough about fail2ban to recommend anything there, but my understanding is that it reads log files for failed requests to trigger blocking IPs.

Ultimately I think the best thing to do is to put authentication in front of your site instead of trying to block by IP, then you can use fail2ban to block anything that triggers too many authentication failures if you find you’re getting too many of them.

1 Like

Thank you for your reply! I’m a complete noob who developed an interest in linux 5 months ago so I’m kinda finding my way.

I have a Jellyfin server, a mediaserver like plex, and in order to connect to it from outside my network I opened port 443 and pointed it to my server. I use Caddy to setup a reverse proxy and to handle the tls certificates. In order to connect to the Jellyfinserver one first has to login with the right credentials. Is this secure?

Reason I ask is about 50 times a day there are, apparently bots, that try to connect through the opened port in my firewall which is making me a worried. I can see this in my Caddy access.log file.

I would love to setup Fail2ban but I can’t find the correct regex filter cause there isn’t one already configured in Fail2ban for Caddy like there is for SSH and NGINX etc.

Best way to be! Learning by doing :thumbsup:

Security isn’t boolean, unfortunately, although I’ll offer my opinion here: the setup you have sounds good! Sufficiently secure for the kind of services you’ve said you’re running, even before you factor in fail2ban, probably.

I don’t think fail2ban supports structured logs, which are Caddy’s default output. This isn’t really a problem though because Caddy v2 supports access logging in Common Log Format (like Apache and NGINX do), it just needs to be configured to do so.

You can modify your existing log directive to change the format. You want single_field:

log (Caddyfile directive) — Caddy Documentation

And the field you want is common_log. There’s an example at the bottom of the page you can probably just copy right in.

Once Caddy’s spitting out CLF access logs, you can configure fail2ban exactly how you would for Apache or NGINX, for which there are about a gazillion guides out there.


I changed my Caddyfile to

log {   format single_field common_log
        output file /media/ramdisk/access.log {
                roll_size 50MiB
                roll_keep 5
                roll_keep_for 48h

The access.log file format did become much more readable but I get the following error in my caddy.service status

raspberrypi caddy[2546]: {"level":"error","ts":1594373493.4464798,"logger":"http.handlers.reverse_proxy","msg":"aborting with incomplete response","error":"http2: stream closed"}

Everything seems to be working correctly as far as I can tell.
Is this errror a concern?

This topic was automatically closed after 30 days. New replies are no longer allowed.