Fail2Ban Setup with NGINX and Cloudflare tunnels


Recommended Posts

This thread is designed to help those of you who want to setup fail2ban docker container on UnRaid.

I have so far setup fail2ban with jails for Vaultwarden and Jellyfin.

 

My setup:

Unraid OS 6.9.2

All containers running on a custom network called 'proxynet'

Nginx Proxy Manager from repository jlesage/nginx-proxy-manager

 

Docker image : https://hub.docker.com/r/crazymax/fail2ban

Official fail2ban project page http://www.fail2ban.org/wiki/index.php/Main_Page

My Respository with instructions for this setup: https://github.com/FrankM77/docker-fail2ban

 

 

Donate: https://paypal.me/built2

 

 

 

 

 

Edited by Built2Succeed
grammar
  • Like 1
  • Thanks 3
Link to comment

I am not sure what I did wrong. The difference between yours and mine is just cloudflare. I do not have subdomains proxied via cloudflare. I am trying to set it up for nginx. the logs displays ip is banned (I am using vpn to test the fail2ban). But I can still access the services. I asked in the reddit to see if I can get quick response. Here is the link to the detail issue and configuration I am using,

fail2ban detecting IP but not blocking : fail2ban (reddit.com)

 

I saw you were using different config for the action. So I gave second try with exact configuration like you and still stuck with the IP not being actually banned. Any idea?

 

Link to comment

Are you using cloudflare to host your site?  I'm certainly no expert and hopefully i don't steer you in the wrong direction.  But it seems to me that your filter and jail are setup correctly since the fail2ban log you show seems to be showing a ban.  Did you go into the container console and type 'fail2ban-client status Nginx' ?  Does it show as banned?  Also I would check your action setup in action.d folder.  I have two files in my action.d folder : iptables-common.local and cloudflare-apiv4.conf.

 

My iptables-common.local file looks like this:

# /mnt/user/appdata/fail2ban/action.d/iptables-common.local

[Init]
blocktype = DROP
[Init?family=inet6]
blocktype = DROP
 

My cloudflare-apiv4.conf file looks like this:

#

# Author: Gilbn from https://technicalramblings.com

# Adapted Source: https://github.com/fail2ban/fail2ban/blob/master/config/action.d/cloudflare.conf and https://guides.wp-bullet.com/integrate-fail2ban-cloudflare-api-v4-guide/

#

# To get your Cloudflare API key: https://dash.cloudflare.com/profile use the Global API Key

#

 

[Definition]

 

# Option:  actionstart

# Notes.:  command executed once at the start of Fail2Ban.

# Values:  CMD

#

actionstart =

 

# Option:  actionstop

# Notes.:  command executed once at the end of Fail2Ban

# Values:  CMD

#

actionstop =

 

# Option:  actioncheck

# Notes.:  command executed once before each actionban command

# Values:  CMD

#

actioncheck =

 

# Option:  actionban

# Notes.:  command executed when banning an IP. Take care that the

#          command is executed with Fail2Ban user rights.

# Tags:      IP address

#            number of failures

#            unix timestamp of the ban time

# Values:  CMD

 

actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" \

            -H "X-Auth-Email: <cfuser>" \

            -H "X-Auth-Key: <cftoken>" \

            -H "Content-Type: application/json" \

            --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"Fail2ban <name>"}'

 

# Option:  actionunban

# Notes.:  command executed when unbanning an IP. Take care that the

#          command is executed with Fail2Ban user rights.

# Tags:      IP address

#            number of failures

#            unix timestamp of the ban time

# Values:  CMD

#

 

actionunban = curl -s -X DELETE "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$( \

              curl -s -X GET "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1&match=all" \

             -H "X-Auth-Email: <cfuser>" \

             -H "X-Auth-Key: <cftoken>" \

             -H "Content-Type: application/json" | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'id'\042/){print $(i+1);}}}' | tr -d '"' | sed -e 's/^[ \t]*//' | head -n 1)" \

             -H "X-Auth-Email: <cfuser>" \

             -H "X-Auth-Key: <cftoken>" \

             -H "Content-Type: application/json"

 

[Init]

 

# Name of the jail in your jail.local file. default = [jail name]

name = default

 

# Option: cfuser

# Notes.: Replaces <cfuser> in actionban and actionunban with cfuser value below

# Values: Your CloudFlare user account

 

cfuser = your_cloudflare_username

 

# Option: cftoken (Global API Key)

# Notes.: Replaces <cftoken> in actionban and actionunban with cftoken value below

# Values: Your CloudFlare API key

cftoken = your_Cloudflare_API_token

 

 

Link to comment

It depends.  You'll need to consult the documentation for the container.  For instance I have Vaultwarden (the unofficial bitwarden) and it logs to STD OUT by default. Which I believe means the screen. So Vaultwarden does not create a logfile by default.  I had to add an environmental variable to get it to log to a file, per the documentation.  Which container are you running that you are trying to find the logfile?

Link to comment
On 1/28/2022 at 9:32 AM, Built2Succeed said:

Are you using cloudflare to host your site?  I'm certainly no expert and hopefully i don't steer you in the wrong direction.  But it seems to me that your filter and jail are setup correctly since the fail2ban log you show seems to be showing a ban.  Did you go into the container console and type 'fail2ban-client status Nginx' ?  Does it show as banned?  Also I would check your action setup in action.d folder.  I have two files in my action.d folder : iptables-common.local and cloudflare-apiv4.conf.

 

My iptables-common.local file looks like this:

# /mnt/user/appdata/fail2ban/action.d/iptables-common.local

[Init]
blocktype = DROP
[Init?family=inet6]
blocktype = DROP
 

My cloudflare-apiv4.conf file looks like this:

#

# Author: Gilbn from https://technicalramblings.com

# Adapted Source: https://github.com/fail2ban/fail2ban/blob/master/config/action.d/cloudflare.conf and https://guides.wp-bullet.com/integrate-fail2ban-cloudflare-api-v4-guide/

#

# To get your Cloudflare API key: https://dash.cloudflare.com/profile use the Global API Key

#

 

[Definition]

 

# Option:  actionstart

# Notes.:  command executed once at the start of Fail2Ban.

# Values:  CMD

#

actionstart =

 

# Option:  actionstop

# Notes.:  command executed once at the end of Fail2Ban

# Values:  CMD

#

actionstop =

 

# Option:  actioncheck

# Notes.:  command executed once before each actionban command

# Values:  CMD

#

actioncheck =

 

# Option:  actionban

# Notes.:  command executed when banning an IP. Take care that the

#          command is executed with Fail2Ban user rights.

# Tags:      IP address

#            number of failures

#            unix timestamp of the ban time

# Values:  CMD

 

actionban = curl -s -X POST "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules" \

            -H "X-Auth-Email: <cfuser>" \

            -H "X-Auth-Key: <cftoken>" \

            -H "Content-Type: application/json" \

            --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"Fail2ban <name>"}'

 

# Option:  actionunban

# Notes.:  command executed when unbanning an IP. Take care that the

#          command is executed with Fail2Ban user rights.

# Tags:      IP address

#            number of failures

#            unix timestamp of the ban time

# Values:  CMD

#

 

actionunban = curl -s -X DELETE "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules/$( \

              curl -s -X GET "https://api.cloudflare.com/client/v4/user/firewall/access_rules/rules?mode=block&configuration_target=ip&configuration_value=<ip>&page=1&per_page=1&match=all" \

             -H "X-Auth-Email: <cfuser>" \

             -H "X-Auth-Key: <cftoken>" \

             -H "Content-Type: application/json" | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'id'\042/){print $(i+1);}}}' | tr -d '"' | sed -e 's/^[ \t]*//' | head -n 1)" \

             -H "X-Auth-Email: <cfuser>" \

             -H "X-Auth-Key: <cftoken>" \

             -H "Content-Type: application/json"

 

[Init]

 

# Name of the jail in your jail.local file. default = [jail name]

name = default

 

# Option: cfuser

# Notes.: Replaces <cfuser> in actionban and actionunban with cfuser value below

# Values: Your CloudFlare user account

 

cfuser = your_cloudflare_username

 

# Option: cftoken (Global API Key)

# Notes.: Replaces <cftoken> in actionban and actionunban with cftoken value below

# Values: Your CloudFlare API key

cftoken = your_Cloudflare_API_token

 

 

My domain is hosted at cloudflare, and not using proxy at the moment ( had issue with nextcloud, that auto upload was not working properly for larger files).

In my iptables, I see all the IPs are banned as well. I have very similar configuration as yours besides the cloudflare part. 😞

 

Link to comment
14 hours ago, 062bel313 said:

My domain is hosted at cloudflare, and not using proxy at the moment ( had issue with nextcloud, that auto upload was not working properly for larger files).

In my iptables, I see all the IPs are banned as well. I have very similar configuration as yours besides the cloudflare part. 😞

 

@062bel313 Just making sure you know that when you uploading via Cloudflare you will be limited to 100MB, however if you upload locally you can upload as much as you like. So rather than paying cloudflare I just gotten used to doing any major uploads at home on my local network bypassing the CF protected domain. I hope you get fail2ban to work but that is my 2 cents on uploading via cloudflare.

 

Also if you dont mind me asking why did you set bantime to "-1" does that set it for forever, dont ban at all, or is it some testing puspose?

Edited by Kevin Marchese
Link to comment
1 hour ago, Kevin Marchese said:

@062bel313 Just making sure you know that when you uploading via Cloudflare you will be limited to 100MB, however if you upload locally you can upload as much as you like. So rather than paying cloudflare I just gotten used to doing any major uploads at home on my local network bypassing the CF protected domain. I hope you get fail2ban to work but that is my 2 cents on uploading via cloudflare.

 

Also if you dont mind me asking why did you set bantime to "-1" does that set it for forever, dont ban at all, or is it some testing puspose?

I have remote users my family members and they always had issues because of cloudflare, i will look into it again.

yes, bantime -1 will block it forever.

Link to comment
On 1/30/2022 at 7:19 PM, Built2Succeed said:

I was wondering.  Did you resolve this issue?  If you do can you post the solution here.  Thank you.

Nope couldn’t figure out why it was not blocking though i have all the ip blocked in the iptables. Decided to not use it after lots of tries and frustration.

Link to comment

Sorry to hear.  It took me many hours of jiggering.  My setup is with cloudflare using argo tunnel, that way I don't have to mess with port forwarding on my router. If you are using unRAID and port forwarding on your router then your solution will be different than mine.  I found this article that might be of interest to you. https://docs.docker.com/network/iptables/

 

Hope that helps you figure it out.  

Link to comment
  • 3 weeks later...

I would like to thank you for your hard work. This is a fantastic option to help secure self-hosted services. Could you expand your instructions? Example, I run Valtwarden as well. As you mentioned it does not log to file. I cant figure out how to add the required unraid docker environmental variable. How do I clone your valtwarden jail.d and filter.d example for other hosts?  NPM keeps all logs as numbers relating to proxy hosts can I use these logs or do I have to add path to individual dockers logs? Can the same regex be used for all all jails? I admit, I don't understand regex at all. I did see a different filter.d example (listed below). Do I need both? Are ports required as everything is HTTPS? Thanks in advance.

 

[INCLUDES]

[Definition]

failregex = ^<HOST>.+" (4\d\d|3\d\d) (\d\d\d|\d) .+$
            ^.+ 4\d\d \d\d\d - .+ \[Client <HOST>\] \[Length .+\] ".+" .+$

  • Thanks 1
Link to comment
  • 1 month later...

NPM does keep log files as you mentiond.  I added a path to my vaultwarden log that i created. You need to add a path to your vaultwarden logfile.  The regex is specially formatted for the logfile format that vaultwarden uses.  So each regex may be slightly different depending on the format of the specific logfile.  For more information/documentation on the formatting of the regex file see https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters

 

Keep in mind how fail2ban works.  Basically three things are going on.

1. Jail - this declares each jail

2. Filter - the detection, this detects break-in attempts by matching patterns within your logfile

3. Action- this, as the name implies, tells fail2ban what actions to take when the filter criteria are met

 

If you go here https://www.fail2ban.org/wiki/index.php/MANUAL_0_8#Filters and look under 'General Settings' you will find a more expansive explanation.

 

 

Link to comment
  • 4 weeks later...

I'm having the same issue as mentioned here above.  This install of fail2ban does not seem to work.

Ok So I have 2 instances of fail2ban.  One is this docker here, the other is the swag docker.  I have done identical jails and setups in both dockers. 

Here I have banned myself in the jellyfin docker.  Take a look at what happens when I run the command iptables -nvL in both containers
 

fail2ban.PNG

 

It says Reject on both, but it looks slightly different on the left in Swags, have a return line.

I must note that swag is also running my reverse proxy, where as this standalone fail2ban container is not.  I do however have both containers running on my same custom network "proxynet".  Swags fail2ban works but for some reason this standalone fail2ban does not.

Edited by 007craft
Link to comment
  • 2 weeks later...

I am sure I must be missing something, but so far I have set up according to your instructions and f2b is reporting that my test ip gets banned. I can however still access the site.

 

Looking a bit further I can see that f2b docker host is banning the IP within the f2b container, and not in the Unraid iptables. Wouldn't this indicate that the ip never would get blocked, as the actual traffic does not hit the f2b container? 

 

Or - as a I'm sure - I've missed something crucial. :)

 

 

Edited by Ulf Thomas Johansen
Link to comment
2 minutes ago, Ulf Thomas Johansen said:

I am sure I must be missing something, but so far I have set up according to your instructions and f2b is reporting that my test ip gets banned. I can however still access the site.

 

Looking a bit further I can see that f2b docker host is banning the IP within the f2b container, and not in the Unraid iptables. Wouldn't this indicate that the ip never would get blocked, as the actual traffic does not hit the f2b container? 

 

Or - as a I'm sure - I've missed something crucial. :)

 

 

This fact never stop amazing me: Literarily 15 seconds after posting this, a thought hit me and I went into the container template and changed from bridge to host! Eureka! How come the answer seem to arrive just after "you've given up". :D

 

Link to comment

I can do everything except mod the IP tables to prevent access.  The filter identifies the failed access attempt and put in the jail but now action is taken. 

 

The action example on docker website doesn't seem to jive with the jail example.

 

I'm very green.  I'll revisit in a few weeks.

 

 

EDIT:  Figured it out.  I had to load the container as HOST and made sure the banaction line in the jail.d match action.d conf file name.

 

 

Edited by VideoVibrations
optimism
Link to comment
  • 1 month later...
On 4/13/2022 at 2:32 AM, 007craft said:

I'm having the same issue as mentioned here above.  This install of fail2ban does not seem to work.

Ok So I have 2 instances of fail2ban.  One is this docker here, the other is the swag docker.  I have done identical jails and setups in both dockers. 

Here I have banned myself in the jellyfin docker.  Take a look at what happens when I run the command iptables -nvL in both containers
 

fail2ban.PNG

 

It says Reject on both, but it looks slightly different on the left in Swags, have a return line.

I must note that swag is also running my reverse proxy, where as this standalone fail2ban container is not.  I do however have both containers running on my same custom network "proxynet".  Swags fail2ban works but for some reason this standalone fail2ban does not.

Exactly right.  This fail2ban does not work with NPM to ban.  Instead it sets firewall rules directly on cloudflare

Link to comment
22 hours ago, Dantheman said:

Quick question....

Does anybody know how i can get email notifications working on a ban action?

 

Got everything working except for the notification through email...

 

Anyone have some directions to set it up...?

Not sure because I haven't set that up myself.  As you may know, some emails use app passwords for security reasons. (gmail for instance).  Hope that helps

Link to comment
  • 3 weeks later...

Hello, i am trying to understand how to configure SSMTP_HOST with this container.

 

I tried adding "--environment=SSMTP_HOST=blabla.com" as an extra parameter when starting the container but it says unknown parameter.

But watching this video, you can see the enviorment parameter, as well as the net_admin, net_raw which are included extra parameters with this container:

 

image.png.8551e6fd7bbd81570b31c0e036bc427b.png

 

Since --cap_add=net_admin is a parameter, i asumed that --enviroment would also be but it isn't

so how exactly do you configure the ssmtp stuff with this container?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.