Nextcloud hinter Reverse Proxy installieren

Hallo!

Heute beschäftige ich mich mit der Installation von Nextcloud in einem Proxmox LXC Container. Wir frühstücken das ganze aber in einer besonderen Konstellation ab. Bedeutet kurz und knapp wir installieren das Ganze unter Debian, mit PHP-FPM hinter einem Nginx Reverse Proxy und einer separaten MySQL Datenbank. In diesem Fall wird der Reverse Proxy das SSL Zertifikat besitzen und die Anfragen an die Cloud im internen Netz unverschlüsselt weiterzureichen.

Was ihr dazu benötigt:

Wir verbinden uns als „root“ per SSH auf den Container. Dann führen wir ein Upgrade durch und installieren grundlegende Pakete.

apt update && apt upgrade -y
apt install htop sudo net-tools unzip software-properties-common curl socat tree unzip wget dirmngr ffmpeg ghostscript gpg gnupg jq libfile-fcntllock-perl bash-completion cron dialog git lsb-release ca-certificates apt-transport-https locate screen libfontconfig1 libfuse2 locate smbclient zip bzip2 gnupg2 -y

Anschließend wechseln wir in das sources Verzeichnis und fügen alternative und vor allem aktuellere Repos dem System hinzu. So können wir sicherstellen, dass unsere Cloud mit den aktuellsten Sicherheitspatches versorgt wird. Dazu gehört PHP und Apache2. Im Normalfall würde ich noch MySQL hinzufügen, da die Datenbank in einem separaten Container läuft, fällt dies weg.

cd /etc/apt/sources.list.d/
echo "deb [arch=amd64] https://packages.sury.org/php/ $(lsb_release -cs) main" | tee php.list
echo "deb [arch=amd64] https://packages.sury.org/apache2/ $(lsb_release -cs) main" | tee apache2.list

Nun müssen wir dem System noch klarmachen, dass die hinzugefügten Repos als sicher zu bewerten sind. Dies erledigen wir, indem wir die Sicherheitsschlüssel der jeweiligen Repo herunterladen und installieren.

wget -q https://packages.sury.org/php/apt.gpg -O- | apt-key add -
wget -q https://packages.sury.org/apache2/apt.gpg -O- | apt-key add -

Nachdem wir die Repos hinzugefügt haben, aktualisieren wir die Paketlisten und upgraden vorhandene Pakete.

apt update && apt upgrade -y

Solltet ihr den LXC Container mithilfe meines Guides erstellt und konfiguriert haben, fällt dieser Step weg. Alle anderen. Ufpasse! Wir konfigurieren die Timezone und Locales des Systems.

dpkg-reconfigure tzdata 
Europe -> Berlin
dpkg-reconfigure locales
de_DE.UTF8 UTF8 -> de_DE.UTF8

Solltet ihr den LXC Container mithilfe meines Guides erstellt und konfiguriert haben, fällt dieser Step weg. Alle anderen. Ufpasse! Wir legen einen User an, erteilen ihm „sudo“ Rechte und wechseln auf den erstellten User.

adduser username
nano /etc/sudoers
# User privilege specification
root    ALL=(ALL:ALL) ALL
username ALL=(ALL:ALL) ALL
su username

Als Nächstes installieren wir Webserver Apache2.

sudo apt install apache2 apache2-utils -y

Anschließend installieren wir Redis und konfigurieren den Server. Redis nutzen wir zum besseren caching und memlocken.

sudo apt install redis -y

sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
sudo sed -i "s/port 6379/port 0/" /etc/redis/redis.conf
sudo sed -i s/\#\ unixsocket/\unixsocket/g /etc/redis/redis.conf
sudo sed -i "s/unixsocketperm 700/unixsocketperm 770/" /etc/redis/redis.conf
sudo sed -i "s/# maxclients 10000/maxclients 512/" /etc/redis/redis.conf

sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak
sudo sed -i '$avm.overcommit_memory = 1' /etc/sysctl.conf

Damit der Webserver User „www-data“ auch Redis nutzen darf, müssen wir ihm die Berechtigung dazu erteilen.

sudo usermod -aG redis www-data

Damit keine alten PHP Versionsleichen auf dem System installiert sind, entfernen wird vorher alle alte Pakete, die eventuell noch durch die initiale Installation des Systems oder anderen Tätigkeiten installiert sind.

sudo apt purge -y php-*

Nun kommt der Löwenteil der Installation. Die Rede ist von PHP 8.1. Wir starten mit dem Installieren.

sudo apt install php-common libapache2-mod-php8.1 imagemagick nfs-common cifs-utils php8.1-{fpm,gd,curl,xml,zip,intl,mbstring,bz2,ldap,apcu,bcmath,gmp,imagick,igbinary,mysql,redis,smbclient,cli,common,opcache,readline}

Damit wir im Fehlerfall noch ein Backup der Configdatei haben, erstellen wir nun erst von jeder Config eines.

sudo cp /etc/php/8.1/cli/php.ini /etc/php/8.1/cli/php.ini.bak
sudo cp /etc/php/8.1/fpm/pool.d/www.conf /etc/php/8.1/fpm/pool.d/www.conf.bak
sudo cp /etc/php/8.1/fpm/php.ini /etc/php/8.1/fpm/php.ini.bak
sudo cp /etc/php/8.1/fpm/php-fpm.conf /etc/php/8.1/fpm/php-fpm.conf.bak
sudo cp /etc/php/8.1/mods-available/apcu.ini /etc/php/8.1/mods-available/apcu.ini.bak
sudo cp /etc/ImageMagick-6/policy.xml /etc/ImageMagick-6/policy.xml.bak

Jetzt kommt das, was ich persönlich HASSE, wenn ich eine Cloud für Testzwecke aufsetze. Ich spreche von den Optimierungen und Einstellungen innerhalb der PHP Configs. Ich wünsche euch viel Spaß! 🙂

sudo sed -i "s/;env\[HOSTNAME\] = /env[HOSTNAME] = /" /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i "s/;env\[TMP\] = /env[TMP] = /" /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i "s/;env\[TMPDIR\] = /env[TMPDIR] = /" /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i "s/;env\[TEMP\] = /env[TEMP] = /" /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i "s/;env\[PATH\] = /env[PATH] = /" /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i "s/;pm.max_requests =.*/pm.max_requests = 1000/" /etc/php/8.1/fpm/pool.d/www.conf

sudo sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/post_max_size =.*/post_max_size = 32G/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/upload_max_filesize =.*/upload_max_filesize = 32G/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/8.1/cli/php.ini
sudo sed -i "s/;cgi.fix_pathinfo.*/cgi.fix_pathinfo=1/" /etc/php/8.1/cli/php.ini

sudo sed -i "s/memory_limit = 128M/memory_limit = 1024M/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/output_buffering =.*/output_buffering = 'Off'/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/max_execution_time =.*/max_execution_time = 3600/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/max_input_time =.*/max_input_time = 3600/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/post_max_size =.*/post_max_size = 32G/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/upload_max_filesize =.*/upload_max_filesize = 32G/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;date.timezone.*/date.timezone = Europe\/\Berlin/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/allow_url_fopen =.*/allow_url_fopen = 1/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;cgi.fix_pathinfo.*/cgi.fix_pathinfo=1/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;session.cookie_secure.*/session.cookie_secure = True/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.enable=.*/opcache.enable=1/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.enable_cli=.*/opcache.enable_cli=1/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.memory_consumption=.*/opcache.memory_consumption=128/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.interned_strings_buffer=.*/opcache.interned_strings_buffer=16/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.max_accelerated_files=.*/opcache.max_accelerated_files=10000/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.revalidate_freq=.*/opcache.revalidate_freq=1/" /etc/php/8.1/fpm/php.ini
sudo sed -i "s/;opcache.save_comments=.*/opcache.save_comments=1/" /etc/php/8.1/fpm/php.ini

sudo sed -i "s|;emergency_restart_threshold.*|emergency_restart_threshold = 10|g" /etc/php/8.1/fpm/php-fpm.conf
sudo sed -i "s|;emergency_restart_interval.*|emergency_restart_interval = 1m|g" /etc/php/8.1/fpm/php-fpm.conf
sudo sed -i "s|;process_control_timeout.*|process_control_timeout = 10|g" /etc/php/8.1/fpm/php-fpm.conf

sudo sed -i '$aapc.enable_cli=1' /etc/php/8.1/mods-available/apcu.ini

sudo sed -i "s/rights=\"none\" pattern=\"PS\"/rights=\"read|write\" pattern=\"PS\"/" /etc/ImageMagick-6/policy.xml
sudo sed -i "s/rights=\"none\" pattern=\"EPS\"/rights=\"read|write\" pattern=\"EPS\"/" /etc/ImageMagick-6/policy.xml
sudo sed -i "s/rights=\"none\" pattern=\"PDF\"/rights=\"read|write\" pattern=\"PDF\"/" /etc/ImageMagick-6/policy.xml
sudo sed -i "s/rights=\"none\" pattern=\"XPS\"/rights=\"read|write\" pattern=\"XPS\"/" /etc/ImageMagick-6/policy.xml

Na, wie schauts mit der Motivation aus? 😛 Da wir PHP-FPM nutzen wollen, müssen wir die normale CLI für Apache2 deaktivieren.

sudo a2dismod php8.1 mpm_prefork status

Nun aktivieren wir PHP-FPM.

sudo a2enconf php8.1-fpm

Wir aktivieren relevante Module für Apache2. Damit die ersten Änderungen wirksam werden, starten wir Apache2 neu.

sudo a2enmod proxy_fcgi setenvif mpm_event rewrite headers env dir mime http2
sudo systemctl restart apache2

Anschließend legen wir die vHost Datei für Apache2 an.

sudo nano /etc/apache2/sites-available/nextcloud.conf
<VirtualHost *:80>
    ServerAdmin admin@domain.tld
    DocumentRoot /var/www/nextcloud/
    ServerName subdomain.domain.tld
    #ServerAlias 192.168.xxx.xxx
 
    #Alias /nextcloud "/var/www/nextcloud/"
    #Fix für __Host-prefix

    <Directory /var/www/nextcloud/>
        Options Indexes FollowSymlinks
        AllowOverride All
        Require all granted
        Satisfy Any
            <IfModule mod_dav.c>
                Dav off
            </IfModule>
        SetEnv HOME /var/www/nextcloud
        SetEnv HTTP_HOME /var/www/nextcloud
    </Directory>
    <Directory /data/nextcloud/>
        Require all denied
    </Directory>
    <Files ".ht*">
        Require all denied
    </Files>
    TraceEnable off
 
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
 
RewriteEngine on
</VirtualHost>

Ist dieser Step erledigt, aktivieren wir die eben angelegte vHost Datei. Danach deaktivieren wir die vHost Default und starten neu.

sudo a2ensite nextcloud.conf
sudo a2dissite 000-default.conf
sudo systemctl restart apache2

Wir laden als nächstes Nextcloud herunter und kopieren den Inhalt der ZIP Datei in das Webverzeichnis unter „/var/www/nextcloud“.

cd /tmp && wget https://download.nextcloud.com/server/releases/latest.zip
sudo unzip latest.zip && sudo mv nextcloud /var/www/
sudo rm latest.zip

Nun legen wir einige Verzeichnisse an. Damit Nextcloud die Daten, die sich in der Cloud befinden, nicht im Webverzeichnis speichert, müssen wir den Speicherort verlagern. Ich persönlich mounte dafür ein ZFS Share in den Container. So sind alle Daten unabhängig von der Cloud, selbst wenn die Cloud mal ausfällt oder der LXC sich ins Nirwana verabschiedet. Damit alle User, die erstellt werden, ein „leeres“ Nutzerverzeichnis besitzen und von diesem „Default Nextcloud Intro Schrott“ verschont bleiben, legen wir ein sogenanntes Skeleton Verzeichnis an. Hier können auch Daten gespeichert werden, die jeder neu erstellte Nutzer bereitgestellt bekommen soll. Da der User „www-data“ Zugriff auf diese Verzeichnisse haben muss, erteilen wir ihm die Berechtigung.

sudo mkdir /data
sudo mkdir /data/nextcloud
sudo mkdir /data/nextcloud/skeleton
sudo chown -R www-data:www-data /data/nextcloud

Damit das Log sammeln übersichtlicher wird, legen wir ein für die Cloud eigenes Verzeichnis an. Auch hier müssen wir Besitzrechte erteilen.

sudo mkdir /var/log/nextcloud
sudo chown -R www-data:www-data /var/log/nextcloud

Nextcloud benötigt obendrein noch eine PHP Config, in der wir diverse Settings setzen müssen. Unter „trusted_proxies“ tragt ihr euren Reverse Proxyserver ein. An Stellen bei denen „subdomain.domain.tld“ eingetragen ist, müsst ihr selbstverständlich eure Domain eintragen.

sudo nano /var/www/nextcloud/config/config.php
<?php
$CONFIG = array (
  'trusted_domains' => 
  array (
    0 => 'localhost',
    1 => 'subdomain.domain.tld',
    2 => '192.168.XXX.XXX',
  ),
  'trusted_proxies' => 
  array (
    0 => '192.168.XXX.XXX',
  ),
  'datadirectory' => '/data/nextcloud/',
  'log_type' => 'file',
  'logtimezone' => 'Europe/Berlin',
  'loglevel' => 2,
  'logfile' => '/var/log/nextcloud/nextcloud.log',
  'log_rotate_size' => '104857600',
  'enable_previews' => true,
  'enabledPreviewProviders' => 
  array (
    0 => 'OC\Preview\PNG',
    1 => 'OC\Preview\JPEG',
    2 => 'OC\Preview\GIF',
    3 => 'OC\Preview\BMP',
    4 => 'OC\Preview\XBitmap',
    5 => 'OC\Preview\Movie',
    6 => 'OC\Preview\PDF',
    7 => 'OC\Preview\MP3',
    8 => 'OC\Preview\TXT',
    9 => 'OC\Preview\MarkDown',
  ),
  'preview_max_x' => 1024,
  'preview_max_y' => 768,
  'preview_max_scale_factor' => 1,
  'skeletondirectory' => '/data/nextcloud/skeleton',
  'filelocking.enabled' => 'true',
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'redis' => 
  array (
    'host' => '/var/run/redis/redis-server.sock',
    'port' => 0,
    'timeout' => 1.5,
  ),
  'default_language' => 'de',
  'default_locale' => 'de_DE',
  'default_phone_region' => 'DE',
  'trashbin_retention_obligation' => '15, 30',
  'updater.release.channel' => 'stable',
  'overwrite.cli.url' => 'https://subdomain.domain.tld/',
  'overwriteprotocol' => 'https',
  'htaccess.RewriteBase' => '/',
);

Der User „www-data“ muss Besitzer des „/var/www/nextcloud“ Verzeichnisses sein.

sudo chown -R www-data:www-data /var/www/nextcloud

Danach führen wir einen Restart der Dienste durch.

sudo systemctl restart apache2
sudo systemctl restart php8.1-fpm
sudo systemctl restart redis

Tada! Wir können die Cloud über ihre IP ansteuern und bekommen den Setup Wizard vor die Nase gesetzt. Wir tragen im ersten Punkt einen Adminnutzer mit Passwort ein. Als Nächstes geben wir das vorher angelegte Datenverzeichnis an. Nun tragen wir den MySQL Nutzer mit Passwort und dazugehörigen Datenbanknamen ein. Localhost ersetzen wir mit der IP des MySQL Server. Im letzten Step klicken wir auf Installation abschließen.

Nun öffnen wir erneut unseren SSH Tunnel und aktualisieren die „.htaccess“ Datei für die Cloud.

sudo -u www-data php /var/www/nextcloud/occ maintenance:update:htaccess

Nun führen wir einen letzten Restart der Services durch.

sudo systemctl restart apache2
sudo systemctl restart php8.1-fpm
sudo systemctl restart redis

Damit die Cloud nicht per AJAX aktualisiert wird, sondern per CRON müssen wir einen Cronjob für den User „www-data“ anlegen.

sudo crontab -u www-data -e
*/5  *  *  *  * php -f /var/www/nextcloud/cron.php

Nun rufen wir die Cloud wieder unter ihrer IP auf und stellen von AJAX auf Cron um. Dazu klicken wir auf Einstellungen -> Grundeinstellungen und ändern AJAX auf Cron.
Anschließend optimieren wir die Anzahl der Worker für PHP FPM. Dazu müssen wir erst den Arbeitsspeicherverbrauch pro Worker ermitteln, der je nach RAM Größe variieren kann. Wir setzen einen Befehl ab und erhalten eine variable Anzahl an Werten zurück. Aus diesen Werten bilden wir den Mittelwert und runden ihn auf eine volle 5-stellige Zahl auf.

ps -C php-fpm8.1 -o rss=

31972
35780
36252

Mittelwert = 34668 = 35000 = 35 MB

Nun öffnen wir diesen Workerrechner. Der erste Parameter ist der Gesamtspeicher, dem der LXC zugewiesen wurde. Der zweite Parameter steht für die Arbeitsspeicherauslastung des Betriebssystems und anderen Diensten. Ich habe hier aufgrund des LXCs und des dadurch geringeren Overheads 0,75 GiB gewählt. Der dritte Parameter steht für einen Arbeitsspeicherpuffer in Prozent. Dieser beleibt auf dem Default Wert. Der letzte Parameter im Bunde ist unser vorher ermittelte Mittelwert. In diesem Beispiel 35 MB.

Ihr kopiert euch nun die folgenden Zeilen aus der Codebox und tragt eure ermittelten Werte in die Zeilen ein. Danach führt ihr diese auf der Commandline aus.

sudo sed -i 's/pm = dynamic/pm = static/' /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i 's/pm.max_children =.*/pm.max_children = '92'/' /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i 's/pm.start_servers =.*/pm.start_servers = '23'/' /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i 's/pm.min_spare_servers =.*/pm.min_spare_servers = '23'/' /etc/php/8.1/fpm/pool.d/www.conf
sudo sed -i 's/pm.max_spare_servers =.*/pm.max_spare_servers = '69'/' /etc/php/8.1/fpm/pool.d/www.conf

Abschließend härten wir unsere Nextcloud Installation noch etwas ab. Folgende Parameter ändern wir wie folgt ab.

nano /etc/apache2/conf-available/security.conf
ServerTokens Prod
ServerSignature Off
TraceEnable Off


Grüße gehen aus dem Archiv!

Abonnieren
Benachrichtige mich bei
guest
14 Kommentare
Älteste
Neuste Meist Bewerteste
Inline Feedbacks
Zeige alle Kommentare
14
0
Bitte lasse uns an deinen Gedanken teilhaben und kommentier den Beitrag.x
Cookie Consent mit Real Cookie Banner