Nextcloud Teil 1.5: Setup mit Docker, Nginx & PostgreSQL

Wer meine Artikel verfolgt dürfte wissen, dass ich vor knapp einem Monat bereits einen ähnlichen Artikel veröffentlich habe: Nextcloud Teil 1: Setup mit Docker & Nginx. Zu damaliger Zeit dachte ich, dass eine Installation mit SQLite als Datenbank vollkommen ausreichen würde. Und das tat es auch, bis ich dann eines Tages beschloss tausende kleiner Dateien gleichzeitig hochzuladen, einen Feedreader zu installieren und auch sonst die Datenbank bis aufs Äußerste zu belasten. Kurzum: Die Schwuppdizität leidete massiv darunter, was wiederum zu, äh, interessantem Fehlverhalten von Nextcloud führte. Anders gesagt: Ich wusste, ich brauche jetzt doch einen Datenbankserver.

Zusammengefasst entspricht dieser Artikel weitgehend dem vorherigen zu diesem Thema, nur dass hier zusätzlich noch PostgreSQL mit aufgesetzt wird. Daher lasse ich auch großartige Erläuterungen weg, wer genaueres wissen will kann diese ja im obig verlinkten Artikel nachlesen.

Docker installieren

# apt-get install apt-transport-https ca-certificates curl software-properties-common
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# apt-key fingerprint 0EBFCD88
# add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# apt-get update
# apt-get install docker

Docker Netzwerk erstellen

Damit die Container untereinander mittels Namensauflösung kommunizieren können (weil IP-Adressen standardmäßig nicht statisch vergeben werden), muss ein separates Netzwerk erstellt werden:

# docker network create --driver bridge nextcloud

PostgreSQL herunterladen & instanziieren

# docker pull postgres:9.6-alpine
# docker volume create --name postgres-data
# docker create -v postgres-data:/var/lib/postgresql/data -e POSTGRES_USER=nextcloud -e POSTGRES_PASSWORD='Password' -e POSTGRES_DB=nextcloud --net=nextcloud --name postgres postgres:9.6-alpine

Wichtig: Ich weiß nicht wieso, aber wenn man den Nutzer oder den Datenbanknamen auf postgres setzt (bzw. die Variablen nicht setzt, da der Standard "postgres" ist), fliegt das ganze – warum auch immer – auf die Fresse. Da müsste mal jemand™ einen Bugreport eröffnen oder dem nachgehen.

Nextcloud herunterladen & instanziieren

# docker pull nextcloud:12-apache
# docker volume create --name nextcloud-data
# docker create -v nextcloud-data:/var/www/html -p 127.0.0.1:32768:80 --net=nextcloud --name nextcloud nextcloud:12-apache

Nginx als Proxy konfigurieren

Den „server“-Abschnitt der nginx.conf wie folgt erweitern/ändern (die vorherige Installation und weitere Konfiguration lasse ich hier außen vor – dafür gibt es im Internet bereits ausreichend Artikel zu finden):

server {
    listen      443 ssl http2; # IPv4, SSL/TLS, HTTP/2
    listen [::]:443 ssl http2; # IPv6, SSL/TLS, HTTP/2
    server_name example.org;
    root /var/www/nextcloud;
    index index.html;
    # Let's Encrypt on port 443
    location ^~ /.well-known {
        root /var/www/letsencrypt;
    }

    # Raise file upload size
    client_max_body_size 512m;

    # Limit download size
    proxy_max_temp_file_size 4096m;

    # Proxy for nextcloud docker
    location / {
        # Headers are already set via https://github.com/nextcloud/server under lib/private/legacy/response.php#L242 (addSecurityHeaders()) 
        # We only need to set headers that aren't already set via nextcloud's addSecurityHeaders()-function 
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
        add_header Referrer-Policy "same-origin";

        # Secure Cookie / Allow cookies only over https
        # https://en.wikipedia.org/wiki/Secure_cookies
        # https://maximilian-boehm.com/hp2134/NGINX-as-Proxy-Rewrite-Set-Cookie-to-Secure-and-HttpOnly.htm
        proxy_cookie_path / "/; secure; HttpOnly";

        # And don't forget to include our proxy parameters
        #include /etc/nginx/proxy_params;
        proxy_set_header Host $http_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;

        # Connect to local port
        proxy_pass http://127.0.0.1:32768; # Don't use http://localhost:32768
    }
}

Dann noch speichern, die neue Konfiguration verifizieren („nginx -t“) und den Webserver die neue Konfiguration übernehmen lassen („systemctl reload nginx.service“).

Systemd service erstellen

Eine Datei /etc/systemd/system/docker-container@.service erstellen und mit folgendem Inhalt füllen:

[Unit]
Description=Docker Container %I
Requires=docker.service
After=docker.service

[Service]
Restart=always
ExecStart=/usr/bin/docker start -a %i
ExecStop=/usr/bin/docker stop -t 2 %i

[Install]
WantedBy=default.target

PostgreSQL & Nextcloud via systemctl starten

# systemctl enable docker-container@postgres.service
# systemctl enable docker-container@nextcloud.service
# systemctl start docker-container@postgres.service
# systemctl start docker-container@nextcloud.service

Cron aktivieren

Den Teil hatte ich letztes Mal auch nicht drin, daher eine kurze Erläuterung: Nextcloud läuft im Prinzip ohne Cron via Ajax. An sich 'ne coole Sache, einziges Problem dabei: Nicht alles lässt sich via Ajax machen. Also habe ich das einfachste gemacht was man machen kann: Den Cron-Service des Hosts dazu missbraucht um im Nextcloud-Docker-Container alle 15 Minuten cron.php laufen zu lassen. Muss auf dem Host wie folgt eingerichtet werden:

echo "*/15 *   * * *   root    /usr/bin/docker exec nextcloud su - www-data -s /bin/bash -c 'php -f /var/www/html/cron.php'" >> /etc/crontab

Nextcloud konfigurieren

Im Browser die Instanz aufrufen, dabei wieder Nutzername und Passwort vergeben. Bei Datenbank natürlich PostgreSQL auswählen und die Daten eingeben. Unter Host:Port kann dank Namensauflösung der Containername eingegeben werden, der Standardport ist 5432. Sah bei mir dann so aus: „postgres:5432“

Nginx als Proxy eintragen

Und zu guter Letzt noch Nginx als Proxy eintragen, weil sonst die Brute-Force-Protection nur localhost als Client-IP sieht und ratet mal, wie schnell das nach hinten losgeht…

Wo die Datei auf dem Host liegt bekommt man mittels „docker volume inspect nextcloud-data“ heraus, darin muss dann die Datei config/config.php erweitert werden:

[…]
  'trusted_proxies'   => ['172.17.0.1'],
  'overwritehost'     => 'example.org',
  'overwriteprotocol' => 'https',
  'overwritewebroot'  => '/',
  'overwritecondaddr' => '^172\.17\.0\.1$',
[…]

Welche IP Adresse man eintragen muss erfährt man via „docker network inspect bridge“.

Updates

Updates der Container laufen relativ simpel ab, prinzipiell ließe sich das auch mit einem systemd-timer schön automatisieren (wobei darauf geachtet werden sollte, dass man einem bestimmten Versionszweig folgt, so dass bspw. keine automatischen Upgrades passieren können):

PostgreSQL

# systemctl stop docker-container@postgres.service
# docker pull postgres:9.6-alpine
# docker container rm postgres
# docker create -v postgres-data:/var/lib/postgresql/data --net=nextcloud --name postgres postgres:9.6-alpine
# systemctl start docker-container@postgres.service

Nextcloud

# systemctl stop docker-container@nextcloud.service"
# docker pull nextcloud:12-apache
# docker container rm nextcloud
# docker create -v nextcloud-data:/var/www/html -p 127.0.0.1:32768:80 --net=nextcloud --name nextcloud nextcloud:12-apache
# systemctl start docker-container@nextcloud.service

Fertig.

Damit wäre alles fertig eingerichtet. Als nächstes folgt dann Teil 2 (d.h., eigentlich ja Teil 3…). Wenn dieser fertig ist reiche hier im Artikel den Link natürlich nach.