Nextcloud Serverinstallation auf Almalinux 9.x und Debian 12

# Nextcloud Serverinstallation auf Almalinux 9.x und Debian 12 mit Docker Compose, Nginx als Reverse Proxy und Monitoring von Docker erstellen

Version: 1.2 2024-01-04 15:00 Simon Rieger

1. Almalinux herunterladen und installieren
   1.1 Almalinux herunterladen
   1.2 Debian herunterladen
   1.3 Hardwareanforderungen beachten
   1.4 Zeitzone einstellen
   1.5 Root-Benutzer deaktivieren und nli-server Benutzer anlegen
   1.6 Netzwerkeinstellungen
   1.7 Minimalinstallation durchführen

2. Distribution starten und Docker Compose einrichten
   2.1 Installation unter Almalinux
   2.2 Installation unter Vsphere
   2.3 Installation unter Debian
   2.4 Docker-Daemon Service setzen
   2.5 Chrony einrichten
   2.6 Einrichten von mehreren Festplatten

3. Installieren von Nextcloud
   3.1 Ordnerstrukturen anlegen
   3.2 Docker-Datei erstellen
   3.3 Nextcloud Server starten
   3.4 Verbindung zur Nextcloud per Port Forwarding herstellen
   3.5 Reverse Proxy mit Nginx einrichten
   3.6 Admin Benutzer für die Nextcloud anlegen
   3.7 Optimierungen

4. Nextcloud Cron einrichten

5. Nextcloud Container updaten
   5.1 Neue Nextcloud Hauptversion verwendet
   5.2 Docker Container updaten

6. Datenbank und Dateien von einer bereits vorhandenen Instanz migrieren
   6.1 Weitere Optimierungen an der Datenbank nach der Migration

7. Volltextsuche und OCR mit migrieren und installieren
   7.1. Anpassungen für ImageMagick
   7.2. Anpassung für Nextcloud
   7.3. Anpassungen für ElasticSearch

8. Quellen

- Hinweis: bei der nachfolgenden Anleitung ist der Domainname durch den Namen "webseite" auszutauschen.

## Almalinux herunterladen und installieren

Almalinux kann über folgenden Direktlink herunterladen werden:

Link zum herunterladen von Almalinux

oder Debian unter diesem Link:

Link zum herunterladen von Debian

Bitte darauf achten das man eine Festplatte mit mindesten 64 GB als Datenträger, 2 vCPUs und 4 GB RAM einbindet.

Anschließend muss die Zeitzone auf Europe/Berlin eingestellt werden.

Den Root-Benutzer kann man deaktivieren und als Benutzer "nli-server" mit Administratorrechten anlegen.

Falls das Netzwerk noch statisch eingerichtet werden muss, kann dies unter dem Reiter Netwerk eingerichtet werden, dabei kann auch noch der Hostname gesetzt werden, anschließend muss der Schriit noch extra bestätigt werden.

Bitte noch darauf achten das man eine Minimalinstallation ausgewählt hat und nicht eine normale mit der Standardsoftware von Almalinux, weil sonst der Gnome Desktop mit installiert wird und den brauchen wir nicht für einen Server.

## Distrubtion starten und docker compose einrichten

Anschließend kann man die VM neustarten und sich per SSH auf dem eben bereits erstellen Benutzer verbinden.

### Installation unter Almalinux

Für die Installation von Docker Compose können wir die Offiziele Dokumentation von CentOS verwenden, da Almalinux mehr oder weniger ein Fork davon ist.

Link für die Installation von Docker

Um die Packete des Systems upzudaten führen wir folgenden Kommando aus:

    sudo dnf update

    sudo dnf update

Wir integrieren das Repository nun erstmal in die yum Konfiguration.

    sudo yum install -y yum-utils
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

    sudo yum install -y yum-utils
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

Danach installieren wir Docker Compose mittels diesen Befehls hier.

    sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

### Installation unter Vsphere

Für die Installation unter Vsphere werden noch die Open-VM-tools benötigt.

Diese kann man mit folgendem Befehl installieren.

    dnf install open-vm-tools

    dnf install open-vm-tools

Nun muss der Befehl noch als Autostart eingerichtet werden mit folgendem Befehl:

    systemctl enable --now vmtoolsd

    systemctl enable --now vmtoolsd

und man kann dies nun überprüfen mit

    systemctl status vmtoolsd

    systemctl status vmtoolsd

### Installation unter Debian

Für die Installation von Docker Compose können wir die Offiziele Dokumentation von Debian verwenden,

Link für die Installation von Docker

Um die Packete des Systems upzudaten führen wir folgenden Kommando aus:

    sudo apt update && sudo apt upgrade

    sudo apt update && sudo apt upgrade

    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg

    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg

    echo \
      "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
      "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

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

    sudo apt-get update
    sudo apt-get install ca-certificates curl gnupg

    sudo install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    sudo chmod a+r /etc/apt/keyrings/docker.gpg

    echo \
      "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
      "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

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

### Docker-Daemon Service setzen

Und richten Docker als Systemd-Service ein und starten den auch gleichzeitig.

    sudo systemctl enable --now docker

    sudo systemctl enable --now docker

Anschließend testen wir mit folgendem Befehl, ob Docker ordnungsgemäß funktioniert.

    sudo docker run hello-world

    sudo docker run hello-world

## Chrony einrichten

Um den Zeitserver einzurichten bitte noch folgende Befehle als ROOT ausführen:

    dnf install chrony

    dnf install chrony

Crony als Systemweiten Service einrichten

    systemctl enable --now chronyd

    systemctl enable --now chronyd

die Firewall noch ergänzen

    firewall-cmd --permanent --add-service=ntp
    firewall-cmd --reload

    firewall-cmd --permanent --add-service=ntp
    firewall-cmd --reload

und danach nochmal neustarten

    systemctl restart chronyd

    systemctl restart chronyd

## Einrichten von mehreren Festplatten

Wenn man die Daten getrennt von dem Betriebssytem haben möchte, formatiert man erstmal die neue Festplatte mit fdisk. Mit folgendem Befehl sehen wir uns die verfügbaren Festplatten genauer an.

    fdisk -l

    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/sdb: 64 GiB, 68719476736 bytes, 134217728 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: gpt
    Disk identifier: 8A25CA1F-8A16-471D-B928-C0EF5BD7B174

    Device       Start       End   Sectors  Size Type
    /dev/sdb1     2048   1230847   1228800  600M EFI System
    /dev/sdb2  1230848   3327999   2097152    1G Linux filesystem
    /dev/sdb3  3328000 134215679 130887680 62.4G Linux LVM

    Disk /dev/mapper/almalinux-root: 37.63 GiB, 40407924736 bytes, 78921728 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/mapper/almalinux-swap: 6.4 GiB, 6874464256 bytes, 13426688 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/mapper/almalinux-home: 18.38 GiB, 19730006016 bytes, 38535168 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    fdisk -l

    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/sdb: 64 GiB, 68719476736 bytes, 134217728 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: gpt
    Disk identifier: 8A25CA1F-8A16-471D-B928-C0EF5BD7B174

    Device       Start       End   Sectors  Size Type
    /dev/sdb1     2048   1230847   1228800  600M EFI System
    /dev/sdb2  1230848   3327999   2097152    1G Linux filesystem
    /dev/sdb3  3328000 134215679 130887680 62.4G Linux LVM

    Disk /dev/mapper/almalinux-root: 37.63 GiB, 40407924736 bytes, 78921728 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/mapper/almalinux-swap: 6.4 GiB, 6874464256 bytes, 13426688 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

    Disk /dev/mapper/almalinux-home: 18.38 GiB, 19730006016 bytes, 38535168 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes

Um /dev/sdb handelt es sich die Systempartition, deswegen wählen wir nun mit fdisk die Festplatte /dev/sda aus.

    [root@SST-S-440 ~]# fdisk /dev/sda

    Welcome to fdisk (util-linux 2.37.4).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.

    Device does not contain a recognized partition table.
    Created a new DOS disklabel with disk identifier 0xbbcd0e1c.

    Command (m for help): p
    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: dos
    Disk identifier: 0xbbcd0e1c

    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p):

    Using default response p.
    Partition number (1-4, default 1):
    First sector (2048-2147483647, default 2048):
    Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-2147483647, default 2147483647):

    Created a new partition 1 of type 'Linux' and of size 1024 GiB.

    Command (m for help):

    Command (m for help): p

    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: dos
    Disk identifier: 0xbbcd0e1c

    Device     Boot Start        End    Sectors  Size Id Type
    /dev/sda1        2048 2147483647 2147481600 1024G 83 Linux

    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.

    [root@SST-S-440 ~]# fdisk /dev/sda

    Welcome to fdisk (util-linux 2.37.4).
    Changes will remain in memory only, until you decide to write them.
    Be careful before using the write command.

    Device does not contain a recognized partition table.
    Created a new DOS disklabel with disk identifier 0xbbcd0e1c.

    Command (m for help): p
    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: dos
    Disk identifier: 0xbbcd0e1c

    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p):

    Using default response p.
    Partition number (1-4, default 1):
    First sector (2048-2147483647, default 2048):
    Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-2147483647, default 2147483647):

    Created a new partition 1 of type 'Linux' and of size 1024 GiB.

    Command (m for help):

    Command (m for help): p

    Disk /dev/sda: 1 TiB, 1099511627776 bytes, 2147483648 sectors
    Disk model: Virtual Disk
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 4096 bytes
    I/O size (minimum/optimal): 4096 bytes / 4096 bytes
    Disklabel type: dos
    Disk identifier: 0xbbcd0e1c

    Device     Boot Start        End    Sectors  Size Id Type
    /dev/sda1        2048 2147483647 2147481600 1024G 83 Linux

    Command (m for help): w
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.

Und formatiert sie anschließend mit ext4.

    [root@SST-S-440 ~]# mkfs.ext4 /dev/sda1
    mke2fs 1.46.5 (30-Dec-2021)
    Discarding device blocks: done
    Creating filesystem with 268435200 4k blocks and 67108864 inodes
    Filesystem UUID: 4a3937fd-26b9-4dd2-9937-d441569a5c5e
    Superblock backups stored on blocks:
            32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
            4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
            102400000, 214990848

    Allocating group tables: done
    Writing inode tables: done
    Creating journal (262144 blocks): done
    Writing superblocks and filesystem accounting information: done

    [root@SST-S-440 ~]# mkfs.ext4 /dev/sda1
    mke2fs 1.46.5 (30-Dec-2021)
    Discarding device blocks: done
    Creating filesystem with 268435200 4k blocks and 67108864 inodes
    Filesystem UUID: 4a3937fd-26b9-4dd2-9937-d441569a5c5e
    Superblock backups stored on blocks:
            32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
            4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968,
            102400000, 214990848

    Allocating group tables: done
    Writing inode tables: done
    Creating journal (262144 blocks): done
    Writing superblocks and filesystem accounting information: done

Damit sie beim nächsten Start automatisch gemounted wird, trägt man die Festplatte noch in die Fstab ein. Davor müssen wir ersteinmal die UUID der Festplatte herausfinden.

    blkid

    blkid

und danach denn Ordner erstellen und die /etc/fstab bearbeiten.

    mkdir -p /opt/data
    nano /etc/fstab

    mkdir -p /opt/data
    nano /etc/fstab

mit folgendem Inhalt ergänzen:

    UUID="4a3937fd-26b9-4dd2-9937-d441569a5c5e" /opt/data ext4 defaults 0 0

    UUID="4a3937fd-26b9-4dd2-9937-d441569a5c5e" /opt/data ext4 defaults 0 0

und anschließend mit STRG + X und dann Y abspeicher und den automatischen Mount ausführen.

    mount -a

    mount -a

## Installieren von der Nextcloud

Zuerst legen wir uns passende Ordner-Strukturen an.

    mkdir -p /opt/containers/nextcloud/{db,app,daten}

    mkdir -p /opt/containers/nextcloud/{db,app,daten}

und Optional falls man die Daten von Nextcloud wo anders gespeichert haben möchte.

    mkdir -p /opt/data/nextcloud/daten

    mkdir -p /opt/data/nextcloud/daten

Um den Texteditor Nano und Vim zu installieren, benutzt ihr folgenden Befehl.

    sudo dnf install nano vim bash-completion

    sudo dnf install nano vim bash-completion

oder für Debian:

    sudo apt install nano vim bash-completion

    sudo apt install nano vim bash-completion

Nun legen wir die eigentliche Docker Datei an. Hierfür habe ich mir die offizielle Nextcloud Compose genommen und etwas modifiziert. Die Datei könnt ihr mit dem Editor eurer Wahl bearbeiten.

Offizielle Nextcloud Compose Anleitung

    nano /opt/containers/nextcloud/docker-compose.yml

    nano /opt/containers/nextcloud/docker-compose.yml

docker-compose.yml

    version: '3.3'

    services:
      nextcloud-db:
        image: mariadb:10.6
        container_name: nextcloud-db
        restart: always
        command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
        volumes:
          - ./db:/var/lib/mysql
        environment:
          - MYSQL_ROOT_PASSWORD=rootpass
          - MYSQL_PASSWORD=userpass
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=nextcloud
          - MYSQL_INITDB_SKIP_TZINFO=1
          - MARIADB_AUTO_UPGRADE=1
        networks:
          - default
        ports:
          - 127.0.0.1:3306:3306

      nextcloud-redis:
        image: redis:alpine
        container_name: nextcloud-redis
        hostname: nextcloud-redis
        restart: always
        command: redis-server --requirepass redispass
        networks:
          - default

      nextcloud-app:
        image: nextcloud:27
        container_name: nextcloud-app
        restart: always
        ports:
          - 8080:80
        depends_on:
          - nextcloud-db
          - nextcloud-redis
        volumes:
          - ./app:/var/www/html
          - /opt/data/nextcloud/daten:/var/www/html/data
        environment:
          - MYSQL_PASSWORD=userpass
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=nextcloud
          - MYSQL_HOST=nextcloud-db
          - TRUSTED_PROXIES=10.161.24.10/24
          #- OVERWRITEPROTOCOL=https
          #- OVERWRITECLIURL=https://cloud.webseite.com
          #- OVERWRITEHOST=cloud.webseite.com
          - REDIS_HOST=nextcloud-redis
          - REDIS_HOST_PASSWORD=redispass
          - PHP_MEMORY_LIMIT=2G
          - PHP_UPLOAD_LIMIT=2G
          - NEXTCLOUD_TRUSTED_DOMAINS=10.161.24.1
        networks:
          - default

    version: '3.3'

    services:
      nextcloud-db:
        image: mariadb:10.6
        container_name: nextcloud-db
        restart: always
        command: --transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW
        volumes:
          - ./db:/var/lib/mysql
        environment:
          - MYSQL_ROOT_PASSWORD=rootpass
          - MYSQL_PASSWORD=userpass
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=nextcloud
          - MYSQL_INITDB_SKIP_TZINFO=1
          - MARIADB_AUTO_UPGRADE=1
        networks:
          - default
        ports:
          - 127.0.0.1:3306:3306

      nextcloud-redis:
        image: redis:alpine
        container_name: nextcloud-redis
        hostname: nextcloud-redis
        restart: always
        command: redis-server --requirepass redispass
        networks:
          - default

      nextcloud-app:
        image: nextcloud:27
        container_name: nextcloud-app
        restart: always
        ports:
          - 8080:80
        depends_on:
          - nextcloud-db
          - nextcloud-redis
        volumes:
          - ./app:/var/www/html
          - /opt/data/nextcloud/daten:/var/www/html/data
        environment:
          - MYSQL_PASSWORD=userpass
          - MYSQL_DATABASE=nextcloud
          - MYSQL_USER=nextcloud
          - MYSQL_HOST=nextcloud-db
          - TRUSTED_PROXIES=10.161.24.10/24
          #- OVERWRITEPROTOCOL=https
          #- OVERWRITECLIURL=https://cloud.webseite.com
          #- OVERWRITEHOST=cloud.webseite.com
          - REDIS_HOST=nextcloud-redis
          - REDIS_HOST_PASSWORD=redispass
          - PHP_MEMORY_LIMIT=2G
          - PHP_UPLOAD_LIMIT=2G
          - NEXTCLOUD_TRUSTED_DOMAINS=10.161.24.1
        networks:
          - default

Die Umgebgungsvariablen OVERWRITEPROTOCOL, OVERWRITECLIURL und OVERWRITEHOST sollten erst gesetzt worden sein, wenn der Reverse Proxy mit SSL-Zertifikat bereits eingerichtet wurde.

Falls eventuell das automatische anlegen der Datenbank, oder die Datenbank nicht von der Nextcloud automatisch übernommen wurde kann mit dem Tool dos2unix der Text in das Unix Format konventiert werden.

## Nextcloud Server starten

Den Server startet ihr wie gewohnt mit folgendem Befehl:

    docker compose -f /opt/containers/nextcloud/docker-compose.yml up -d

    docker compose -f /opt/containers/nextcloud/docker-compose.yml up -d

Falls Probleme auftreten solltet, wechselt in das Verzeichnis wo die Docker Compose Datei liegt und für einen dieser folgenden Befehlen aus.

    cd /opt/containers/nextcloud/

    docker compose logs nextcloud-app
    docker compose logs nextcloud-db
    docker compose logs nextcloud-redis

    cd /opt/containers/nextcloud/

    docker compose logs nextcloud-app
    docker compose logs nextcloud-db
    docker compose logs nextcloud-redis

## Verbindung zur Nextcloud per Port Forwarding herstellen

Falls ihr noch nicht auf eure Nextcloud zugreifen könnt, weil sie von einer Firewall blockiert wird, oder auf einem anderem Server liegt könnt ihr mittels Port Forwarding drauf zugreifen.

Unter Linux verwendet ihr folgenden Befehl:

    ssh -L 8080:127.0.0.1:8080 server -N

    ssh -L 8080:127.0.0.1:8080 server -N

Unter Putty fügt ihr fügt ihr folgendes im Connection -> SSH -> Tunnels reiter hinzu.

## Reverse Proxy mit Nginx einrichten

Den Reverse Proxy Nginx installieren wir lokal auf das System ohne Docker zu verwenden.
Für das Zertifikat benutzen wir Let´s Encrypt und automatisieren es mit Certbot.

Installieren können wir die Packete mit:

    sudo dnf install epel-release

    sudo dnf install certbot python3-certbot-nginx nginx

    sudo dnf install epel-release

    sudo dnf install certbot python3-certbot-nginx nginx

oder für Debian:

    sudo apt install python3-certbot-nginx nginx

    sudo apt install python3-certbot-nginx nginx

und überprüfen danach ob nun Certbot vorhanden ist.

    certbot --version

    certbot --version

Für Almalinux fügen wir noch ein paar Firewall-Regeln hinzu.

    sudo firewall-cmd --permanent --add-port=80/tcp --zone=public
    sudo firewall-cmd --permanent --add-port=443/tcp --zone=public
    sudo firewall-cmd --reload

    setsebool -P httpd_can_network_connect 1

    sudo cat /var/log/audit/audit.log | grep nginx | grep denied

    sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M mynginx
    sudo semodule -i mynginx.pp

    setsebool -P httpd_can_network_relay 1

    sudo firewall-cmd --permanent --add-port=80/tcp --zone=public
    sudo firewall-cmd --permanent --add-port=443/tcp --zone=public
    sudo firewall-cmd --reload

    setsebool -P httpd_can_network_connect 1

    sudo cat /var/log/audit/audit.log | grep nginx | grep denied

    sudo cat /var/log/audit/audit.log | grep nginx | grep denied | audit2allow -M mynginx
    sudo semodule -i mynginx.pp

    setsebool -P httpd_can_network_relay 1

Dann erstellen wir die Konfiguration des Reverse Proxys. Das geht am einfachsten mit dem Tool von DigitalOcean.

Ich habe hier bereits eine vorkonfiguriete Konfiguration erstellt, dort müsst ihr einfach nur den Domain-Namen ändern.

Was noch zu beachten ist, das man noch in der Konfiguration bei Debian den Benutzer und die Gruppe für den zu benötigten User noch anpasst.

Vorkonfigurierte Nginx Konfiguration

Ihr drückt dann einmal auf Als Base64 kopieren und follgt dementsprechend die Anleitung.

Hier nochmal die vollständige Anleitung.

kopiere einen Base64 String der komprimierten Konfiguration, füge ihn auf der Kommandozeile deines Servers ein und führe ihn aus.

Wechsle in das NGINX Konfigurationsverzeichnis deines Servers:

    cd /etc/nginx

    cd /etc/nginx

Erstelle ein Backup deiner aktuellen NGINX Konfiguration:

    tar -czvf nginx_$(date +'%F_%H-%M-%S').tar.gz nginx.conf sites-available/ sites-enabled/ nginxconfig.io/

    tar -czvf nginx_$(date +'%F_%H-%M-%S').tar.gz nginx.conf sites-available/ sites-enabled/ nginxconfig.io/

Entpacke das komprimierte Konfigurationsverzeichnis mittels tar:

    tar -xzvf nginxconfig.io-cloud.webseite.com.tar.gz | xargs chmod 0644

    tar -xzvf nginxconfig.io-cloud.webseite.com.tar.gz | xargs chmod 0644

Erzeuge Diffie-Hellman Schlüssel indem du diesen Befehl auf deinem Server ausführst:

    openssl dhparam -out /etc/nginx/dhparam.pem 2048

    openssl dhparam -out /etc/nginx/dhparam.pem 2048

Erstelle ein ACME-Challenge Verzeichnis (für Let's Encrypt):

    mkdir -p /var/www/_letsencrypt
    chown nginx /var/www/_letsencrypt

    mkdir -p /var/www/_letsencrypt
    chown nginx /var/www/_letsencrypt

Kommentiere SSL-relevante Direktiven in deiner Konfiguration aus:

    sed -i -r 's/(listen .*443)/\1; #/g; s/(ssl_(certificate|certificate_key|trusted_certificate) )/#;#\1/g; s/(server \{)/\1\n    ssl off;/g' /etc/nginx/sites-available/cloud.webseite.com.conf

    sed -i -r 's/(listen .*443)/\1; #/g; s/(ssl_(certificate|certificate_key|trusted_certificate) )/#;#\1/g; s/(server \{)/\1\n    ssl off;/g' /etc/nginx/sites-available/cloud.webseite.com.conf

This command will add a temporary ssl off directive to ensure that SSL directives are not active. This may cause NGINX to emit a warning, which is safe to ignore. The directive will be removed once Certbot is configured.

Führe einen reload deines NGINX Server aus:

    sudo nginx -t && sudo systemctl reload nginx

    sudo nginx -t && sudo systemctl reload nginx

Erhalte SSL Zertifikate von Let's Encrypt mittels Certbot:

    certbot certonly --webroot -d cloud.webseite.com --email support@webseite.com -w /var/www/_letsencrypt -n --agree-tos --force-renewal

    certbot certonly --webroot -d cloud.webseite.com --email support@webseite.com -w /var/www/_letsencrypt -n --agree-tos --force-renewal

Kommentiere SSL-relevante Direktiven in deiner Konfiguration ein:

    sed -i -r -z 's/#?; ?#//g; s/(server \{)\n    ssl off;/\1/g' /etc/nginx/sites-available/cloud.webseite.com.conf

    sed -i -r -z 's/#?; ?#//g; s/(server \{)\n    ssl off;/\1/g' /etc/nginx/sites-available/cloud.webseite.com.conf

Führe einen reload deines NGINX Server aus:

    sudo nginx -t && sudo systemctl reload nginx

    sudo nginx -t && sudo systemctl reload nginx

Konfiguriere Certbot um NGINX neu zu laden, wenn die Zertifikate erfolgreich erneuert wurden:

    echo -e '#!/bin/bash\nnginx -t && systemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
    sudo chmod a+x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh

    echo -e '#!/bin/bash\nnginx -t && systemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
    sudo chmod a+x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh

Jetzt gehts los! 🎉

Lade NGINX neu, um deine neue Konfiguration zu verwenden:

    sudo nginx -t && sudo systemctl reload nginx

    sudo nginx -t && sudo systemctl reload nginx

Und damit das zukünftige neuerstellen der Zertifikate möglich ist

    systemctl enable --now certbot-renew.timer

    systemctl enable --now certbot-renew.timer

Dann modifizieren wir noch die cloud.webseite.com.conf im nginx Verzeichnis.

    nano /etc/nginx/sites-available/cloud.webseite.com.conf

    nano /etc/nginx/sites-available/cloud.webseite.com.conf

cloud.webseite.com.conf

Wir fügen noch diese Einträge dort hinzu:

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

        location /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }

        location /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

        location /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }

        location /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

Und dokumentieren schließlich diesen Bereich aus:

        include                 nginxconfig.io/security.conf;

        include                 nginxconfig.io/security.conf;

So das es schließlich so aussieht:

    server {
        listen                  443 ssl http2;
        listen                  [::]:443 ssl http2;
        server_name             cloud.webseite.com;

        # SSL
        ssl_certificate         /etc/letsencrypt/live/cloud.webseite.com/fullchain.pem;
        ssl_certificate_key     /etc/letsencrypt/live/cloud.webseite.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/cloud.webseite.com/chain.pem;

        # security
        #include                 nginxconfig.io/security.conf;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

        # logging
        access_log              /var/log/nginx/cloud.webseite.com-access.log combined buffer=512k flush=1m;
        error_log               /var/log/nginx/cloud.webseite.com-error.log warn;

        # reverse proxy
        location / {
            proxy_pass            http://127.0.0.1:8080;
            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;
            include               nginxconfig.io/proxy.conf;
        }

        location /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }

        location /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

        # additional config
        include nginxconfig.io/general.conf;
    }

    # HTTP redirect
    server {
        listen      80;
        listen      [::]:80;
        server_name cloud.webseite.com;

        # logging
        access_log  /var/log/nginx/cloud.webseite.com-access.log combined buffer=512k flush=1m;
        error_log   /var/log/nginx/cloud.webseite.com-error.log warn;
        include     nginxconfig.io/letsencrypt.conf;

        location / {
            return 301 https://cloud.webseite.com$request_uri;
        }
    }

    server {
        listen                  443 ssl http2;
        listen                  [::]:443 ssl http2;
        server_name             cloud.webseite.com;

        # SSL
        ssl_certificate         /etc/letsencrypt/live/cloud.webseite.com/fullchain.pem;
        ssl_certificate_key     /etc/letsencrypt/live/cloud.webseite.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/cloud.webseite.com/chain.pem;

        # security
        #include                 nginxconfig.io/security.conf;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";

        # logging
        access_log              /var/log/nginx/cloud.webseite.com-access.log combined buffer=512k flush=1m;
        error_log               /var/log/nginx/cloud.webseite.com-error.log warn;

        # reverse proxy
        location / {
            proxy_pass            http://127.0.0.1:8080;
            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;
            include               nginxconfig.io/proxy.conf;
        }

        location /.well-known/carddav {
            return 301 $scheme://$host/remote.php/dav;
        }

        location /.well-known/caldav {
            return 301 $scheme://$host/remote.php/dav;
        }

        # additional config
        include nginxconfig.io/general.conf;
    }

    # HTTP redirect
    server {
        listen      80;
        listen      [::]:80;
        server_name cloud.webseite.com;

        # logging
        access_log  /var/log/nginx/cloud.webseite.com-access.log combined buffer=512k flush=1m;
        error_log   /var/log/nginx/cloud.webseite.com-error.log warn;
        include     nginxconfig.io/letsencrypt.conf;

        location / {
            return 301 https://cloud.webseite.com$request_uri;
        }
    }

Und das war es eigentlich schon, wichtig dabei ist das euer Server als A-Record im Domainbestellsystem hinterlegt worden ist.

## Admin Benutzer für die Nextcloud anlegen

Wir öffnen dann die Webseite zur Nextcloud: Link zur Nextcloud

Wichtig dabei zu beachten ist, wenn der Admin Benutzer angelegt ist, ist nur noch ein Zugriff über den Reverse Proxy mit Nginx auf dem OVERWRITECLIURL möglich der dann im vorherigen Schritt eingerichtet wurde. Deswegen ist es auch Sinnvoll erst diesen Schritt erst auszuführen wenn der Nginx auch komplett läuft und auf die FQDN zugreifen kann.

## Optimierungen

Wenn ihr oben rechts auf eueren “Buchstaben”. Dann wählt ihr “Einstellungen” -> “Übersicht” aus. Nun solltet ihr feststellen, dass Nextcloud noch “Optimierungsbedarf” sieht. Dies wollen wir nun tun.

(https://goneuland.de/wp-content/uploads/2022/01/nextcloud23-001.png)

### Standardtelefonregion festlegen

Dazu öffnet ihr folgende Datei:

    nano /opt/containers/nextcloud/app/config/config.php

    nano /opt/containers/nextcloud/app/config/config.php

Fügt nun folgende Zeile hinzu:

     'default_phone_region' => 'DE',

     'default_phone_region' => 'DE',

Dies setzt die Standardregion auf Deutschland. Beispiele dazu findet ihr hier. Nun könnt ihr die Datei wieder schließen.

Bei mir sieht es dann so aus:

      'dbuser' => 'nextcloud',
      'dbpassword' => 'test',
      'installed' => true,
      'default_phone_region' => 'DE',
    );

      'dbuser' => 'nextcloud',
      'dbpassword' => 'test',
      'installed' => true,
      'default_phone_region' => 'DE',
    );

## Container neu starten

Nun starten wir Nextcloud neu um sicherzugehen, dass alle Einstellungen übernommen werden.

    docker compose -f /opt/containers/nextcloud/docker-compose.yml down

    docker compose -f /opt/containers/nextcloud/docker-compose.yml up -d

    docker compose -f /opt/containers/nextcloud/docker-compose.yml down

    docker compose -f /opt/containers/nextcloud/docker-compose.yml up -d

Nun sollte es so aussehen:

(https://goneuland.de/wp-content/uploads/2022/01/nextcloud23-004.png)

## Nextcloud Cron einrichten

Nun fügen wir auf unserem Server noch einen Cron Eintrag hinzu. Dieser bewirkt, dass Nextcloud alle 5 Minuten die Hintergrundjobs abarbeitet. Um Cron zu starten gebt ihr folgendes ein:

    crontab -e

    crontab -e

Beim ersten Start erscheint nun folgende Meldung. Wählt hier “1” aus.

    no crontab for root - using an empty one

    Select an editor.  To change later, run 'select-editor'.
      1. /bin/nano        <---- easiest
      2. /usr/bin/vim.tiny

    Choose 1-2 [1]: 1

    no crontab for root - using an empty one

    Select an editor.  To change later, run 'select-editor'.
      1. /bin/nano        <---- easiest
      2. /usr/bin/vim.tiny

    Choose 1-2 [1]: 1

Hier fügt ihr nun folgende Zeile hinzu:

    */5 * * * * docker exec -u www-data nextcloud-app-1 php cron.php

    */5 * * * * docker exec -u www-data nextcloud-app-1 php cron.php

Diese Zeile bewirkt, dass euer Server alle 5 Minuten die “cron.php” Datei ausführt in eurem Nextcloud Container.

Nachdem ihr dies eingerichtet habt, könnt ihr dies auch kontrollieren. Geht dazu in eure Nextcloud als Administrator. Wählt dann bei Hintergrundaufgaben noch “Cron (Empfohlen)”. Hier solltet ihr nun folgendes in den Einstellungen sehen. Wichtig ist, dass die “Letzte Aufgabe ausgeführt…” maximal 5 Minuten sein sollte. Wenn dies so ist, dann funktioniert alles.

(https://goneuland.de/wp-content/uploads/2022/09/nextcloud-cron.png)

## Nextcloud Container updaten

Man kann den Nextcloud Container Updaten, indem man in folgendes Verzeichnis wechselt und die docker-compose.yml bearbeitet:

    cd /opt/containers/nextcloud
    nano docker-compose.yml

    cd /opt/containers/nextcloud
    nano docker-compose.yml

Falls man bei dieser Hauptversion bleiben möchte, dann bitte den nächsten Schritt überspringen.

## Neue Nextcloud Hauptversion verwendet

Wichtig dabei zu beachten, wenn man noch die Hauptversion updaten will auch den Tag von Version zu Version hochzuzählen.

    nextcloud-app:
        image: nextcloud:27

    nextcloud-app:
        image: nextcloud:27

In diesem Falle die Version nextcloud:27 zu nextcloud:28, aber nicht von Version 27 zu 29.

Eventuell muss man auch die Version der MariaDB Datenbank hochzählen, falls die neue Version die ältere Datenbank nicht mehr unterstützt wird.

Unter folgendem Link kann man sich die Tags zu den Nextcloud Versionen anzeigen lassen.

## Docker Container updaten

Um nun die neue Version von Nextcloud herunterzuladen machen wir erst einmal ein Backup von den Container, da Backups wichtig und richtig sind.

    cd /opt/containers/
    tar -czf nextcloud-backup-$(date "+%F").tar.gz nextcloud/

    cd /opt/containers/
    tar -czf nextcloud-backup-$(date "+%F").tar.gz nextcloud/

nun müssen folgende Befehle ausgeführt werden damit die neuen Images gepulled werden und anschließend ausgeführt werden.

    cd nextcloud
    docker compose pull
    docker compose up -d

    cd nextcloud
    docker compose pull
    docker compose up -d

## Datenbank und Dateien von einer bereits vorhandenen Instanz migrieren

Hierdurch werden die Nextcloud Datenbank vom alten System gedumpt:

    mysqldump --single-transaction --default-character-set=utf8mb4 -h 127.0.0.1 -u root -p nextcloud > NextCloud-dump-2023-07-24.sql

    mysqldump --single-transaction --default-character-set=utf8mb4 -h 127.0.0.1 -u root -p nextcloud > NextCloud-dump-2023-07-24.sql

und anschließend auf das neue System hinzugefügt:

    mysql -h 127.0.0.1 -u nextcloud -p nextcloud < NextCloud-dump.sql
    ./occ upgrade

    mysql -h 127.0.0.1 -u nextcloud -p nextcloud < NextCloud-dump.sql
    ./occ upgrade

    Nextcloud or one of the apps require upgrade - only a limited number of commands are available
    You may use your browser or the occ upgrade command to do the upgrade
    Setting log level to debug
    Updating database schema
    Updated database
    Updating <files> ...
    Updated <files> to 1.22.0
    Updating <activity> ...
    Updated <activity> to 2.19.0
    Updating <circles> ...
    Updated <circles> to 27.0.1
    Updating <cloud_federation_api> ...
    Updated <cloud_federation_api> to 1.10.0
    Updating <dav> ...

    Fix broken values of calendar objects

     Done
        0/0 [->--------------------------]   0%
    Clean up old calendar subscriptions from deleted users that were not cleaned-up
     Done
        0/0 [----->----------------------]   0%
    Updated <dav> to 1.27.0
    Updating <encryption> ...
    Updated <encryption> to 2.15.0
    Updating <files_sharing> ...
    Updated <files_sharing> to 1.19.0
    Updating <files_trashbin> ...
    Updated <files_trashbin> to 1.17.0
    Updating <files_versions> ...
    Updated <files_versions> to 1.20.0
    Updating <sharebymail> ...
    Updated <sharebymail> to 1.17.0
    Updating <workflowengine> ...
    Updated <workflowengine> to 2.9.0
    Updating <admin_audit> ...
    Updated <admin_audit> to 1.17.0
    Updating <comments> ...
    Updated <comments> to 1.17.0
    Updating <notifications> ...
    Updated <notifications> to 2.15.0
    Updating <systemtags> ...
    Updated <systemtags> to 1.17.0
    Updating <theming> ...
    Migrate old user accessibility config
     Done
      471/471 [============================] 100%
    Updated <theming> to 2.2.0
    Updating <bruteforcesettings> ...
    Updated <bruteforcesettings> to 2.7.0
    Updating <contactsinteraction> ...
    Updated <contactsinteraction> to 1.8.0
    Updating <dashboard> ...
    Updated <dashboard> to 7.7.0
    Updating <federatedfilesharing> ...
    Updated <federatedfilesharing> to 1.17.0
    Updating <files_pdfviewer> ...
    Updated <files_pdfviewer> to 2.8.0
    Updating <files_rightclick> ...
    Updated <files_rightclick> to 1.6.0
    Updating <logreader> ...
    Updated <logreader> to 2.12.0
    Updating <photos> ...
    Updated <photos> to 2.3.0
    Updating <privacy> ...
    Updated <privacy> to 1.11.0
    Updating <provisioning_api> ...
    Updated <provisioning_api> to 1.17.0
    Updating <recommendations> ...
    Updated <recommendations> to 1.6.0
    Updating <serverinfo> ...
    Updated <serverinfo> to 1.17.0
    Updating <settings> ...
    Updated <settings> to 1.9.0
    Updating <twofactor_backupcodes> ...
    Updated <twofactor_backupcodes> to 1.16.0
    Updating <updatenotification> ...
    Updated <updatenotification> to 1.17.0
    Updating <user_status> ...
    Updated <user_status> to 1.7.0
    Updating <viewer> ...
    Updated <viewer> to 2.1.0
    Updating <weather_status> ...
    Updated <weather_status> to 1.7.0
    Starting code integrity check...
    Finished code integrity check
    Update successful
    Maintenance mode is kept active
    Resetting log level

    Nextcloud or one of the apps require upgrade - only a limited number of commands are available
    You may use your browser or the occ upgrade command to do the upgrade
    Setting log level to debug
    Updating database schema
    Updated database
    Updating <files> ...
    Updated <files> to 1.22.0
    Updating <activity> ...
    Updated <activity> to 2.19.0
    Updating <circles> ...
    Updated <circles> to 27.0.1
    Updating <cloud_federation_api> ...
    Updated <cloud_federation_api> to 1.10.0
    Updating <dav> ...

    Fix broken values of calendar objects

     Done
        0/0 [->--------------------------]   0%
    Clean up old calendar subscriptions from deleted users that were not cleaned-up
     Done
        0/0 [----->----------------------]   0%
    Updated <dav> to 1.27.0
    Updating <encryption> ...
    Updated <encryption> to 2.15.0
    Updating <files_sharing> ...
    Updated <files_sharing> to 1.19.0
    Updating <files_trashbin> ...
    Updated <files_trashbin> to 1.17.0
    Updating <files_versions> ...
    Updated <files_versions> to 1.20.0
    Updating <sharebymail> ...
    Updated <sharebymail> to 1.17.0
    Updating <workflowengine> ...
    Updated <workflowengine> to 2.9.0
    Updating <admin_audit> ...
    Updated <admin_audit> to 1.17.0
    Updating <comments> ...
    Updated <comments> to 1.17.0
    Updating <notifications> ...
    Updated <notifications> to 2.15.0
    Updating <systemtags> ...
    Updated <systemtags> to 1.17.0
    Updating <theming> ...
    Migrate old user accessibility config
     Done
      471/471 [============================] 100%
    Updated <theming> to 2.2.0
    Updating <bruteforcesettings> ...
    Updated <bruteforcesettings> to 2.7.0
    Updating <contactsinteraction> ...
    Updated <contactsinteraction> to 1.8.0
    Updating <dashboard> ...
    Updated <dashboard> to 7.7.0
    Updating <federatedfilesharing> ...
    Updated <federatedfilesharing> to 1.17.0
    Updating <files_pdfviewer> ...
    Updated <files_pdfviewer> to 2.8.0
    Updating <files_rightclick> ...
    Updated <files_rightclick> to 1.6.0
    Updating <logreader> ...
    Updated <logreader> to 2.12.0
    Updating <photos> ...
    Updated <photos> to 2.3.0
    Updating <privacy> ...
    Updated <privacy> to 1.11.0
    Updating <provisioning_api> ...
    Updated <provisioning_api> to 1.17.0
    Updating <recommendations> ...
    Updated <recommendations> to 1.6.0
    Updating <serverinfo> ...
    Updated <serverinfo> to 1.17.0
    Updating <settings> ...
    Updated <settings> to 1.9.0
    Updating <twofactor_backupcodes> ...
    Updated <twofactor_backupcodes> to 1.16.0
    Updating <updatenotification> ...
    Updated <updatenotification> to 1.17.0
    Updating <user_status> ...
    Updated <user_status> to 1.7.0
    Updating <viewer> ...
    Updated <viewer> to 2.1.0
    Updating <weather_status> ...
    Updated <weather_status> to 1.7.0
    Starting code integrity check...
    Finished code integrity check
    Update successful
    Maintenance mode is kept active
    Resetting log level

Und für die Dateien einmal die in den Nextcloud Data-Verzeichnis ableget wurde mit folgendem Befehl die Rechte anlegen:

    cd /opt/data/nextcloud/
    cp -Rv /opt/extern-data/nextcloud/data/* .
    chown -cRv www-data:www-data .

    cd /opt/data/nextcloud/
    cp -Rv /opt/extern-data/nextcloud/data/* .
    chown -cRv www-data:www-data .

und anschließend die Dateien neu einscannen:

    docker compose exec --user www-data -it nextcloud-app /bin/bash
    ./occ files:scan --all

    docker compose exec --user www-data -it nextcloud-app /bin/bash
    ./occ files:scan --all

## Weitere Optimierungen an der Datenbank nach der Migration

Falls noch Probleme im Status mit der Datenbank vorhanden sind, sind diese Befehle auszuführen um die Tabellen zu reparieren:

    [root@SST-S-440 nextcloud]# docker compose exec --user www-data -it nextcloud-app /bin/bash
    www-data@bbb02abc82f0:~/html$ ./occ db:add-missing-indices

    [root@SST-S-440 nextcloud]# docker compose exec --user www-data -it nextcloud-app /bin/bash
    www-data@bbb02abc82f0:~/html$ ./occ db:add-missing-indices

Das Ergebniss sollte dann so aussehen:

    Check indices of the share table.
    Check indices of the filecache table.
    Adding additional size index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional size index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional path index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional parent index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Check indices of the twofactor_providers table.
    Check indices of the login_flow_v2 table.
    Check indices of the whats_new table.
    Check indices of the cards table.
    Check indices of the cards_properties table.
    Check indices of the calendarobjects_props table.
    Check indices of the schedulingobjects table.
    Check indices of the oc_properties table.
    Adding properties_pathonly_index index to the oc_properties table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_jobs table.
    Adding job_lastcheck_reserved index to the oc_jobs table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_direct_edit table.
    Adding direct_edit_timestamp index to the oc_direct_edit table, this can take some time...
    oc_direct_edit table updated successfully.
    Check indices of the oc_preferences table.
    Adding preferences_app_key index to the oc_preferences table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_mounts table.
    Adding mounts_user_root_path_index index to the oc_mounts table, this can take some time...
    oc_mounts table updated successfully.
    Check indices of the oc_systemtag_object_mapping table.
    Adding systag_by_tagid index to the oc_systemtag_object_mapping table, this can take some time...
    oc_systemtag_object_mapping table updated successfully.
    Adding additional textstep_session index to the oc_text_steps table, this can take some time...
    oc_text_steps table updated successfully.

    Check indices of the share table.
    Check indices of the filecache table.
    Adding additional size index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional size index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional path index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Adding additional parent index to the filecache table, this can take some time...
    Filecache table updated successfully.
    Check indices of the twofactor_providers table.
    Check indices of the login_flow_v2 table.
    Check indices of the whats_new table.
    Check indices of the cards table.
    Check indices of the cards_properties table.
    Check indices of the calendarobjects_props table.
    Check indices of the schedulingobjects table.
    Check indices of the oc_properties table.
    Adding properties_pathonly_index index to the oc_properties table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_jobs table.
    Adding job_lastcheck_reserved index to the oc_jobs table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_direct_edit table.
    Adding direct_edit_timestamp index to the oc_direct_edit table, this can take some time...
    oc_direct_edit table updated successfully.
    Check indices of the oc_preferences table.
    Adding preferences_app_key index to the oc_preferences table, this can take some time...
    oc_properties table updated successfully.
    Check indices of the oc_mounts table.
    Adding mounts_user_root_path_index index to the oc_mounts table, this can take some time...
    oc_mounts table updated successfully.
    Check indices of the oc_systemtag_object_mapping table.
    Adding systag_by_tagid index to the oc_systemtag_object_mapping table, this can take some time...
    oc_systemtag_object_mapping table updated successfully.
    Adding additional textstep_session index to the oc_text_steps table, this can take some time...
    oc_text_steps table updated successfully.

Und noch ein weiterer Befehl:

    www-data@bbb02abc82f0:~/html$ ./occ db:add-missing-primary-keys

    www-data@bbb02abc82f0:~/html$ ./occ db:add-missing-primary-keys

Und weitere Anpassungen an der Datenbank mit:

    mysql -h 127.0.0.1 -u nextcloud -p nextcloud

    mysql -h 127.0.0.1 -u nextcloud -p nextcloud

und folgenden Befehlen:

    use nextcloud

    DROP TABLE oc_textprocessing_tasks;
    DROP TABLE oc_open_local_editor;

    use nextcloud

    DROP TABLE oc_textprocessing_tasks;
    DROP TABLE oc_open_local_editor;

Dessen Ausgabe so aussehen sollte:

    Check primary keys.
    Adding primary key to the federated_reshares table, this can take some time...
    federated_reshares table updated successfully.
    Adding primary key to the systemtag_object_mapping table, this can take some time...
    systemtag_object_mapping table updated successfully.
    Adding primary key to the comments_read_markers table, this can take some time...
    comments_read_markers table updated successfully.
    Adding primary key to the collres_resources table, this can take some time...
    collres_resources table updated successfully.
    Adding primary key to the collres_accesscache table, this can take some time...
    collres_accesscache table updated successfully.
    Adding primary key to the filecache_extended table, this can take some time...
    filecache_extended table updated successfully.

    Check primary keys.
    Adding primary key to the federated_reshares table, this can take some time...
    federated_reshares table updated successfully.
    Adding primary key to the systemtag_object_mapping table, this can take some time...
    systemtag_object_mapping table updated successfully.
    Adding primary key to the comments_read_markers table, this can take some time...
    comments_read_markers table updated successfully.
    Adding primary key to the collres_resources table, this can take some time...
    collres_resources table updated successfully.
    Adding primary key to the collres_accesscache table, this can take some time...
    collres_accesscache table updated successfully.
    Adding primary key to the filecache_extended table, this can take some time...
    filecache_extended table updated successfully.

Anschließend noch diesen Befehl ausführen und zusätzlich bestätigen:

    www-data@bbb02abc82f0:~/html$ ./occ db:convert-filecache-bigint
    Following columns will be updated:

    * federated_reshares.share_id
    * filecache.mtime
    * filecache.storage_mtime
    * filecache_extended.fileid
    * files_trash.auto_id
    * mounts.storage_id
    * mounts.root_id
    * mounts.mount_id
    * share_external.id
    * share_external.parent

    This can take up to hours, depending on the number of files in your instance!
    Continue with the conversion (y/n)? [n] y

    www-data@bbb02abc82f0:~/html$ ./occ db:convert-filecache-bigint
    Following columns will be updated:

    * federated_reshares.share_id
    * filecache.mtime
    * filecache.storage_mtime
    * filecache_extended.fileid
    * files_trash.auto_id
    * mounts.storage_id
    * mounts.root_id
    * mounts.mount_id
    * share_external.id
    * share_external.parent

    This can take up to hours, depending on the number of files in your instance!
    Continue with the conversion (y/n)? [n] y

## Volltextsuche und OCR mit migrieren und installieren

Folgenden Text der Docker Compose Datei hinzufügen:

      elasticsearch:
        build: ./elasticsearch
        container_name: elasticsearch
        restart: unless-stopped
        environment:
          - discovery.type=single-node
        ulimits:
          memlock:
            soft: -1
            hard: -1
        volumes:
          - ./elasticsearch/data:/usr/share/elasticsearch/data
        networks:
          - default

      elasticsearch:
        build: ./elasticsearch
        container_name: elasticsearch
        restart: unless-stopped
        environment:
          - discovery.type=single-node
        ulimits:
          memlock:
            soft: -1
            hard: -1
        volumes:
          - ./elasticsearch/data:/usr/share/elasticsearch/data
        networks:
          - default

und folgendes beim Nextcloud ändern bzw. ausdokumentieren:

    # image: nextcloud:27
    build: ./nextcloud-app

    # image: nextcloud:27
    build: ./nextcloud-app

### Anpassungen für ImageMagick

ImageMagick wird verwendet um aus PDF Seiten Fotos zu erstellen. Diese können später per OCR erkannt werden. Es gibt derzeit wohl ein kleines Hindernis (Github Quelle) weshalb wir hier noch eine extra Anpassung vornehmen müssen.

    mkdir /opt/containers/nextcloud/imagemagick/
    nano /opt/containers/nextcloud/imagemagick/policy.xml

    mkdir /opt/containers/nextcloud/imagemagick/
    nano /opt/containers/nextcloud/imagemagick/policy.xml

Inhalt:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE policymap [
      <!ELEMENT policymap (policy)+>
      <!ATTLIST policymap xmlns CDATA #FIXED ''>
      <!ELEMENT policy EMPTY>
      <!ATTLIST policy xmlns CDATA #FIXED '' domain NMTOKEN #REQUIRED
        name NMTOKEN #IMPLIED pattern CDATA #IMPLIED rights NMTOKEN #IMPLIED
        stealth NMTOKEN #IMPLIED value CDATA #IMPLIED>
    ]>

    <policymap>
      <!-- <policy domain="system" name="shred" value="2"/> -->
      <!-- <policy domain="system" name="precision" value="6"/> -->
      <!-- <policy domain="system" name="memory-map" value="anonymous"/> -->
      <!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
      <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
      <policy domain="resource" name="memory" value="256MiB"/>
      <policy domain="resource" name="map" value="512MiB"/>
      <policy domain="resource" name="width" value="16KP"/>
      <policy domain="resource" name="height" value="16KP"/>
      <!-- <policy domain="resource" name="list-length" value="128"/> -->
      <policy domain="resource" name="area" value="128MB"/>
      <policy domain="resource" name="disk" value="1GiB"/>
      <!-- <policy domain="resource" name="file" value="768"/> -->
      <!-- <policy domain="resource" name="thread" value="4"/> -->
      <!-- <policy domain="resource" name="throttle" value="0"/> -->
      <!-- <policy domain="resource" name="time" value="3600"/> -->
      <!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
      <!-- <policy domain="module" rights="none" pattern="{PS,PDF,XPS}" /> -->
      <!-- <policy domain="delegate" rights="none" pattern="HTTPS" /> -->
      <!-- <policy domain="path" rights="none" pattern="@*" /> -->
      <!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
      <!-- <policy domain="cache" name="synchronize" value="True"/> -->
      <!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/> -->
      <!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
      <!-- <policy domain="system" name="shred" value="2"/> -->
      <!-- <policy domain="system" name="precision" value="6"/> -->
      <!-- not needed due to the need to use explicitly by mvg: -->
      <!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
      <!-- use curl -->
      <policy domain="delegate" rights="none" pattern="URL" />
      <policy domain="delegate" rights="none" pattern="HTTPS" />
      <policy domain="delegate" rights="none" pattern="HTTP" />
      <!-- in order to avoid to get image with password text -->
      <policy domain="path" rights="none" pattern="@*"/>
      <!-- disable ghostscript format types -->
      <policy domain="coder" rights="none" pattern="PS" />
      <policy domain="coder" rights="none" pattern="PS2" />
      <policy domain="coder" rights="none" pattern="PS3" />
      <policy domain="coder" rights="none" pattern="EPS" />
      <policy domain="coder" rights="read | write" pattern="PDF" />
      <policy domain="coder" rights="none" pattern="XPS" />
    </policymap>

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE policymap [
      <!ELEMENT policymap (policy)+>
      <!ATTLIST policymap xmlns CDATA #FIXED ''>
      <!ELEMENT policy EMPTY>
      <!ATTLIST policy xmlns CDATA #FIXED '' domain NMTOKEN #REQUIRED
        name NMTOKEN #IMPLIED pattern CDATA #IMPLIED rights NMTOKEN #IMPLIED
        stealth NMTOKEN #IMPLIED value CDATA #IMPLIED>
    ]>

    <policymap>
      <!-- <policy domain="system" name="shred" value="2"/> -->
      <!-- <policy domain="system" name="precision" value="6"/> -->
      <!-- <policy domain="system" name="memory-map" value="anonymous"/> -->
      <!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
      <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
      <policy domain="resource" name="memory" value="256MiB"/>
      <policy domain="resource" name="map" value="512MiB"/>
      <policy domain="resource" name="width" value="16KP"/>
      <policy domain="resource" name="height" value="16KP"/>
      <!-- <policy domain="resource" name="list-length" value="128"/> -->
      <policy domain="resource" name="area" value="128MB"/>
      <policy domain="resource" name="disk" value="1GiB"/>
      <!-- <policy domain="resource" name="file" value="768"/> -->
      <!-- <policy domain="resource" name="thread" value="4"/> -->
      <!-- <policy domain="resource" name="throttle" value="0"/> -->
      <!-- <policy domain="resource" name="time" value="3600"/> -->
      <!-- <policy domain="coder" rights="none" pattern="MVG" /> -->
      <!-- <policy domain="module" rights="none" pattern="{PS,PDF,XPS}" /> -->
      <!-- <policy domain="delegate" rights="none" pattern="HTTPS" /> -->
      <!-- <policy domain="path" rights="none" pattern="@*" /> -->
      <!-- <policy domain="cache" name="memory-map" value="anonymous"/> -->
      <!-- <policy domain="cache" name="synchronize" value="True"/> -->
      <!-- <policy domain="cache" name="shared-secret" value="passphrase" stealth="true"/> -->
      <!-- <policy domain="system" name="pixel-cache-memory" value="anonymous"/> -->
      <!-- <policy domain="system" name="shred" value="2"/> -->
      <!-- <policy domain="system" name="precision" value="6"/> -->
      <!-- not needed due to the need to use explicitly by mvg: -->
      <!-- <policy domain="delegate" rights="none" pattern="MVG" /> -->
      <!-- use curl -->
      <policy domain="delegate" rights="none" pattern="URL" />
      <policy domain="delegate" rights="none" pattern="HTTPS" />
      <policy domain="delegate" rights="none" pattern="HTTP" />
      <!-- in order to avoid to get image with password text -->
      <policy domain="path" rights="none" pattern="@*"/>
      <!-- disable ghostscript format types -->
      <policy domain="coder" rights="none" pattern="PS" />
      <policy domain="coder" rights="none" pattern="PS2" />
      <policy domain="coder" rights="none" pattern="PS3" />
      <policy domain="coder" rights="none" pattern="EPS" />
      <policy domain="coder" rights="read | write" pattern="PDF" />
      <policy domain="coder" rights="none" pattern="XPS" />
    </policymap>

### Anpassung für Nextcloud

In der aktuellen Version muss noch GhostScript in den Nextcloud Container hinzugefügt werden. Daher müssen wir uns den Container selbst bauen.

    mkdir /opt/containers/nextcloud/nextcloud-app/
    nano /opt/containers/nextcloud/nextcloud-app/Dockerfile

    mkdir /opt/containers/nextcloud/nextcloud-app/
    nano /opt/containers/nextcloud/nextcloud-app/Dockerfile

Inhalt:

    FROM nextcloud
    RUN apt-get update
    RUN apt-get install -y ghostscript
    RUN apt install -y libmagickwand-dev --no-install-recommends
    RUN pecl install imagick; exit 0
    RUN docker-php-ext-enable imagick
    RUN rm -rf /var/lib/apt/lists/*

    FROM nextcloud
    RUN apt-get update
    RUN apt-get install -y ghostscript
    RUN apt install -y libmagickwand-dev --no-install-recommends
    RUN pecl install imagick; exit 0
    RUN docker-php-ext-enable imagick
    RUN rm -rf /var/lib/apt/lists/*

### Anpassungen für ElasticSearch

Um die OCR Erkennung in ElasticSearch zu realisieren benötigen wir noch das Programm Tesseract. Daher müssen wir uns den ElasticSearch Container auch selbst bauen.

    mkdir /opt/containers/nextcloud/elasticsearch/
    nano /opt/containers/nextcloud/elasticsearch/Dockerfile

    mkdir /opt/containers/nextcloud/elasticsearch/
    nano /opt/containers/nextcloud/elasticsearch/Dockerfile

Inhalt:

    FROM elasticsearch:7.17.10
    RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install --batch ingest-attachment
    RUN apt-get update
    RUN apt-get upgrade -y
    RUN apt-get install -y tesseract-ocr tesseract-ocr-deu tesseract-ocr-eng

    FROM elasticsearch:7.17.10
    RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install --batch ingest-attachment
    RUN apt-get update
    RUN apt-get upgrade -y
    RUN apt-get install -y tesseract-ocr tesseract-ocr-deu tesseract-ocr-eng

Hier könnt ihr noch weitere Sprachen installieren zur OCR Erkennung. Eine Übersicht alles Sprachen findet ihr hier.

Folgende Plugins müssen installiert werden:

Und folgende Einstellungen gesetzt werden:

Nach der DB-Migration folgende Befehle ausführen.

    docker compose exec --user www-data -it app /bin/bash

    ./occ fultextsearch:migration:24
    ./occ fulltextsearch:index
    ./occ fulltextsearch:live

    docker compose exec --user www-data -it app /bin/bash

    ./occ fultextsearch:migration:24
    ./occ fulltextsearch:index
    ./occ fulltextsearch:live

Das Ergebniss müsste schließlich so aussehen:

## Quellen

https://hub.docker.com/_/nextcloud/

https://teqqy.de/nextcloud-docker-tutorial-step-by-step-zum-erfolg/

https://goneuland.de/nextcloud-server-mit-docker-compose-und-traefik-installieren/

https://goneuland.de/nextcloud-server-mit-elasticsearch-collabora-office-docker-compose-und-traefik-installieren/

https://wiki.ubuntuusers.de/SSH/#SSH-Tunnel

https://idroot.us/install-certbot-almalinux-8/

https://stackoverflow.com/questions/23948527/13-permission-denied-while-connecting-to-upstreamnginx

https://github.com/nextcloud/docker/blob/master/README.md

https://howtodotech.de/nextcloud-dateien-mit-occ-filesscan-neu-einscannen/

https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html

https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html

https://gdevillele.github.io/engine/admin/systemd/

https://linuxconfig.org/how-to-configure-ntp-server-and-client-on-almalinux

https://www.my-it-brain.de/wordpress/nextcloud-im-container-teil-3-mit-reverse-proxy/