After running Nextcloud for quite some time, I’d like to summarize some tweaks, optimizations and security fixes I added to my original setup. Some of them are straight from the documentation. While I was the only user, some optimizations were not really needed. Many hints applied are available in the Nextcloud documentation . The tuning page provides a lot of information how to optimize your installation and is worth reading. Some things like redis based file locking should be configured with the first setup of the server.

Database settings

On the mariadb server I did some tuning according to the tuning documentation. The two buffer settings were suggestions from phpmyadmin shown after some days.

innodb_buffer_pool_size = 1G
innodb_log_file_size    = 256M

read_rnd_buffer_size    = 4M
sort_buffer_size        = 4M

php-fpm settings

In the php fpm settings I started out using the values from the documentation. As I have double the memory of the example I can ensure that there are more workers ready for higher load. When there is not much load this is not really a big thing. You will notice it when many requests have to be processed at the same time.

pm = dynamic
pm.max_children = 120
pm.start_servers = 12
pm.min_spare_servers = 6
pm.max_spare_servers = 18

haproxy settings

In the haproxy settings I redirect all non https traffic to https. All security header are sent by the Nextcloud server and get passed through to the client. We also enable http/2 to allow faster loading of the web page. The last thing is a preparation step for the fail2ban setup by passing the client ip to the Nextcloud server.

frontend http-in
    bind *:80
    default_backend redirect_to_https

frontend https-in
    # enable http/2 and http/1.1 as fallback
    bind *:443 ssl crt /etc/ssl/private/cloud.domain.tld.pem alpn h2,http/1.1
    acl acl_nextcloud hdr(host) -i cloud.domain.tld
    # additional acls

    use_backend cloud if acl_nextcloud 
    # additional backends

backend cloud
    # the following option is one peace in the puzzle to get fail2ban to work behind haproxy
    option forwardfor header X-Real-IP
    # if the traffic from haproxy is encrypted with a private cert
    # server nextcloud1 192.168.x.y:443 check ssl verify none
    # if the traffic from haproxy to the host is not encrypted anymore
    server nextcloud1 192.168.x.y:80 check

backend redirect_to_https
    redirect scheme https

fail2ban settings

The special part on my setup is that I do the public SSL certificate offloading on my haproxy load balancer. This also has the advantage of only having the Let’s encrypt acme-setup on one system and not spreading to all hosts.

Many points are described in the documentation about hardening your installation. If your installation is available from the public internet, you really should implement the suggestions found in the hardening and security guidance.

So first, we have to make sure haproxy passes the real ip address of the client to the server. The option forwardfor header X-Real-IP is already present in the example above.

Next we need to update the apache configuration (or nginx) to be able to handle this header by enabling remoteip and adding some configuration options.

a2enmod remoteip

Now we have to edit the configuration file for the remote proxy at /etc/apache2/conf-enabled/proxy_remoteip.conf. It might be, that you have to create that file. Just use the exact IP or a network if you have multiple proxies passing requests to Nextcloud.

RemoteIPHeader X-Real-IP
RemoteIPTrustedProxy 192.168.0.0/24

Finally we have to configure Nextcloud to make it aware of the header and trusted proxy server. Just edit your nextcloudroot/config/config.php file and add the following entries.

‘trusted_proxies’ => array(‘INSERT_YOUR_PROXY_IP_HERE’),
‘forwarded_for_headers’ => [‘HTTP_X_REAL_IP’],

Now we have enabled the Nextcloud installation to provide all the information needed by fail2ban to work correctly. You can check this by having a look at the Nextcloud logs. The log entries should now contain the real client ip address and not the value of the haproxy host. If something did not work you still see only the ip address of your haproxy host and you have to check all configuration options again.

To make Nextlcoud work in fail2ban we have to provide filter rules. The rules are taken from the official documentation and placed at /etc/fail2ban/filter.d/nextcloud.conf.

[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)?"

Next we have to edit /etc/fail2ban/jail.d/nextcloud.local and add some information about the server and where the log file is located. Please make sure the log file is already available during boot up. I accidentally had mine on the data share mounted a bit later and this made fail2ban fail to start during boot.

[nextcloud]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
maxretry = 3
bantime = 86400
findtime = 43200
logpath = /path/to/data/directory/nextcloud.log

After setting everything up, we have to make sure fail2ban starts on boot and then restart it to apply the configuration.

systemctl enable haproxy.service
systemctl restart haproxy.service

Now you can check the status of your fail2ban settings for Nextcloud by using fail2ban-client status nextcloud. To make sure it works, you can open your Nextcloud in a private browser window and try to login with invalid credentials. You then should see the count change.