Überarbeitung der Apache-Konfiguration für Ubuntu 20.04

Aus Debacher-Wiki
Zur Navigation springenZur Suche springen
Die Druckversion wird nicht mehr unterstützt und kann Darstellungsfehler aufweisen. Bitte aktualisiere deine Browser-Lesezeichen und verwende stattdessen die Standard-Druckfunktion des Browsers.

Meine bisherige Konfiguration für den Webserver stammt noch ursprünglich aus dem Jahr 2006. Ich habe sie dann mit jedem neuen Server immer nur auf die dann aktuellere Linux-Version angepasst. Dabei entstand zwar immer ein funktionsfähiges System, aber viele Dinge sind nicht mehr einfach nachvollziehbar.

Vorbemerkung

Momentan habe ich meinen alten Hetzner-Server nicht im produktiven Einsatz, habe ihn auf Ubuntu 20.04 aktualisiert und bin dabei die einzelnen Komponenten systematisch zu konfigurieren. Ich werde dabei aber nicht alle Altlasten wirklich los werden, immerhin müssen die reichlich vorhandenen Systeme aktualisierbar bleiben ohne große Verschiebe-Prozesse.

Für die Aktualisierung des Mailservers habe ich einen eigenen Text erstellt Überarbeitung der Mail-Konfiguration für Ubuntu 20.04.

Diese Seite beschreibt die Einrichtung und Konfiguration von virtuellen Servern und beinhaltet:

  • MySQL
  • Apache
  • letsencrypt

Apache-Vhosts.png

Datenbank-MySQL

Zur Installation von Server und Client dient der folgende Aufruf:

apt install mysql-client mysql-server mysql-common

Ich habe dann die Konfigurationsdatei /etc/mysql/mysql.conf.d/mysqld.cnf ergänzt

#ergänzt von U.D.
innodb_flush_log_at_trx_commit = 2

und die Datenbank neu gestartet. Den Datenbankzugriff sollte man nicht über das Netz erlauben, also auch in der Firewall den entsprechenden Port nicht öffnen. Die Datenbank wird ja in der Regel nur über lokale Anwendungen genutzt und über PHPMyAdmin administriert.


MySQL-Passwort

In aktuellen Datenbank-Versionen hat der Benutzer root keinen Zugriff mittels Passwort und kann daher z.B. auch nicht per phpmyadmin arbeiten. Der folgende MySQL-Befehl zeigt die Einstellung

mysql> SELECT user,authentication_string,plugin,host FROM mysql.user;
+---------------------+-------------------------------------------+-----------------------+-----------+
| user                | authentication_string                     | plugin                | host      |
+---------------------+-------------------------------------------+-----------------------+-----------+
| root                |                                           | auth_socket           | localhost |
| mysql.session       | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys           | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
...

Ändern lässt sich diese Einstellung mittels:

use mysql;
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password';
flush privileges;

Dann ergibt sich:

mysql> select user,authentication_string,plugin,host FROM mysql.user;
+---------------------+-------------------------------------------+-----------------------+-----------+
| user                | authentication_string                     | plugin                | host      |
+---------------------+-------------------------------------------+-----------------------+-----------+
| root                | *A9172BC315E0BF4D14D201C4CD16374ED187B2B3 | mysql_native_password | localhost |
| mysql.session       | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |
| mysql.sys           | *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE | mysql_native_password | localhost |

Damit ist das Passwort gesetzt. Will man es später einmal ändern, so muss man berücksichtigen, dass sich das Passwort für MySQL nicht mehr mit den altbekannten Kommandos setzen lässt, weil das Passwort nicht mehr im Feld password, sondern im Feld authentication_string zu finden ist:

use mysql;
UPDATE user SET authentication_string= password('password') WHERE User = 'root';
flush privileges;

Siehe auch https://stackoverflow.com/questions/30692812/mysql-user-db-does-not-have-password-columns-installing-mysql-on-osx

und

https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-20-04-de

Nachdem das Passwort gesetzt ist, kann sich der Benutzer root auch per phpmyadmin anmelden.

MySQL im Zusammenspiel mit phpmyadmin

Eine etwas einfachere Lösung das Passwort-Problem zu lösen gibt es, wenn mit phpmyadmin gearbeitet wird. In der Datei /etc/mysql/debian.cnf sind die Zugangsdaten für einen bei der Installation angelegten User zu finden:

# Automatically generated for Debian scripts. DO NOT TOUCH!
[client]
host     = localhost
user     = debian-sys-maint
password = BmhrjzFR0D0521NX
socket   = /var/run/mysqld/mysqld.sock
[mysql_upgrade]
host     = localhost
user     = debian-sys-maint
password = BmhrjzFR01D021NX
socket   = /var/run/mysqld/mysqld.sock

Mit dem hier befindlichen Benutzer und dem hier befindlichen zufällig generiertem Passwort kann man per phpmyadmin auf die Datenbank zugreifen. Hier kann man dann bequem einen Benutzer mit allen gewünschten Rechten anlegen.

Man muss also nicht dem Benutzer root den Zugriff ermöglichen. Aus Sicherheitsgründen ist es sowieso sinnvoller einen individuellen Benutzer anzulegen, da oft genug versucht wird sich über phpmyadmin einzuloggen. Ich habe mich auch angewöhnt in der Datei /etc/apache2/conf-available/phpmyadmin.conf die Alias-Zeile auszukommentieren:

#Alias /phpmyadmin /usr/share/phpmyadmin

So kann ich erreichen, dass das Tool nicht allen virtuellen Systemen zur Verfügung steht, sondern die Berechtigung aktiv konfiguriert werden muss.

letsencrypt

Für die verschlüsselte Übertragung von Webseiten werden Zertifikate von letsencrypt benötigt. Das notwendige Paket ist bei Ubuntu dabei:

apt install certbot

Für jede meiner virtuellen Domains habe ich dann eine letsencrypt.ini erstellt, mit folgendem Inhalt:

 # Aufruf mit: /usr/bin/certbot certonly --config /var/www/vhosts/meine-maildomain.de/letsencrypt.ini
 # Wir nutzen 4096 bit RSA key statt 2048
 rsa-key-size = 4096
 
 # allgemeine Angaben
 email = uwe@meine-maildomain.de
 authenticator = webroot
 
 # Domains fuer die wir Zertifikate beantragen, die erste in
 # der liste legt den Hauptnamen fest. Alle Domains müssen beim
 # Aufruf erreichbar sein
 domains = meine-maildomain.de, www.meine-maildomain.de
 
 # Dies ist das Verzeichnis zur Domain, wo letsencrypt seinen Hash in
 # /.well-known/acme-challenge schreiben will. Der Pfad muss auf / enden
 # es muss in der vserver.conf stehen:   Alias /.well-known   /var/www/htdocs/.well-known
 webroot-path = /var/www/htdocs/

Die Reihenfolge der Domains spielt insofern eine Rolle, als die erste Domain als Bezeichner für die Verzeichnisstruktur innerhalb von /etc/letsencrypt benutzt wird. Es bietet sich also an mit einer kürzeren Angabe zu beginnen.

Zum Erzeugen der Zertifikate dient dann der Aufruf:

/usr/bin/certbot certonly --config /var/www/vhosts/meine-maildomain.de/letsencrypt.ini

Die täglichen Aktualisierungsversuche für die Zertifikate übernimmt ein Con-Job, der automatisch angelegt wird (/etc/cron.d/certbot). Leider bekommt man dann keine Mails mehr, sondern muss in die Logdateien schauen, ob alles geklappt hat. Falls mir das auf Dauer nicht gefällt, so mache ich das wieder über den eigenen Cron-Job.

Was ich jetzt erst entdeckt habe ist das Prinzip der Hooks. Man kann bei letsencript an mehreren Stellen Scripten hinterlegen, die bei Aktualisierung eines Zertifikates aufgerufen werden. Damit kann man z.B. den Webserver oder den Mailserver neu starten.


Zertifikate erweitern

Das Erweitern von letsencrypt Zertifikaten ist relativ einfach. Ich ergänze eine die Domains-Zeile in der Konfigurationsdatei und rufe den Erzeugungsprozess neu auf. Letsencrypt erkennt die Situation und fragt, ob ich das Zertifikat erweitern oder erneuern möchte. Wählt man hier erweitern, so wird das passende Zertifikat neu erzeugt.


Zertifikat reduzieren

Manchmal soll eine Domain aus einem Zertifikat entfernt werden, weil man eventuell sie an anderer Stelle benötigt, oder sie nicht mehr verfügbar ist. Ich habe bisher keinen direkten Weg gefunden, wenn man vorgeht wie beim Erweitern und einfach die Liste verkürzt, dann legt Letsenctypt ein zusätzliches Zertifikat an, mit der Ergänzung -0001 am Namen. Man muss also das Zertifikat löschen und neu erstellen.

certbot delete --cert-name MeineDomain

Es geht auch interaktiv mit

certbot delete

es erscheint eine Liste der vorhandenen Zertifikate und man gibt die Nummer des Zertifikates an, das man löschen möchte.

Anschließend legt man das Zertifikat mit der verkleinerten Liste neu an.

Man muss aber damit rechnen, dass man von Letsencrypt Hinweis-Mails bekommt, wenn sich das eigentlich gelöschte Zertifikat dem Ablauf-Zeitpunkt nähert. So weit geht die Lösung nämlich nicht.

Dienste neu starten

In der Regel müssen z.B. die Mail-Dienste neue gestartet werden, wenn das benutzte Zertifikat erneuert wurde. Sonst wird weiterhin das alte Zertifikat benutzt. Letsencrypt kennt Hooks, über die Aktionen ausgelöst werden.

Hier die Datei /etc/letsencrypt/renewal-hooks/deploy/postfix-dovecot-reload.sh

#!/bin/sh
# Dieses script liegt ausführbar in: /etc/letsencrypt/renewal-hooks/deploy

for domain in $RENEWED_DOMAINS
do
    if [ "$domain" = "mail.<meine Domain>.de" ]
    then
        systemctl reload postfix
        systemctl reload dovecot
        
    fi
done


Mehr Änderungen

Seit dem 1.12.2020 gibt der Cerbot auf den Servern mit Ubuntu 18.04 die folgende Meldung aus:

Your system is not supported by certbot-auto anymore.
Certbot will no longer receive updates. 
Please visit https://certbot.eff.org/ to check for other alternatives.

Aktuell funktioniert die Aktualisierung der Zertifikate noch, aber der Client wird nicht mehr aktualisiert.

Auf https://certbot.eff.org finde ich für mein System dann die Anleitung ein Snap mit dem Certbot zu installieren. Da der snapd auf den Systemen bereits vorhanden ist geht die Installation relativ einfach in folgenden Schritten (als root):

snap install core 
snap refresh core
snap install --classic certbot

Dann noch einen Link setzen:

ln -s /snap/bin/certbot /usr/bin/certbot

Danach kann man dann ausprobieren, ob der Certbot mit den vorhandenen Zertifikaten funktioniert:

certbot renew --dry-run

Denkbar ist dann ein Cronjob der Art:

/usr/bin/certbot renew

Meine Crontab habe ich dann angepasst, obwohl mir nicht ganz klar ist, ob die Aktualisierung nicht schon automatisch geschieht.

Mit

systemctl list-timers

kann man sich die Timer anschauen, die nicht über Cron laufen, sondern über den Systemd-Timer. Es gibt dort einen snap.certbot.renew.timer, der im Verzeichnis /etc/systemd/system/ zu finden ist, aber wohl nur für die Aktualisierung des Snaps zuständig ist.

Sonstige Timer sind übrigens meist im Verzeichnis /lib/systemd/system/ zu finden.

Ein neues Zertifikat erzeugt man dann mit

/usr/bin/certbot certonly --config /var/www/vhosts/<domain>/letsencrypt.ini

Apache

Der Apache Webserver ist ein enorm umfangreiches Stück Software. Ich hoffe, dass meine Konfiguration einigermaßen sinnvoll ist.

Installation

Die folgenden grundlegenden Pakete habe ich installiert

apt install apache2 apache2-bin apache2-data apache2-doc apache2-utils		

Dann ein paar Pakete für PHP

apt install libapache2-mod-php  php php-auth-sasl php-bz2 php-cli php-db php-gd php-geoip php-imap php-log php-mail php-curl php-imagick php-intl
apt install php-mbstring php-mdb2 php-mysql php-net-smtp php-phpseclib php-soap php-tcpdf php7.4-zip phpmyadmin 
apt install php-apcu php7.4-opcache

Da sind eventuell noch Doppelungen drin, sowohl das Paket, als auch das Metapaket. Es ist aber das, was mir

dpkg --get-selections | grep php

lieferte.

Nicht vorhanden waren die Pakete php-gettext und php-recode, die Ursache muss ich noch recherchieren.

Nun noch ein paar Perl-Pakete:

apt install libapache2-mod-perl2 libapache2-reload-perl libapparmor-perl libarchive-zip-perl libauthen-sasl-perl libbsd-resource-perl libcairo-perl
apt install libcgi-fast-perl libfile-basedir-perl libfile-desktopentry-perl libfile-mimeinfo-perl libfont-afm-perl libgd-graph-perl libglib-perl libgtk2-perl
apt install libhtml-form-perl libhtml-format-perl libhtml-template-perl libhttp-daemon-perl libimage-magick-perl libmailtools-perl libnet-dbus-perl libtie-ixhash-perl
apt install libx11-protocol-perl libxml-xpathengine-perl libdbi-perl libdbd-mysql libclass-dbi-mysql-perl

Nach erfolgter Konfiguration (s.u.) darf man nicht vergessen die notwendigen Ports in der Firewall frei zu geben:

ufw allow "Apache Full"

Server-Module

Vorsichtshalber noch einmal ein paar Apache-Module aktivieren:

a2enmod perl
a2enmod cgi
a2enmod expires
a2enmod headers 
a2enmod rewrite
a2enmod ssl
a2dismod status
service apache2 restart


für Typo3

Da ich viel mit Typo3 arbeite habe ich etwas an den PHP-Einstellungen gedreht in der /etc/php/7.4/apache2/php.ini:

post_max_size=12M
upload_max_filesize=12M
max_execution_time=240
max_input_vars = 1500

Typo3 benötigt unbedingt imagemagick (oder alternativ graphicsmagick)

apt install imagemagick imagemagick-doc
apt install graphicsmagick ghostscript webalizer

Reihenfolge-Probleme bei der Apache-Konfiguration

Bei der Apache-Konfiguration muss man sehr auf die Reihenfolge der einzelnen Einstellungen achten. Dabei spielt der Aufbau der Hauptkonfigurationsdatei /etc/apache2/apache2.conf eine wichtige Rolle. Hier werden der Reihe nach alle Dateien aus folgenden Unterverzeichnissen eingebunden:

  • mods-enabled
  • conf-enabled
  • sites-enabled

Die Dateien aus den einzelnen Verzeichnissen werden dann jeweils in alphabetischer Reihenfolge eingebunden, intern entsteht dabei eine einzige große Konfigurationsdatei. Innerhalb dieser virtuellen Datei spielen die Reihenfolgen eine Rolle.

Bei der Reihenfolge von Alias (auch SriptAlias) Anweisungen und Redirects, die in unterschiedlichen Kontexten auftreten, werden die Direktiven nach den üblichen Zusammenführungsregeln verarbeitet. Wenn jedoch mehrere Aliase oder Redirects im gleichen Kontext (z.B. im gleichen Abschnitt) auftreten, werden sie in einer bestimmten Reihenfolge verarbeitet.

Zunächst werden alle Umleitungen verarbeitet, bevor Aliase verarbeitet werden, und daher werden auf eine Anforderung, die mit einer Umleitung oder einer RedirectMatch übereinstimmt, niemals Aliase angewendet. Zweitens werden die Aliase und Redirects in der Reihenfolge verarbeitet, in der sie in den Konfigurationsdateien erscheinen, wobei die erste Übereinstimmung Vorrang hat.

Wenn also in der /etc/apache2/conf-available/postfixadmin.conf steht

Alias /postfixadmin /usr/share/postfixadmin/public

kann ich dies nicht im allgemeinen Teil der /etc/apache2/sites-available/000-default.conf überschreiben, weil die erst später inkludiert wird. Nur innerhalb einer Directory oder VirtualHost Struktur kann ich Veränderungen vornehmen, weil dies spezieller ist.

Aus dem gleichen Grund muss man, wenn zwei oder mehr dieser Direktiven auf denselben Unterpfad angewendet werden, den spezifischsten Pfad zuerst auflisten, damit alle Direktiven eine Wirkung haben. Zum Beispiel wird die folgende Konfiguration wie erwartet funktionieren:

ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/
ScriptAlias /cgi-bin/ "/var/www/vhosts/default/cgi-bin/"

Aber wenn die beiden oben genannten Richtlinien in umgekehrter Reihenfolge angewendet würden, würde der /cgi-bin vor dem /cgi-bin/mailman-Alias stehen, so dass die letztere Richtlinie ignoriert würde.

Es ist sinnvoll beim Start von Apache auf die Meldungen im Syslog zu achten. Habe ich z.B. den Alias /postfixadmin bei den conf-enabled nicht auskommentiert, so erscheint bei meiner Konfiguration (s.u.) die Meldung

The Alias directive in /etc/apache2/sites-enabled/000-default.conf at line 19 will probably never match because it overlaps an earlier Alias.

/etc/apache2/sites-available/000-default.conf

Diese Datei besteht bei mir aus drei Teilen:

  • Zuerst die allgemeinen Einstellungen, die dann für alle virtuellen Systeme gelten, sofern sie nicht überschrieben werden.
  • Dann der virtuelle Default-Server für Port 80. Er würde aufgerufen, wenn jemand über die IP-Adresse, den Namen beim Provider (static.w.x.y.z.clients.your-server.de) oder eine nicht vorgesehene Domain kommt.
  • Der entsprechende virtuelle Default-Server für Port 443.

Die virtuellen Standard-Server sind auch im Zusammenhang mit letsencrypt-Zertifikaten für den Mailserver ganz praktisch. Ich muss nicht für mail.meine-maildomain.de eine Webseite konfigurieren, wenn ich ein Zertifikat erstellen oder erweitern möchte. Letsencrypt landet im Zweifelsfall hier und kann den Zugriff verifizieren. Der Standard-Server auf Port 443 erleichtert dann die Kontrolle der erstellten Zertifikate für den Mailserver, wenn das hier angegebene Zertifikat auch im Mailsystem genutzt wird.

ServerName default
ServerAdmin Uwe@meine-maildomain.de
 
ServerTokens Major
ServerSignature off
TraceEnable off
ProxyRequests off
 
UseCanonicalName Off
DocumentRoot /var/www/vhosts/default/httpdocs
 
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
 
CustomLog /var/log/apache2/vhosts_access.log vhost_combined
 
Alias /webmail       /var/www/htdocs/dummy
Alias /phpmyadmin    /var/www/htdocs/dummy
Alias /postfixadmin  /var/www/htdocs/dummy
 
Alias /webstat       /var/www/htdocs/webalizer
Alias /roundcube     /var/lib/roundcube
 
<IfDefine MAILMAN>
  ScriptAlias     /mailman/       /var/www/htdocs/dummy
  Alias           /mailmanicons/  /var/www/htdocs/dummy
  Alias           /pipermail/     /var/www/htdocs/dummy
</IfDefine>
 
<IfModule mod_userdir.c>
  UserDir disabled
</IfModule>
 
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 1 month"
  ExpiresByType text/html "access plus 1 week"
  ExpiresByType image/gif "access plus 1 week"
  ExpiresByType image/jpeg "access plus 1 week"
  ExpiresByType image/png "access plus 1 week"
  ExpiresByType text/css "access plus 1 week"
  ExpiresByType text/javascript "access plus 1 week"
  ExpiresByType application/x-javascript "access plus 1 week"
  ExpiresByType text/xml "access plus 1 week"
</IfModule>
 
<IfModule mod_setenvif.c>
  # SEO
  BrowserMatchNoCase (mindUp|meanpathbot|seoscanners|AiHitBot|BLEXBot|DotBot|linkdexbot|MJ12bot|SEOkicks-Robot) ist_ein_bot
  # Sammeln Backlinks & Links
  BrowserMatchNoCase (exabot|Baidu|Haosou|Semrush|MegaIndex|AhrefsBot|BacklinkCrawler|dlcbot|spbot) ist_ein_bot
  # Performance Testing
  BrowserMatchNoCase (200PleaseBot|LoadTimeBot) ist_ein_bot
  # BilderSuche
  BrowserMatchNoCase (psbot|Yandex) ist_ein_bot
  # Harvester & Marketing
  BrowserMatchNoCase (MegaIndex|Applebot|XoviBot|CareerBot|GrapeshotCrawler|iCjobs|magpie-crawler|proximic) ist_ein_bot
  # Nutzlos, Schlecht bzw. unbekannt
  BrowserMatchNoCase (PetalBot|360Spider|AfD-Verbotsverfahren|Barkrowler|PeoplePal|ltx71|CalendarAgent|JobboerseBot|GarlikCrawler|Mail.RU_B
  # Per IP
  SetEnvIfNoCase Remote_Addr (62\.138\.0\.25) ist_ein_bot
  # kyivstar.net
  SetEnvIfNoCase Remote_Addr ^(5\.248|46\.118|37\.115|178\.137) ist_ein_bot
  # Einträge von 2020
  BrowserMatchNoCase (MaviBot|oBot|MetaJobBot|seocompany|coccocbot-image|SeznamBot) ist_ein_bot
</IfModule>
 
<IfModule mod_ssl.c>
  SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
  SSLHonorCipherOrder On
  SSLCompression off  
  SSLCipherSuite ALL:!aNULL:RC4+RSA:+HIGH:+MEDIUM:+LOW:+EXP:+eNULL
</IfModule>

<Directory "/var/www/vhosts">
  AllowOverride All
  Options +SymLinksIfOwnerMatch -Indexes
  Require all granted
 
  <IfModule mod_php7.c>
    php_value date.timezone "Europe/Berlin"    
    php_value open_basedir /var/www/:/tmp/
    php_value include_path /var/www/:/tmp/
  </IfModule>
 
</Directory>
  
<VirtualHost *:80>
  Alias /.well-known   /var/www/htdocs/.well-known
  <Directory /var/www/vhosts/default/httpdocs>
    AllowOverride All
    Options None
    Require all granted
  </Directory>
 
</VirtualHost>
 
<IfModule mod_ssl.c>
  <VirtualHost _default_:443 >
    SSLEngine on
   # Wenn das erste Zertifikat mit Letsencryp erstellt ist, dann die Zertifikate austauschen
   # SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
   # SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
    SSLCertificateFile /etc/letsencrypt/live/<dummy>/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/<dummy>/privkey.pem
 
    <FilesMatch "\.(cgi|shtml|phtml|php)$">
      SSLOptions +StdEnvVars
    </FilesMatch>
 
    <Directory /var/www/vhosts/default/httpdocs>
      SSLRequireSSL
      AllowOverride All
      Options None
      Require all granted
    </Directory>
 
  </VirtualHost>
 
</IfModule>


Die SSL-Einstellungen der Seite kann man unter https://www.cdn77.com/tls-test (Hinweis: deren Cache lässt sich anscheinend nicht löschen) und ganz ausführlich unter https://www.ssllabs.com/ssltest/ testen lassen. Es geht übrigens auch ohne externen Dienstleister mittels

nmap --script ssl-enum-ciphers -p 443 example.com

Ursprünglich hatte ich hier auch einen Alias für .well-known mir drin, das führt aber zu Problemen bei z.B. Nextcloud, hier wird mit Unterverzeichnissen von .well-known gearbeitet und dann treten Probleme mit der Reihenfolge auf.

Vserver-Konfiguration

Für jeden weiteren VServer erfolgt die Konfiguration in /etc/apache2/vhosts/sites-available/<dummy>.conf nach folgendem System, wobei <dummy> durch z.B. den Domainnamen ersetzt wird. Das zugehörige Verzeichnis wird dann mit diesem Namen unterhalb von /var/www/vhosts/ angelegt.

<VirtualHost *:80>
  ServerName   www.<dummy>:80
  ServerAlias <dummy>
  DocumentRoot /var/www/vhosts/<dummy>/httpdocs
 
  CustomLog  /var/log/apache2/<dummy>_access.log combined
  ErrorLog   /var/log/apache2/<dummy>_error.log
 
  CustomLog /var/log/apache2/vhosts_access.log vhost_combined
 
  ScriptAlias  /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/
  Alias  /webstat       /var/www/vhosts/<dummy>/webstat
  Alias /.well-known   /var/www/htdocs/.well-known
 # Nur bei Bedarf aktivieren
 # Alias /phpmyadmin /usr/share/phpmyadmin
 # Alias /postfixadmin  /usr/share/postfixadmin/public
 
  <Directory /var/www/vhosts/<dummy>/httpdocs>
 
    <IfModule mod_setenvif.c>
      <RequireAll> 
        Require all granted
        Require not env ist_ein_bot
      </RequireAll> 
    </IfModule>
 
    <IfModule mod_php7.c>
      php_admin_flag engine on
      php_admin_value include_path    "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
      php_admin_value open_basedir    "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
    </IfModule>
 
    Options -Includes +ExecCGI
  </Directory>
 
  <Directory "/var/www/vhosts/<dummy>/cgi-bin">
    AllowOverride None
    Options +ExecCGI -Includes
    Require all granted
  </Directory>
 
</VirtualHost>
 
# soll SSL aktiviert werden das _no entfernen
<IfModule mod_ssl_no.c>
 
  <VirtualHost *:443>
    ServerName   www.<dummy>:443
    ServerAlias <dummy>
    DocumentRoot /var/www/vhosts/<dummy>/httpdocs
 
    CustomLog  /var/log/apache2/<dummy>_access.log combined
    ErrorLog   /var/log/apache2/<dummy>_error.log
 
    CustomLog /var/log/apache2/vhosts_access.log vhost_combined
 
    ScriptAlias  /cgi-bin/ /var/www/vhosts/<dummy>/cgi-bin/
    Alias  /webstat /var/www/vhosts/<dummy>/webstat
    Alias /.well-known   /var/www/htdocs/.well-known
   # Nur bei Bedarf aktivieren
   # Alias /phpmyadmin /usr/share/phpmyadmin
   # Alias /postfixadmin  /usr/share/postfixadmin/public
    SSLEngine on
 
    <Directory /var/www/vhosts/<dummy>/httpdocs>
      <IfModule mod_setenvif.c>
        <RequireAll> 
          Require all granted
          Require not env ist_ein_bot
        </RequireAll> 
      </IfModule>
 
      <IfModule mod_php7.c>
        php_admin_flag engine on
        php_admin_value include_path    "/var/www/vhosts/<dummy>/httpdocs:.:/tmp:./:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
        php_admin_value open_basedir    "/var/www/vhosts/<dummy>/httpdocs:/tmp:.:/usr/share/php/PEAR/:/srv/www/typo3src:/usr/bin"
      </IfModule>
 
      Options -Includes +ExecCGI
    </Directory>
 
    <Directory "/var/www/vhosts/<dummy>/cgi-bin">
      AllowOverride None
      Options +ExecCGI -Includes
      Require all granted
    </Directory>
  
    SSLCertificateFile /etc/letsencrypt/live/<dummy>/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/<dummy>/privkey.pem
  </VirtualHost>
 
</IfModule>

Verwaltungs-Vserver

Für die Nutzung von

  • postfixadmin
  • phpmyadmin
  • rspamd
  • eigenen CGI Scripten

habe ich mir einen speziellen virtuellen Server erstellt, der keine eigenen Ordner bekommt, sondern auf dem Default-Server aufsetzt. /etc/apache2/vhosts/sites-available/verwaltung.conf

<VirtualHost *:80>
  ServerName   verwaltung.<dummy>:80
  DocumentRoot /var/www/vhosts/default/httpdocs
 
  CustomLog  /var/log/apache2/verwaltung_access.log combined
  ErrorLog   /var/log/apache2/verwaltung_error.log
 
  CustomLog /var/log/apache2/vhosts_access.log vhost_combined
 
  ScriptAlias  /cgi-bin/ /var/www/vhosts/default/cgi-bin/
  Alias  /webstat        /var/www/vhosts/default/webstat
  Alias /phpmyadmin      /usr/share/phpmyadmin
  Alias /postfixadmin    /usr/share/postfixadmin/public
  Alias /.well-known     /var/www/htdocs/.well-known
  
  <Directory /var/www/vhosts/default/httpdocs>
 
    <IfModule mod_setenvif.c>
      <RequireAll> 
        Require all granted
        Require not env ist_ein_bot
      </RequireAll> 
    </IfModule>
  
    Options -Includes +ExecCGI
  </Directory>
 
  <Directory "/var/www/vhosts/default/cgi-bin">
    AllowOverride None
    Options +ExecCGI -Includes
    Require all granted
  </Directory>
 
  RewriteEngine On
  ProxyRequests Off
  <Location /rspamd>
    Order allow,deny
    Allow from all
  </Location>
  RewriteRule ^/rspamd$ /rspamd/ [R,L]
  RewriteRule ^/rspamd/(.*) http://localhost:11334/$1 [P,L]
 
</VirtualHost>
 
# soll SSL aktiviert werden das _no entfernen
<IfModule mod_ssl_no.c>
 
  <VirtualHost *:443>
    ServerName   verwaltung.<dummy>:443
    DocumentRoot /var/www/vhosts/default/httpdocs
 
    CustomLog  /var/log/apache2/verwaltung_access.log combined
    ErrorLog   /var/log/apache2/verwaltung_error.log
 
    ScriptAlias  /cgi-bin/  /var/www/vhosts/default/cgi-bin/
    Alias  /webstat         /var/www/vhosts/default/webstat
    Alias /phpmyadmin       /usr/share/phpmyadmin
    Alias /postfixadmin     /usr/share/postfixadmin/public
    Alias /.well-known      /var/www/htdocs/.well-known
 
    SSLEngine on
 
    <Directory /var/www/vhosts/default/httpdocs>
 
      <IfModule mod_setenvif.c>
        <RequireAll> 
          Require all granted
          Require not env ist_ein_bot
        </RequireAll> 
      </IfModule>
 
      Options -Includes +ExecCGI
    </Directory>
 
    <Directory "/var/www/vhosts/default/cgi-bin">
      AllowOverride None
      Options +ExecCGI -Includes
      Require all granted
    </Directory>
 
    SSLCertificateFile /etc/letsencrypt/live/verwaltung.<dummy>/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/verwaltung.<dummy>/privkey.pem
 
    RewriteEngine On
    ProxyRequests Off
    <Location /rspamd>
      Order allow,deny
      Allow from all
    </Location>
    RewriteRule ^/rspamd$ /rspamd/ [R,L]
    RewriteRule ^/rspamd/(.*) http://localhost:11334/$1 [P,L]
 
  </VirtualHost>
 
</IfModule>

Logdateien

Da ich die Logdateien für meine virtuellen Server mit Webalizer auswerten möchte, brauche ich eine Erweiterung für Logrotate:

/var/log/apache2/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 640 root adm
        sharedscripts
        postrotate
                if invoke-rc.d apache2 status > /dev/null 2>&1; then \
                    invoke-rc.d apache2 reload > /dev/null 2>&1; \
                fi;
        endscript
        prerotate
             /root/webalizer.sh
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi; \
        endscript
}

Entweder hängt man diesen Teil an /etc/logrotate.d/apache2 an oder man erstellt eine neue Datei /etc/logrotate.d/apache-vhosts .