Aufsetzen von Nextcloud mit Collabora

Für das hosten einer eigenen Cloud habe ich nach kurzem Suchen 2 Open-Source Lösungen im Netz gefunden: Owncloud und Nextcloud. Während Owncloud wohl den ersten Meilenstein begründet hat, ist das Userinterface wirklich nicht das Gelbe vom Ei. Also habe ich Nextcloud eine Chance gegeben, meine erste eigene Cloud zu werden. Dateien hochladen ist schon ein guter Anfang, aber das Bearbeiten von Office Dokumenten in Nextcloud geht nur im Verbund mit Collabora. Hier also meine Erfahrungen beim Aufsetzen von Nextcloud und Collabora.

Sidenote: Beide Systeme scheinen denselben Kern zu haben bzw. Nextcloud scheint auf Owncloud zu basieren. Das hat vor allem den Vorteil, dass es eine Überschneidung in der Vielfalt von Plugins für das System gibt. Die Oberfläche von Nextcloud ist jedoch übersichtlicher, sodass dies für mich aktuell die bessere Lösung darstellt.

Eine Liste der Quellen für die vorliegende Konfiguration befindet sich am Ende des Beitrags. Der Rest basiert auf dem guten, alten Trial-and-Error Verfahren.

Was ist denn Collabora?

Ich glaube, dass jede(r), die/der diesen Beitrag liest, im Besitz eines Google-Accounts ist. Sicher kennen die meisten dann auch die Vorteile des gemeinsamen und gleichzeitigen Arbeitens an einem Dokument in Google-Drive. „Collabora Office“ ermöglicht ein solches Arbeiten ebenfalls. Allerdings auf Basis des Open Source Office Pakets „LibreOffice“.

Ein weiterer Vorteil ist, dass Collabora selbst gehostet werden kann und daher einzig einer Privatperson oder einem Unternehmen untersteht. Die Kommunikation mit diesem Server findet also stets im eigenen Ökosystem und – per SSL Verschlüsselung – geheim statt.

Einrichtung der Cloud

Der Betrieb meines Servers basiert grundlegend auf Docker. Anfragen werden über den NGINX-Proxy von jwilder im Zusammenhang mit dem Proxy-Companion von JrCs weitergeleitet. Wie das Zusammenspiel dieser Container funktioniert, werde ich hier nicht weiter erklären. Das können die Readme(s) der Projekte sowieso besser.

Folgend also die Konfiguration für Nextcloud, basierend auf einer docker-compose.yaml, einer NGINX Konfiguration und einer Sammlung von Variablen:

# .env
CON_PREFIX=nextcloud
FILES_ENDPOINT=./data
# docker-compose.yaml
version: '3.5'

volumes:
    nc-volume:

services:
    web:
        image: nginx:latest
        container_name: ${CON_PREFIX}-web
        restart: unless-stopped
        env_file: .env
        expose:
            - 80
            - 443
        volumes:
            - nc-volume:/var/www/html
            - nginx.conf:/etc/nginx/conf.d/nginx.conf
        environment:
            VIRTUAL_HOST: my-cloud.my-domain.com
            VIRTUAL_PORT: 443
            VIRTUAL_PROTO: https
            LETSENCRYPT_HOST: my-cloud.my-domain.com
            LETSENCRYPT_EMAIL: mail@my-domain.com
        links:
            - php

    php:
        image: nextcloud:17-fpm
        container_name: ${CON_PREFIX}-app
        restart: unless-stopped
        env_file: .env
        volumes:
            - nc-volume:/var/www/html
            - ${FILES_ENDPOINT}/cloud/config:/var/www/html/config
            - ${FILES_ENDPOINT}/cloud/data:/var/www/html/data

networks:
    default:
        external:
            name: ${NETWORK}

Der Grund für php als Namen für den Nextcloud Container findest sich beim fastcgi_pass der NGINX Konfiguration:

# nginx.conf
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name _;
    root /var/www/html;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    error_log /var/log/nginx/project_error.log;
    access_log /var/log/nginx/project_access.log;

    add_header Referrer-Policy "no-referrer" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Download-Options "noopen" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Permitted-Cross-Domain-Policies "none" always;
    add_header X-Robots-Tag "none" always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    client_max_body_size 10G;
    fastcgi_buffers 64 4k;

    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application;

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

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

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

    location / {
        rewrite ^ /index.php;
    }

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

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

    location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
        proxy_set_header Host $host;
        fastcgi_pass php:9000;
        fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
        fastcgi_param HTTPS on;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param modHeadersAvailable true;
        fastcgi_param front_controller_active true;
        fastcgi_buffer_size 32k;
        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
        include fastcgi_params;

        try_files $fastcgi_script_name =404;
    }

    location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
        try_files $uri/ =404;
        index index.php;
    }

    location ~ \.(?:css|js|woff2?|svg|gif|map)$ {
        add_header Cache-Control "public, max-age=15778463";
        add_header Referrer-Policy "no-referrer" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Download-Options "noopen" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Permitted-Cross-Domain-Policies "none" always;
        add_header X-Robots-Tag "none" always;
        add_header X-XSS-Protection "1; mode=block" always;

        try_files $uri /index.php$request_uri;
        access_log off;
    }

    location ~ \.(?:png|html|ttf|ico|jpg|jpeg|bcmap)$ {
        try_files $uri /index.php$request_uri;
        access_log off;
    }
}

Damit allein sollte Nextcloud schon einen guten Eindruck machen und ordnungsgemäß funktionieren. Im App-Store findet sich auch schon die passende Anwendung für das Verarbeiten von Office-Dateiformaten: „Collabora Online“. Damit das Zusammenspiel funktioniert, müssen wir die Konfiguration aber noch etwas erweitern.

Collabora hinzufügen

Die einfachste (und in Zusammenhang mit NGINX wohl einzige) Möglichkeit, Collabora zu nutzen, ist das Aufsetzen eines Docker-Containers unter einer Subdomain. Collabora stellt einen offiziellen Container zur Verfügung, der nur noch mit einem SSL Zertifikat ausgestattet werden muss. Da mein Docker-Server mit Proxy + Companion dies bereits gewährleistet, muss ich nur noch die Subdoain herrichten und folgendes in die docker-compose.yaml einfügen:

# docker-compose.yaml

# ...

services:
    # ...

    collabora:
        image: collabora/code
        container_name: ${CON_PREFIX}-collabora
        restart: unless-stopped
        env_file: .env
        expose:
            - 9980
        environment:
            VIRTUAL_HOST: my-office.my-domain.com
            VIRTUAL_PORT: 9980
            VIRTUAL_PROTO: https
            LETSENCRYPT_HOST: my-office.my-domain.com
            LETSENCRYPT_EMAIL: mail@my-domain.com
            domain: my-cloud.my-domain.com
            dictionaries: de_DE en_GB en_US
        cap_add:
            - MKNOD

Der neu aufgesetzte Collabora Container braucht auf dem Server einige Minuten, um sich ordnungsgemäß hochzufahren. Ist der Container bereit, sollte der Aufruf von my-office.my-domain.com im Browser ein „OK“ ausgeben. Alles Weitere muss für Nextcloud hergerichtet werden.

Folgende Einstellungen müssen der NGINX Konfigurationen hinzugefügt werden:

# nginx.conf
server {
    # Nextcloud conf
    # ...

    # Collabora conf
    location ^~ /loleaflet {
        proxy_pass https://collabora:9980;
        proxy_set_header Host $http_host;
    }

    # WOPI discovery URL
    location ^~ /hosting/discovery {
        proxy_pass https://collabora:9980;
        proxy_set_header Host $http_host;
    }

   # main websocket
   location ~ ^/lool/(.*)/ws$ {
       proxy_pass https://collabora:9980;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";
       proxy_set_header Host $http_host;
       proxy_read_timeout 36000s;
   }

   # download, presentation and image upload
   location ~ ^/lool {
       proxy_pass https://collabora:9980;
       proxy_set_header Host $http_host;
   }

   # Admin Console websocket
   location ^~ /lool/adminws {
       proxy_pass https://collabora:9980;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "Upgrade";
       proxy_set_header Host $http_host;
       proxy_read_timeout 36000s;
   }
}

Mit dieser Konfiguration leitet NGINX alle Zugriffe auf „rich-text-documents“ an den Websocket von Collabora weiter. Die App „Collabora Online“ definiert, welche genau das sind.

Da wir weiterhin in unserem eigenen Ökosystem agieren und Zugriffe auf Port 9980 von außen verhindern möchten, wird https://collabora:9980 für den proxy_pass genutzt. Sollte der Dienst am Ende nicht erreichbar sein und z.B. einen 404 Fehler auswerfen, könnte das Einsetzen der echte URL my-office.my-domain.com ein Lösungsansatz sein.

Der richtige Port für die App

Zuletzt muss nur noch die App über den Standort des Websockets informiert werden. Dazu finden wir in den Einstellungen den Punkt „Collabora Online“ in der Sidebar. In das Feld ganz oben sollte die echte Domain my-office.my-domain.com eingetragen werden. Im Gegensatz zum Placeholder, der einen Port :9980 am Ende der Eingabe vorschlägt, sollte man dies unterlassen! In meinem Fall wurde Collabora nur erreicht, wenn gar kein Port spezifiziert wurde.

Nun sollte dem Arbeiten mit Calc, Writer und Co. in der eigenen Cloud nichts mehr im Wege stehen. Probiert es gleich mal aus!

Das Fazit

Das war mein kleiner Guide zum Aufsetzen von Nextcloud mit Collabora. Etwas frickelig war es zwischendurch, wenn sich nur noch mit Trial-and-Error der korrekte Port bzw. die Domain herausfinden lässt. Auch bisherige Dokumentation für eine allumfassende NGINX Konfiguration ist recht dünn im Internet. Es hat sich jedoch gelohnt, denn nun kann ich meine Office-Arbeiten auch unterwegs lösen, mit Freunden und Kollegen teilen, in PDF umwandeln und auf ein beliebiges Endgerät herunterladen.

Zum Abschluss sei allerdings noch gesagt, dass Collabora keine „eier-legende Wollmilchsau“ ist. Der Funktionsumfang kann nicht mit Google-Drive mithalten und kommt nicht mal an den Umfang von LibreOffice auf einem PC/Linux heran. Auch die Verarbeitung ist mit dem Umweg über SSL plus dem Hin- und Her zwischen den Servern/Containern nicht die schnellste. Trotzdem hat das Verarbeiten und Filtern einer Inventarliste in Calc oder ein Stichwortzettel im Writer definitiv einen Mehrwert, wenn das ausführende Endgerät ein PC, Notebook, Tablet oder sogar ein Smartphone sein kann.

Quellen

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.