Skip to content

Instantly share code, notes, and snippets.

@GAS85
Last active February 25, 2024 07:18
  • Star 37 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save GAS85/957e0b1a4f30120225a7be09b173eb24 to your computer and use it in GitHub Desktop.
Harden Nextcloud 17+ with Fail2Ban, GUI and WebDAV - Ubuntu 20.04

Fail2ban and Nextcloud

Prerequsits

  • Ubuntu 20.04
  • nextcloud, fail2ban and e.g. iptables are installed

Note

Finally since 29 Juli 2020 this procedure is a part of an official Nextcloud Documentation. Please follow the link: https://docs.nextcloud.com/server/latest/admin_manual/installation/harden_server.html#setup-fail2ban

Short how-to harden your Nextcloud Server with Fail2Ban

Install fail2ban:

sudo apt update && sudo apt install fail2ban -y

Create the Nextcloud-filter:

sudo nano /etc/fail2ban/filter.d/nextcloud.conf

Paste the following lines, this will cover GUI Failed login and WebDAV:

[Definition]
_groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)
failregex = ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"

If you want to protect also from direct IP access or wrong Domain name access configure it as below (as per https://github.com/nextcloud/vm/blob/master/apps/fail2ban.sh)

[Definition]
_groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)
failregex = ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
            ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"

Create a new jail:

sudo nano /etc/fail2ban/jail.d/nextcloud.local

Paste the following rows:

[nextcloud]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
#Number of retrys before to ban
maxretry = 3
#time in seconds
bantime = 36000
findtime = 36000
#Log path, on Ubuntu usually is following
logpath = /var/www/nextcloud/data/nextcloud.log
#For Univention Appliances the logfile is in /var/lib/univention-appcenter/apps/nextcloud/data/nextcloud-data/nextcloud.log
#logpath = /var/lib/univention-appcenter/apps/nextcloud/data/nextcloud-data/nextcloud.log

Re-start the fail2ban-service:

sudo service fail2ban restart

and enjoy your Nextcloud-Server!


P.S.

Pattern For GUI:

#Nextcloud 17+
{"reqId":"BRHKHyh1lVFon5D33u4K","level":2,"time":"2020-01-13T12:34:00+00:00","remoteAddr":"10.11.12.13","user":"--","app":"no app in context","method":"POST","url":"\/index.php\/login","message":"Login failed: Tralololjlkl (Remote IP: 10.11.12.13)","userAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko\/20100101 Firefox\/72.0","version":"17.0.2.1"}
{"reqId":"y6OUpenieOevULRMaAFi","level":1,"time":"2020-06-10T13:19:06+00:00","remoteAddr":"10.11.12.13","user":"--","app":"core","method":"GET","url":"/","message":"Trusted domain error. \"10.11.12.13\" tried to access using \"Trololo.com\" as host.","userAgent":"curl/7.58.0","version":"18.0.6.0"}

#Nextcloud <= 16
{"reqId":"bFnTdevf7ZdCMQ5ddmNl","level":2,"time":"2019-04-03T21:49:30+00:00","remoteAddr":"10.11.12.13","user":"--","app":"core","method":"POST","url":"\/index.php\/login","message":"Login failed: 'Tralololjlkl' (Remote IP: '10.11.12.13')","userAgent":"Mozilla\/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko\/20100101 Firefox\/66.0","version":"15.0.5.3"}

For WebDav:

#Nextcloud 17+
{"reqId":"lqdbtb7y3pZSv8sGM0mD","level":2,"time":"2020-01-26T22:20:32+00:00","remoteAddr":"10.11.12.13","user":"--","app":"core","method":"PUT","url":"\/remote.php\/webdav\/files","message":"Login failed: 'webdavlogin' (Remote IP: '10.11.12.13')","userAgent":"curl\/7.58.0","version":"17.0.2.1"}

#Nextcloud <= 16
{"reqId":"Q4wX3I4LOUeuMV4wRK91","level":2,"time":"2019-04-03T22:14:11+00:00","remoteAddr":"10.11.12.13","user":"--","app":"core","method":"GET","url":"\/remote.php\/dav\/files","message":"Login failed: 'test' (Remote IP: '10.11.12.13')","userAgent":"Mozilla\/5.0 (X11; Ubuntu; Linux x86_64; rv:66.0) Gecko\/20100101 Firefox\/66.0","version":"15.0.5.3"}

Test WebUI and Webdav and Trusted domain error.

# fail2ban-regex /var/nextcloud/data/nextcloud.log /etc/fail2ban/filter.d/nextcloud.local -v --print-all-matched

Running tests
=============

Use   failregex filter file : nextcloud, basedir: /etc/fail2ban
Use      datepattern : ,?\s*"time"\s*:\s*"Year-Month-Day[T ]24hour:Minute:Second(Zone offset)?"
Use         log file : /var/nextcloud/data/nextcloud.log
Use         encoding : UTF-8


Results
=======

Failregex: 3 total
|-  #) [# of hits] regular expression
|   1) [2] ^\{(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*),?\s*"remoteAddr":"<HOST>"(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*),?\s*"message":"Login failed:
|      10.11.12.13  Wed Jun 10 13:07:43 2020
|      10.11.12.13  Wed Jun 10 13:07:50 2020
|   2) [1] ^\{(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*),?\s*"remoteAddr":"<HOST>"(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*),?\s*"message":"Trusted domain error.
|      10.11.12.13  Wed Jun 10 15:19:06 2020
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [1654] ,?\s*"time"\s*:\s*"Year-Month-Day[T ]24hour:Minute:Second(Zone offset)?"
`-

Lines: 1654 lines, 0 ignored, 3 matched, 1651 missed
[processed in 0.61 sec]

|- Matched line(s):
|  {"reqId":"2uzhhzlkkzXEp9yICWXE","level":2,"time":"2020-06-10T11:07:43+00:00","remoteAddr":"10.11.12.13","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: Gggggg (Remote IP: 10.11.12.13)","userAgent":"Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0","version":"18.0.6.0"}
|  {"reqId":"2QPK9SkSVBj6r2d9ojnk","level":2,"time":"2020-06-10T11:07:50+00:00","remoteAddr":"10.11.12.13","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: Gggggvvvvg (Remote IP: 10.11.12.13)","userAgent":"Mozilla/5.0 (Android 9; Mobile; rv:68.0) Gecko/68.0 Firefox/68.0","version":"18.0.6.0"}
|  {"reqId":"y6OUpenieOevULRMaAFi","level":1,"time":"2020-06-10T13:19:06+00:00","remoteAddr":"10.11.12.13","user":"--","app":"core","method":"GET","url":"/","message":"Trusted domain error. \"10.11.12.13\" tried to access using \"Trololo.com\" as host.","userAgent":"curl/7.58.0","version":"18.0.6.0"}
`-
Missed line(s): too many to print.  Use --print-all-missed to print all 1651 lines
@tiagofreire-pt
Copy link

For Univention Appliances the logfile is in: /var/lib/univention-appcenter/apps/nextcloud/data/nextcloud-data/nextcloud.log

@badgateway666
Copy link

The Pattern did change: There are no '' around the login-name and the ip anymore.

[Definition]
failregex=^{.Login failed: . (Remote IP: ).*}$
ignoreregex =

@GAS85
Copy link
Author

GAS85 commented Jan 13, 2020

Thanks!
Did it changed for Trusted Domain error also?

@stucksubstitute
Copy link

The pattern doesn't work. See i.e. here. Any suggestions?

@GAS85
Copy link
Author

GAS85 commented Jan 26, 2020

The pattern doesn't work. See i.e. here. Any suggestions?

Could you please try it? What you provide is independend of this solution. I will try to push correction into nextcloudpi repo --> nextcloud/nextcloudpi#1070

@datdomse
Copy link

datdomse commented Feb 27, 2020

The Pattern doesn't work with webdav.
I used this from here.

[Definition] failregex = ^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"}$ ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","app":"core".*","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)".*}$ ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: .* \(Remote IP: <HOST>\).*}$ ignoreregex =

Now it finally works with Nextcloud 18 stable.

@GAS85
Copy link
Author

GAS85 commented Feb 27, 2020

@datdomse you are right, I check source code of NC and it seems that it is producing different logs output depends on different issues. This is not the best practice how to implement it.
I added 2nd line to enable checks of WebDav in a config and also test. Thanks you for reporting.

@GAS85
Copy link
Author

GAS85 commented Apr 2, 2020

Thanks to Bernie_O we have one common line to catch it all now!
Check this for more info: https://help.nextcloud.com/t/fail2ban-native-support/602/26?u=gas85

@cfanatic
Copy link

cfanatic commented Apr 2, 2020

Came to say thanks. Great how-to.

@hansbaer443
Copy link

hansbaer443 commented Apr 16, 2020

First of all thank you very much for this how-to.
With my setup fail2ban didn't match trusted domain errors with the RE ^.*\"remoteAddr\":\"<HOST>\".*Trusted domain error.*\$
I'm no expert with REs but can it be, that there shouldn't be a backslash just before the new line ("$")?
I tried it with ^.*\"remoteAddr\":\"<HOST>\".*Trusted domain error.*$ and it seems to be working.

@GAS85
Copy link
Author

GAS85 commented Apr 16, 2020

You means it should looks like this? ^."remoteAddr":"<HOST>".Trusted domain error.$

@hansbaer443
Copy link

hansbaer443 commented Apr 16, 2020

I updated my earlyer post. Sorry it was unclear because I dindn't use the "insert code" function.

You means it should looks like this? ^."remoteAddr":"".Trusted domain error.$

Nearley, I think it should be ^.*\"remoteAddr\":\"<HOST>\".*Trusted domain error.*$

@GAS85
Copy link
Author

GAS85 commented Apr 16, 2020

Thanks! I did update the post.

@Hydranet
Copy link

I tried the regex used in the filter you mentioned here for nextcloud 18 but it didn't work for me. I found another one that did work for me, might be worth looking into.

@GAS85
Copy link
Author

GAS85 commented Jun 10, 2020

@Hydranet Could you please provide more information what is the issue?

Just tested it on a 18.0.6 and it works as expected. You can see that IP 10.10.10.10 is recognized by fail2ban, but due to whitelist it is not banned and Ignored.

2020-06-10 12:47:05,573 fail2ban.actions        [1726]: NOTICE  [apache-directIPAccess] Ban 256.257.258.259
2020-06-10 13:07:43,693 fail2ban.filter         [1726]: INFO    [nextcloud] Ignore 10.10.10.10 by ip
2020-06-10 13:07:50,002 fail2ban.filter         [1726]: INFO    [nextcloud] Ignore 10.10.10.10 by ip
2020-06-10 13:09:27,006 fail2ban.actions        [1726]: NOTICE  [apache-directIPAccess] Unban 257.258.259.260

@Hydranet
Copy link

Hydranet commented Jun 10, 2020

@GAS85

Nexcloud version: 18.0.6
Php version: 7.2

I tried attaching a text file so it would be easier to read, but for some reason github is refusing my txt file.

This is my log output when trying to use the nextcloud_fail2ban.md filter:
2020-06-10 13:21:16,905 fail2ban.filter         [9248]: WARNING Found a match for '{"reqId":"XuDCEyXVf4x1q0Gp@5g80QAAAIg","level":2,"time":"2020-06-10T11:21:16+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}' but no valid date/time found for '{"reqId":"XuDCEyXVf4x1q0Gp@5g80QAAAIg","level":2,"time":"2020-06-10T11:21:16+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}'. Please try setting a custom date pattern (see man page jail.conf(5)). If format is complex, please file a detailed issue on https://github.com/fail2ban/fail2ban/issues in order to get support for this format.
2020-06-10 13:22:16,206 fail2ban.filter         [9248]: WARNING Found a match for '{"reqId":"XuDCTiXVf4x1q0Gp@5g86QAAAI4","level":2,"time":"2020-06-10T11:22:16+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}' but no valid date/time found for '{"reqId":"XuDCTiXVf4x1q0Gp@5g86QAAAI4","level":2,"time":"2020-06-10T11:22:16+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}'. Please try setting a custom date pattern (see man page jail.conf(5)). If format is complex, please file a detailed issue on https://github.com/fail2ban/fail2ban/issues in order to get support for this format.
2020-06-10 13:23:19,521 fail2ban.filter         [9248]: WARNING Found a match for '{"reqId":"XuDCjiXVf4x1q0Gp@5g9BgAAAIM","level":2,"time":"2020-06-10T11:23:19+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}' but no valid date/time found for '{"reqId":"XuDCjiXVf4x1q0Gp@5g9BgAAAIM","level":2,"time":"2020-06-10T11:23:19+00:00","remoteAddr":"10.31.251.11","user":"--","app":"no app in context","method":"POST","url":"/index.php/login","message":"Login failed: testuser (Remote IP: 10.31.251.11)","userAgent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36","version":"18.0.6.0"}'. Please try setting a custom date pattern (see man page jail.conf(5)). If format is complex, please file a detailed issue on https://github.com/fail2ban/fail2ban/issues in order to get support for this format.

This my log output when using the nextcloudpie filter:
2020-06-10 13:25:46,850 fail2ban.filter         [9433]: INFO    [nextcloud] Found 10.31.251.11 - 2020-06-10 13:25:46
2020-06-10 13:27:04,187 fail2ban.filter         [9433]: INFO    [nextcloud] Found 10.31.251.11 - 2020-06-10 13:27:04
2020-06-10 13:27:58,284 fail2ban.filter         [9433]: INFO    [nextcloud] Found 10.31.251.11 - 2020-06-10 13:27:58
2020-06-10 13:27:59,006 fail2ban.actions        [9433]: NOTICE  [nextcloud] Ban 10.31.251.11
2020-06-10 13:29:59,267 fail2ban.actions        [9433]: NOTICE  [nextcloud] Unban 10.31.251.11

@GAS85
Copy link
Author

GAS85 commented Jun 10, 2020

Have not Idea why it is not causing any warning on my system, but here is description of this issue with a good explanation fail2ban/fail2ban#2485 (comment)

So I added new rules and also updated test section. Thanks, @Hydranet for notice it.

@Hydranet
Copy link

Hydranet commented Nov 20, 2020

Just an update, I recently came across nextcloud hardening documentation which I never knew existed until just now. It even has a section on fail2ban and what filter to use which is the exact same filter I found somewhere else and posted here in an earlier comment of mine.

@GAS85
Copy link
Author

GAS85 commented Nov 24, 2020

@Hydranet, thanks, finally it is there, it took only 2 years 😄. I add a note at the beginning .

@stucksubstitute
Copy link

Just tested it on my Nextcloud version 19.0.4.2 - works fine! Thanks.

@sanfx
Copy link

sanfx commented Oct 11, 2021

Has anyone set this up for nextcloud 21 ?

@GAS85
Copy link
Author

GAS85 commented Oct 12, 2021

Works for me fine on 21. It is even part of the official documentation.

@cloudengineer89
Copy link

guys, please help me with my settings fail2ban for NC.
This is how my nextcloud.conf looks like:
[Definition] failregex = ^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)","level":2,"time":".*"}$ ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","app":"core".*","message":"Login failed: '.*' \(Remote IP: '<HOST>'\)".*}$ ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: .* \(Remote IP: <HOST>\).*}$
and this is how my nextcloud.local looks like:
[nextcloud]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
maxretry = 3
bantime = 20
findtime = 10
logpath = var/log/apache2/nextcloud-access.log

So when I try to test fail login attempt on web page in NC i don't see any logging text in my /var/log/fail2ban.log
Were can I miss something?

@GAS85
Copy link
Author

GAS85 commented Oct 24, 2022

Hey, your nextlcoud.conf for Fail2Ban looks outdated. It was valid for versions below 17, or something. Please have a look above in a document, or linked nextcloud admin doc.
Also few Remarks:

  1. bantime and findtime is in a seconds, so set them to something like 10, or 20 make no sense. You need to put them to bigger values, e.g. as provided here.
  2. To test, please use command from the document above, even before to enable this configuration in fail2ban:
fail2ban-regex /var/nextcloud/data/nextcloud.log /etc/fail2ban/filter.d/nextcloud.local -v --print-all-matched

@cloudengineer89
Copy link

Hey, your nextlcoud.conf for Fail2Ban looks outdated. It was valid for versions below 17, or something. Please have a look above in a document, or linked nextcloud admin doc. Also few Remarks:

  1. bantime and findtime is in a seconds, so set them to something like 10, or 20 make no sense. You need to put them to bigger values, e.g. as provided here.
  2. To test, please use command from the document above, even before to enable this configuration in fail2ban:
fail2ban-regex /var/nextcloud/data/nextcloud.log /etc/fail2ban/filter.d/nextcloud.local -v --print-all-matched

Since I don't have a file nextcloud.log in /var/nextcloud/data I change the path in the comment where I see my login errors which I did on purpose.
here is my console output:

fail2ban-regex /var/log/apache2/nextcloud-access.log /etc/fail2ban/filter.d/nextcloud.local -v --print-all-matched

Running tests
=============

Use   failregex line : /etc/fail2ban/filter.d/nextcloud.local
ERROR: No failure-id group in '/etc/fail2ban/filter.d/nextcloud.local'

@GAS85
Copy link
Author

GAS85 commented Oct 25, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment