Docker-Compose Method - Recommended

Install Docker

Update the repo to get latest versions

sudo apt update

Install the latest version

sudo apt install docker.io

Set Docker to start on startup

sudo systemctl enable --now docker

Give your user permissions to docker, replacing user with your username

sudo usermod -aG docker user

Once you have run this command close and reopen your session if you accessing remotely. This is to apply the permissions in the above step

Test it has installed correctly by getting the docker version

docker --version

Docker Compose

I also install docker-compose as some dockers need you to compose from a yml file. This downloads v2.16.0, just change this if the version updates to a later version

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

Give permissions to this

sudo chmod +x /usr/local/bin/docker-compose

Test it has installed correctly by getting the docker-compose version

docker-compose --version

Install Nextcloud

I keep all my dockers in a dockers folder in my home directory. If it doesn’t exist already, create this folder:-

mkdir ~/dockers

Now create a folder for Nextcloud to live in.

mkdir ~/dockers/nextcloud ~/dockers/

Create a folder for the www data

mkdir ~/dockers/nextcloud/data  

Create a folder for the database

mkdir ~/dockers/nextcloud/sqldata  

Change directory to this folder

cd ~/dockers/nextcloud

Create a docker-compose.yml file

nano docker-compose.yml

Paste the following. Change the 8081 part of 8081:80 if you want it to listen on an alternative port to port 8081. Change the MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD. Ch

---
version: '2'

services:
  app:
    image: nextcloud
    restart: always
    ports:
      - 8081:80
    volumes:
      - ./data:/var/www/html
    environment:
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextclouduser
      - MYSQL_PASSWORD=changeme
      - MYSQL_HOST=db
  db:
    image: mariadb
    restart: always
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    volumes:
      - ./sqldata:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=pleasechangeme
      - MYSQL_PASSWORD=changeme
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud

Save the file with ctl + x, then y to save.

Run the docker-compose file with the following:-

docker-compose up -d
  1. Browse to the server ip and the port mentioned in the compose file, eg http://1.1.1.1:8081 and you should get the default page. If you want HTTPS, follow the next part, otherwise jump to Finish Setup

Adding HTTPS using Nginx Proxy Manager

Install Nginx Proxy Manager

I keep all my dockers in a dockers folder in my home directory. If it doesn’t exist already, create this folder:-

mkdir ~/dockers

Now create a folder for Nginx Proxy Manager to live in.

mkdir ~/dockers/nginxproxymanager

Change directory to this folder

cd ~/dockers/nginxproxymanager

Create 2 directories, data and letsencrypt, for nginxproxymanager to save to:-

mkdir data letencrypt

Create a docker-compose.yml file

nano docker-compose.yml

Paste the following. If you want to save the data to another directory change the volumes to point to the directories you want to.

version: '3'
services:
   app:
     image: 'jc21/nginx-proxy-manager:latest'
     restart: unless-stopped
     ports:
     - '80:80'
     - '81:81'
     - '443:443'
     environment:
     DB_MYSQL_HOST: "db"
     DB_MYSQL_PORT: 3306
     DB_MYSQL_USER: "npm"
     DB_MYSQL_PASSWORD: "npm"
     DB_MYSQL_NAME: "npm"
     volumes:
     - ./data:/data
     - ./letsencrypt:/etc/letsencrypt
 db:
     image: 'jc21/mariadb-aria:latest'
     restart: unless-stopped
     environment:
     MYSQL_ROOT_PASSWORD: 'npm'
     MYSQL_DATABASE: 'npm'
     MYSQL_USER: 'npm'
     MYSQL_PASSWORD: 'npm'
     volumes:
     - ./data/mysql:/var/lib/mysql

Save the file with ctl + x, then y to save.

Run the docker-compose file with the following:-

docker-compose up -d

First run Nginx Proxy Manger

Browse to http://serverip:81 and you will get the login screen. Default login is [email protected] password changeme. You will then get the edit user screen. Update the user email and press Save. You will then be prompted to change the password. Save this and you will get the main login screen.

Creating a wildcard certificate with DNS Challenge

Go to SSL Certificates, select “Add SSL Certificate”.

In the domain name type *.domainname, so *.llewellynhughes.co.uk for example. Edit the email if you need to. Tick “Use DNS Challenge”. Select your DNS provider. If your current DNS provider isn’t there, sign up for a free Cloudflare account and use their DNS, pointing your existing DNS Name Servers (ns) to Cloudflare. Agree to the terms and conditions and Save.

Your SSL Certificate should now be created and renewed automatically.

Proxying to an existing site

This presumes you have set your DNS record for your domain name. I use Adguard as my DNS server, so added a DNS Rewrite here to point back to my Nginx Proxy Manager. I have a DNS record for nextcloud.llewellynhughes.co.uk, with a DNS rewrite for that URL to go to my server ip.

Go to Hosts, Proxy Hosts, Add Proxy Host.

Domain names, fill in the url you have setup. In my example it’s nextcloud.llewellynhughes.co.uk.

Scheme is http Forward Hostname/IP is my server ip Port is my nextcloud install port, so 8081.

Tick Block Known Exploits and WebSocket Support.

Leave custom locations blank. For other projects you might need to use this for subfolders.

SSL, select your SSL Certificate created. I tick Force SSL, HTTP/2 Support, HSTS Enabled.

Nothing in advanced. These are for advanced Nginx configs.

Once done, Click Save.

After this, test going to your https url and it should work

Finishing setup

  1. Add your domain to trusted_domains

    sudo nano ~/dockers/nextcloud/data/config/config.php

  2. Under trusted_domains, add your url so it looks like this

    ‘trusted_domains’ => array ( 0 => ‘nextcloud.example.com’, ),

  3. Once on the site, create an admin account, open storage and database, and paste your data folder into there from the docker redirect. This will make files appear in ~/dockers/nextcloud/data/data folder

    /var/www/html/data
    
  4. Add the nextcloud database settings.

    nextcloud
    password
    nextcloud
    localhost
    
  5. Press finish setup.

  6. All should be ready.

Nginx Method

Installing nginx if it’s not installed

  1. First, update the repo to get latest versions

    sudo apt update
    
  2. Install nginx

    sudo apt install nginx (you can ignore this step if you ran it above for the above install)
    
  3. Enable the service to start on boot

    sudo systemctl enable nginx
    

Install PHP

  1. Update the repo to get latest versions

    sudo apt update
    
  2. Install php and php extensions

    sudo apt install imagemagick php-imagick php7.4-common php7.4-mysql php7.4-fpm php7.4-gd php7.4-json php7.4-curl  php7.4-zip php7.4-xml php7.4-mbstring php7.4-bz2 php7.4-intl php7.4-bcmath php7.4-gmp
    

Installing MariaDB

  1. First, update the repo to get latest versions (you can ignore this step if you ran it above for the above installs)

    sudo apt update
    
  2. Install Maridadb-server and mariadb-client

    sudo apt install mariadb-server mariadb-client
    
  3. Secure the installation

    sudo mysql_secure_installation
    
  4. First will prompt you for current password, this will be blank so just press enter

    Enter current password for root (enter for none): 
    
  5. Next, it will ask you to set a root password. Press Y and enter a password, and then confirm.

    Set root password? [Y/n] Y
    
  6. The rest, accept the defaults, and complete the configuration.

  7. Enable the service to start on boot.

    sudo systemctl enable mariadb-server
    

Setting up database for Nextcloud

  1. Login to mysql, this was prompt you for your password you set earlier.

    sudo mysql -u root -p
    
  2. Create database

    CREATE DATABASE nextcloud;
    
  3. Create a user (Please change the password at the end to a secure password)

    create user 'nextclouduser'@'localhost' identified by 'your-password';
    
  4. Grant privileges to the above account

    grant all privileges ON nextcloud.* TO 'nextclouduser'@'localhost';
    
  5. Flush privileges and exit

    flush privileges;
    exit;       
    

Installing Nextcloud

  1. Download the latest release, there is no “latest release, so get the latest url from https://nextcloud.com/install/#instructions-server

    wget https://download.nextcloud.com/server/releases/nextcloud-21.0.1.zip
    
  2. Unzip and move to the nginx directory, ignore the first command if you unzip installed already.

    sudo apt install unzip
    
    sudo unzip nextcloud-21.0.1.zip -d /usr/share/nginx/
    
  3. Amend permissions of the folder

    sudo chown www-data:www-data /usr/share/nginx/nextcloud/ -R
    
  4. Create the nginx config file

    sudo nano /etc/nginx/conf.d/nextcloud.conf
    
  5. Copy and paste the below into the file for the config. Change the server_name to your server name/IP. If you want to change the port too, change the listen 80 line.

    server {
    listen 80;
    listen [::]:80;
    server_name nextcloud.example.com;
    
    # Add headers to serve security related headers
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header Referrer-Policy no-referrer;
    
    #I found this header is needed on Ubuntu, but not on Arch Linux. 
    add_header X-Frame-Options "SAMEORIGIN";
    
    # Path to the root of your installation
    root /usr/share/nginx/nextcloud/;
    
    access_log /var/log/nginx/nextcloud.access;
     error_log /var/log/nginx/nextcloud.error;
    
    location = /robots.txt {
       allow all;
       log_not_found off;
       access_log off;
    }
    
    # The following 2 rules are only needed for the user_webfinger app.
    # Uncomment it if you're planning to use this app.
    #rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
    #rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json
    # last;
    
    location = /.well-known/carddav {
        return 301 $scheme://$host/remote.php/dav;
    }
    location = /.well-known/caldav {
       return 301 $scheme://$host/remote.php/dav;
    }
    
    location ~ /.well-known/acme-challenge {
      allow all;
    }
    
    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;
    
    # Disable gzip to avoid the removal of the ETag header
    gzip off;
    
    # Uncomment if your server is build with the ngx_pagespeed module
    # This module is currently not supported.
    #pagespeed off;
    
    error_page 403 /core/templates/403.php;
    error_page 404 /core/templates/404.php;
    
    location / {
       rewrite ^ /index.php;
    }
    
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
       deny all;
    }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
       deny all;
    }
    
    location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
       include fastcgi_params;
       fastcgi_split_path_info ^(.+\.php)(/.*)$;
       try_files $fastcgi_script_name =404;
       fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
       fastcgi_param PATH_INFO $fastcgi_path_info;
       #Avoid sending the security headers twice
       fastcgi_param modHeadersAvailable true;
       fastcgi_param front_controller_active true;
       fastcgi_pass unix:/run/php/php7.4-fpm.sock;
       fastcgi_intercept_errors on;
       fastcgi_request_buffering off;
    }
    
    location ~ ^/(?:updater|ocs-provider)(?:$|/) {
       try_files $uri/ =404;
       index index.php;
    }
    
    # Adding the cache control header for js and css files
    # Make sure it is BELOW the PHP block
    location ~* \.(?:css|js)$ {
        try_files $uri /index.php$uri$is_args$args;
        add_header Cache-Control "public, max-age=7200";
        # Add headers to serve security related headers (It is intended to
        # have those duplicated to the ones above)
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;
        add_header Referrer-Policy no-referrer;
        # Optional: Don't log access to assets
        access_log off;
    }
    
    location ~* \.(?:svg|gif|png|html|ttf|woff|ico|jpg|jpeg)$ {
        try_files $uri /index.php$uri$is_args$args;
        # Optional: Don't log access to other assets
        access_log off;
    }
    }   
    
  6. Create a data folder where you want to save the nextcloud data and give it permissions

    sudo mkdir /usr/share/nginx/nextcloud-data
    sudo chown www-data:www-data /usr/share/nginx/nextcloud-data -R
    
  7. Test the nginx config.

    sudo nginx -t
    
  8. If the above comes back successfully, restart nginx service.

    sudo systemctl reload nginx
    
  9. Browse to the web site you set in the nginx config file above and it should appear, http://nextcloud.example.com:80

  10. You should then get a https certificate to secure your server if you are accessing it externally. I am using lets encrypt, but as I am not exposing it externally I used dns authorisation instead of http. If you want to skip this step, go to Finishing setup.

Securing the server over dns

  1. Add latest certbot repository

    sudo apt-add-repository ppa:certbot/certbot
    
  2. Install certbot

    sudo apt install certbot
    
  3. First get the certbot file

    wget https://github.com/joohoi/acme-dns-certbot-joohoi/raw/master/acme-dns-auth.py
    
  4. Change permissions on file

    chmod +x acme-dns-auth.py
    
  5. Edit file

    chmod +x acme-dns-auth.py
    
  6. Change first line to python3

    #!/usr/bin/env python3
    
  7. Move to the lets encrypt folder

    sudo mv acme-dns-auth.py /etc/letsencrypt/
    
  8. Create request (change nextcloud.example.com for your url)

    sudo certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d \*.nextcloud.example.com -d nextcloud.example.com
    
  9. It will then prompt you to add a cname to your dns host. Log into your dns, and create a cname. Press enter once complete. If it fails due to dns replication timings, just run the above command again.

    sudo certbot certonly --manual --manual-auth-hook /etc/letsencrypt/acme-dns-auth.py --preferred-challenges dns --debug-challenges -d \*.nextcloud.example.com -d nextcloud.example.com
    

Applying the cert

  1. Once complete it will tell you where the certificate and chain have been saved. Change nextcloud.example.com to the domain used above and it will probably be in there.

    Congratulations! Your certificate and chain have been saved at
    /etc/letsencrypt/live/nextcloud.example.com/fullchain.pem
    Your key file has been saved at
    /etc/letsencrypt/live/nextcloud.example.com/privkey.pem
    
  2. Open the nextcloud nginx to use https

    sudo nano /etc/nginx/conf.d/nextcloud.conf
    
  3. Replace this

    listen 80;
    listen [::]:80;
    server_name nextcloud.example.com;
    
  4. With the following, changing the ssl_certificate and ssl_certificate_key fields to point to the correct location.

    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name nextcloud.example.com;
    ssl_certificate /etc/letsencrypt/live/nextcloud.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/nextcloud.example.com/privkey.pem;
    
  5. Test the nginx config.

    sudo nginx -t
    
  6. If the above comes back successfully, restart nginx service.

    sudo systemctl reload nginx
    
  7. You should now be able to browse to your website on https://nextcloud.example.com replacing for your domain name.

Finishing setup

  1. Add your domain to trusted_domains

    sudo nano /usr/share/nginx/nextcloud/config/config.php

  2. Under trusted_domains, add your url so it looks like this

    ‘trusted_domains’ => array ( 0 => ‘nextcloud.example.com’, ),

  3. Once on the site, create an admin account, open storage and database, and paste your data folder into there from step 6 of installing nextcloud

    /usr/share/nginx/nextcloud-data
    
  4. Add the nextcloud database settings.

    nextclouduser
    password
    nextcloud
    localhost
    
  5. Press finish setup.

  6. All should be ready.