Nextcloud SSL - letsencrypt https | Docker

Diese Seite gibt es auch in Deutsch

To synchronize contacts, appointments and photos with my NAS, I tested Nextcloud and thus turned my back on other cloud providers for my private data to some extent. Thanks to Docker, the installation is easier and more flexible than ever, allowing NextCloud to run on almost any hardware.

Docker Basics

Docker allows applications to be launched by command in a so-called container.
A container is an isolated environment independent of the operating system (OS):
So the OS does not matter, provided Docker can be installed.
When a container is first launched, Docker independently loads all the necessary sources
aus dem Internet.
Docker can be installed on Windows, macOS or an Linux Distribution
Besides Docker, I originally used and later adapted the following Github project as the basis for NextCloud: https://github.com/ichiTechs/Dockerized-SSL-NextCloud-with-MariaDB. The project basically consists of two files, which I describe in adapted version here. The main reason for the adaptation was to separate the reverse proxy from the NextCloud setup, allowing multiple web services to run with a respective SSL certificate. The NextCloud installation on a hardware, at my home, can be encrypted and reached securely from the Internet with the Let's Encrypt reverse proxy.

Step by step

Docker and Let's Encrypt reverse proxy:

  1. Select hardware: PC, notebook or better: virtuel server, Raspberry PI or a NAS: QNAP, Synology or homebrew NAS
  2. Install OS: Windows, Linux
  3. Install Docker, see Docker
  4. create a DNS entry in the internet to the public IP address and
    nginx reverse proxy setup: nginx-LetsEncrypt reverse proxy in practice

Container for NextCloud:

  1. create docker-compose.yml and nginx.conf
  2. Start container

docker-compose.yml

The docker-compose.yml file contains the config for the containers, such as the database user, the domain and network settings for the communication between the individual containers. The file should be adjusted accordingly before the first start. As mentioned above, the setup described here requires a DNS entry on the IP of the Nextcloud installation in addition to Docker and the nginx-LetsEncrypt reverse proxy.

Content of the file: docker-compose.yml

[+]
version: '2'
services:
  web:
    image: nginx
    container_name: nextcloud_webserver
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    links:
      - app
    volumes_from:
      - app
    environment:
      - VIRTUAL_HOST=next.domain.tld
      - VIRTUAL_NETWORK=nginx-proxy
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=next.domain.tld
      - LETSENCRYPT_EMAIL=admin@domain.tld
    networks:
      - nextcloud
    restart: always
  app:
    image: nextcloud:fpm
    container_name: nextcloud_fpm
    links:
      - db
      - redis
    volumes:
      - ./apps:/var/www/html/apps
      - ./config:/var/www/html/config
      - ./data:/var/www/html/data
    networks:
      - nextcloud
    restart: always
  redis:
    image: redis
    container_name: nextcloud_redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - ./redis:/data
    entrypoint: redis-server --appendonly yes
    networks:
      - nextcloud
    restart: always
  db:
    image: mariadb:10.5
    container_name: nextcloud_db
    volumes:
      - ./db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=xxx
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=xxx
    networks:
      - nextcloud
    restart: always
networks:
  nextcloud:
    external:
      name: webproxy

nginx.conf

Contents of nginx.conf file

[+]
# config file for nginx webserver to work with NextCloud app.

user www-data;

events {
  worker_connections 2048;
}

http {
  upstream backend {
      server app:9000;
  }
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  server {
    listen 80;

    # Add headers to serve security related headers
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
    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;

    root /var/www/html;
    client_max_body_size 0; # 0=unlimited - set max upload size
    fastcgi_buffers 64 4K;

    gzip off;

    index index.php;
    error_page 403 /core/templates/403.php;
    error_page 404 /core/templates/404.php;

    rewrite ^/.well-known/carddav /remote.php/dav/ permanent;
    rewrite ^/.well-known/caldav /remote.php/dav/ permanent;

    location = /robots.txt {
      allow all;
      log_not_found off;
      access_log off;
    }

    location ~ ^/(build|tests|config|lib|3rdparty|templates|data)/ {
      deny all;
    }

    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
      deny all;
    }

    location / {
      rewrite ^/remote/(.*) /remote.php last;
      rewrite ^(/core/doc/[^\/]+/)$ $1/index.html;
      try_files $uri $uri/ =404;
    }

    location ~ \.php(?:$|/) {
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      fastcgi_param HTTPS on;
      fastcgi_param modHeadersAvailable true; #Avoid sending the security headers twice
      fastcgi_pass backend;
      fastcgi_intercept_errors on;
    }

    # Adding the cache control header for js and css files
    # Make sure it is BELOW the location ~ \.php(?:$|/) { block
    location ~* \.(?:css|js)$ {
      add_header Cache-Control "public, max-age=7200";
      # Add headers to serve security related headers
      add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
      add_header X-Content-Type-Options nosniff;
      add_header X-Frame-Options "SAMEORIGIN";
      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;
      # Optional: Don't log access to assets
      access_log off;
    }

    # Optional: Don't log access to other assets
    location ~* \.(?:jpg|jpeg|gif|bmp|ico|png|swf)$ {
      access_log off;
    }
  }
}

Creating the config and starting the containers

The following command creates the containers with the config stored in docker-compose.yml.

docker-compose up -d

Add container / customize docker-compose.yml

Add Collabora

Collabora is an online version of LibreOffice and allows you to create or collaborate on Office documents online via your web browser. Prerequisite for use from the Internet is an additional DNS name, i.e. an A-record to the public IP of the server and an additional Let`s Encrypt certificate, which in turn can be defined via the environment variables and is automatically issued and extended by the nginx-LetsEncrypt reverse proxy.

To use Callabora in Nextcloud, the following block can be customized and inserted in docker-compose.yml:

[+]
collabora:
 image: collabora/code
 container_name: nextcloud_collabora
 expose:
 - 9980
 cap_add:
 - MKNOD
 environment:
 - domain=next.deineDomain
 - VIRTUAL_HOST=office.deineDomain
 - VIRTUAL_NETWORK=nginx-proxy
 - VIRTUAL_PORT=9980
 - VIRTUAL_PROTO=https
 - LETSENCRYPT_HOST=office.deineDomain
 - LETSENCRYPT_EMAIL=deineEmail-Addresse
 networks:
 - nextcloud
 restart: always

Add OnlyOffice

Only-Office can also be used to edit Word, Excel or PowerPoint documents online. Here, too, an additional DNS name is required for access from the Internet : nginx-LetsEncrypt Reverse Proxy. Compared to Collabora, Only-Office is a bit more streamlined, since much more program logic takes place in the browser. Compared to Collabora, I have not had any disconnections when editing documents with OnlyOffice, so I replaced Collabora with OnlyOffice in the meantime.

[+]
 onlyoffice:
 image: onlyoffice/documentserver
 container_name: nextcloud_onlyoffice
 stdin_open: true
 tty: true
 volumes:
  - ./onlyoffice/data:/var/lib/onlyoffice/documentserver/App_Data 
 expose:
 - '80'
 - '443'
 environment:
 - VIRTUAL_HOST=document.domain.xx
 - VIRTUAL_NETWORK=nginx-proxy
 - LETSENCRYPT_HOST=document.domain.xx
 - LETSENCRYPT_EMAIL=email@domain.xx
 - JWT_ENABLED=true
 - JWT_SECRET=secretwithoutnumbers
 - JWT_HEADER=Authorization
 networks:
 - nextcloud
 restart: always

Customized docker-compose.yml with OnlyOffice

[+]
version: '2'

services:
  web:
    image: nginx
    container_name: nextcloud_webserver
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    links:
      - app
    volumes_from:
      - app
    environment:
      - VIRTUAL_HOST=next.domain.tld
      - VIRTUAL_NETWORK=nginx-proxy
      - VIRTUAL_PORT=80
      - LETSENCRYPT_HOST=next.domain.tld
      - LETSENCRYPT_EMAIL=admin@.domain.tld
    networks:
      - nextcloud
    restart: always
  app:
    image: nextcloud:fpm
    container_name: nextcloud_fpm
    links:
      - db
      - redis
      - onlyoffice
    volumes:
      - ./apps:/var/www/html/apps
      - ./config:/var/www/html/config
      - ./data:/var/www/html/data
    networks:
      - nextcloud
    restart: always
  redis:
    image: redis
    container_name: nextcloud_redis
    restart: always
    ports:
      - "6379:6379"
    volumes:
      - ./redis:/data
    entrypoint: redis-server --appendonly yes
    networks:
      - nextcloud
    restart: always
  onlyoffice:
     image: onlyoffice/documentserver
     container_name: nextcloud_onlyoffice
     stdin_open: true
     tty: true 
     volumes:
        - ./onlyoffice/data:/var/lib/onlyoffice/documentserver/App_Data 
     expose:
        - '80'
        - '443'
     environment:
        - VIRTUAL_HOST=document.domain.tld
        - VIRTUAL_NETWORK=nginx-proxy
        - LETSENCRYPT_HOST=document.domain.tld
        - LETSENCRYPT_EMAIL=adin@domain.tld
        - JWT_ENABLED=true
        - JWT_SECRET=xxx
        - JWT_HEADER=Authorization
     networks:
        - nextcloud
     restart: always 
  db:
    image: mariadb:10.5
    container_name: nextcloud_db
    volumes:
      - ./db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=xxx
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=xxx
    networks:
      - nextcloud
    restart: always
networks:
  nextcloud:
    external:
      name: webproxy

OnlyOffice empty documents

ATTENTION: If the address for the internal requests cannot be resolved, the documents will not be updated in NextCloud, they will still be in the container, in the folder: /var/lib/onlyoffice/documentserver/App_Data. For this reason, the folder should definitely be mapped to a local folder to avoid data loss. Responsible for updating the Only-Office documents in NextCloud is the cron job, so it is also not insignificant that it runs regularly.

I also had to add the following lines in the Nextcloud config starting from a certain version:

File: /config/config.php

$CONFIG = array (
...
  'onlyoffice' =>
  array (
    'verify_peer_off' => false,
  ),
...

Maintenance

Update container

For the update of the container I wrote myself a small .sh file:

docker-compose pull
docker-compose up -d
sleep 20

docker exec --user www-data nextcloud_fpm php occ upgrade
sleep 20
docker exec --user www-data nextcloud_fpm php occ db:add-missing-indices
docker exec --user www-data nextcloud_fpm php occ app:disable twofactor_totp calendar news contacts onlyoffice previewgenerator tasks mail drawio
docker exec --user www-data nextcloud_fpm php occ app:enable twofactor_totp calendar news contacts onlyoffice  previewgenerator tasks mail drawio
docker exec --user www-data nextcloud_fpm php occ maintenance:mode --off
~

After apps were missing from time to time, I first deactivated them in the script and then reactivated them.

Without the "occ upgrade" command, the upgrade would be initiated the next time the web interface was called via the browser:

As used in the Bash-Script: Various apps may have to be reactivated, either via the GUI or via command:

docker exec --user www-data nextcloud_fpm php occ app:enable twofactor_totp calendar news contacts onlyoffice phonetrack previewgenerator spreed audioplayer

scan files

docker exec --user www-data nextcloud_fpm php occ files:scan --all

rebuild birthday calendar

docker exec --user www-data nextcloud_fpm php occ dav:sync-birthday-calendar User

backup: database dump

docker exec db mysqldump --user=root --password=password -h localhost nextcloud > dump.sql.gz

Tuning - Settings - Optimizations

CronJob

on the host OS

sudo crontab -e
*/5 * * * docker exec --user www-data nextcloud_fpm php -f /var/www/html/cron.php > /dev/null 2>&1

Security and setup warnings

docker exec --user www-data nextcloud_fpm php occ maintenance:mode --on
docker exec --user www-data nextcloud_fpm php occ db:convert-filecache-bigint
docker exec --user www-data nextcloud_fpm php occ maintenance:mode --off
docker exec --user www-data nextcloud_fpm php occ db:add-missing-indices

Brute Force Protection and Reverse Proxy:

In logging:

/config/config.php:

add from:

'trusted_proxies' => array('172.18.0.2'),
 'forwarded_for_headers' => array('HTTP_X_FORWARDED_FOR')

Connections:

root@soxn:/nextcloud# nano nginx.conf

events { worker_connections 768; }

changed to 2048;

NGINX Bad Gateway - OnlyOffice

Initially, I needed the following workaround to start OnlyOffice, but it has since become obsolete ...

Bash script:

#!/bin/bash 

url="https://document.DOMAIN"
keyword="Bad Gateway"

if curl -s "$url" | grep "$keyword"
then
    # if the keyword is in the conent
    echo " ERROR"
	docker restart onlyoffice
else
    echo "the website is working fine"
fi

sudo crontab -e

*/10 * * * * . /nextcloud/check.sh > /dev/null 2>&1

Preview Images

Show the last changed files:

find . -type f -cmin 5

Read setting: docker exec --user www-data nextcloud_fpm php -d memory_limit=4G occ config:app:get previewgenerator squareSizes

docker exec --user www-data nextcloud_fpm php -d memory_limit=4G occ config:app:set --value "256" previewgenerator squareSizes

client_max_body_size

File uploadsize.conf

client_max_body_size 10G;

docker-compose.yml

services:
 proxy:
 image: jwilder/nginx-proxy
 container_name: proxy
 ports:
 - 80:80
 - 443:443
 volumes:
 - ./proxy/conf.d:/etc/nginx/conf.d
 - ./proxy/vhost.d:/etc/nginx/vhost.d
 - ./proxy/html:/usr/share/nginx/html
 - ./proxy/certs:/etc/nginx/certs:ro
 - /var/run/docker.sock:/tmp/docker.sock:ro
 - ./uploadsize.conf:/etc/nginx/conf.d/uploadsize.conf:ro

Redis

config/apcu.config.php

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

Docker .env

If a .env file is created in the folder where the docker-compose.yml file is located, it can be used to modify Docker parameters:

#.env 
COMPOSE_HTTP_TIMEOUT=200

Troubleshooting

Internal Server Error

After a power failure I had the following problem:

Internal Server Error

The server encountered an internal error and was unable to complete your request.
Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.
More details can be found in the server log.

The Redis container kept restarting. In the log I could find the following entry:

Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix 

After I deleted the redis folder ./nextcloud/redis the installation could be started again.

WARNING:[pool www] server reached pm.max_children setting (5), consider raising it

With the default settings, the following warning was displayed in the log of the nextcloud:fpm container:

WARNING: [pool www] server reached pm.max_children setting (5), consider raising it 

The limit can be raised in the FPM config file www.conf, which is hidden in the nextcloud:fpm container:

To view the file, we can connect to the container:

docker exec --user www-data -it nextcloud_fpm bash

To make the changes to the config file available after a reboot, the file can be placed outside the container, but to do this the file must exist:

Use cat /usr/local/etc/php-fpm.d/www.conf to display the contents of www. conf and create www.conf in the root folder:

Add the following line to nextcloup_fpm:

- ./www.conf:/usr/local/etc/php-fpm.d/www.conf #added 4 max-childs-config

with nano.conf the www. conf can be adjusted:

After I have 8GB Ram in my NAS I adjusted the following values:

pm.max_children = 80 #(vorher 5)
pm.start_servers = 2
pm.min_spare_servers = 2 #(voher 1)
pm.max_spare_servers = 15 #(vorher 3)

The complete file looks like this for me:

www.conf

[www]
user = www-data
group = www-data
listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 80
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 15

Exception: Database error when running migration latest for app core

An exception occurred while executing a query: SQLSTATE[HY000]: General error: 4047 InnoDB refuses to write tables with ROW_FORMAT=COMPRESSED or KEY_BLOCK_SIZE.

The problem is due to the MariaDB version. From version 10.6 on compressed columns are not supported anymore.

I have solved the problem for now by using version 10.5 of MariaDB:

docker-compose.yml

...
  db:
    image: mariadb:10.5
    container_name: nextcloud_db
...

see: help.nextcloud.com/t/update-to-22-failed-with-database-error-updated/120682

Docker as user / without root privileges

sudo groupadd docker
sudo gpasswd -a $USER docker

Router OpenWrt- internal IP

Since my NAS and thus the NextCloud installation at home is directly accessible via WLAN, without detour: WLAN - router - Internet - router, it makes sense of course to call the installation directly, for this an additional DNS entry at the router is sufficient: Split-DNS. The NextCloud domain is thus resolved in the WLAN with an internal IP.

Here is an example of how to configure my OpenWrt-based router:

vi /etc/config/dhcp

config 'domain'
option name 'next.domain.xx'
option ip 192.168.1.5

config 'domain'
option name 'office.domain.xx'
option ip 192.168.1.5

config 'domain'
option name 'document.domain.xx'
option ip 192.168.1.5

Windows webdav

\next.domain.xx@SSL\DavWWWRoot\remote.php\dav\files\user

FolderSync Rasperry PI

Install:

sudo apt install owncloud-client-cmd

and add it to crontab

crontab -e

* * * owncloudcmd /localfolder https://user:password@nextcloudURL/remote.php/webdav/Ordner >/dev/null 2>&1

Conclusion

NextCloud adds countless features to my NAS and gives me the ability to bring cloud services back home:
With NextCloud I now have sync clients for Android, Windows and Linux, can create office documents, charts or polls in the browser. Besides the photos from the SmartPhone, I can also synchronize or share my contacts and calendar entries and could even run my own messenger incl. call and video function and much more ...

positive Bewertung({{pro_count}})
Rate Post:
{{percentage}} % positive
negative Bewertung({{con_count}})

THANK YOU for your review!



Questions / Comments


By continuing to browse the site, you agree to our use of cookies. More Details