Nextcloud via Docker with nginx reverse proxy

🍪 4 min read

In this post I would like to briefly explain how Nextcloud can be set up via Docker and behind an nginx reverse proxy. I assume a server with nginx set up, equivalent to the setup from my server and nginx setup notes. The sources for the Docker images and docker-compose examples are available in the corresponding GitHub repository of Nextcloud Docker. In this setup we will use the version with Mariadb/Cron/Redis/Apache. I create the example files like follows:

mkdir /home/dennis/nextcloud
cd /home/dennis/nextcloud
vim db.env

Add the MYSQL access information, make sure to use a appropriate MYSQL_PASSWORD.

MYSQL_PASSWORD=supersecurepassword
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud

Next we’ll create the docker-compose configuration file.

vim docker-compose.yml

Add the following content, make sure to replace MYSQL_ROOT_PASSWORD with a appropriate value. Also note, that we use port 5678 instead the default port 80. This is because we’ll use nginx as our reverse proxy later.

version: '3'

services:
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=supersecuremysqlrootpassworddifferentthanmysqlpassword
    env_file:
      - db.env

  redis:
    image: redis
    restart: always

  app:
    build: ./app
    restart: always
    ports:
      - 5678:80
    volumes:
      - nextcloud:/var/www/html
    environment:
      - MYSQL_HOST=db
    env_file:
      - db.env
    depends_on:
      - db
      - redis

  cron:
    build: ./app
    restart: always
    volumes:
      - nextcloud:/var/www/html
    entrypoint: /cron.sh
    depends_on:
      - db
      - redis

volumes:
  db:
  nextcloud:

Next, lets create the app directory and add the actual Dockerfile.

mkdir app
cd app
vim Dockerfile

The Dockerfile itself is rather simple, it uses the nextcloud:apache image and overrides the default redis config, because we’ll use redis.

FROM nextcloud:apache

COPY redis.config.php /usr/src/nextcloud/config/redis.config.php

As our last file we’ll create the redis configuration file.

vim redis.config.php

Here is the content of the redis configuration:

<?php
$CONFIG = array (
  'memcache.locking' => '\OC\Memcache\Redis',
  'redis' => array(
    'host' => 'redis',
    'port' => 6379,
  ),
);

After we’ve created the configuration files we can start nextcloud via docker-compose:

cd /home/dennis/nextcloud
docker-compose up -d

Obtain Let’s Encrypt certificate

To SSL encrypt the connection to our Nextcloud server, a certificate is required. We’ll use a Let’s encrypt certificate. Start by creating a nginx configuration file for our nextcloud instance. The examples use the subdomain nextcloud.dennisnotes.com, change it according to the domain you want to use.

sudo vim /etc/nginx/sites-available/nextcloud.dennisnotes.com.conf

As in our basic nginx setup we start with a simple nginx configuration which just handles standard HTTP serving for our subdomain.

server {
    listen 80;
    listen [::]:80 ipv6only=on;

    server_name nextcloud.dennisnotes.com;
    root /var/www/dennisnotes.com;

    index index.html;
    location / {
            try_files $uri $uri/ =404;
    }
}

After creating the configuration file test it and restart nginx to enable it.

sudo ln -s /etc/nginx/sites-available/nextcloud.dennisnotes.com.conf /etc/nginx/sites-enabled/nextcloud.dennisnotes.com.conf
sudo nginx -t
sudo systemctl stop nginx
sudo systemctl start nginx
sudo systemctl status nginx

Now let certbot obtain a certificate for us and apply the default nginx SSL configuration like follows:

sudo certbot --rsa-key-size 4096 --nginx

Select nextcloud.dennisnotes.com, fill in information like email etc.

nginx setup

Next we will edit the configuration file again to use nginx as a reverse proxy for our nextcloud instance.

sudo vim /etc/nginx/sites-available/nextcloud.dennisnotes.com.conf

Here is a example configuration file, which I use:

server {
    server_name nextcloud.dennisnotes.com;
    root /var/www/dennisnotes.com;

    index index.html;

    location / {
        proxy_pass http://localhost:5678/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
        client_max_body_size 0;

        access_log /var/log/nginx/nextcloud.access.log;
        error_log /var/log/nginx/nextcloud.error.log;
    }

    location /.well-known/carddav {
      return 301 $scheme://$host/remote.php/dav;
    }

    location /.well-known/caldav {
      return 301 $scheme://$host/remote.php/dav;
    }

    listen [::]:443 ssl http2; # managed by Certbot
    listen 443 ssl http2; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/nextcloud.dennisnotes.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/nextcloud.dennisnotes.com/privkey.pem; # managed by Certbot
    ssl_trusted_certificate /etc/letsencrypt/live/nextcloud.dennisnotes.com/chain.pem;
    include /etc/nginx/snippets/ssl.conf;
}

server {
    if ($host = nextcloud.dennisnotes.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

        listen 80;
        listen [::]:80;

        server_name nextcloud.dennisnotes.com;
    return 404; # managed by Certbot
}

Fail2Ban

In the last step we create a Fail2ban configuration for Nextcloud. This blocks IPs from which three attempts were made to log on to our Nextcloud instance with incorrect user data. Start by creating the filter definition:

vim /etc/fail2ban/filter.d/nextcloud.conf

Here is the regex which will filter for Login failed messages in the nextcloud logfiles:

[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>'\)".*}$
ignoreregex =

Now create the actual jail configuration for nextcloud.

vim /etc/fail2ban/jail.d/nextcloud.conf

Here is the content of the configuration file. Note the logpath which points to the nextcloud docker volume, in which our nextcloud docker container writes into. Change the maxretry and bantime values accordingly to your needs.

[nextcloud]
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
maxretry = 3
bantime = 10800
logpath = /var/lib/docker/volumes/nextcloud_nextcloud/_data/data/nextcloud.log

After a new configuration has been added, the fail2ban service must be restarted. After the restart, the new configuration should appear in the status query from the fail2ban client, which can then also be viewed in detail.

sudo systemctl restart fail2ban
sudo fail2ban-client status
sudo fail2ban-client status nextcloud

Configuration

To finish the configuration of nextcloud you can now visit your nextcloud instance (e.g. https://nextcloud.dennisnotes.com).

Update Nextcloud

To update Nextcloud you just need to pull the new images via docker-compose and rebuild the containers. The manual update via the admin interface is disabled by the nextcloud docker team, the wanted way to upgrade is via upgrading the docker images to ensure compatibility.

docker-compose stop
docker-compose rm
docker-compose pull
docker-compose build --pull
docker-compose up -d

Or as a one-liner:

docker-compose stop && docker-compose rm --force && docker-compose pull && docker-compose build --pull && docker-compose up -d