How to Set up Nextcloud Docker with Nginx Reverse Proxy

Nextcloud is a Dropbox-like open source software that you can self host it on your server and use it to store, backup and synchronize your files and data across multiple devices. If you are looking to move away from Dropbox/Google Drive, and want to have complete control over your data, Nextcloud is the best choice.

The standard way of setting up Nextcloud is complicated, requires a lot of (server and software) configuration and it is prone to errors. Upgrading it is also an hassle. However, with the release of the official Nextcloud docker image, it is now very easy to install and use Nextcloud.

In this tutorial, I will show how to set up a Nextcloud Docker with Nginx reverse proxy. The server used in this tutorial is running Ubuntu 18.04.

Install Docker and docker-compose

If you have not install docker on your server, this is the first step to do so.

1. update the system:

sudo apt update

2. Install the package and dependencies for docker:

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

3. Add the docker’s gpg key

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

4. Add the docker’s repository.

sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

5. Lastly, update the system and install docker:

sudo apt update
sudo apt-get install docker-ce docker-ce-cli containerd.io

6. If you want to run docker as user (instead of root), add your username to the docker group:

sudo groupadd docker
sudo usermod -aG docker username

7. Next, we are going to install docker-compose (the latest version is 1.24.0 as of this post).

sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

8. Restart the server.

Set up Nextcloud

We are going to make use of docker-compose to run Nextcloud docker image. To get started, first create a “nextcloud” folder, and cd to it.

mkdir nextcloud
cd nextcloud

1. Create a docker-compose file:

nano docker-compose.yml

2. Paste the following code to the file:

version: '3'

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

  redis:
    image: redis
    restart: always

  app:
    build: ./app
    restart: always
    ports:
      - 5234: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:

We will map the server port 5234 to the docker image port 80. Save (Ctrl + O) and exit (Ctrl + X) the file.

3. The docker-compose file will get the database credential from the “db.env” file, so we need to create the file and add our database details.

nano db.env

Add your database details in.

MYSQL_ROOT_PASSWORD=mysupersecurerootpassword
MYSQL_PASSWORD=mysupersecureuserpassword
MYSQL_DATABASE=nextcloud
MYSQL_USER=nextcloud

You can change the root and user password. Save (Ctrl + O) and exit (Ctrl + X) the file.

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

mkdir app
cd app
nano Dockerfile

Add the following lines to the Dockerfile:

FROM nextcloud:apache
 
COPY redis.config.php /usr/src/nextcloud/config/redis.config.php

Save (Ctrl + O) and exit (Ctrl + X) the file.

5. In the “app” folder, create the “redis.config.php” file.

nano redis.config.php

Paste the following configuration to the php file.

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

6. Lastly, run the docker image:

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

Set up Let’s Encrypt SSL Certificate

We will use certbot to obtain and manage Let’s Encrypt certificate. To get started, first install certbot.

sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot python-certbot-nginx

Next, create a Nginx conf file for the nextcloud domain:

sudo nano /etc/nginx/sites-available/nextcloud

Add the following lines:

server {
    listen 80;
    listen [::]:80 ipv6only=on;
 
    server_name mynextcloudurl.com;
    root /var/www/mynextcloudurl.com;
 
    index index.html;
    location / {
            try_files $uri $uri/ =404;
    }
}

Save and exit the file. Make it active:

sudo ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/
sudo systemctl reload nginx

Lastly, obtain a certificate with the command:

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

When prompted, select your nextcloud url and fill up the information. Allow it to replace the conf file.

Setting up Nginx Reverse Proxy

In the Nginx conf file, add (or replace the location / block) the following lines:

location / {
    proxy_pass http://localhost:5234/; # set this to the nextcloud port set in doccker-compose file
    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;
 
    client_max_body_size 0;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
 
    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;
}

Save and exit the file. Restart Nginx:

sudo systemctl reload nginx

On your browser, load your nextcloud url and it should prompt you to set up your administrator account.

Securing the server (optional)

We can use fail2ban to prevent unauthorized access to the server. For the following configuration, we will block IPs that made three unsuccessful login attempts to our Nextcloud installation.

1. Start by creating the fail2ban conf file:

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

Add the following codes to filter out the 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 =

2. Next, create the actual jail configuration for nextcloud.

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

Add the following lines to the file. You can change the maxretry and bantime values according 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

3. Restart the fail2ban service.

sudo systemctl restart fail2ban

You can check the fail2ban status with the following commands.

sudo fail2ban-client status
sudo fail2ban-client status nextcloud

Updating Nextcloud

To update Nextcloud to the newer version, you just need to pull the new images via docker-compose and rebuild the containers.

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

That’s it.