Nextcloud Server Docker | Setup + https: Let's Encrypt [ssl]

Diese Seite gibt es auch in Deutsch

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

Nextcloud server profile:

SoftwareServer
GitHubhttps://github.com/nextcloud/server
current version 24.0.6
found2022-10-06

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):
When a container is first launched, Docker independently loads all the necessary sources
from the internet.
Docker can be installed on Windows, macOS or an Linux Distribution

To ensure that Nextcloud is can be reached securely from the Internet, I use a Let's Encrypt reverse proxy. At first I used Nginx as Reverse-Proxy, but later replaced it with Traefik. The reverse proxy provides an encrypted HTTPS connection and makes it possible to run multiple websites on one server.

Step by step Nextcloud and Docker including access from the internet

Hardware requirement:
  1. Almost any hardware can be used for the Docker installation: For example, a virtual server of a provider, or for home: a PC, notebook, Raspberry PI, MAC, a NAS: QNAP, Synology or any other hardware on which Windows or Linux can be installed.
Internet access requirements:
  1. The secure access from the Internet is best done via a domain with a DNS entry to the public IP addres, see Domain and its management. In the case of a rented server from a provider, the provider assigns an IP address. If you want to operate a server in your own home network, you need to set up port forwarding.
  2. For the certificate management and access to the web services I use a reverse proxy and Let's Encrypt certificates.

As a basis for Nextcloud I originally used the following GitHub project and later adapted it: 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 thereverse proxy from the Nextcloud setup, allowing multiple web services to run with a respective SSL certificate. The Nextcloud installation is running on hardware in my case, at my home.

Container for Nextcloud:

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

docker-compose.yml

The docker-compose.yml file contains the configuration for the containers, such as the database user, domain, and network settings for the individual containers to communicate with each other. The file should be customized accordingly before the first launch (labels= section). As mentioned earlier, the setup described here requires a DNS entry on the IP of the Nextcloud installation in addition to Docker and the Traefik 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
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.next.rule=Host(`next.domain.tld`)"      
      - "traefik.http.routers.next.entrypoints=web"
      - "traefik.http.routers.next.entrypoints=websecure"
      - "traefik.http.routers.next.tls.certresolver=myresolver"  
    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

The file does not use volumes, but subfolders below the docker-compose.yml file

📢 A new post will probably be linked here on 2022-10-13: Docker Volumes vs Bind Mounts allow push notifications?
Additionally, a nginx config file is referenced in the docker-compose file, this is expected in the same folder:

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 creating or collaborate on Office documents online via the web browser. Prerequisite for the 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. The certificate is again defined via the environment variables can and automatically issued and renewed by the Traefik 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

The configuration for Collabora was only tested with the Nginx-LetsEncrypt reverse proxy therefore the reverse proxy setting is in the environment section and not in the labels section 

Add OnlyOffice

In addition, Word, Excel or PowerPoint documents can be edited online with Only-Office. Here, too ,an additional DNS name is required for access from the Internet : Traefik 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 have 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'
     labels:
      - "traefik.enable=true"
      - "traefik.http.routers.document.rule=Host(`document.domain.tld`)"      
      - "traefik.http.routers.document.entrypoints=web"
      - "traefik.http.routers.document.entrypoints=websecure"
      - "traefik.http.routers.document.tls.certresolver=myresolver"  
      - "traefik.http.middlewares.document-headers.headers.accesscontrolalloworiginlist=*"
      - "traefik.http.middlewares.document-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.document.middlewares=document-headers"
     environment:
        - JWT_ENABLED=true
        - JWT_SECRET=mysecret
        - 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'
     labels:
      - "traefik.enable=true"
      - "traefik.http.routers.document.rule=Host(`document.domain.tld`)"      
      - "traefik.http.routers.document.entrypoints=web"
      - "traefik.http.routers.document.entrypoints=websecure"
      - "traefik.http.routers.document.tls.certresolver=myresolver"  
      - "traefik.http.middlewares.document-headers.headers.accesscontrolalloworiginlist=*"
      - "traefik.http.middlewares.document-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.document.middlewares=document-headers"
     environment:
        - JWT_ENABLED=true
        - JWT_SECRET=mysecret
        - 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,
  ),
...

OnlyOffice Unknown error

After switching from Nginx-LetsEncrypt Reverse Proxy to Traefik, I had the following problem when calling documents: Unknown error. Press "OK" to reterun to document list

The cause was missing headers. In Traefik, these can be adjusted via middleware. The middleware is already inserted in the example above.

...
      - "traefik.http.middlewares.document-headers.headers.accesscontrolalloworiginlist=*"
      - "traefik.http.middlewares.document-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.document.middlewares=document-headers"
...

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

If files are added directly and not via the Nextcloud web interface, they can be detected and added via filescan:

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

To make the display in the image gallery work faster, the preview images can be generated in advance using the "Preview Generator" plugin.

After installing the app, the preview images can be generated using the following command:

docker exec --user www-data nextcloud_fpm php occ preview:generate-all -vvv

To ensure that new preview images are generated regularly, I added a cron job on the host system:

sudo crontab -e
15 3 * * * docker exec --user www-data nextcloud_fpm php occ preview:pre-generate > /dev/null 2>&1

see also: Linux CronJobs - scheduled tasks | Debian crontab [explained]

client_max_body_size

siehe nginx-LetsEncrypt Reverse Proxy in der Praxis

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!

Updated: 2022-09-20 von Bernhard


Top articles in this section


Home Assistant Docker Conbee 2 and Zigbee2MQTT / deCONZ
Thanks to numerous integration options,Home Assistant is a simple platform for controlling a wide range of smart home devices. Compared to ioBroker, I found it much easier to get started with Home Assistant. While for ioBroker I was still searching for which frontend I could use for my dashboards, with Home-Assistant I had a ready-made system out of the box. Home Assistant's Lovelance dashboards can be easily clicked together in the GUI and adapted for special customizations in the code editor...

Running Docker Mailserver yourself | a field report
With the help of a suitable Docker image, it is relatively easy to run a mail server yourself. I originally used the integrated mail server of the Host Europe vServer (Plesk) and came across a very simple Docker container while looking for a replacement. The lightweight container provides a mail server without a graphical management interface, but can be managed with a few simple commands. Any email client can be used to send and receive the mails, for this POP3 or IMAP is offered for receiving...

Commissioning Zigbee2MQTT in Docker - step by step
Zigbee2MQTT is an open source Zigbee bridge which can be easily integrated into existing smart home solutions thanks to the MQTT network protocol. As an example, Zigbee2MQTT combined with MQTT broker Mosquitto and Home Assistant can collect, display, record and control data from Zigbee devices. The setup described here uses Docker as a base. Manufacturer's website: https://www.zigbee2mqtt.io

Questions / Comments


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