Tag Archive: mysql

Seafile 4.0.x mit Nginx und MySQL-Backend auf Debian/Ubuntu

seafile nginx mysql

Dass Seafile ursprünglich in China entwickelt wurde, tut der Sache keinen Abbruch, dass es sich um eine sichere und gute Open-Source Software mit Entwicklern aus der ganzen Welt handelt.
Seafile ist ähnlich OwnCloud eine selbst gehostete Cloud-Lösung zum Austausch von Dateien. Und noch mehr…
Für weitere Information empfehle ich einen Blick auf die Webseite.

Ich beschreibe hier die Einrichtung auf Basis von MySQL/MariaDB, „verstecken“ werde ich den Dienst hinter Nginx mit HTTPS.

Wovon ich ausgehe:

  • Nginx Server in Grundkonfiguration (siehe Artikel)
  • SSL-Zertifikat, es darf selbstsigniert sein (Tipp: https://startssl.com)
  • MySQL oder MariaDB Datenbank
  • Erreichbarkeit unter Subdomain „cloud.domain.tld“
  • Als Servernamen verwende ich durchgehend „servername“

Eine schöne Übersicht zur Kommunikation des Dienstes auf Basis von Nginx (Quelle):
Nginx, Seafile

Changelog

  • 24. Januar 2015 – Korrektur für Webdienst ([fileserver] anstatt [httpserver]), Download von Seafile via wget gefixt, Pfad der „seafile.conf“ korrigiert, seit v3.10 lautet „HTTP_SERVER_ROOT“ „FILE_SERVER_ROOT“
  • 19. Mai 2014 – Init-Script Anpassungen an Seafile 3.0.3
  • 18. Mai 2014 – Artikel angepasst an Seafile 3.0.3, Runlevel des Init-Scripts angepasst
  • 13. Mär 2014 – HTTP_SERVER_ROOT fixed (keine Preview, kein Download)
  • 15. Mär 2014 – Service nicht installiert

Installation und Konfiguration

Seafile definiert folgende Abhängigkeiten für die Installation und Ausführung, welche via „apt-get“ installiert werden können:

apt-get install python2.7 python-setuptools python-simplejson python-imaging python-mysqldb

Einen unpriviligierten Benutzer erstellen, „-d“ definiert das Heimverzeichnis, das später neben den Cloud-Daten auch die gesamte Seafile-Installation beinhalten wird. Ein Passwort wird nicht vergeben, da ein Login mit der fiktiven Shell „false“ nicht möglich ist:

useradd -m -d /srv/seafile -s /bin/false seafile

Ich wechsel zum Benutzer „seafile“ unter manueller Angabe einer Shell, in diesem Fall Bash:

su - seafile -s /bin/bash

Den Verzeichnisbaum lege ich dem Muster der Empfehlung Seafiles nach an.

Auch ist darauf zu achten, dass die neueste Version heruntergeladen wird! v4.0.6 ist zum Zeitpunkt des Artikels (Update 22.01.2015) aktuell.
In meinem Fall benutze ich die x86_64-Version für ein 64bit-System, reine 32bit-Systeme greifen entsprechend zum anderen Paket.

„servername“ im ersten Befehl bitte zwei mal ersetzen, es muss natürlich nicht der echte Servername sein.

mkdir -p servername/installed && cd servername/installed
wget --content-disposition -O seafile-server.tar.gz https://bitbucket.org/haiwen/seafile/downloads/seafile-server_4.0.6_x86-64.tar.gz && tar -xzvf *tar.gz -C ../ && cd ..

Die Struktur im Überblick:

seafile@www:~/servername$ tree -L 2
.
├── installed
│   └── seafile-server_4.0.6_x86-64.tar.gz
└── seafile-server-4.0.6
    ├── check_init_admin.py
    ├── reset-admin.sh
    ├── runtime
    ├── seaf-fuse.sh
    ├── seafile
    ├── seafile.sh
    ├── seahub
    ├── seahub.sh
    ├── setup-seafile-mysql.py
    ├── setup-seafile-mysql.sh
    ├── setup-seafile.sh
    └── upgrade

Nun in das Verzeichnis „seafile-server-4.0.6“ wechseln und das Script zur Erstellung der MySQL Datenbanken anstoßen:

cd seafile-server-4.0.6/
./setup-seafile-mysql.sh

Die aufkommenden Fragen zur Konfiguration nun beantworten.
Für die meisten Optionen wähle ich die Vorgabe, indem ich mit „Enter“ bestätige.

Im Folgenden erwähne ich nur Optionen, deren Standardwert ich verändert habe

Zwischendurch wird das „root“-Passwort der MySQL-Installation abgefragt.
Folgende manuelle Eingaben sind wichtig:

What is the name of the server? It will be displayed on the client.
3 – 15 letters or digits
[ server name ] servername

What is the ip or domain of the server?
For example: www.mycompany.com, 192.168.1.101
[ This server’s ip or domain ] cloud.domain.tld

——————————————————-
Please choose a way to initialize seafile databases:
——————————————————-

[1] Create new ccnet/seafile/seahub databases
[2] Use existing ccnet/seafile/seahub databases

[ 1 or 2 ] 1

What is the host of mysql server?
[ default „localhost“ ] je nach Konfiguration

What is the port of mysql server?
[ default „3306“ ] je nach Konfiguration

What is the password of the mysql root user?
[ root password ] je nach Konfiguration

verifying password of user root … done

Enter the name for mysql user of seafile. It would be created if not exists.
[ default „root“ ] seafileusr (zum Beispiel)

Enter the password for mysql user „seafileusr“:
[ password for seafileusr ] Passwort für den neuen Benutzer „seafileusr“

———————————
This is your configuration
———————————
[…]
———————————
Press ENTER to continue, or Ctrl-C to abort
———————————
Enter
—————————————————————–
Your seafile server configuration has been finished successfully.
—————————————————————–

Bitte nicht „root“ als MySQL-Benutzer für Seafile benutzen.

Da ich Seafile via HTTPS benutzen möchte, ändere ich zwei Dateien:

nano ~/servername/ccnet/ccnet.conf

Hier die Option „SERVICE_URL“ suchen und aus „http“ „https“ mache, etwa:

SERVICE_URL = https://cloud.domain.tld

Die Zweite Datei öffnen:

nano ~/servername/seahub_settings.py

Am Ende der Datei einfügen:

FILE_SERVER_ROOT = 'https://cloud.domain.tld/seafhttp'
ACHTUNG: Seit Version 3 wird der Administrator nicht mehr mit dem Setup erstellt.

Erst durch ein einmalig manuelles Starten der Dienste wird hierzu aufgefordert.

~/servername/seafile-server-latest/seafile.sh start
~/servername/seafile-server-latest/seahub.sh start-fastcgi

Es folgt:

What is the email for the admin account?
[ admin email ] username@domain.tld

What is the password for the admin account?
[ admin password ] sicherespasswort

Enter the password again:
[ admin password again ] sicherespasswort

Zum Abschluss noch die manuell gestarteten Dienste wieder beenden:

~/servername/seafile-server-latest/seafile.sh stop
~/servername/seafile-server-latest/seahub.sh stop

Der lokale Webdienst sollte zudem auf „localhost“ gebunden, um direkten externen Zugriff zu verhindern:

nano ~/servername/seafile-data/seafile.conf

Hier nun folgende Änderung vorhehmen:

[fileserver]
host=127.0.0.1
port=8082

Ab hier bitte mit „exit“ die Shell verlassen und zum Beispiel als „root“ weiterarbeiten!

Da der Seafile-Server hinter einem Nginx-Backend via SSL läuft, benötige ich anstatt vier nur drei Freigaben in der Firewall:

443/TCP – HTTPS – IN/OUT
10001/TCP – Ccnet Daemon – IN/OUT
12001/TCP – Seafile Daemon – IN/OUT

Zum Beispiel (kann auch ignoriert werden):

/sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT ACCEPT
/sbin/iptables -I INPUT -i lo -p all -j ACCEPT # Interne Kommunikation via localhost vollständig freigeben
/sbin/iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A INPUT -p tcp -d PUB.LIC.SRV.IP -m state --state NEW -m multiport --dport 10001,12001,443 -j ACCEPT

Achtung: Bitte nicht blind übernehmen, da ihr euch ansonsten von der SSH aussperrt!

Für Nginx richte ich eine neue Site mit der Subdomain „cloud.domain.tld“ ein.
Wird diese Konfiguration übernommen, so bitte den Pfad „/srv/seafile/servername/seafile-server-latest/seahub“ anpassen, ebenso „server_name“, ssl_certificate und ssl_certificate_key:

server {
        listen       80;
        server_name  cloud.domain.tld;
        rewrite ^/(.*) https://$server_name/$1 permanent;
}
server {
        listen 443; #IPv4
        #listen [::]:443; # IPv6
        ssl on;
        ssl_certificate /etc/nginx/certs/ssl-unified.crt;
        ssl_certificate_key /etc/nginx/certs/ssl.key;
        server_name cloud.domain.tld;

        location / {
                fastcgi_pass    127.0.0.1:8000;
                fastcgi_param   SCRIPT_FILENAME     $document_root$fastcgi_script_name;
                fastcgi_param   PATH_INFO           $fastcgi_script_name;

                fastcgi_param   SERVER_PROTOCOL     $server_protocol;
                fastcgi_param   QUERY_STRING        $query_string;
                fastcgi_param   REQUEST_METHOD      $request_method;
                fastcgi_param   CONTENT_TYPE        $content_type;
                fastcgi_param   CONTENT_LENGTH      $content_length;
                fastcgi_param   SERVER_ADDR         $server_addr;
                fastcgi_param   SERVER_PORT         $server_port;
                fastcgi_param   SERVER_NAME         $server_name;

                fastcgi_param   HTTPS on;
                fastcgi_param   HTTP_SCHEME https;
        }

        location /seafhttp {
                rewrite ^/seafhttp(.*)$ $1 break;
                proxy_pass http://127.0.0.1:8082;
                client_max_body_size 0;
        }

        location /media {
                root /srv/seafile/servername/seafile-server-latest/seahub;
        }
}

In diesem Fall erfolgt eine Weiterleitung von HTTP auf HTTPS. PHP oder Sonstiges braucht nicht definiert zu werden!

Nginx nun „reloaden“:

service nginx reload

Bevor das Init-Script angelegt- und der Dienst gestartet wird, werfe ich noch einen Blick in die Datei „hosts“:

nano /etc/hosts

Hier bitte sicherstellen, dass folgender Eintrag vorhanden ist:

127.0.0.1       cloud.domain.tld

Im Git-Repository findet sich ein Init-Script, das Seafile und Seahub als unprivilegierter Benutzer startet, auch lässt sich definieren, dass Seahub nur im FastCGI-Modus gestartet wird.
Ich habe es etwas angepasst.

Das Script erstellen:

nano /etc/init.d/seafile

Der Inhalt, in dem „user“ und „seafile_dir“ bitte angepasst werden:

#!/bin/bash

### BEGIN INIT INFO
# Provides:          seafile
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts Seafile and Seahub
# Description:       starts Seafile and Seahub
### END INIT INFO

#### CONFIG START ####
user=seafile
seafile_dir=/srv/seafile/servername
##### CONFIG END #####

script_path=${seafile_dir}/seafile-server-latest
seafile_init_log=${seafile_dir}/logs/seafile.init.log
seahub_init_log=${seafile_dir}/logs/seahub.init.log
[ -d ${seafile_dir}/logs ] || mkdir ${seafile_dir}/logs && chown $user:$user ${seafile_dir}/logs

# Change the value of fastcgi to true if fastcgi is to be used
fastcgi=true
# Set the port of fastcgi, default is 8000. Change it if you need different.
fastcgi_port=8000

case "$1" in
        start)
                sudo -u ${user} ${script_path}/seafile.sh start >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh start-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh start >> ${seahub_init_log}
                fi
        ;;
        restart)
                sudo -u ${user} ${script_path}/seafile.sh restart >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh restart-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh restart >> ${seahub_init_log}
                fi
        ;;
        stop)
                ${script_path}/seafile.sh $1 >> ${seafile_init_log}
                ${script_path}/seahub.sh $1 >> ${seahub_init_log}
        ;;
        *)
                echo "Usage: /etc/init.d/seafile {start|stop|restart}"
                exit 1
        ;;
esac

Das Script noch als ausführbar markieren und den Dienst installieren sowie starten:

chmod +x /etc/init.d/seafile
update-rc.d seafile defaults
service seafile start

Der Client kann nun installiert und konfiguriert werden.
Vorab darf das Webpanel bewundert und ebenfalls konfiguriert werden: https://cloud.domain.tld

Danke an die Hinweise aus den Kommentaren!

Debian Wheezy: Von MySQL zu MariaDB 10.0 migrieren (unattended)

MariaDB ist ein Fork von MySQL und sogar ein echtes „Drop-in Replacement“ für dieses. Ein Umstieg von MySQL auf MariaDB verläuft somit fast immer reibungslos, eine Nachkonfiguration ist nicht notwendig.
In seltenen Fällen und besonders bei Verwendung eigener (Web-)Anwendungen mit MySQL-Backend, rate ich dringlichst einen Blick auf die Kompatibilitätsübersicht.

Eine kurze, eilig übersetzte Zusammenfassung:

  • .frm-Dateien sind binärkompatibel.
  • Alle Client-APIs, Protokolle und „structs“ sind identisch.
  • Alle Dateinamen, Anwendungsdateien, Pfade, Ports, Sockets etc. sind identisch.
  • Alle MySQL-Anschlüsse (PHP, Perl, Python, Java, .NET, MyODBC, Ruby, MySQL C etc.) funktionieren mit MariaDB.
  • Das Paket „mysql-client“ arbeitet mit MariaDB zusammen.
  • Die „shared client library“ ist binärkompatibel mit der MySQL „client library“.
  • Selten gibt es Probleme mit PHP5 und der alten „mysql_connect“-Methode in Verbindung mit MariaDB, hier ein Fix.

Ja, es ist WordPress-kompatibel.

Was macht das Script?

Das Script geht folgendermaßen vor:

  • „python-software-properties“ installieren, um das Repository einfacher hinzuzufügen.
  • Schlüsselbund um den Schlüssel für das MariaDB 10.0 Repository erweitern.
  • Repository aktualisieren, setzen des Root-Passworts für die unbeaufsichtigte Installation.
  • Installation von MariaDB 10.0 – diese entfernt das Paket „mysql-server“! Alle Daten bleiben jedoch erhalten!
  • Log-Datei „migration.log“ im selben Verzeichnis des Scripts

Script und Anleitung

#!/bin/bash
if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root" 1>&2
    exit 1
fi

EXPECTED_ARGS=1
E_BADARGS=65

if [ $# -ne $EXPECTED_ARGS ]
then
  echo "Usage: `basename $0` SQL_ROOT_PW"
  exit $E_BADARGS
fi

MYSQL_PASS=$1

echo -en "Migrating MySQL to MariaDB...\t\t"
apt-get update >> migration.log 2>&1
apt-get install -y python-software-properties >> migration.log 2>&1
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db >> migration.log 2>&1
add-apt-repository 'deb http://mirror.netcologne.de/mariadb/repo/10.0/debian wheezy main' >> migration.log 2>&1
apt-get update >> migration.log 2>&1
export DEBIAN_FRONTEND=noninteractive
debconf-set-selections <<< "mariadb-server-10.0 mysql-server/root_password password $MYSQL_PASS"
debconf-set-selections <<< "mariadb-server-10.0 mysql-server/root_password_again password $MYSQL_PASS"
apt-get install -y mariadb-server-10.0 >> migration.log 2>&1
if [ $? -ne 0 ] ; then
  echo -e "\e[00;31m ERR\e[00m"
  exit 1
fi
echo -e "\e[00;32m OK\e[00m"

Usage: # ./script.sh SQL_ROOT_PW
Vorab als ausführbar markieren: chmod +x script.sh
Falls Fehler auftreten, „migration.log“ prüfen.

Im Notfall zurück zu MySQL

Sollte das Upgrade nicht funktionieren, kann MySQL im Notfall schnell wiederhergestellt werden. Hier eine Schritt-für-Schritt Beschreibung für ein Downgrade:

service mysql stop
apt-get remove -y mariadb-server mariadb-server-10.0
rm /var/lib/mysql/debian-*
add-apt-repository -r 'deb http://mirror.netcologne.de/mariadb/repo/10.0/debian wheezy main'
apt-get update
export DEBIAN_FRONTEND=text
apt-get install -y mysql-server

How-To: nginx, PHP-FPM (multiple Sockets), MySQL und Subdomains in Debian Wheezy/Jessie

Im Gegensatz zu dem Klassiker „LAMP“ (Linux, Apache, MySQL und PHP), beschreibe ich hier die Methode „LNMP“, also weniger Apache, mehr nginx. Als kleine Zugabe soll jeder Server (jede Site/Subdomain) einen eigenen PHP Socket zugeteilt bekommen und durch „open_basedir“ der Zugriff auf die eigene Site limitiert werden.

Changelog

  • 07.06.2015 – PHP: Fix für Debian Jessie (danke an Kevin für den Hinweis!)
  • 03.08.2014 – „date.timezone“ und „listen.allowed_clients“ gesetzt
  • 17.01.2014 – Kritische Funktionen deakvieren
  • 18.05.2014 – „listen.*“-Parameter für PHP5-FPM, welche nun Pflicht sind

Das Szenario

Um alles ein wenig Anschaubarer zu machen, gehe ich von folgendem Umstand aus:

Das Szenario
Das Szenario

Es wird davon ausgegangen, dass für die Domäne „domain.tld“ ein A-Record „*“ besteht, welcher alle Anfragen auf die öffentliche IP des Webservers leitet. Während des Schreibens habe ich meine lokale „hosts“ Datei („/etc/hosts“) abgeändert, um die Konfiguration zu testen, wobei „192.168.67.129“ die IP meines Test-Servers ist. Zum Ausprobieren ohne Domäne sehr hilfreich:

192.168.67.129 domain.tld
192.168.67.129 www.domain.tld
192.168.67.129 notavailable.domain.tld
192.168.67.129 custom1.domain.tld
192.168.67.129 custom2.domain.tld

Wie bereits beschrieben erhalten alle Sites einen eigenen PHP Socket mit zusätzlichem Attribut für das „open_basedir“.

Installation

Es reicht grundsätzlich die Installation folgender Pakete aus:

apt-get install nginx mysql-server mysql-client php5-fpm php5-mysql

Während der Installation von MySQL wird ein Passwort für den root-Benutzer abgefragt, welches frei wählbar ist aber sich von dem des lokalen root-Benutzers Unterscheiden sollte.

Natürlich gibt es verschiedene nginx Pakete mit unterschiedlichen Funktionen. Das Paket „nginx“ installiert z.B. „nginx-full“. Eine Übersicht gibt es hier

Abhängig von der später eingesetzten Software (Drupal, Joomla, WordPress, Webmail etc.), können noch weitere PHP-Module benötigt werden. Diese Abhängigkeiten werden natürlich in den Dokumenten der Anbieter beschrieben. „php5-mysql“ ist das Modul zur Anbindung an die die MySQL Datenbank.

Konfiguration

Ein kleines bisschen Sicherheit

Es ist immer zu empfehlen, die Version des Webservers und PHP zu verstecken. Selbstverständlich werden so keine Angriffe verhindert, allerdings kann das Auffinden von anfälligen (veralteten) Versionen erschwert werden. Folgende zwei Dateien dazu editieren:

/etc/nginx/nginx.conf:

server_tokens off;

/etc/php5/fpm/php.ini:

expose_php = Off

Für alle Sockets sollten zudem kritische Funktionen zum Ausführen von Anwendungen deaktiviert werden. Diese können für einzelne Sockets bei Bedarf freigegeben werden:

/etc/php5/fpm/php.ini:

disable_functions=phpinfo,exec,shell_exec,system,passthru

Auch MySQL kann schnell minimal abgesichert werden, dazu „mysql_secure_installation“ ausführen:

Enter current password for root (enter for none): Passwort von der Installation des MySQL eingeben
Change the root password? [Y/n] n
Alles Weitere mit Enter bestätigen

Einrichtung der Sites

Zuerst die Sites bereinigen:

rm /etc/nginx/sites-*/*

Und im Anschluß vier neue Sites anlegen (z.B. via „nano“):

/etc/nginx/sites-available/default:

server {
       listen         80;
       rewrite        ^ http://www.domain.tld permanent;
}

/etc/nginx/sites-available/www:

server {
        listen 80;

        root /usr/share/nginx/www;
        access_log /var/log/nginx/access_log_www;
        index index.html index.htm index.php;

        server_name domain.tld www.domain.tld;

        location / {
        }

        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm-www.sock;
                fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
                fastcgi_index index.php;
                include fastcgi_params;
        }
}

/etc/nginx/sites-available/custom1:

server {
        listen 80;

        root /usr/share/nginx/custom1;
        access_log /var/log/nginx/access_log_custom1;
        index index.html index.htm index.php;

        server_name custom1.domain.tld;

        location / {
        }

        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm-custom1.sock;
                fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
                fastcgi_index index.php;
                include fastcgi_params;
        }
}

/etc/nginx/sites-available/custom2:

server {
        listen 80;

        root /usr/share/nginx/custom2;
        access_log /var/log/nginx/access_log_custom2;
        index index.html index.htm index.php;

        server_name custom2.domain.tld;

        location / {
        }

        location ~ \.php$ {
                fastcgi_split_path_info ^(.+\.php)(/.+)$;
                fastcgi_pass unix:/var/run/php5-fpm-custom2.sock;
                fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
                fastcgi_index index.php;
                include fastcgi_params;
        }
}

Hinweis: Durch „server_name“ reagieren die Sites nur auf eben ihren Namen.

Nun die Sites für nginx sichtbar machen:

cd /etc/nginx/sites-enabled
ln -s /etc/nginx/sites-available/* .

Wichtig: Die Site „default“ ist die Anlaufstelle für Aufrufe der IP-Adresse oder unbekannten Sub-Domains. Für unsere Konfiguration werden diese Aufrufe auf www.domain.tld umgeleitet, dafür steht der „redirect“.

Einrichtung der PHP Sockets

Der PHP FastCGI Process Manager (php-fpm) durchsucht das Verzeichnis „/etc/php5/fpm/pool.d“ nach zu erstellenden Sockets. Alle vorhandenen vorab löschen:

rm /etc/php5/fpm/pool.d/*

Drei neue Konfigurationen werden hier erstellt, die „Listener“ entsprechen denen aus den Sites:

/etc/php5/fpm/pool.d/www.conf:

[www]
listen = /var/run/php5-fpm-www.sock
listen.backlog = 4096
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 5
pm.max_requests = 40
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
php_admin_value[open_basedir] = /usr/share/nginx/www/:/tmp/
php_admin_value[date.timezone] = Europe/Berlin

/etc/php5/fpm/pool.d/custom1.conf:

[custom1]
listen = /var/run/php5-fpm-custom1.sock
listen.backlog = 4096
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 5
pm.max_requests = 40
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
php_admin_value[open_basedir] = /usr/share/nginx/custom1/:/tmp/
php_admin_value[date.timezone] = Europe/Berlin

/etc/php5/fpm/pool.d/custom2.conf:

[custom2]
listen = /var/run/php5-fpm-custom2.sock
listen.backlog = 4096
user = www-data
group = www-data
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
listen.mode = 0660
pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 5
pm.max_requests = 40
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp
php_admin_value[open_basedir] = /usr/share/nginx/custom2/:/tmp/
php_admin_value[date.timezone] = Europe/Berlin

Das Limit der Backlogs kann nicht einfach beliebig erhöht werden, das System hat hierfür ein globales Limit (Standard: 1000), welches in der Datei /etc/sysctl.conf eingestellt werden kann:

echo "net.core.netdev_max_backlog=4096" >> /etc/sysctl.conf
echo "net.core.somaxconn=4096" >> /etc/sysctl.conf
echo "net.ipv4.tcp_max_syn_backlog=4096" >> /etc/sysctl.conf
sysctl -p # Änderungen einlesen

Die „pm“ Attribute haben großen Einfluss auf die Leistung und Resourcenverwendung von PHP auf das System. Damit auch auf die Website. Zur besseren Konfiguration nach Bedarf einfach Google bemühen, da eine Erklärung zu komplex für dieses How-To wäre. Läuft auf der Site „custom1“ beispielsweise eine weitaus komplexere Anwendung (~Joomla) als auf „custom2“ (~Postfixadmin), sollten die Einstellungen natürlich angepasst werden.
Kleiner Hinweis: Bei sehr, sehr vielen Sites mit vielen Prozessen, könnte irgendwann auch die Einstellung „fs.file-max“ in der Datei „/etc/sysctl.conf“ wichtig werden.

Die „php_admin_value“ Attribute können ebenfalls eingesetzt werden, um die globalen Einstellungen aus der Datei „/etc/php5/fpm/php.ini“ zu überschreiben. Zum Beispiel lassen sich eigene memory_limits einrichten.

Verzeichnisse und Dateien anlegen

Die Verzeichnisse der Sites dieses Beispiels liegen unter „/usr/share/nginx“.
Achtung: Möchte man einen anderen Ort hierfür wählen, müssen die Sockets („open_basedir“) sowie die Site Konfigurationen angepasst werden!

Das Webroot bereinigen und die neuen Ordner für die Sites anlegen, abschließend den Besitzer auf www-data abändern:

rm -r /usr/share/nginx/*
mkdir /usr/share/nginx/{www,custom1,custom2}
chown -R www-data:www-data /usr/share/nginx/*

Access- und Error-Log

Der Speicherort ist selbstverständlich frei wählbar, allerdings muss das Verzeichnis exisiteren, damit die Dateien von nginx automatisch erstellt werden.

In den Site Konfigurationen ist der Speicherort „/var/log/nginx“ für die Access Logs jedoch gezielt gewählt, da hier die automatisch mit der Installation von nginx erzeugte Regel für „logrotate“ greift. Die Regel befindet sich in der Datei „/etc/logrotate.d/nginx“. Wird der Speicherort also geändert, sollte man sich Gedanken über das rotieren der Logs machen, damit diese nicht den Speicherplatz unnötig belegen. Auch die Übersicht leidet nach einigen Monaten stark. Die vorhandene Regel kann hierzu als Beispiel dienen.

Es ließe sich zusätzlich das „error_log“ per Site definieren, worauf ich in diesem Beispiel verzichtet habe. Die Fehler werden in die global via „/etc/nginx/nginx.conf“ definierte Datei geschrieben. Der Pfad lautet in der Standard-Installation „/var/log/nginx/error_log“.

Der Site „default“ wurde kein solches Attribut erteilt, weshalb hierfür auch die Zugriffe in die globale Datei „/var/log/nginx/access_log“ geschrieben werden.

Fertigstellung

Die Dienste durchstarten

Abschließend die Änderungen übernehmen, indem die zugehörigen Dienste neugestartet werden:

service php5-fpm restart
service nginx restart

Konfiguration testen

Um ganz sicher zu gehen, dass nun alles funktioniert, kann in den Webroots jeweils eine Datei „index.php“ angelegt werden, die die PHP Konfiguration ausgibt („phpinfo“) sowie den Sitename anzeigt:

echo "Sitename CUSTOM1 

" > /usr/share/nginx/custom1/index.php echo "Sitename CUSTOM2

" > /usr/share/nginx/custom2/index.php echo "Sitename WWW

" > /usr/share/nginx/www/index.php

Sieht nicht schön aus, aber erfüllt seinen Zweck.

Zusätzlich die „Worker“ überprüfen:

ps aux | grep php-fpm

ps aux | grep php-fpm
ps aux | grep php-fpm
Die Ausgabe zeigt, dass die definierten Worker auch tatsächlich arbeiten. Da die Konfiguration gerade neugestartet wurde und die Prozesse noch nicht ausgelastet sind, entspricht die Anzahl dem Attribut „pm.start_servers“, nämlich 3.

Viel Erolg!