Inhaltsverzeichnis

Konfiguration Server

Zusätzliches für www.soscisurvey.de

Vorbereitung

Geänderte Konfigurationsdateien ansehen:

sudo debsums -ce
diff /etc/whatever{,.dpkg-dist}

Basis-Setup

Setup eines Befragungsservers auf Basis eines Debian oder Ubuntu Servers.

SSH KeepAlive, vgl. How to Keep Alive SSH Sessions

sudo vim /etc/ssh/ssh_config
Host *
    ServerAliveInterval 300
    ServerAliveCountMax 2
sudo vim /etc/ssh/sshd_config
ClientAliveInterval 60
ClientAliveCountMax 2

Key-Fingerprints für SSH notieren (ssh_host_rsa_key und alle anderen, mal als md5, mal ohne):

sudo ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key -E md5

Benutzer einrichten, Kennwörter in KeePass. s2access bekommt ein 32-stelliges Passwort, sosci erlaubt den Login nur via KeyFile.

sudo useradd -m sosci
sudo useradd -m s2access
sudo passwd sosci
sudo passwd s2access
sudo usermod -a -G sudo sosci
sudo usermod -a -G sudo s2access

Noch die Shell ändern:

sudo vim /etc/passwd
sosci:x:1001:1001::/home/sosci:/bin/bash
s2access:x:1002:1002::/home/s2access:/bin/bash

Kein Passwort für root

sudo vim /etc/shadow

Zugang via Keyfile (Using PuTTY and keyfiles to SSH...), dafür Login als sosci.

mkdir ~/.ssh
chmod -R 700 ~/.ssh
vim ~/.ssh/authorized_keys
# Inhalt aus ''puttygen''
chmod 600 ~/.ssh/authorized_keys

# Edit /etc/ssh/sshd_config so it contains
sudo vim /etc/ssh/sshd_config
AuthorizedKeysFile %h/.ssh/authorized_keys
PermitRootLogin no

sudo service ssh restart

Passwort-Login für alles außer s2access deaktivieren, vgl. How to disable SSH login with password for some users?

sudo vim /etc/ssh/sshd_config
# Am Ende der Datei einfügen
PasswordAuthentication no
Match User s2access
PasswordAuthentication yes

sudo service ssh restart

Eventuell noch früheren Nutzer löschen.

sudo deluser whatever

Software

# System aktualisieren
sudo apt update
sudo apt dist-upgrade
sudo apt remove apache2
sudo apt autoremove

# Software installieren
sudo apt install less vim elinks debsums fail2ban munin libwww-perl monit unattended-upgrades duplicity duply tmux ncdu
sudo apt install iptables rkhunter chkrootkit mailutils
sudo apt install nginx mysql-server apachetop php-fpm php-mysql php-json php-xml php-gd php-mbstring php-zip php-intl dovecot-pop3d opendkim opendkim-tools apache2-utils

# Nur für Let's Encrypt
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot

sudo apt-get update
sudo apt-get install python-certbot-nginx

Hinweis: apache2-utils sind für htaccess-Passwörter, die für Munin gebraucht werden.

Sicherheit

Sicherheitsupdates

unattended-upgrades muss noch aktiviert werden, vgl UnattendedUpgrades

sudo dpkg-reconfigure -plow unattended-upgrades
/etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Mail "info@soscisurvey.de";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "05:00";

Wöchentliche Updates

sudo vim /root/mailinfo.update.sh
/root/mailinfo.update.sh
#!/bin/sh
printf "Subject:[Server] s2survey.net Update\n\n%s\n." "`/root/update.sh`" | /usr/sbin/sendmail -t info@soscisurvey.de
sudo vim /root/update.sh
/root/update.sh
#!/bin/bash
sudo apt-get update
sudo apt-get --quiet --assume-yes --show-upgraded dist-upgrade
sudo apt-get autoremove
/root/kernel-clean.sh
#! /bin/bash
printf "\n\nAktueller Kernel\n"
uname -a
 
printf "\n\nZu entfernen\n"
dpkg -l 'linux-[ihs]*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\([-0-9]*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | tee kernel-clean.list
 
printf "\n"
read -p "Press enter to continue"
 
cat kernel-clean.list | xargs sudo apt-get -y purge
rm kernel-clean.list
/root/mailinfo.reboot.sh
#!/bin/sh
printf "Subject:[Server] s2survey.net (2019) Reboot\n\nServer rebootet\n." | /usr/sbin/sendmail -t info@soscisurvey.de
/root/postfix.sh
#!/bin/bash
# Update the postfix databases and reload
postmap /etc/postfix/virtual
postmap /etc/postfix/senders
postalias /etc/aliases
postfix reload
sudo chmod u+x /root/kernel-clean.sh
sudo chmod u+x /root/update.sh
sudo chmod u+x /root/mailinfo.update.sh
sudo chmod u+x /root/mailinfo.reboot.sh
sudo chmod u+x /root/postfix.sh

Backup-Scripte

Siehe auch Backup unter Linux mit duply.

sudo vim /etc/fstab
mkdir /mnt/backup
touch /mnt/backup/NOT\ MOUNTED
touch /mnt/backup/s2survey2019
nas01.internetwire.de:/home/sosci /mnt/backup nfs nfsvers=3,soft,timeo=30,addr=95.130.16.146 0 0
/root/backup/backup-daily.sh
#!/bin/bash
echo "
 
 
 
********** Backup (Daily) **********" >> /var/log/backup-daily.log
date >> /var/log/backup-daily.log
mount /mnt/backup >> /var/log/backup-daily.log
echo "
" >> /var/log/backup-daily.log
 
/usr/bin/duply database backup_purge --force >> /var/log/backup-daily.log
#/usr/bin/duply sosci-database-A backup_purge --force >> /var/log/backup-daily.log
#/usr/bin/duply sosci-database-B backup_purge --force >> /var/log/backup-daily.log
#/usr/bin/duply server backup_purge --force >> /var/log/backup-daily.log
/usr/bin/duply files backup_purge --force >> /var/log/backup-daily.log
 
sleep 20
umount /mnt/backup >> /var/log/backup-daily.log
/root/backup/backup-weekly.sh
#!/bin/bash
echo "
 
 
***** Backup (Weekly) *****" >> /var/log/backup-weekly.log
date >> /var/log/backup-weekly.log
mount /mnt/backup >> /var/log/backup-weekly.log
echo "
" >> /var/log/backup-weekly.log
 
/usr/bin/duply server backup_purge --force >> /var/log/backup-weekly.log
# /usr/bin/duply s2server-etc backup_purge --force >> /var/log/backup-weekly.log
# /usr/bin/duply s2server-root backup_purge --force >> /var/log/backup-weekly.log
 
# Disk space information sent to standard output
 
echo "***** Backup Weekly Stats *****
"
/usr/local/nagios/libexec/check_disk -w 15% -c 8% -p /mnt/backup
echo ""
du /mnt/backup --max-depth=2 -h
 
sleep 20
 
umount /mnt/backup >> /var/log/backup-weekly.log
sudo chmod u+x /root/backup/backup-daily.sh
sudo chmod u+x /root/backup/backup-weekly.sh
sudo duply server create
sudo duply database create
sudo duply files create
sudo mkdir /root/backup/
sudo mkdir /root/backup/mysql/
sudo su
cd ~/.duply/server
gpg --gen-key
mv conf conf.dist
vim conf
vim exclude
/root/.duply/server/conf
GPG_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_PW='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_OPTS="--pinentry-mode loopback"
TARGET='file:///mnt/backup/s2survey2019/server'
TARGET_USER=''
TARGET_PASS=''
SOURCE='/'
MAX_AGE=3M
MAX_FULLBKP_AGE=2M
DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE "
/root/.duply/server/exclude
/initrd.img
/lib64
/vmlinuz
/dev/
/proc/
/sys/
/tmp/
/run/
/mnt/
/media/
/lost+found/
 
/home/sosci/backup/
/usr/share/doc/
/usr/src/
/var/backup/
/var/cache/
/var/www/
/var/tmp/
/var/lib/mysql/
/var/lib/lxcfs/cgroup/
/root/.cache/
/root/backup/mysql/
cd ~/.duply/database
mv conf conf.dist
vim conf
vim pre
vim post
chmod u+x pre
chmod u+x post
/root/.duply/database/conf
GPG_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_PW='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_OPTS="--pinentry-mode loopback"
TARGET='file:///mnt/backup/s2survey2019/database'
SOURCE='/root/backup/mysql'
MAX_AGE=1M
MAX_FULL_BACKUPS=31
MAX_FULLBKP_AGE=23h
DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE "
/root/.duply/database/pre
#!/bin/sh
datetime=`date +%Y-%m-%d_%H-%M-%S`
mysqldump -ubackup -pXXXXXXXXXXXXXXXXXXXX --databases s2survey --ignore-table s2survey.s2_receivers --quick --single-transaction | gzip -9 > /root/backup/mysql/s2survey-$datetime.sql.gz
mysqldump -ubackup -pXXXXXXXXXXXXXXXXXXXX --quick --single-transaction s2survey s2_receivers | gzip -9 > /root/backup/mysql/s2survey-receivers-$datetime.sql.gz
/root/.duply/database/post
#!/bin/sh
rm /root/backup/mysql/s2survey-*
cd ~/.duply/files
mv conf conf.dist
vim conf
vim exclude

Das Backup kann entweder auf das lokale Laufwerk (gemountetet Backup-Speicher) oder vis SFTP erfolgen. Eventuell ist dafür noch das Modul python-paramiko (via apt)) erforderlich.

/root/.duply/files/conf
GPG_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_PW='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_OPTS="--pinentry-mode loopback"
TARGET='file:///mnt/backup/s2survey2019/files'
SOURCE='/var/www/s2survey/html'
MAX_AGE=1M
MAX_FULL_BACKUPS=2
MAX_FULLBKP_AGE=14D
DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE "
/root/.duply/files/conf
GPG_KEY='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
GPG_PW=''
TARGET='sftp://s2backup@207.180.212.193/sosci/files'
TARGET_USER='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
TARGET_PASS='XXXXXXXXXXXXXXXXXXXXXXXXXXX'
SOURCE='/var/www/soscisurvey/html'
MAX_AGE=13D
MAX_FULL_BACKUPS=1
MAX_FULLBKP_AGE=1M
DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE "
/root/.duply/files/exclude
/var/www/s2survey/html/view/
/var/www/s2survey/html/system/cache/
/var/www/s2survey/html/system/temp/
/var/www/s2survey/html/system/session/
/var/www/s2survey/html/system/lock/
 
/var/www/s2survey/html/files/protected/000000/
/var/www/s2survey/html/CUSTOM_PROJECT/

Wichtig: Schlüssel auf RAM-Disk übertragen und in KeePass sichern.

gpg --list-secret-keys
gpg --output private.pgp --armor --export-secret-key email@adresse.de
gpg --output public.pgp --armor --export email@adresse.de

Noch nicht eingearbeitet

NTP-Server einstellen

s. Time Synchronization

sudo vim /etc/systemd/timesyncd.conf
NTP=ptbtime1.ptb.de
FallbackNTP=ntp1.lrz.de

fail2ban

Den anderen Befragungsserver als vertrauenswürdig akzeptieren.

sudo vim /etc/fail2ban/jail.local
/etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 95.130.22.98
findtime = 600
bantime  = 600
maxretry = 3
destemail = info@soscisurvey.de
chain = INPUT
 
[serial-fail]
# SoSci Surveys locks IPs on its own, this is only the upper limit
enabled  = true
port     = http,https
filter   = serial-fail
action   = iptables-allports
           mail-whois[name=Serial Fail, dest=info@soscisurvey.de]
logpath  = /var/www/s2survey/html/system/logfiles/token-fail.log
maxretry = 50
bantime  = 7200
 
[sshd]
enabled = true
mode    = aggressive
 
[php-url-fopen]
enabled = true
 
# Nur wenn installiert
[owncloud]
enabled = true
sudo vim /etc/fail2ban/filter.d/serial-fail.conf
/etc/fail2ban/filter.d/serial-fail.conf
[Definition]
failregex = <HOST>\s+(invalid|serial|deliveryToken)
ignoreregex =

rkhunter

xinet wird für Nagios erlaubt.

sudo vim /etc/rkhunter.conf
PKGMGR=DPKG
XINETD_ALLOWED_SVC=/etc/xinetd.d/nrpe

sudo rkhunter --propupd

sudo vim /etc/default/rkhunter
CRON_DAILY_RUN="true"
CRON_DB_UPDATE="true"
REPORT_EMAIL="info@soscisurvey.de"
mkdir /var/log/chkrootkit/
vim /etc/chkrootkit.conf
RUN_DAILY="true"

Cronjobs

sudo crontab -e

# m     h       dom     mon     dow     command
@reboot                                 /root/mailinfo.reboot.sh
15      00      *       *       *       /etc/cron.daily/chkrootkit > /var/log/chkrootkit/daily.log
30      00      *       *       *       /etc/cron.daily/rkhunter
00      01      *       *       *       /root/backup/backup-daily.sh
00      02      *       *       sun     /root/backup/backup-weekly.sh
30      04      *       *       *       /root/mailinfo.update.sh
00      05      *       *       sun     /usr/bin/certbot renew --post-hook "service nginx reload"
55      05      *       *       sun     /sbin/reboot
sudo crontab -e -uwww-data

# m     h       dom     mon     dow     command
*/1     *       *       *       *       /var/www/s2survey/script/crontask.sh >/dev/null 2>&1
0      3       *       *       *       /var/www/s2survey/script/cronjob.sh

Einstellungen

Firewall

sudo mkdir /etc/iptables
sudo bash -c "iptables-save > /etc/iptables/rules.v4"
sudo bash -c "ip6tables-save > /etc/iptables/rules.v6"
rules.v4
## Generated by iptables-save v1.4.8
## Modified manually!
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [11:777]
#
## Loopback
-A INPUT -i lo -j ACCEPT
-A INPUT -s localhost -j ACCEPT
#-A OUTPUT -o lo -j ACCEPT
#
## Monitoring-Server
-A INPUT -s 95.130.16.86 -j ACCEPT
-A INPUT -s 95.130.16.67 -j ACCEPT
#
## Test performance
#-A INPUT -s 92.75.27.206 -j ACCEPT
#
## Accept established connections
#-A INPUT -m state --state RELATED,ESTABLISHED -m limit --limit 50/second --limit-burst 50 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
#
## Record new incoming connections per IP
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh --set
-A INPUT -p tcp --dport 80 -m state --state NEW -m recent --name http --set
# -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name https --set
#
## Limit numbers of new connections/time per IP
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh --rcheck --seconds 10 --hitcount 6 -j LOG --log-prefix SSH-DROP:
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name ssh --rcheck --seconds 10 --hitcount 6 -j REJECT --reject-with tcp-reset
-A INPUT -p tcp --dport 80 -m state --state NEW -m recent --name http --rcheck --seconds 2 --hitcount 20 -j REJECT --reject-with tcp-reset
# Okay, this is a problem for RTR mobile as there may be more than 20 new connections in 2 seconds
# -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name https --rcheck --seconds 1 --hitcount 20 -j LOG --log-prefix HTTPS-DROP:
# -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --name https --rcheck --seconds 1 --hitcount 20 -j REJECT --reject-with tcp-reset
#
## Limit number of concurrent connections per IP
## Easy, because university networks may require some connections
#-A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 100 -j REJECT --reject-with tcp-reset
#-A INPUT -p tcp --syn --dport 443 -m connlimit --connlimit-above 100 -j REJECT --reject-with tcp-reset
#
#
## SSH (only from certain IPs)
#
# Allow from www.onlineforschung.org 178.238.229.119
-A INPUT -s 178.238.229.119 -p tcp -m tcp --dport 22 -j ACCEPT
# Allow from s2survey.net 95.130.22.100
-A INPUT -s 95.130.22.100 -p tcp -m tcp --dport 22 -j ACCEPT
# LRZ/Arbeitsplatz
-A INPUT -s 138.246.2.0/24 -p tcp -m tcp --dport 22 -j ACCEPT
# Kabelnetz: 46.128.22.170
-A INPUT -s 46.128.21.0/23 -p tcp -m tcp --dport 22 -j ACCEPT
# Temporär
# -A INPUT -s 93.233.109.195 -p tcp -m tcp --dport 22 -j ACCEPT
#
# NUL Packages (Portscanner) blockieren
-A INPUT -p tcp --tcp-flags ALL NONE -j DROP
# SYN flood blockieren
-A INPUT -p tcp ! --syn -m state --state NEW -j DROP
# XMAS blockieren
-A INPUT -p tcp --tcp-flags ALL ALL -j DROP
#
#
## SMTP
-A INPUT -p tcp -m tcp --dport 25 -j ACCEPT
#
## HTTP/S
#-A INPUT -p tcp -m tcp --dport 80 -m state --state NEW -m limit --limit 50/min --limit-burst 200 -j ACCEPT
#-A INPUT -p tcp -m tcp --dport 443 -m state --state NEW -m limit --limit 50/min --limit-burst 200 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
#
#
## Test Port
#-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT
#-A INPUT -p tcp -m tcp --dport 8081 -j ACCEPT
#
#
## Ping (limited)
-A INPUT -p icmp --icmp-type timestamp-request -j DROP
-A INPUT -p icmp --icmp-type timestamp-reply -j DROP
-A INPUT -p icmp -m limit --limit 1/s --limit-burst 1 -j ACCEPT
-A INPUT -p icmp -j LOG --log-prefix PING-DROP:
-A INPUT -p icmp -j DROP
#
## Ping (outgoing)
-A OUTPUT -p icmp -j ACCEPT
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# -A OUTPUT -j ACCEPT
# -A OUTPUT -o lo -j ACCEPT
# -A OUTPUT -o eth0 -j ACCEPT
#
#
## Monit (port 2812)
-A INPUT -p tcp -m tcp --dport 2812 -m state --state NEW -m limit --limit 5/min --limit-burst 20 -j ACCEPT
# -A INPUT -p tcp -m tcp --dport 2812 -j ACCEPT
#
# Final action
-A INPUT -j DROP
#
COMMIT

Die Konfiguration beim Neustart laden (bis Ubuntu 16).

sudo vim /etc/network/if-up.d/firewall
#!/bin/bash
/sbin/iptables-restore < /etc/iptables/rules.v4
/sbin/ip6tables-restore < /etc/iptables/rules.v6

sudo chmod +x /etc/network/if-up.d/firewall

Die Konfiguration beim Neustart laden (ab Ubuntu 18), vgl. sudo systemctl enable iptables-load.service

sudo vim /etc/iptables/restore.sh
sudo vim /etc/systemd/system/iptables-load.service
sudo chmod u+x /etc/iptables/restore.sh
/etc/iptables/restore.sh
#!/bin/bash
/sbin/iptables-restore < /etc/iptables/rules.v4
/sbin/ip6tables-restore < /etc/iptables/rules.v6
/etc/systemd/system/iptables-load.service
[Unit]
Description = Load firewall rules on startup
 
[Service]
Type=oneshot
ExecStart=/etc/iptables/restore.sh
 
[Install]
WantedBy=network-pre.target

Den Service aktivieren und zum Testen gleich noch starten (–now).

sudo systemctl enable iptables-load.service --now

SFTP

FTP-Benutzer einrichten, der nur auf SoSci Survey zugreifen kann.

sudo groupadd www-ftp
sudo useradd -g www-ftp -m -d /home/www-ftp -s /sbin/nologin www-ftp
sudo mkdir /home/www-ftp/.ssh
sudo vim /home/www-ftp/.ssh/authorized_keys
# Schlüssel aus PuttyGen einsetzen
sudo chown -R www-ftp:www-ftp /home/www-ftp/.ssh
sudo chmod 700 /home/www-ftp/.ssh/
sudo chmod 600 /home/www-ftp/.ssh/authorized_keys
 
sudo chown root:root /var/www/s2survey
sudo chown -R www-ftp:www-data /var/www/s2survey/html
sudo chmod 770 /var/www/s2survey/html
/etc/passwd
www-ftp:x:1003:1003::/html:/usr/sbin/nologin
/etc/ssh/sshd_config
#Subsystem       sftp    /usr/libexec/openssh/sftp-server
Subsystem       sftp    internal-sftp
 
# am Ende (!) der Datei noch
Match User www-ftp
    AuthorizedKeysFile /home/www-ftp/.ssh/authorized_keys
    ChrootDirectory /var/www/s2survey
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
 
Match all
sudo systemctl reload sshd

Wenn es Probleme gibt, sshd im Debug-Mode laufen lassen:

sudo /usr/sbin/sshd -d -p 3321

nginx

Das Erstellen eines Schlüssels für dhparam dauert eine gute Weile.

sudo mkdir /var/www/ssl/
sudo openssl dhparam -out /var/www/ssl/dhparam.pem 4096

Dann müssen eventuell noch gültige Zertifikate und Schlüssel nach /var/www/ssl/ kopiert werden.

Die eigentliche Konfiguration wird dann in /etc/nginx/conf.d untergebracht.

/etc/nginx/conf.d/ssl.conf
# SSL Settings
 
ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE, and TLSv1
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS";
ssl_ecdh_curve secp384r1;
ssl_dhparam /var/www/ssl/dhparam.pem;
## Use a SSL/TLS cache for SSL session resume.
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
# HTTP-Strict Transport Security (HSTS)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
/etc/nginx/conf.d/logs.conf
# Logging Settings
 
log_format noip '0.0.0.0 - $remote_user [$time_local]  '
    '"$request" $status $body_bytes_sent '
    '"$http_referer" "$http_user_agent"';
 
log_format noagent '0.0.0.0 - $remote_user [$time_local]  '
    '"$request" $status $body_bytes_sent '
    '"$http_referer" "na"';
/etc/nginx/conf.d/gzip.conf
gzip_disable "msie6";
gzip_vary on;
/etc/nginx/fastcgi_params
fastcgi_connect_timeout 65;
fastcgi_send_timeout    180;
fastcgi_read_timeout    900;
/etc/logrotate.d/nginx
/var/log/nginx/*.log
/var/www/s2survey/log/*.log {
        weekly
        missingok
        rotate 28
        dateext
        compress
        delaycompress
        notifempty
        create 0640 www-data adm
        sharedscripts
        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript
        postrotate
                # [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
                invoke-rc.d nginx rotate >/dev/null 2>&1
        endscript
}

Let's Encrypt

Und eventuell muss auch die Konfiguration den letsencrypt kopiert werden. Dafür muss auf dem einen Server erstmal das Verzeichnis auf den Nutzer sosci übereignet werden:

sudo chown -R sosci:sosci /etc/letsencrypt/

Dann muss auf dem anderen Server mit Symlinks kopiert werden:

sudo rsync -avz -e ssh sosci@s2survey.net:/etc/letsencrypt /etc/

Und dann die Dateieigentümer wiederhergestellt auf dem einen Server

sudo chown -R root:root /etc/letsencrypt/

Zum Testen dann…

sudo /usr/bin/certbot renew --post-hook "service nginx reload"

Websites

/etc/nginx/sites-available/01.s2survey.conf
# PHP-FPM processes to be used by SoSci Survey
upstream sosci {
    server unix:/run/php/php-fpm.sock max_fails=5 fail_timeout=30s;
    server 127.0.0.1:9002 backup;
}
 
# Limitation for requets per second
# Expect no more than 5 PHP requests (not images) per second = 300 per minute = 30 people doing 10 pages per minute
limit_req_zone $binary_remote_addr zone=php:10m rate=5r/s;
# (Much) less login attempts - for the SoSci Panel at the moment
limit_req_zone $binary_remote_addr zone=login:10m rate=15r/m;
 
# Main domain(s)
server {
        #listen   [::]:80 default ipv6only=on; ## listen for ipv6
        listen 443 ssl http2;
 
        server_name s2survey.net s2survey.de;
 
        ssl on;
        # The server certificate must appear before the chained certificates in the combined file
        # cat www.example.com.crt bundle.crt > www.example.com.chained.crt
        # ssl_certificate_key /etc/letsencrypt/live/s2survey.net/privkey.pem; # fallback
        # ssl_certificate /etc/letsencrypt/live/s2survey.net/fullchain.pem; # fallback
        ssl_certificate_key /var/www/ssl/s2survey.2017.key;
        ssl_certificate /var/www/ssl/s2survey.2018.cert;
 
        # Content
        root /var/www/s2survey/html;
        index index.php index.html index.htm;
        error_page 404 = /spellcheck.php;
        client_max_body_size    80M;
 
        access_log /var/www/s2survey/log/n-access.log noagent;
        error_log /var/www/s2survey/log/n-error.log;
 
        # Forbidden directories
        location ~ ^/(inc|lib|system)/ {
                deny all;
                return 403;
        }
        location ~ ^/files/(protected|upload|share)/ {
                deny all;
                return 403;
        }
        location ~ ^/download/(release|system|working)/ {
                deny all;
                return 403;
        }
 
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        location ~ /\.ht {
                deny all;
                return 403;
        }
 
        # Munin
        location ^~ /munin/static/ {
                alias /etc/munin/static/;
                expires modified +1w;
        }
 
        location ^~ /munin/ {
                alias /var/cache/munin/www/;
                expires modified +310s;
                try_files $uri $uri/ =404;
                auth_basic "Munin";
                auth_basic_user_file /etc/munin/munin-htpasswd;
        }
 
        # PHP FPM status
        location ~ ^/(status\.primary|ping\.primary)$ {
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass unix:/run/php/php-fpm.sock;
                log_not_found off;
                allow 95.130.22.98;
                allow 127.0.0.1;
                deny all;
        }
        location ~ ^/(status\.secondary|ping\.secondary)$ {
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                fastcgi_pass 127.0.0.1:9002;
                log_not_found off;
                allow 95.130.22.98;
                allow 127.0.0.1;
                deny all;
        }
 
        # Different PHP settings for the sosci administration
        location ~ ^/admin/(.+\.php)$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
                # No secondary pool for that
                fastcgi_pass unix:/run/php/php-fpm.sock;
                fastcgi_index index.php;
                fastcgi_param SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
                # Special
                fastcgi_param PHP_VALUE "
                        max_execution_time = 20
                        memory_limit = 256M
                        max_file_uploads = 50
                        post_max_size = 80M
                ";
        }
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
 
                # First, you need to capture fastcgi errors
                fastcgi_intercept_errors      on;
                # Specifies in which cases a request should be passed to the next server
                fastcgi_next_upstream         error timeout http_500 http_503;
                # Limits the time during which a request can be passed
                # to the next server
                fastcgi_next_upstream_timeout 10s;
                # Limits the number of possible tries for passing
                # a request to the next server
                fastcgi_next_upstream_tries   2;
                # Upstream to pass request to
                fastcgi_pass sosci;
 
                fastcgi_index index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
                # Limitations for survey projects
                fastcgi_param PHP_VALUE "
                        max_execution_time = 5
                        memory_limit = 64M
                        max_file_uploads = 5
                        post_max_size = 16M
                ";
        }
 
        # Docs
        location /doc/ {
                alias /usr/share/doc/;
                autoindex on;
                allow 127.0.0.1;
                allow 95.130.22.100;
                deny all;
        }
 
        # Cache management
        location ~* \.(?:ico|css|js|gif|jpg|jpeg|png|flv|pdf|swf)$ {
                expires 1d;
                add_header Vary Accept-Encoding;
                # access_log off;
        }
 
        # Anything else
        location ~ / {
                # First attempt to serve request as file, then
                # as directory, then fall back to index.html
                try_files $uri $uri/ =404; #$uri/ /index.php /index.html =404;
        }
 
}
/etc/nginx/sites-available/02.customers.conf
server {
        listen          95.130.22.101:80;
        server_name
                access.lgbti-label.ch
                verbaendeumfrage2019.divv.de;
 
        # Allow certbot auth
        root     /var/www/s2survey/certbot;
        location ~ ^/.well-known/ {
        }
 
        # redirect everything else
        location ~ / {
                # add_header X-Debug "$host";
                rewrite        ^ https://$host$request_uri? permanent;
        }
 
        access_log /var/www/s2survey/log/n-access-custom.log noagent;
        error_log /var/www/s2survey/log/n-error-custom.log;
}
 
server {
        listen 95.130.22.101:443 ssl;
        server_name access.lgbti-label.ch;
 
        root /var/www/s2survey/html/_$host;
        index index.php index.html index.htm;
        client_max_body_size    64M;
 
        access_log /var/www/s2survey/log/n-access-custom.log noagent;
        error_log /var/www/s2survey/log/n-error-custom.log;
 
        ssl on;
        ssl_certificate_key /etc/letsencrypt/live/access.lgbti-label.ch/privkey.pem;
        ssl_certificate /etc/letsencrypt/live/access.lgbti-label.ch/fullchain.pem;
 
        location ~ /\.ht {
                deny all;
                return 403;
        }
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
 
                fastcgi_intercept_errors      on;
                fastcgi_next_upstream         error timeout http_500 http_503;
                fastcgi_next_upstream_timeout 10s;
                fastcgi_next_upstream_tries   2;
                fastcgi_pass sosci;
 
                fastcgi_index index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
                # Limitations for survey projects
                fastcgi_param PHP_VALUE "
                        max_execution_time = 5
                        memory_limit = 64M
                        max_file_uploads = 5
                        post_max_size = 16M
                ";
        }
 
        # Cache management
        location ~* \.(?:ico|css|js|gif|jpg|jpeg|png|flv|pdf|swf)$ {
                expires 1d;
                add_header Vary Accept-Encoding;
                # access_log off;
        }
 
        # Anything else
        location ~ / {
                # First attempt to serve request as file, then
                # as directory, then fall back to index.html
                try_files $uri $uri/ =404; #$uri/ /index.php /index.html =404;
        }
 
}
/etc/nginx/sites-available/06.redirect.conf
# HTTP to HTTPS redirects
server {
        listen          80;
        server_name     s2survey.net www.s2survey.net s2survey.com www.s2survey.com s2survey.de www.s2survey.de;
        rewrite         ^ https://$server_name$request_uri? permanent;
}
 
# (Sub-)Domains to be redirected
server {
        listen 443 ssl http2;
 
        server_name www.s2survey.net s2survey.com www.s2survey.com;
 
        ssl on;
        # The server certificate must appear before the chained certificates in the combined file
        # cat www.example.com.crt bundle.crt > www.example.com.chained.crt
        ssl_certificate_key /etc/letsencrypt/live/s2survey.net/privkey.pem; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/s2survey.net/fullchain.pem; # managed by Certbot
 
        rewrite         ^ https://s2survey.net$request_uri? permanent;
 
 
 
}
 
# (Sub-)Domains to be redirected
server {
        listen 443 ssl http2;
 
        server_name www.s2survey.de;
 
        ssl on;
        ssl_certificate_key /etc/letsencrypt/live/s2survey.net/privkey.pem; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/s2survey.net/fullchain.pem; # managed by Certbot
 
        rewrite         ^ https://s2survey.de$request_uri? permanent;
 
}
/etc/nginx/sites-available/09.nossl.s2survey.conf
# Allows access without SSL for single projects
server {
        listen          80;
        #listen   [::]:80 default ipv6only=on; ## listen for ipv6
 
        root /var/www/soscisurvey/html;
        index index.php index.html index.htm;
        error_page 404 = /spellcheck.php;
 
        server_name nossl.s2survey.net;
 
        access_log /var/www/soscisurvey/log/nossl-access.log noip;
        error_log /var/www/soscisurvey/log/nossl-error.log;
 
 
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        location ~ /\.ht {
                deny all;
        }
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
 
                fastcgi_intercept_errors      on;
                fastcgi_next_upstream         error timeout http_500 http_503;
                fastcgi_next_upstream_timeout 10s;
                fastcgi_next_upstream_tries   2;
                fastcgi_pass sosci;
 
                fastcgi_index index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
                # Limitations for survey projects
                fastcgi_param PHP_VALUE "
                        max_execution_time = 5
                        memory_limit = 64M
                        max_file_uploads = 5
                        post_max_size = 16M
                ";
        }
 
        # Allowed directories
        location /images/ {
                try_files $uri =404;
                allow all;
        }
        location /view/ {
                try_files $uri =404;
                allow all;
        }
 
        # Allowed projects
        location /curtest/ {
                try_files $uri $uri/ =404;
                allow all;
        }
 
        location / {
                allow 127.0.0.1;
                deny all;
                try_files $uri $uri/ =404;
        }
}
/etc/nginx/sites-available/default
server {
        listen          80;
        #listen   [::]:80 default ipv6only=on; ## listen for ipv6
 
        root /var/www/default/html;
        index index.php index.html index.htm;
 
        # Make site accessible from http://localhost/
        server_name localhost;
 
        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        location ~ /\.ht {
                deny all;
        }
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
                fastcgi_pass sosci;
 
                fastcgi_index index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
        }
 
        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to index.html
                try_files $uri $uri/ =404;
                # Uncomment to enable naxsi on this location
                # include /etc/nginx/naxsi.rules
        }
 
        # Server status
        location = /server-status {
                # copied from http://blog.kovyrin.net/2006/04/29/monitoring-nginx-with-rrdtool/
                stub_status on;
                #extended_status on;
                access_log   off;
                allow 127.0.0.1;
                allow 95.130.22.98;
                deny all;
        }
 
        # Server status for munin
        location = /nginx_status {
                stub_status on;
                access_log   off;
                allow 127.0.0.1;
                allow 95.130.22.98;
                deny all;
        }
 
        # Also access munin via localhost
        location ^~ /munin/static/ {
                alias /etc/munin/static/;
                expires modified +1w;
        }
 
        location ^~ /munin/ {
                alias /var/cache/munin/www/;
                expires modified +310s;
                try_files $uri $uri/ =404;
                auth_basic "Munin";
                auth_basic_user_file /etc/munin/munin-htpasswd;
        }
 
}

Dann die Seiten noch aktivieren

sudo ln -s /etc/nginx/sites-available/01.s2survey.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/02.customers.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/06.redirect.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/09.nossl.s2survey.conf /etc/nginx/sites-enabled/

E-Mail

Für die eingehenden E-Mails ist ein gesonderter Server zuständig, konfiguriert nach thomas-leister.de.

Die Server-SSL-Schlüssel können leider nicht direkt für TLS verwendet, werden also erstmal neue erstellen.

sudo openssl req -new -x509 -days 3650 -nodes -out /etc/ssl/certs/postfix.pem -keyout /etc/ssl/private/postfix.key

Country Name (2 letter code) [AU]:                            DE
State or Province Name (full name) [Some-State]:              Bayern
Locality Name (eg, city) []:                                  Muenchen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:   SoSci Survey GmbH
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:               s2survey.net
Email Address []:                                             info@soscisurvey.de

Damit es mit ausgehenden E-Mails und der Erkennung von Mail-Rückläufern funktioniert, sind folgende Änderungen erforderlich.

/etc/postfix/main.cf
##### TLS settings ######
# see https://thomas-leister.de/erweiterte-postfix-ssltls-konfiguration-verschluesselte-server-server-verbindungen/
 
tls_ssl_options = NO_COMPRESSION
tls_high_cipherlist=EDH+CAMELLIA:EDH+aRSA:EECDH+aRSA+AESGCM:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:+CAMELLIA256:+AES256:+CAMELLIA128:+AES128:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!DSS:!RC4:!SEED:!ECDSA:CAMELLIA256-SHA:AES256-SHA:CAMELLIA128-SHA:AES128-SHA
 
### outgoing connections ###
smtp_tls_security_level=may
smtp_tls_cert_file=/etc/ssl/certs/postfix.pem
smtp_tls_key_file=/etc/ssl/private/postfix.key
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtp_bind_address = 95.130.22.100
 
### incoming connections ###
smtpd_sasl_security_options = noanonymous
smtpd_use_tls=yes
smtpd_tls_security_level=may
smtpd_tls_cert_file=/etc/ssl/certs/postfix.pem   # Hier werden die SSL-Zertifikate des Webservers verwendet!
smtpd_tls_key_file=/etc/ssl/private/postfix.key
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3
smtpd_tls_mandatory_ciphers = high
smtpd_tls_exclude_ciphers = ECDHE-RSA-RC4-SHA
smtpd_tls_mandatory_exclude_ciphers = ECDHE-RSA-RC4-SHA
 
# Allow 64 MB message size
message_size_limit = 67108864
 
# email accounts (hosting)
virtual_alias_domains = s2survey.de, www.s2survey.de, s2survey.com, www.s2survey.com
virtual_alias_maps = hash:/etc/postfix/virtual
 
# sender aliases
sender_canonical_maps=hash:/etc/postfix/senders
 
# Limit connections per server (default 20)
smtp_destination_concurrency_limit = 3
 
# Stop retries after 36 hours (to quickly delete problem-mails)
bounce_queue_lifetime = 24h
maximal_queue_lifetime = 36h
 
### Basic settings ###
myhostname = s2survey.net
mydestination = $myhostname, mail.s2survey.net, www.s2survey.net, soscisurvey2, localhost.localdomain, localhost
inet_protocols = ipv4
/etc/postfix/senders
root      info@s2survey.net
www-data  info@s2survey.net
/etc/postfix/virtual
root                         info@soscisurvey.de
webmaster                    info@soscisurvey.de
postmaster                   info@soscisurvey.de
root@mail.s2survey.net       info@soscisurvey.de
 
info@s2survey.net            info@soscisurvey.de
info@s2survey.com            info@soscisurvey.de
info@s2survey.de             info@soscisurvey.de
 
hostmaster@s2survey.net      info@soscisurvey.de
hostmaster@www.s2survey.net  info@soscisurvey.de
hostmaster@s2survey.com      info@soscisurvey.de
hostmaster@www.s2survey.com  info@soscisurvey.de
hostmaster@s2survey.de       info@soscisurvey.de
hostmaster@www.s2survey.de   info@soscisurvey.de
webmaster@s2survey.net       info@soscisurvey.de
webmaster@www.s2survey.net   info@soscisurvey.de
webmaster@s2survey.com       info@soscisurvey.de
webmaster@www.s2survey.com   info@soscisurvey.de
webmaster@s2survey.de        info@soscisurvey.de
webmaster@www.s2survey.de    info@soscisurvey.de
postmaster@s2survey.net      info@soscisurvey.de
postmaster@www.s2survey.net  info@soscisurvey.de
postmaster@s2survey.com      info@soscisurvey.de
postmaster@www.s2survey.com  info@soscisurvey.de
postmaster@s2survey.de       info@soscisurvey.de
postmaster@www.s2survey.de   info@soscisurvey.de
 
noreply@s2survey.net         info@soscisurvey.de
wiki@s2survey.net            info@soscisurvey.de
root@s2survey.net            info@soscisurvey.de
www-data@s2survey.net        info@soscisurvey.de
 
mailer@s2survey.net          mailer
survey@s2survey.net          mailer

Für die ausgehenden E-Mails sind einige Anpassungen erforderlich, damit sie durch den Spamfilter kommen. Zu Testen mit mail tester.

Die TLS-Konfiguration kann man mit https://www.checktls.com/checktls.com überprüfen.

Für die Rückläufer-Mails benötigen wir außerdem noch einen Nutzer für das Mail-Postfach mit Passwort.

sudo adduser mailer
sudo vim /etc/passwd
 
mailer:x:1000:1000:,,,:/home/mailer:/usr/sbin/nologin

Zuletzt noch DKIM einrichten, damit Mails von @s2survey.net nirgends hängen bleiben.

Hierzu folgende Anleitung: DKIM für Postfix.

sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod go-rw /etc/opendkim/keys
/etc/opendkim.conf
UserID                  opendkim:opendkim
UMask                   002
Socket                  inet:8892@localhost
AutoRestart             yes
AutoRestartRate         10/1h
# Später weniger Logging
Syslog                  yes
SyslogSuccess           yes
LogWhy                  yes
# Nicht zu streng sein
Canonicalization        relaxed/simple
# interne Mails nicht mit OpenDKIM verarbeiten
ExternalIgnoreList      refile:/etc/opendkim/trusted
InternalHosts           refile:/etc/opendkim/trusted
# Keys pro Domain
# (refile: für Dateien mit regulären Ausdrücke)        
SigningTable            refile:/etc/opendkim/signing.table
KeyTable                /etc/opendkim/key.table       
# diesen Signatur-Algorithmus verwenden
SignatureAlgorithm      rsa-sha256
# Always oversign From (sign using actual From and a null From to prevent
# malicious signatures header fields (From and/or others)
OversignHeaders         From
/etc/opendkim/trusted
127.0.0.1
::1
localhost
soscisurvey2
s2survey
s2survey.net
/etc/opendkim/signing.table
# Nur Mails @s2survey.net signieren
*@s2survey.net s2survey
/etc/opendkim/key.table
s2survey s2survey.net:2019a:/etc/opendkim/keys/2019a.private
sudo su
cd /etc/opendkim/keys
opendkim-genkey -d s2survey.net -b 3072 -r -s 2019a
chown opendkim:opendkim *
exit
sudo systemctl restart opendkim
opendkim-testkey -d s2survey.net -s 2019a -vvv

Zuletzt noch einen DNS-Eintrag für s2survey.net erzeugen (z.B. 2019a._domainkey.s2survey.net), entsprechend dem Inhalt der Datei 2019a.txt. Dabei kommt alles zwischen den Klammern in den TXT Eintrag, aber Anführungszeichen, Leerzeichen und Zeilenumbrüche werden entfernt.

/etc/postfix/main.cf
# OpenDKIM
milter_default_action = accept   
milter_protocol   = 6              
smtpd_milters     = inet:localhost:8892
non_smtpd_milters = inet:localhost:8892

MySQL

Webserver (nginx)

s. auch https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-with-http-2-support-on-ubuntu-16-04

SSL

Wird generell in nginx konfiguriert. Allerdings ist sicherzustellen, dass die Schlüssel unter /var/www/s2survey/ssl vorhanden sind und dass die richtigen Prozesse auf diese zugreifen können.

sudo chown -R root:ssl-cert /var/www/ssl

HTTP/2

PHP-FPM

Der Standard-Pool www.conf muss gelöscht oder umbenennt werden, z.B. mv www.conf www.conf.dpkg-dist.

sudo mv /etc/php/7.2/fpm/pool.d/www.conf /etc/php/7.2/fpm/pool.d/www.conf.dist
sudo vim /etc/php/7.2/fpm/pool.d/primary.conf
sudo vim /etc/php/7.2/fpm/pool.d/secondary.conf
/etc/php/7.2/fpm/pool.d/primary.conf
[primary]
user = www-data
group = www-data
listen = /run/php/php-fpm.sock
listen.backlog = 1023
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 16
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 2500
pm.status_path = /status.primary
ping.path = /ping.primary
env[PATH] = /usr/local/bin:/usr/bin:/bin
/etc/php/7.2/fpm/pool.d/secondary.conf
[secondary]
user = www-data
group = www-data
listen = 127.0.0.1:9002
listen.backlog = 511
listen.owner = www-data
listen.group = www-data
listen.allowed_clients = 127.0.0.1
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s;
pm.max_requests = 500
pm.status_path = /status.secondary
ping.path = /ping.secondary
env[PATH] = /usr/local/bin:/usr/bin:/bin

Und dann noch ein paar Änderungen in der php.ini

/etc/php/7.2/fpm/conf.d/10-sosci.ini
display_errors = On
display_startup_errors = On
post_max_size = 256M
upload_max_filesize = 256M
max_file_uploads = 50
mail.add_x_header = On

SoSci Survey

Zwei Scripte (gehören www-data), werden beim Übertragen der Inhalte evtl. nicht automatisch kopiert (permission denied).

sudo mkdir /var/www/s2survey/script
sudo vim /var/www/s2survey/script/crontask.sh
sudo vim /var/www/s2survey/script/cronjob.sh
sudo chown www-data:www-data /var/www/s2survey/script/crontask.sh
sudo chown www-data:www-data /var/www/s2survey/script/cronjob.sh
sudo chmod u+x /var/www/s2survey/script/crontask.sh
sudo chmod u+x /var/www/s2survey/script/cronjob.sh
 
sudo chown www-data:www-data /var/www/s2survey/script
sudo chown www-data:www-data /var/www/s2survey/log
sudo chmod 700 /var/www/s2survey/script
sudo chmod 700 /var/www/s2survey/log
/var/www/s2survey/script/crontask.sh
#!/bin/bash
cd /var/www/s2survey/html/admin/
/usr/bin/php /var/www/s2survey/html/admin/crontask.php password=123456
/var/www/s2survey/script/cronjob.sh
#!/bin/bash
cd /var/www/s2survey/html/admin/
/usr/bin/php /var/www/s2survey/html/admin/cronjob.php password=123456

MySQL

sudo vim /etc/mysql/conf.d/s2survey.conf
sudo systemctl restart mysql
/etc/mysql/conf.d/s2survey.conf
[mysqld]
key_buffer_size         = 64M
max_allowed_packet      = 32M
max_connections         = 512
query_cache_limit       = 4M
query_cache_size        = 64M
 
slow_query_log          = 1
slow_query_log_file     = /var/log/mysql/mysql-slow.log
long_query_time         = 5
 
# InnoDb configuration
innodb_file_per_table = 1
innodb_buffer_pool_size = 2G # 50% of System Memory was better
innodb_log_file_size=128M
innodb_log_buffer_size = 512M
innodb_thread_concurrency = 8
innodb_flush_method=O_DSYNC # Mixed mode for InnoDB
innodb_io_capacity=100
innodb_lock_wait_timeout=20
# innodb_additional_mem_pool_size = 20M
# innodb_data_file_path = ibdata1:50M:autoextend
sudo su
mysql

Einen neuen Root-Nutzer mit Passwort anlegen, vgl https://tableplus.io/blog/2018/10/how-to-create-a-superuser-in-mysql.html

CREATE USER 'master'@'localhost' IDENTIFIED BY 'XXXXXXXXXXXXXX';
GRANT ALL PRIVILEGES ON *.* TO 'master'@'localhost' WITH GRANT OPTION;
SHOW GRANTS FOR master@localhost;
FLUSH PRIVILEGES;
 
CREATE DATABASE s2survey;
CREATE USER 's2survey'@'localhost' IDENTIFIED BY 'XXXXXXXXXXXXXX';
GRANT ALL PRIVILEGES ON s2survey.* TO 's2survey'@'localhost';
FLUSH PRIVILEGES;
 
QUIT;

Überwachung

Monit

# PHP-Service herausfinden
systemctl list-unit-files | grep enabled
sudo vim /etc/monit/conf.d/s2survey.conf
sudo vim /etc/monit/conf.d/mysql
sudo vim /etc/monit/conf.d/nginx
sudo vim /etc/monit/conf.d/php-fpm
sudo vim /etc/monit/php-fpm.stop.sh
sudo vim /etc/monit/conf.d/system
sudo vim /etc/monit/conf.d/sosci
sudo vim /etc/monit/webserver.stop.sh
sudo vim /etc/monit/webserver.start.sh
sudo vim /etc/monit/webserver.restart.sh
# Nur wenn relevant
sudo vim /etc/monit/conf.d/postfix
/etc/monit/conf.d/s2survey.conf
set daemon 20
set mail-format { from: monit@s2survey.net }
set httpd port 2812 and
        use address 0.0.0.0
        allow admin:"XXXXXXXXXXX"
/etc/monit/conf.d/mysql
check process mysqld with pidfile /var/run/mysqld/mysqld.pid
    start program = "/usr/sbin/service mysql start"
    stop program = "/usr/sbin/service mysql stop"
    if failed host 127.0.0.1 port 3306
        for 3 cycles
        then restart
    if 3 restarts within 20 cycles
        then timeout
/etc/monit/conf.d/nginx
check process nginx with pidfile /var/run/nginx.pid
   start program = "/usr/sbin/service nginx start"
   stop program  = "/usr/sbin/service nginx stop"
   if failed port 80 for 2 cycles
     then restart
   if cpu > 50% for 2 cycles
     then alert
/etc/monit/conf.d/php-fpm
check process php-fpm with pidfile /var/run/php/php7.2-fpm.pid
        group php-www
        start program = "/bin/systemctl start php7.2-fpm"
        stop program = "/etc/monit/php-fpm.stop.sh"
        if failed unixsocket /var/run/php/php-fpm.sock
                then alert
        if failed unixsocket /var/run/php/php-fpm.sock
                for 2 times within 3 cycles
                then restart
        if failed unixsocket /var/run/php/php-fpm.sock
                for 5 cycles
                then exec "/sbin/reboot"
        if 5 restarts within 8 cycles
                then alert
/etc/monit/php-fpm.stop.sh
#!/bin/bash
 
# Stop php-fpm
/bin/systemctl stop php7.2-fpm stop
 
# Kill any further instances of PHP-FPM
/usr/bin/pkill php7.2-fpm
/etc/monit/conf.d/system
check system Memory
        group resources
        if memory usage > 75% for 5 cycles then alert
                else if passed within 5 cycles then alert
        if loadavg (15min) is greater than 0.9 for 2 cycles then alert
                else if passed within 5 cycles then alert
 
check filesystem rootfs with path /
        if space usage > 75% then alert
check device bootfs with path /boot
        if space usage > 75% then alert
/etc/monit/conf.d/sosci
# Website must be accessible
CHECK HOST sosci WITH ADDRESS 95.130.22.100
  START PROGRAM = "/etc/monit/webserver.start.sh"
  STOP PROGRAM  = "/etc/monit/webserver.stop.sh"
  # IF NOT EXIST THEN ALERT
   # if failed (url https://www.soscisurvey.de/example/?debug&password=demo and content == 'onlineFragebogen' and timeout 20 seconds)
   #   then alert
  IF FAILED (url https://s2survey.net/s2survey/ and content == 'onlineFragebogen' and timeout 20 seconds)
    FOR 2 CYCLES
    THEN RESTART
  IF FAILED (url https://s2survey.net/s2survey/ and content == 'onlineFragebogen' and timeout 20 seconds)
    FOR 4 CYCLES
    THEN EXEC "/sbin/reboot"
 
# Crontask must run every minute
CHECK FILE crontask WITH PATH /var/www/s2survey/html/system/logfiles/crontask.log
    IF DOES NOT EXIST THEN ALERT
    IF timestamp > 20 minutes THEN ALERT
 
# Cronjob must run daily
CHECK FILE cronjob WITH PATH /var/www/s2survey/html/system/logfiles/cronjob.log
    IF DOES NOT EXIST THEN ALERT
    IF timestamp > 25 hours THEN ALERT
/etc/monit/webserver.stop.sh
#!/bin/bash
 
# Stop php-fpm
/etc/monit/php-fpm.stop.sh
 
# Stop nginx
/bin/systemctl stop nginx
/etc/monit/webserver.start.sh
#!/bin/bash
/bin/systemctl start php7.2-fpm
/bin/systemctl start nginx
/etc/monit/webserver.restart.sh
#!/bin/bash
/etc/monit/webserver.stop.sh
/etc/monit/webserver.start.sh
/etc/monit/conf.d/postfix
CHECK PROCESS postfix WITH PIDFILE /var/spool/postfix/pid/master.pid
    start program = "/usr/sbin/service postfix start"
    stop program  = "/usr/sbin/service postfix stop"
    if cpu > 60% for 2 cycles then alert
    if cpu > 80% for 5 cycles then restart
    if failed host localhost port 25 type tcp protocol smtp
       with timeout 15 seconds
      then alert
    if 3 restarts within 5 cycles then timeout
sudo chmod u+x /etc/monit/php-fpm.stop.sh
sudo chmod u+x /etc/monit/webserver.stop.sh
sudo chmod u+x /etc/monit/webserver.start.sh
sudo chmod u+x /etc/monit/webserver.restart.sh
monit -t

Munin

sudo ln -s /usr/share/munin/plugins/nginx_request /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/nginx_status /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/http_loadtime /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/iostat /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/iostat_ios /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/postfix_mailqueue /etc/munin/plugins/
sudo ln -s /usr/share/munin/plugins/postfix_mailvolume /etc/munin/plugins/

Noch ein Extra-PlugIn für PHP-FPM

cd /usr/share/munin/plugins/
sudo wget -O php-fpm https://raw.github.com/MorbZ/munin-php-fpm/master/php-fpm.php
sudo chmod +x php-fpm
sudo ln -s /usr/share/munin/plugins/php-fpm /etc/munin/plugins/php-fpm-memory
sudo ln -s /usr/share/munin/plugins/php-fpm /etc/munin/plugins/php-fpm-cpu
sudo ln -s /usr/share/munin/plugins/php-fpm /etc/munin/plugins/php-fpm-count
sudo ln -s /usr/share/munin/plugins/php-fpm /etc/munin/plugins/php-fpm-time
sudo service munin-node restart
sudo vim /etc/munin/munin.conf
 
> [localhost.localdomain]
< [s2survey.net]
sudo htpasswd -c /etc/munin/munin-htpasswd admin

Reload

sudo systemctl reload php7.2-fpm nginx monit sshd
sudo systemctl restart munin-node unattended-upgrades

Umziehen

Inhalte kopieren

# Vorab: Arbeits-Cache löschen, Schreibcache auflösen
 
# Dann die Dateien kopieren
sudo rsync -av -e ssh --delete sosci@s2survey.net:/var/www/s2survey /var/www/
sudo chown -R www-data:www-data /var/www/s2survey/

Eventuell auch /etc/letsencrypt kopieren. Anschließend wieder dem Benutzer root übergeben.

sudo mysqldump -uroot -p --databases s2survey --quick --single-transaction | gzip -9 > /home/sosci/s2survey-mysql-transfer.sql.gz

Auf dem anderen Server die Daten holen und einspielen.

scp sosci@s2survey.net:~/s2survey-mysql-transfer.sql.gz ~/
gunzip -c s2survey-mysql-transfer.sql.gz | mysql -u s2survey -p s2survey

IP-Adresse ändern

Zum Ändern der IP-Adresse s. netplan und [https://www.linux.com/learn/intro-to-linux/2018/9/how-use-netplan-network-configuration-tool-linux|linux.com]].

Es kann sinnvoll sein, erstmal eine IP-Adresse umzustellen und dann die andere.

/etc/netplan/01-netcfg.yaml
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
          ens160:
                  dhcp4: no
                  dhcp6: no
                  addresses: [95.130.22.100/28,95.130.22.101/28]
                  gateway4: 95.130.22.97
                  nameservers:
                          addresses: [95.130.16.100,95.130.16.121]

Die Konfiguration kann dann wie folgt testweise geladen werden:

sudo netplan try

Zuletzt

sudo certbot renew --force-renewal

Domain aufschalten

sudo su
cd /var/www/s2survey/html
vim VERZEICHNIS/index.php
# ergänzen (s. unten)
ln -s VERZEICHNIS _DOMAINNAME
vim /etc/nginx/sites-available/02.customers.conf
# (1) Domain oben im HTTP:80 ergänzen
# (2) Neuer Eintrag für die Domain (sonst müssten sie ein Zertifikat teilen)
#     => Aber erstmal mit Zertifikat von anderer Domain, sonst schlägt der Config-Test fehl
sudo systemctl reload nginx
 
certbot certonly --webroot --debug-challenges --dry-run -d DOMAINNAME -w /var/www/s2survey/certbot
certbot -d DOMAINNAME -w /var/www/s2survey/certbot
<?PHP
# change to the correct working directory
chdir('../PROJECT_DIR/');
// Start or continue interview
require('../inc/Interviewer.php');
Interviewer::run(PROJECT_ID);
?>
server {
        listen 95.130.22.101:443 ssl;
        server_name DOMAINNAME;
 
        root /var/www/s2survey/html/_$host;
        index index.php index.html index.htm;
        client_max_body_size    64M;
 
        access_log /var/www/s2survey/log/n-access-custom.log noagent;
        error_log /var/www/s2survey/log/n-error-custom.log;
 
        ssl on;
        ssl_certificate_key /etc/letsencrypt/live/DOMAINNAME/privkey.pem; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/DOMAINNAME/fullchain.pem; # managed by Certbot
 
 
        location ~ /\.ht {
                deny all;
                return 403;
        }
 
        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        location ~ \.php$ {
                limit_req zone=php burst=50;
                try_files $uri =404;
 
                fastcgi_intercept_errors      on;
                fastcgi_next_upstream         error timeout http_500 http_503;
                fastcgi_next_upstream_timeout 10s;
                fastcgi_next_upstream_tries   2;
                fastcgi_pass sosci;
 
                fastcgi_index index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                include fastcgi_params;
                # Limitations for survey projects
                fastcgi_param PHP_VALUE "
                        max_execution_time = 5
                        memory_limit = 64M
                        max_file_uploads = 5
                        post_max_size = 16M
                ";
        }
 
        # Cache management
        location ~* \.(?:ico|css|js|gif|jpg|jpeg|png|flv|pdf|swf)$ {
                expires 1d;
                add_header Vary Accept-Encoding;
                # access_log off;
        }
 
        # Anything else
        location ~ / {
                # First attempt to serve request as file, then
                # as directory, then fall back to index.html
                try_files $uri $uri/ =404;
        }
}

Sonstiges

CSR für SSL

cd /var/www/ssl
 
# Schlüssel erzeugen:
sudo su
openssl genrsa 4096 > s2survey.2019.key
# Certificate Request
openssl req -new -key s2survey.2019.key -out s2survey.2019.csr
 
Country Name (2 letter code) [AU]:DE
State or Province Name (full name) [Some-State]:Bayern
Locality Name (eg, city) []:Muenchen
Organization Name (eg, company) [Internet Widgits Pty Ltd]:SoSci Survey GmbH
Organizational Unit Name (eg, section) []:Survey Hosting
Common Name (e.g. server FQDN or YOUR name) []:s2survey.net
Email Address []:info@soscisurvey.de
 
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

IPv6-Adresse

Die IP-Adresse wird entweder unter /etc/network/interfaces oder via NetworkManager (nmtui) oder via netplan festgelegt.

Mit Partnergate ist abgesprochen, dass die IPv6 2a02:2940:0:c007::102/64 für den Server .102 verwendet wird u.s.w.

Wichtig: Vor dem Aktivieren von IPv6 auch die Firewall entsprechend anpassen.

NetworkManager

Einige Befehle für den NetworkManager:

/etc/NetworkManager/conf.d/99-local.conf
[connection]
ipv6.ip6-privacy=0
ipv6.addr-gen-mode=stable-privacy
/etc/NetworkManager/system-connections/Wired connection 1
[connection]
id=Wired connection 1
uuid=92b0a2d7-d185-4bf7-b3e9-8606a0e08355
type=ethernet
permissions=
timestamp=1574712975
 
[ethernet]
mac-address-blacklist=
 
[ipv4]
address1=95.130.22.102/28,95.130.22.97
dns=95.130.16.100;95.130.16.121;
dns-search=
method=manual
 
[ipv6]
addr-gen-mode=stable-privacy
address1=2a02:2940:0:c007::102/64,2a02:2940:0:c007::1
dns-search=
ip6-privacy=0
method=manual