LINUX, NGINX, MYSQL, PHP und sicheres WordPress!

Ich wollte schon immer ein sicheres WordPress installieren und das ohne Update-hassle. Immerhin ist es ein OpenSource-System das oft durch Software-Schwachstellen auffällt.

Als Erstes möchte ich dir ein WordPress-Plugin namens “ Simply Static“ vorstellen. Mit diesem Plugin kannst du eine statische Kopie von deinen Blog erzeugen. Das heißt, dass alle Bilder, Assets wie Javascripte und Stylescheets und Seiteninhalten kopiert werden. Du findest im erzeugten Abbild keine ausfürbaren PHP-Dateien. Jegliche dynamischen Schnittstellen für WordPress-Exploits funktionieren danach nicht mehr. Wir werden nun eine komplette Installation gemeinsam durchführen. Am besten fangen wir bei der JiffyBox an.

JIffybox provisionieren

Die JiffyBox ist die Vitalisierungs-Lösung von Domain-Factroy. Wenn ich mich dort Registriert habe, kann ich selbstständig virtuelle Rechner erstellen und managen. Ich suche die Jiffybox-Übersicht auf und drücke dort auf „Neue JiffyBox erstellen„. Danach kann ich die Leistung und das Betriebs-System wählen. Ich nehme das Server-Ubuntu in der LTS-Variante (Long Term Support = Diese Version hat eine lange Lebenszeit und ein Updategarantie).

Ich könnte meine Rechner nun „WordPress-Hosting“ nennen. Ich wähle aber doch lieber einen für mich eindeutigen und neutralen Namen, weil die Hosting-Funktion nicht aus dem Computer-Name erkennbar sein soll. Ich kann nun auf „Zahlungpflichtig Bestellen“ klicken und erhalte eine eMail mit den Zugangs-Daten meiner neuen JiffyBox.


Domain routen / pointen

Um das Ziel für meine Domain „shoopido.com“ zu setzen, muss ich einen sogenannten A-Record bearbeiten. Ich gehe in das Kunden-Menü von Domain-Factory und klicke dort auf „Nameserver-Einstellungen“.

Dort wähle ich meine Domain „shoopido.com“ aus und klicke auf „Editieren„.

Danach bearbeite ich die beiden A-Records „shoopido.com“ und „*.shoopido.com“ und trage dort die IP meiner neuen JiffyBox ein.

Gut! Die Domain ist nun adressiert.


Erste Schritte/Vorbereitung

Ich logge mich auf der Jiffybox via SSH ein und führe die folgenden Befehle aus. Als erstes sollten alle Paket-Quellen und Pakete aktualisiert werden.

#\~: apt-get update
#\~: apt-get upgrade


Werbung


SSH-Server mit Public-Key einrichten

Schlüssel-Paar generieren

Zum erstellen eines Schlüsselpaar benutzt Du den folgenden Befehl. Das machst du natürlich auf deinen eigenen Rechner, da nur du deinen Private-Key/dein haben sollst. Mit deinen privaten Schlüssel kommt ein Hacker auf alle System, die deinen Public-Schlüssel führen.

#\~: ssh-keygen -t rsa

Public-Key Hinterlegen

Öffnet die Datei „~/.ssh/authorized_keys“ im Vim-Editor um Deinen Public-Schlüssen zu hinterlegen.

#\~: vim ~/.ssh/authorized_keys

Bitte drücke „i“-Taste um in den Insert-Modus zu wechseln. Nun kannst Du den Public-Key einfügen.

Danach drückst Du die „esc“-Taste um den Befehls-Modus zu wechseln und dann „:wq“ für „write“ und „quit„.


SSH-Port Anpassen und Passwörter anbschalten

Mit „vim /etc/ssh/sshd_config“ können wir die SSH-Daemon-EInstellungen anzupassen. In den ersten Zeile ist bereits „Port 22“ zusehen. Ich kann mit den Cursor-Tasten in diese Zeile wechseln und mit der „i„-Taste für den Insert-Modus. Ich trage nun eine 12 statt der 22 ein und wechsel mit der „esc„-Taste wieder in den Befehls-Modus. Mit „:/PasswordAuthentication“ kannst Du nach der „PasswordAuthentication“-Einstellung suchen. Auch hier wechsel ich auf i=insert und deaktiviere die Einstellung:

Hier noch einmal eine Übersich der wichtigen Einstellungen:

Port 12 #der Port ist 12 statt 22
PasswordAuthentication no #passworte sind nicht zulässig
RSAAuthentication yes #der Loggin über Schlüssel wird aktiviert
PubkeyAuthentication yes

Danach muss der SSH-DIenst neu gestartet werden.

#\~: service ssh restart

Zum Testen öffnest Du eine zweite Konsole. Bitte terminiere nicht die aktuelle/erste Session, da Du diech vielleicht im Fehlerfall aussperrst. Mit dem Folgenden Befehl kannst Dich anmelden:

#\~: ssh -p 12 -i /.ssh/private_key root@ip-adresse

Gut zu wissen:

Man kann auch im JiffyBox-Panel eine Konsole öffnen. Dazu klickt man auf „Konfigurieren“ und danach auf „Konsole und Recovery“. Man könnte den SSH-Dienst abschalten, wenn dieser nicht benötigt wird.


mysql installieren

Wir installieren den Mysql – Server. Mit dem „mysql_secure_installation“-Befehl werden Sicherheitsbeamte Einstellungen überprüft. Hier sollte man jede Frage mit „y“ beantworten.

#\~: apt-get install mysql-server
#\~: mysql_secure_installation

Siehe:

In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.

Enter current password for root (enter for none):
OK, successfully used password, moving on...

Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.

You already have a root password set, so you can safely answer 'n'.

Change the root password? [Y/n] Y
 ... skipping.

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] Y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

Werbung


WordPress-Datenbank

Ich lege gleich eine neue Datenbank an:

#\~: mysql --user=root

Jede Applikation sollte einen dedizierte Datenbank und einen eigenen Benutzer haben. Ich benutze folgende Befehle:

Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 48
Server version: 10.0.34-MariaDB-0ubuntu0.16.04.1 Ubuntu 16.04

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> CREATE USER 'shoopido'@'localhost' IDENTIFIED BY 'passwort1234';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> CREATE DATABASE shoopido;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> GRANT ALL PRIVILEGES ON shoopido.* TO 'shoopido'@'localhost';
Query OK, 0 rows affected (0.00 sec)

Das wars! Die Datenbank ist vorbereitet.


PHP installieren

Folgende Pakete müssen fpr PHP installiert werden:

#\~: apt-get install php7.0-common php7.0-fpm php7.0-cli php7.0-json php7.0-mysql php7.0-curl php7.0-intl php7.0-mcrypt php-pear php7.0-gd php7.0-zip php7.0-xml php7.0-mbstring

Ich öffnen die Datei „/etc/php/7.0/fpm/php.ini“ in vim:

#\~: vim /etc/php/7.0/fpm/php.ini

Der Befehls-Modus von Vim ist uns nach den vorhergehenden Schritten bekannt. Wir suchen mit „/fix_pathinfo“ nach cgi.fix_pathinfo=1 und wechseln in den Edit-Mod „i„. Danach ändern den Wert von 1 nach 0 und speichern wir das Ganze mit „:wq

NGINX und Let’s Encrypt

Nun kann der HTTP-Server, apache2-utils und Let’s-Encrypt installiert werden. Das Paket apache2-utils benötigen wir für einen Passwort-Schutz.

#\~: apt-get install nginx letsencrypt apache2-utils

Wichtige NGINX-Einstellungen

Nach der Nginx-Installation kannst nusst Du folgende Datei erstellen:

#\~: vim /etc/nginx/conf.d/own.conf

Der Inhalt dieser Datei ist:

server_names_hash_bucket_size 64; #dieser Wert wird an die Plattform angepasst werden
server_tokens off; #hiermit wird die Server-Signatur verändert

limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m; #vorbereitung für max 30 Request/Minute und ip
limit_conn_zone $binary_remote_addr zone=addr:10m; #Vorbereitung für max Connections pro ip

Seiten-Layout

Jetzt kann das Seiten Layout erstellt werden. Unter cms.shoopido.com wird das WordPress installiert. Unter der anderen Url, www.shoopido.com wird eine statische Spieglung ausgegeben.

#\~: cd /var/www/
#\~: rm -r *
#\~: mkdir -p /var/www/cms.shoopido.com/{usr,public,private,log,backup}
#\~: mkdir -p /var/www/www.shoopido.com/{usr,public,private,log,backup}

Die Server – Konfiguration wird wie folgt erstellt:

#\~: vim /etc/nginx/sites-available/shoopido.com

Der Inhalt ist folgender. Das Ziel „well-known“ wird später für LetsEncrypt benötigt.

server {
  listen       80;
  server_name  cms.shoopido.com;
  root   /var/www/cms.shoopido.com/public;

  access_log /var/www/cms.shoopido.com/log/access.log;
  error_log /var/www/cms.shoopido.com/log/error.log;

  location ~ /.well-known {
    allow all;
  }

  location / {
    index  index.html index.htm;
  }
}

server {
  listen       80;
  server_name  www.shoopido.com;
  root   /var/www/www.shoopido.com/public;

  access_log /var/www/www.shoopido.com/log/access.log;
  error_log /var/www/www.shoopido.com/log/error.log;

  location ~ /.well-known {
    allow all;
  }

  location / {
    index  index.html index.htm;
  }
}

Mit den folgenden Symlink kann nich diese Server-Config in den produktiv-status übernehmen:

#\~: ln -s /etc/nginx/sites-available/shoopido.com /etc/nginx/sites-enabled/shoopido.com

Die Server – Konfiguration lässt sich überprüfen. Ich prüfe wo sich der Nginx-Server befindet und teste anschließend die Konfiguration.

#\~: whereis nginx
nginx: /usr/sbin/nginx /etc/nginx /usr/share/nginx
#\~: /usr/sbin/nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Jetzt können wir die Zertifikate installieren:

#\~: letsencrypt certonly -a webroot --webroot-path=/var/www/cms.shoopido.com/public/ -d cms.shoopido.com

Als erstes muss ich eine eMail-Adresse für LetsEncrypt hinterlegen:

Wenn Alles geklappt hat, dann sehe ich folgedens:

Das erste Zertifikat wurde erfolgreich erstellt. Nun können wir ein weiteres erstellen und den Diffie-Hellman-Parameter generieren.

#\~: letsencrypt certonly -a webroot --webroot-path=/var/www/www.shoopido.com/public/ -d www.shoopido.com/sites-available/shoopido.com /etc/nginx/sites-enabled/shoopido.com
#\~: openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Zertifikate automatisch aktualisieren

Das Aktualisieren aller Zetifikate per cronjob geht wie folgt aus:

#\~: crontab -e

Das sind die Cronjobs:

30 2 * * 1 /usr/bin/letsencrypt renew >> /var/log/le-renew.log
35 2 * * 1 /bin/systemctl reload nginx

Werbung


Basic-Auth für das CMS

Ich erstelle noch einen Basic-Auth-Nutzer für die CMS-Domain. Das heißt, dass später nur ein Authentifizierter Nutzer PHP-Script unter der CMS-Domain sehen kann. Ich erstelle in meinen CMS-Verzeichnis eine Nutzer/Passwort-Liste und gebe gleich den ersten Nutzernamen an:

#\~:  htpasswd -c /var/www/cms.shoopido.com/usr/.htpasswd nutzername-angeben

Tor/Darknet-Nutzer blockieren

Jetzt will ich auch Tor-Nutzer für mein zukünftiges CMS blockieren. Meine statische Kopie darf später auch im Darknet gesehen werden. Ich habe mir folgendes Script angepasst:

#!/bin/sh
# Copyright 2012, Nico R. Wohlgemuth 

WGET=/usr/bin/wget
LIST=/etc/nginx/conf.d/tor-ips.conf #ziel der blacklist
LISTBAK=/etc/nginx/conf.d/tor-ips.bak 
TEMPLIST=/tmp/torlist.txt

wget -qO- https://check.torproject.org/exit-addresses | grep ExitAddress | cut -d ' ' -f 2 | sed "s/^/deny /g; s/$/;/g" > $TEMPLIST

if [ ! -s $TMPTEMPLIST ]; then
   echo "error: list is empty or was not downloaded"
   exit 1
fi

head -n3 $TEMPLIST
tail -n3 $TEMPLIST

echo -e "\ndoes this look okay? [y/n]: "
read yesno

if [ $yesno != "y" ]; then
   echo "error: aborted"
   rm $TEMPLIST
   exit 2
else
   mv $LIST $LISTBAK
   mv $TEMPLIST $LIST
fi

/usr/sbin/nginx -t
if [ $? -ne 0 ]; then
echo "deine config ist kaputtt"
else
/bin/systemctl reload nginx
echo "alles ok"
fi

Wenn ich nach der komplette Konfiguration meine Seite aufrufe, sehe ich das:


Kleines Finale

Noch einmal die ganze Server-Konfiguration und /etc/nginx/sites-available/shoopido.com:

server {
  listen       80;
  server_name  www.shoopido.com shoopido.com *.shoopido.de;
  return       301 https://www.shoopido.com$request_uri;
}

server {
  listen 443 ssl;
  server_name  cms.shoopido.com;
  root   /var/www/cms.shoopido.com/public;
  index index.php index.htm index.html;

  auth_basic "Restricted"; #For Basic Auth
  auth_basic_user_file /var/www/cms.shoopido.com/usr/.htpasswd;  #For Basic Auth

  access_log /var/www/cms.shoopido.com/log/access.log;
  error_log /var/www/cms.shoopido.com/log/error.log;

  location ~ /\.well-known\/acme-challenge {
    auth_basic off;
    allow all;
  }

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_ecdh_curve secp384r1;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.8.8 8.8.4.4 valid=300s;
  resolver_timeout 5s;
  # Disable preloading HSTS for now.  You can use the commented out header line that includes
  # the "preload" directive if you understand the implications.
  #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
  add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  ssl_certificate /etc/letsencrypt/live/cms.shoopido.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/cms.shoopido.com/privkey.pem;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  location / {
    limit_req zone=one; #request limit
    limit_conn addr 30; #connection limit
    include /etc/nginx/conf.d/tor-ips.conf; #tor ips blocken
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
  }
}

server {
  listen 443 ssl;
  server_name  www.shoopido.com shoopido.com *.shoopido.com;
  root   /var/www/www.shoopido.com/public/static-files;

  access_log /var/www/www.shoopido.com/log/www-access.log;
  error_log /var/www/www.shoopido.com/log/www-error.log;

  location ~ /\.well-known\/acme-challenge {
    allow all;
  }

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_ecdh_curve secp384r1;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.8.8 8.8.4.4 valid=300s;
  resolver_timeout 5s;
  # Disable preloading HSTS for now.  You can use the commented out header line that includes
  # the "preload" directive if you understand the implications.
  #add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
  add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  ssl_certificate /etc/letsencrypt/live/www.shoopido.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/www.shoopido.com/privkey.pem;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  index index.htm index.html;

  location / {
    limit_req zone=one; #request limit
    limit_conn addr 30; #connection limit
  }

  location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
    expires max;
    log_not_found off;
  }
}

Wie immer kann ich mit „/usr/sbin/nginx -t“ die Konfiguration überprüfen und mit service nginx reload übernehmen.


WordPress-Installieren

ich gehe in privates CMS-Verzeichnis:

#\~: cd /var/www/cms.shoopido.com/private/

Download und entpacke WordPress:

#\~: wget https://de.wordpress.org/wordpress-4.9.7-de_DE.zip
#\~: unzip wordpress-4.9.7-de_DE.zip

Ich kopiere die WordPress-Dateien in das Ziel-Verzeichnis:

#\~: cp -r /var/www/cms.shoopido.com/private/wordpress/* /var/www/cms.shoopido.com/public/

Bei der Installation gibst du die deine MYSQL-Daten an.


Großes Finale

Logrotaion einrichten

Für die Log-rotation lege ich folgenden Datei an: Terminal:

Diesen Inhalt trage ich ein:

#\~: vim /etc/logrotate.d/365layouts-app
/var/www/*/log/*.log {
        daily
        missingok
        rotate 24
        compress
        delaycompress
        notifempty
        create 0640 www-data www-data
        sharedscripts
        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript
        postrotate
                invoke-rc.d nginx rotate >/dev/null 2>&1
        endscript
}

Mit diesen Muster „/var/www/*/log/*.log“ werden alle Logs unter var/www täglich rotiert.

„Simply Static“- Einrichten

Das Wichtigste ist das Ziel-Verzeichnis. Im Aktuellen Beispiel würde /var/www/www.shoopido.com/public/ drin stehen.

Außerdem muss ich auch noch unter „Advanced“ die Basic-Auth – Daten für das Kopieren angeben:

Alle Dateien gehören www-data

Chown steht für change owner und erlaubt das Ändern des Eigentümer-Benutzers und/oder der Eigentümer-Gruppe von Dateien. Mit folgen Befehl setzt du die Zuordnung: Terminal:

#\~: cd /var
#\~: chown -R www-data:www-data www

You may also like...