OPNsense/Caddy: Default-VirtualHost-Konfiguration mit Apache, WordPress und Nextcloud

Diese Dokumentation beschreibt den Aufbau und die Migration eines bestehenden Webservers hinter einen Reverse Proxy mit OPNsense und Caddy. Im Mittelpunkt steht eine Umgebung mit Apache, mehreren WordPress-Websites und Nextcloud, bei der sowohl die bestehende URL-Struktur als auch der direkte Zugriff auf den internen Webserver erhalten bleiben sollen.

Die externe HTTPS-Verbindung wird dabei vollständig durch Caddy übernommen. Caddy terminiert TLS, verarbeitet die eingehenden Anfragen und leitet sie anhand des Hostnamens an den zuständigen Apache-VirtualHost weiter. Apache selbst verbleibt auf dem internen Webserver und stellt die eigentlichen Websites und Anwendungen bereit.

Ein besonderer Schwerpunkt liegt auf dem Zusammenspiel zwischen Caddy und Apache, der Trennung zwischen externer und interner URL-Struktur sowie der parallelen Unterstützung von neuen Subdomain-Adressen und bestehenden pfadbasierten URLs. Dadurch können vorhandene Links, WordPress-Strukturen sowie Nextcloud-DAV-Zugriffe während und nach der Migration weiterhin genutzt werden.

Die dargestellte Konfiguration basiert auf einer tatsächlich aufgebauten und getesteten Umgebung. Neben der eigentlichen Konfiguration werden auch die erforderlichen Anpassungen und Prüfungen dokumentiert. Dadurch lässt sich der gesamte Aufbau nachvollziehen und bei einem späteren Server-, Domain- oder Infrastrukturwechsel gezielt anpassen.

Beispielwert Bedeutung
olddomain.de alte Domain (Pfad-basierte Adressierung)
newdomain.de neue Domain (Subdomain-basierte Adressierung)
olddomain/myblog / myblog.newdomain.de Blog-Site; alter | neuer Pfad /myblog/ |  /myblog.newdomain.de/
www.website1.de … www.website4.de WordPress-Sites; Verzeichnis /var/www/www.websiteN.de; Subdomain websiteN.newdomain.de; Alias /www.websiteN.de
olddomain.d/nextcloud / nextcloud.newdomain.de Nextcloud; alter| neuer Pfad /nextcloud | nextcloud.newdomain.de (direkt per IP und als alter Pfad auf der alten Domain)
192.178.0.0/24 internes Netz des Reverse Proxys
192.178.1.0/24 Netz des Webservers: 192.178.1.100 = Webserver, 192.178.0.1 = Adresse des Gateway aus Sicht des Webservers

Inhaltsverzeichnis

1. Ziel und Architektur 7. Fehleranalyse und typische Probleme
2. Apache-Webserver 8. CardDAV und Kalender
3. Zusammenspiel zwischen Caddy und Apache 9. Vollständige Konfigurationsübersicht
4. OPNsense / Caddy 10. Prüf- und Testverfahren
5. WordPress und URL-Struktur 11. Ablauf einer Anfrage
6. Alte URLs und URL-Remapping

1. Ziel und Architektur

1.1 Ziel

Ein bestehender Apache-Webserver mit mehreren WordPress-Sites und einer Nextcloud-Instanz wird hinter einem Reverse Proxy (Caddy auf OPNsense) betrieben. Die Domain wechselt von olddomain.de (Pfad-basierte Adressierung, z. B. /myblog/) auf newdomain.de (Subdomain-basierte Adressierung, z. B. myblog.newdomain.de). Konfigurationen und Weiterleitungen sind so weit wie möglich nicht von der Domain abhängig, damit bei einem weiteren Umzug nur wenige Stellen anzupassen sind.

  • Jede WordPress-Site ist über eine eigene Subdomain des Reverse Proxys und zusätzlich direkt über die Server-IP erreichbar.
  • Alte Links der Form https://olddomain.de// werden auf https://.newdomain.de/ weitergeleitet. Der Teil bleibt unverändert.
  • Die alte Nextcloud-URL https://olddomain.de/nextcloud bleibt für Browser (Weiterleitung) und für DAV-Clients (WebDAV, CalDAV, CardDAV) nutzbar.

1.2 Komponenten der tatsächlichen Umgebung

Komponente Rolle Details
Client/Browser Ausgangspunkt der Anfrage ruft z. B. https://myblog.newdomain.de/ auf
DNS (deSEC) Namensauflösung der neuen Domain newdomain.de: A-Record auf die öffentliche IP (automatisch aktualisiert); Wildcard-CNAME * → newdomain.de
DNS (alte Domain) Namensauflösung der alten Domain olddomain.de zeigt weiterhin auf die öffentliche IP (durch funktionierende Weiterleitungen bestätigt)
Internet-Router Router/Internetzugang 192.178.0.1; Portfreigaben 80/443 auf der Fritzbox für OPNsense
OPNsense Firewall/DMZ-Gateway, VM auf einem Hypervisor Hostname opnsense-proxy; WAN-Adresse im internen Netz 192.178.0.3; Netz zum Webserver 192.178.1.0/24
Caddy (os-caddy) Reverse Proxy, TLS-Terminierung läuft direkt auf der OPNsense; HTTP/1.1 und HTTP/2 (HTTP/3 aus)
Apache Webserver VM webserver, 192.178.1.100, Port 80 (nur HTTP)
WordPress Webanwendung PHP/MySQL, je Site ein Verzeichnis unter /var/www/www.
Nextcloud Webanwendung /var/www/nextcloud

1.3 Weg einer Anfrage

1.4 Externe URL und interner Zielserver

Die extern sichtbare URL (https://myblog.newdomain.de/category/smart-home/) und die interne Adresse des Zielservers (http://192.178.1.100/) sind zwei getrennte Ebenen:

  • Extern: Schema https, Hostname myblog.newdomain.de, Pfad /category/smart-home/. TLS endet am Caddy.
  • Intern: Caddy öffnet eine neue HTTP-Verbindung zu 192.178.1.100:80 und übergibt den ursprünglichen Hostnamen im Host-Header. Der Pfad bleibt unverändert.
  • Direktzugriff (ohne Reverse Proxy): http://192.178.1.100/www.myblog/category/smart-home/. Der Host-Header lautet hier 192.178.1.100; der Pfad enthält zusätzlich den Alias-Präfix /www.myblog.

1.5 Zuordnung der Sites

Alte URL (Domain olddomain.de) Neue URL über Reverse Proxy Verzeichnis auf dem Webserver Direktzugriff per IP/Pfad
https://olddomain/myblog/ https://myblog.newdomain.de/ /var/www/www.myblog http://192.178.1.100/www.myblog/
https://olddomain/www.website1.de/ https://website1.newdomain.de/ /var/www/www.website1.de http://192.178.1.100/www.website1.de/
https://olddomain/www.website2.de/ https://website2.newdomain.de/ /var/www/www.website2.de http://192.178.1.100/www.website2.de/
https://olddomain/www.website3.de/ https://website3.newdomain.de/ /var/www/www.website3.de http://192.178.1.100/www.website3.de/
https://olddomain/www.website4.de/ https://website4.newdomain.de/ /var/www/www.website4.de http://192.178.1.100/www.website4.de/
https://olddomain/nextcloud https://nextcloud.newdomain.de/ /var/www/nextcloud http://192.178.1.100/nextcloud/

Zurück zur Übersicht


2. Apache-Webserver

2.1 Installation und Module

Die PHP-Pakete (WordPress, Nextcloud) und der Datenbankserver richten sich nach den Anforderungen der jeweiligen Anwendungen.

Modul Verwendung Folge bei Fehlen
macro in 000-default.conf Apache startet nicht: AH00526: Invalid command 'Macro'
rewrite WordPress-Permalinks über .htaccess Unterseiten liefern 404
headers Header always set Strict-Transport-Security in nextcloud.conf Konfigurationsfehler beim Start
remoteip RemoteIPHeader/RemoteIPInternalProxy in nextcloud.conf Konfigurationsfehler beim Start
env, setenvif SetEnv, SetEnvIf (Nextcloud, HTTPS-Erkennung) Konfigurationsfehler bzw. fehlende HTTPS-Erkennung
alias Alias-Direktiven für den Direktzugriff Direktzugriff per IP nicht möglich

Das Modul macro entfällt bei der Variante ohne Makro (Kapitel 2.4.1).

2.2 Verzeichnisstruktur

Die Verzeichnisse der WordPress-Sites beginnen einheitlich mit www.. Auf diesem Präfix beruht die gemeinsame <Directory "/var/www/www.*">-Freigabe in 000-default.conf. Ein Verzeichnis ohne dieses Präfix erhielte kein AllowOverride All; die .htaccess-Rewrite-Regeln von WordPress würden ignoriert.

2.3 Aufbau der Debian-Konfiguration

apache2.conf enthält am Ende IncludeOptional sites-enabled/*.conf. Die Dateien in sites-enabled/ werden in alphabetischer Reihenfolge eingelesen. Das ist die Grundlage für die Sonderstellung von 000-default.conf (Kapitel 2.5).

Die Datei apache2.conf enthält außerdem die globale Zugriffsbasis:

Das Dateisystem ist standardmäßig gesperrt; /var/www/ ist freigegeben, jedoch ohne .htaccess-Auswertung (AllowOverride None). Die Freigabe der .htaccess-Auswertung erfolgt je Anwendung in den VirtualHost-Dateien.

2.4 Die Datei 000-default.conf

Die Konfiguration der einzelnen Hosts kann entweder zentral in der Datei /etc/apache2/sites-available/000-default.conf vorgenommen oder alternativ auf einzelne Konfigurationsdateien pro Host unter /etc/apache2/sites-available/.conf verteilt werden.

Der Vorteil der zentralen Konfiguration liegt in der Verwendung von Apache-Makros, mit denen gemeinsame Einstellungen für mehrere Websites zusammengefasst und wiederverwendet werden können. Nachteil ist, dass einzelne Websites nicht unabhängig über a2ensite bzw. a2dissite aktiviert oder deaktiviert werden können. Bei getrennten Dateien unter /etc/apache2/sites-available/.conf ist dies dagegen für jeden Host einzeln möglich.

In diesem Beispiel wird die gesamte Konfiguration der Dienste und Websites zentral über die Datei 000-default.conf vorgenommen. Dies hat den Vorteil, dass sich die Konfiguration mithilfe von Apache-Makros zusammenfassen und dadurch eine zentrale Verwaltung aller Websites und Dienste realisieren lässt. Website-spezifische Konfigurationsdateien unter /etc/apache2/sites-available/www..conf werden in diesem Aufbau nicht benötigt.

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

Funktion der Datei: Die Datei ersetzt die fünf früheren Einzel-VirtualHosts (www.<websiteN>.conf) und den früheren Default-VirtualHost. Sie definiert (a) die Freigabe aller WordPress-Verzeichnisse, (b) ein Makro für namensbasierte WordPress-VirtualHosts, (c) den Default-VirtualHost für Direktzugriffe und (d) die fünf Site-Zuordnungen.

Erläuterung der einzelnen Bestandteile

Bestandteil Zweck Folge ohne diese Einstellung
<Directory "/var/www/www.*"> mit AllowOverride All Auswertung der WordPress-.htaccess für alle Verzeichnisse mit Präfix www. Permalinks liefern 404; nur index.php-URLs funktionieren
<Macro WPSite $sub $dir> Ein VirtualHost-Muster für alle WordPress-Sites; Parameter: Subdomain und Verzeichnis je Site eine eigene Datei mit Duplikaten
ServerName $sub.<newdomain> Pflichtangabe; der Wert wird nie von Clients angefragt
Definiert den primären Hostnamen des VirtualHosts. Auch bei einem Reverse Proxy wird dieser zur Zuordnung des Host-Headers verwendet.
Apache vergibt einen Standardnamen, Warnungen im Log
ServerAlias $sub.* Erlaubt zusätzliche Hostnamen für denselben VirtualHost. Dies kann sinnvoll sein, wenn die Domain flexibel gehalten oder später geändert werden soll. Bei fest eingetragenem ServerName myblog.newdomain.de müsste jeder Domainwechsel in jeder VHost-Datei nachgezogen werden
DocumentRoot /var/www/$dir Zuordnung Subdomain → Verzeichnis falsche oder keine Site
ErrorLog/CustomLog mit $sub getrennte Logs je Site (myblog-error.log, …) gemeinsame Logs, schwerere Diagnose
Default-VirtualHost (erster Eintrag auf *:80 in alphabetischer Dateireihenfolge) fängt Anfragen ab, die zu keinem ServerName/ServerAlias passen, insbesondere Direktaufrufe über die IP Direktzugriff per IP würde einen der Site-VHosts treffen
Alias /www. /var/www/www. Direktzugriff http://192.178.1.100/www./ Direktzugriff liefert 404
Alias /nextcloud mit , Dav off, SetEnv HOME Direktzugriff auf Nextcloud per IP http://192.178.1.100/nextcloud liefert 404 (tatsächlich aufgetreten, Kapitel 7.11)
<If … Require all denied> Hosts mit Punkt im Namen, die keinen eigenen VirtualHost haben (unbekannte Subdomains), erhalten 403; IP-Adressen und Kurznamen ohne Punkt bleiben zugelassen Unbekannte Hostnamen erreichen die Alias-Pfade (/www.website2.de/ unter beliebigem Hostnamen)

Reihenfolge innerhalb der Datei: Das Makro ist vor seiner Verwendung definiert; der Default-VirtualHost steht vor den Use WPSite-Zeilen. Maßgeblich für die Default-Eigenschaft ist jedoch die Reihenfolge der Dateien in sites-enabled/ (Kapitel 2.5), nicht die Reihenfolge innerhalb der Datei, solange keine weitere Datei einen *:80-VirtualHost enthält, der alphabetisch früher einsortiert wird. Apache vergleicht den Host-Header mit ServerName und mit ServerAlias, wobei der erste Treffer gewinnt. ServerName $sub. sollte daher auf die neue domain verweisen, da sonst nur der ServerAlias greift.

2.4.1 Variante ohne Makro

Die Datei 000-default.conf kann auch ohne mod_macro aufgebaut werden. In diesem Fall werden die fünf WordPress-VirtualHosts jeweils vollständig ausgeschrieben; mod_macro und a2enmod macro sind dann nicht erforderlich.

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

Unterschiede zur Makro-Variante

Punkt Mit Makro (Kapitel 2.4) Ohne Makro
Apache-Modul macro erforderlich nicht erforderlich
WordPress-VirtualHosts eine Definition (<Macro WPSite $sub $dir>) und je Site eine Zeile Use WPSite <sub> <dir> je Site ein vollständiger <VirtualHost>-Block
Neue Site eine Zeile Use WPSite … Block kopieren und vier Angaben anpassen: ServerName, ServerAlias, DocumentRoot, Dateinamen der Logs
Default-VirtualHost erster <VirtualHost> der Datei unverändert; er muss auch hier vor den WordPress-VirtualHosts stehen, damit er der Default-Server bleibt (Kapitel 2.5.2)
<Directory "/var/www/www.*">, Aliase, <If>-Regel unverändert unverändert

Einrichtung

Einzeldateien statt einer Datei: Die WordPress-VirtualHost-Blöcke können alternativ in eigene Dateien /etc/apache2/sites-available/www..conf ausgelagert und mit a2ensite www. aktiviert werden.  000-default.conf behält <Directory "/var/www/www.*"> und den Default-VirtualHost. Da die Dateinamen www.* alphabetisch nach 000-default.conf einsortiert werden, bleibt der Default-VirtualHost der Default-Server. ServerAlias .* bleibt unverändert, die Konfiguration ist weiterhin domainunabhängig.

Neue Site ergänzen (Beispiel website5, Verzeichnis /var/www/www.website5.de)

  1. Verzeichnis /var/www/www.website5.de anlegen bzw. die Site dorthin kopieren.
  2. Im Default-VirtualHost den Alias ergänzen: Alias /www.website5.de /var/www/www.website5.de.
  3. Einen VirtualHost-Block für website5 nach dem Muster der vorhandenen Blöcke anfügen.
  4. In der wp-config.php der Site $direct_path auf '/www' . '.website5.de' setzen (Kapitel 5.3).
  5. In Caddy die Subdomain website5 mit Handler reverse_proxy 192.178.1.100 anlegen (Kapitel 4.2) und in newdomain-redirect.conf bei Bedarf eine Zeile import legacy_site … ergänzen (Kapitel 4.5).
  6. apache2ctl configtest && systemctl reload apache2.

2.5 VirtualHosts: Auswahlverfahren und Sonderstellung von 000-default.conf

2.5.1 Wie Apache den VirtualHost auswählt

Apache ermittelt den passenden VirtualHost in zwei Schritten:

1. Adressebene (IP-Adresse und Port):
Zunächst wird anhand der lokalen IP-Adresse und des Ports bestimmt, welche VirtualHosts für die eingehende Verbindung infrage kommen. Bei *:80 lauschen die entsprechenden VirtualHosts auf allen lokalen IP-Adressen am Port 80 und gehören damit zur gleichen VirtualHost-Gruppe.

2. Namensebene (Host-Header):
Innerhalb dieser Gruppe vergleicht Apache den Host-Header der Reverse Proxy Anfrage mit den Angaben in ServerName und ServerAlias. Die VirtualHosts werden dabei in der Reihenfolge berücksichtigt, in der sie von Apache eingelesen wurden. Der erste passende VirtualHost wird verwendet.

In ServerAlias können auch Wildcards wie nextcloud.* verwendet werden. ServerName und ServerAlias sind daher auch bei einem Reverse Proxy relevant, da der von Caddy weitergereichte Host-Header zur Auswahl des passenden Apache-VirtualHosts verwendet wird.

Die tatsächliche Zuordnung zeigt:

Die Ausgabe nennt je *:80 den „default server“ (mit Datei und Zeile) sowie jeden namensbasierten VirtualHost mit Datei/Zeile.

2.5.2 Warum 000-default.conf besondere Bedeutung hat

sites-enabled/*.conf wird alphabetisch eingelesen. Das Präfix 000- sortiert die Datei vor alle anderen. Der erste *:80-VirtualHost ist damit der Default-VirtualHost. Das hat drei Folgen:

  • Direktaufrufe über die IP (Host: 192.178.1.100) passen zu keinem ServerAlias (myblog.* usw. trifft keine IP-Adresse) und landen deshalb im Default-VirtualHost. Dort sind die Alias-Pfade (/www./, /nextcloud) definiert.
  • Unbekannte Hostnamen landen ebenfalls dort. Die -Regel sperrt solche Anfragen (403), sofern der Host ein FQDN ist.
  • Würde eine andere Datei alphabetisch vor 000-default.conf einsortiert, würde deren VirtualHost zum Default und IP-Aufrufe lieferten dessen Inhalt.

2.5.3 Vergleich der VirtualHost-Arten

Art Beispiel in dieser Umgebung Auswahlkriterium Besonderheit
Default-VirtualHost 000-default.conf, erster erster auf *:80; greift, wenn nichts anderes passt Direktzugriff über IP, Aliase
Normaler namensbasierter HTTP-VirtualHost Makro WPSite (ServerAlias myblog.*), nextcloud.conf (ServerName nextcloud.newdomain.de) Port 80 und Host-Header eigenes DocumentRoot je Site
HTTPS-VirtualHost ( mit SSLEngine on, Zertifikat) in dieser Architektur nicht im Einsatz,SSL übernimmt der Reverse Proxy default-ssl.conf liegt in sites-available/, Port 443 und Host-Header (bzw. SNI) Apache würde selbst TLS terminieren
Weitere namensbasierte VirtualHosts weitere Use WPSite-Zeilen wie oben ergänzen sich ohne neue Datei

TLS endet in dieser Architektur am Caddy. Apache lauscht ausschließlich auf Port 80. Das Schema der ursprünglichen Anfrage wird über den Header X-Forwarded-Proto weitergegeben (Kapitel 3 und 5).

2.5.4 Mehrere Domains auf derselben IP

Mehrere Domains/Hostnamen auf derselben IP und demselben Port werden ausschließlich über den Host-Header getrennt (namensbasierte VirtualHosts). Im Fall der Reverse-Proxy-Nutzung sind alle Anfragen Verbindungen von Caddy zu 192.178.1.100:80; die Unterscheidung der Sites erfolgt allein über den weitergegebenen Hostnamen.

2.5.5 Warum ein Direktaufruf einen anderen VirtualHost erreicht als der Domainaufruf

Aufruf Host-Header bei Apache Ergebnis
https://myblog.newdomain.de/ über Caddy myblog.newdomain.de Treffer ServerAlias myblog.* → DocumentRoot /var/www/www.myblog
http://192.178.1.100/www.myblog/ 192.178.1.100 kein Treffer → Default-VirtualHost → Alias /www.myblog → dasselbe Verzeichnis
http://192.178.1.100/ 192.178.1.100 Default-VirtualHost → /var/www/html

Das Zielverzeichnis ist in beiden Fällen identisch, der Weg dorthin unterscheidet sich: einmal über DocumentRoot eines namensbasierten VirtualHosts (URL-Pfad ab /), einmal über einen Alias im Default-VirtualHost (URL-Pfad ab /www.myblog/). Daraus folgt der Bedarf an der URL-Umschaltung in WordPress (Kapitel 5).

2.6 Die Datei nextcloud.conf

Pfad: /etc/apache2/sites-available/nextcloud.conf

Direktive Zweck Folge ohne diese Einstellung
ServerName nextcloud.newdomain.de wählt diesen VirtualHost für den Host-Header nextcloud.newdomain.de. Diese Zeile ist domainabhängig und beim Domainumzug anzupassen. Anfragen landen im Default-VirtualHost
Alias /nextcloud Zugriff unter dem Pfad /nextcloud an diesem Host. Der Alias bedient zugleich die alte URL olddomain.de/nextcloud/…: Caddy reicht DAV-/OCS-Pfade mit unverändertem Pfad (/nextcloud/remote.php/…) und umgeschriebenem Host nextcloud. an diesen VirtualHost durch. Nextcloud leitet seinen Webroot aus dem Skriptpfad ab; die Antworten enthalten dadurch /nextcloud/remote.php/dav/… – so, wie alte Clients es erwarten. Ohne den Alias findet Apache unter /nextcloud/… keine Datei (404); weder der Direktzugriff /nextcloud/ an diesem Host noch die Durchreichung der alten URL funktionieren.
RemoteIPHeader X-Forwarded-For / RemoteIPInternalProxy 192.178.1.1 mod_remoteip setzt die Client-IP aus X-Forwarded-For, sofern die Verbindung von der Proxy-Adresse 192.178.1.1 stammt Logs und Nextcloud sehen nur die IP des Proxys
SetEnvIf X-Forwarded-Proto "https" HTTPS=on Nextcloud erkennt, dass die ursprüngliche Anfrage per HTTPS erfolgte Nextcloud erzeugt http://-URLs, Mixed Content/Redirect-Probleme
Header always set Strict-Transport-Security … HSTS –
mit AllowOverride All Nextcloud-.htaccess Rewrite-Regeln wirkungslos
Dav off deaktiviert mod_dav, damit Nextcloud WebDAV selbst abwickelt Konflikte mit mod_dav
SetEnv HOME, HTTP_HOME Nextcloud-Home-Verzeichnis für PHP –

Hinweis: Domainabhängig bleiben ServerName nextcloud.newdomain.de und der Eintrag trusted_domains in der Nextcloud-config.php.

2.7 Sites aktivieren und deaktivieren

Die ursprünglichen Einzel-VirtualHosts (www.website1.de.conf, www.website3.de.conf, www.myblog.conf, www.website2.de.conf, www.website4.de.conf) sind durch das Makro in 000-default.conf ersetzt und müssen deaktiviert sein. Andernfalls existieren doppelte VirtualHosts für dieselben Namen. Bei der Variante ohne Makro mit Einzeldateien (Kapitel 2.4.1) sind die Dateien stattdessen aktiviert.

Die Dateien selbst können in sites-available/ als Sicherung verbleiben.

2.8 Test der Apache-Konfiguration und Neustart

2.9 Prüfung mit curl auf dem Webserver

Die Befehle sind auf dem Webserver selbst (webserver) auszuführen. Seiten URL ( myblog website1 …) und IP sind anzupassen. Ein Aufruf auf einem anderen Rechner liefert andere Ergebnisse (Kapitel 7.13).


Zurück zur Übersicht


3. Zusammenspiel zwischen Caddy und Apache

3.1 Zwei Entscheidungsebenen

Caddy entscheidet, an welchen Backend-Server eine Anfrage weitergeleitet wird. Apache entscheidet anschließend anhand des eingehenden Requests, insbesondere des Host-Headers und des Ports, welcher VirtualHost die Anfrage verarbeitet.

Beide Ebenen verwenden unabhängige Konfigurationen, die aufeinander abgestimmt sein müssen:

Ebene Eingabe Entscheidung Konfiguration
Caddy TLS-SNI und Host-Header der Client-Anfrage Site-Block (Domain) → Handler → Backend-Adresse (192.178.1.100) /usr/local/etc/caddy/Caddyfile, caddy.d/*.conf
Apache lokale IP:Port und Host-Header der von Caddy gesendeten Anfrage VirtualHost → DocumentRoot/Alias /etc/apache2/sites-available/*.conf

3.2 Ablauf im Detail

  1. Browser: ruft https://myblog.newdomain.de/category/smart-home/ auf. DNS liefert die öffentliche IP; TLS-SNI und Host lauten myblog.newdomain.de.
  2. Caddy – Site-Auswahl: Der Site-Block myblog.newdomain.de im generierten Caddyfile passt auf SNI/Host. Das Wildcard-Zertifikat für *.newdomain.de wird für den TLS-Handshake verwendet.
  3. Caddy – Backend-Auswahl: Der Handler reverse_proxy 192.178.1.100 legt das Ziel fest. Ein Port ist nicht angegeben, es gilt Port 80 (HTTP).
  4. Neue Verbindung Caddy → Apache: Caddy öffnet eine eigene HTTP-Verbindung zu 192.178.1.100:80 und sendet:

  1. Apache – VirtualHost-Auswahl: Zieladresse *:80; Host: myblog.newdomain.de trifft ServerAlias myblog.* des Makros WPSite → DocumentRoot /var/www/www.myblog.
  2. Apache – Dateizuordnung: /category/smart-home/ existiert nicht als Datei; die .htaccess-Regel RewriteRule . index.php [L] übergibt an WordPress.
  3. WordPress: wp-config.php erkennt über X-Forwarded-Proto HTTPS und setzt WP_HOME/WP_SITEURL auf https://myblog.newdomain.de. WordPress erzeugt die Seite.
  4. Rückweg: Apache → Caddy → Browser (TLS).

3.3 Weitergegebene Informationen

Information Verhalten bei reverse_proxy (Standardverhalten laut Caddy-Dokumentation) Verwendung
URI/Pfad und Query unverändert Auswahl von Dateien/Rewrites, WordPress-Routing
Host wird unverändert mit dem ursprünglichen Hostnamen weitergegeben Apache-VirtualHost-Auswahl
X-Forwarded-For Client-IP Logs; mod_remoteip (Nextcloud-VHost)
X-Forwarded-Proto https HTTPS-Erkennung in WordPress (wp-config.php) und Nextcloud (SetEnvIf)
X-Forwarded-Host ursprünglicher Hostname derzeit nicht ausgewertet
vom Client mitgesendete X-Forwarded-*-Header werden von Caddy überschrieben, sofern keine vertrauenswürdigen vorgeschalteten Proxys konfiguriert sind verhindert gefälschte Weitergabeinformationen

In den generierten Handlern (reverse_proxy 192.178.1.100 { }) sind keine zusätzlichen Header-Direktiven gesetzt; es gelten ausschließlich die Standardwerte. Dass X-Forwarded-Proto und Host tatsächlich bei Apache ankommen, ist durch die funktionierende HTTPS-Erkennung und die funktionierende VirtualHost-Auswahl belegt.

3.4 Warum der Apache-Pfad nicht dem externen Pfad entspricht

Der externe Pfad (/category/smart-home/) ist unabhängig von der Dateisystemstruktur. Die Zuordnung zu /var/www/www.myblog erfolgt ausschließlich durch den VirtualHost (DocumentRoot). Bei der Alt-Domain war das Verzeichnis dagegen Teil der URL (/myblog/…, /www.website4.de/…); der Präfix wird von Caddy entfernt (Kapitel 4.5). Beim Direktzugriff über die IP ist der Präfix wieder Teil des Pfads (/www.myblog/…, Alias). Aus diesen drei Pfadformen folgt, dass WordPress seine Basis-URL je nach Zugriffsart bestimmen muss (Kapitel 5).

3.5 Konkrete Beispiele für notwendige Abstimmung

Beispiel 1: neue Site shop. Erforderlich sind zwei zusammengehörige Änderungen:

  • Caddy: Subdomain shop mit Handler reverse_proxy 192.178.1.100.
  • Apache: Use WPSite shop www.shop.example in 000-default.conf plus Verzeichnis /var/www/www.shop.example.

Fehlt der Caddy-Eintrag, trifft die Anfrage den Wildcard-Block ohne Handler und erreicht Apache nicht. Fehlt der Apache-Eintrag, erreicht die Anfrage den Default-VirtualHost und wird mit 403 abgewiesen (für unbekannte FQDN getestet).

Beispiel 2: Durchreichung /nextcloud (alte Domain). Der Handler enthält header_up Host nextcloud.{args[0]}. Ohne diese Zeile erhielte Apache Host: olddomain.de; kein VirtualHost passt, der Default-VirtualHost sperrt den FQDN mit 403, und Nextcloud würde den Host zudem als nicht vertrauenswürdig behandeln. Mit der Zeile wird der Nextcloud-VirtualHost nextcloud.newdomain.de ausgewählt.

3.6 Auswirkungen falscher Host- oder Pfadkonfiguration

Fehler Wirkung
Host-Header zeigt auf unbekannten Namen Default-VirtualHost: 403 (FQDN) oder Inhalt von /var/www/html (IP)
Backend-Port/Adresse in Caddy falsch 502/Timeout bei Caddy
RewriteBase / oder absolute Substitution (/index.php) in .htaccess funktioniert nur bei DocumentRoot-Zugriff, nicht beim Alias-Direktzugriff (und umgekehrt)
WP_HOME/WP_SITEURL passen nicht zur aufgerufenen URL fehlende CSS/JS, Redirect-Schleifen, falsche Links
Fehlendes X-Forwarded-Proto-Handling WordPress/Nextcloud erzeugen http://-URLs hinter HTTPS

Zurück zur Übersicht


4. OPNsense / Caddy

4.1 Dateien und Aufbau

Datei/Verzeichnis Funktion
/usr/local/etc/caddy/Caddyfile automatisch von OPNsense generiert („DO NOT EDIT“); wird aus den Einträgen der GUI erzeugt (Reverse Proxy → Domänen, Subdomänen, Handler)
/usr/local/etc/caddy/caddy.d/*.global benutzerdefinierte globale Optionen (in den globalen Block importiert)
/usr/local/etc/caddy/caddy.d/*.conf benutzerdefinierte Site-Blöcke (am Ende des generierten Caddyfiles importiert)
/usr/local/etc/caddy/certificates/.pem / .key Zertifikat und Schlüssel aus dem OPNsense-Trust-Store
/var/log/caddy/caddy.log Caddy-Log

Eigene Konfigurationen gehören ausschließlich nach caddy.d/. Änderungen am generierten Caddyfile gehen bei der nächsten GUI-Änderung verloren.

Nach Änderungen an der Caddy-Konfiguration muss der Caddy-Dienst neu geladen bzw. neu gestartet werden.

4.2 Generierter Caddyfile

Pfad: /usr/local/etc/caddy/Caddyfile. Zertifikatsdateinamen und die ACME-Kontakt-E-Mail sind durch Platzhalter ersetzt.

Erläuterung

Element Funktion
Globaler Block: servers { protocols h1 h2 } HTTP/1.1 und HTTP/2; HTTP/3 deaktiviert
email, grace_period, skip_install_trust ACME-Kontakt, Wartezeit beim Beenden, keine Installation einer lokalen CA im System
*.newdomain.de { tls … } und newdomain.de { tls … } laden das Wildcard-Zertifikat (SAN newdomain.de) aus dem Trust-Store. Die Blöcke enthalten bewusst keine Handler. Caddy verwendet das geladene Zertifikat für alle passenden SNI-Namen, auch für die einzelnen Subdomain-Blöcke ohne eigene tls-Direktive.
Subdomain-Blöcke mit handle { reverse_proxy 192.178.1.100 } Backend-Auswahl für die Webserver-Sites (myblog, website1, website2, website3, website4, nextcloud)
import …/caddy.d/*.conf (letzte Zeile) bindet newdomain-redirect.conf ein

4.3 Zertifikate, ACME und DNS-01

  • Das Zertifikat *.newdomain.de (SAN newdomain.de) wird vom OPNsense-Plugin os-acme-client per DNS-01-Challenge über die deSEC-API (API-Token: ) ausgestellt.
  • DNS-01 ist für Wildcard-Zertifikate zwingend erforderlich. Der Nachweis erfolgt über einen TXT-Eintrag unter _acme-challenge. bei deSEC; der Webserver oder Port 80 müssen dafür nicht erreichbar sein.
  • Caddy bezieht das Zertifikat aus dem OPNsense-Trust-Store (/usr/local/etc/caddy/certificates/.pem/.key) und erneuert es nicht selbst. Die Erneuerung übernimmt os-acme-client.
  • Nach einem Domainwechsel sind in os-acme-client neues Zertifikat (neue Domain, Wildcard + Basisdomain) auszustellen und in Caddy (Domain-Eintrag) auszuwählen.
  • Zertifikat der Alt-Domain olddomain.de: Das vorhandene Wildcard-Zertifikat deckt diese Domain nicht ab. Für die Alt-Domain wird daher in der OPNsense-Caddy-Konfiguration ein eigenes SSL-Zertifikat verwendet. Über die Einstellung „Automatisches HTTPS“ kann Caddy das benötigte Zertifikat automatisch beziehen und verwalten. Dadurch kann die Alt-Domain weiterhin per HTTPS erreicht und anschließend auf die neue Domain weitergeleitet werden.

4.4 Reverse-Proxy-Ziele und Header

Alle Webserver-Handler verwenden den Standard von reverse_proxy (Kapitel 3.3): kein zusätzlicher Header, Host bleibt erhalten. Zusätzliche Header-Direktiven sind nur im Block der Alt-Domain gesetzt (header_up Host, Kapitel 4.5).

4.5 Die Datei newdomain-redirect.conf (Weiterleitung der alten Domain)

Pfad: /usr/local/etc/caddy/caddy.d/newdomain-redirect.conf

Funktionsweise

Element Wirkung
olddomain.de { import legacy_redirect newdomain.de 192.178.1.100:80 } einzige Stelle, an der die neue Domain und das Backend stehen. Bei einem weiteren Domainwechsel ist nur diese Zeile (und der Name des Site-Blocks, falls die Alt-Domain wechselt) anzupassen.
Snippet (legacy_site) wiederverwendbare Regel: erkennt einen alten Pfadpräfix ({args[0]}, regulärer Ausdruck), entfernt ihn und leitet auf https://.? mit Status 301 weiter. {uri} enthält nach dem Umschreiben den Rest-Pfad inklusive Query.
route @legacy_… { uri path_regexp …; redir … } route erzwingt die geschriebene Reihenfolge (zuerst uri, dann redir). Außerhalb von route gilt die feste Caddy-Direktivenreihenfolge, in der redir vor uri ausgeführt würde; der Präfix bliebe dann im Ziel-URL erhalten.
Regex ^/(?:{args[0]})(?:/ $)
@nextcloud_api … reverse_proxy {args[1]} { header_up Host nextcloud.{args[0]} } Nextcloud-Client-Pfade (remote.php, ocs, status.php, public.php, .well-known) unter /nextcloud/ werden nicht umgeleitet, sondern transparent an Apache durchgereicht. Der Pfad bleibt /nextcloud/…; der Host wird auf nextcloud. gesetzt, damit der Nextcloud-VirtualHost greift. Begründung: Bei einem Redirect auf einen anderen Host verwerfen WebDAV-Clients den Authorization-Header; zudem erwarten alte Clients Antworten mit dem Präfix /nextcloud/.
import legacy_site nextcloud nextcloud … Browser-Pfade unter /nextcloud/ (z. B. /nextcloud/index.php/s/) werden auf https://nextcloud.newdomain.de/… umgeleitet.
letzte Zeile redir https://myblog.{args[0]}{uri} 301 Auffangregel: alles Übrige wird mit unverändertem Pfad und Query auf die Blog-Subdomain umgeleitet; kein alter Link endet in einem 404 des Proxys.

Die Reihenfolge der Zeilen ist relevant: Die erste zutreffende route beendet die Verarbeitung. Die spezifischen Regeln stehen deshalb vor der Auffangregel.

Aufruf Ergebnis
/myblog/category/smart-home/ 301 → https://myblog.newdomain.de/category/smart-home/
/myblog/?p=12&x=1 301 → https://myblog.newdomain.de/?p=12&x=1
/www.websiteN.de/index.php/gallery/category/item/ 301 → https://websiteN.newdomain.de/index.php/gallery/category/item/
/www.websiteN.de/wp-admin_custom 301 → https://websiteN.newdomain.de/wp-admin_custom
/www.websiteN.de/wp-admin 301 → https://websiteN.newdomain.de/wp-admin
/www.websiteN.de/?s=a 301 → https://websiteN.newdomain.de/?s=a
/nextcloud/index.php/s/AbC123?dir=/x 301 → https://nextcloud.newdomain.de/index.php/s/AbC123?dir=/x
/nextcloud/remote.php/dav/… kein Redirect; durchgereicht an Apache (207 bei PROPFIND, Antworten mit /nextcloud/remote.php/dav/…-Pfaden)
/index.php/s/abc (kein bekannter Präfix) 301 → https://myblog.newdomain.de/index.php/s/abc

Hinweis: Die Auffangregel leitet auch alte Nextcloud-Links ohne /nextcloud-Präfix auf die Blog-Subdomain um.

4.6 Temporärer Access-Log zur Diagnose

Zur Analyse, welche Pfade ein Client auf der Alt-Domain abfragt, wurde zeitweise ein Access-Log im Block der Alt-Domain aktiviert. Pfad: /usr/local/etc/caddy/Caddyfile:

Caddy neu starten und lezten 20 Logs ausgeben:

Das Log enthält je Anfrage Methode, Pfad, Status und Antwort-Header. Nach der Diagnose ist der log-Block wieder zu entfernen, damit die Datei nicht unbegrenzt wächst.

4.7 Domainmigration

4.7.1 Gründe

Alte Links (Blog-Beiträge, Lesezeichen, externe Verweise, Nextcloud-Freigaben, DAV-Clients) bleiben dauerhaft im Umlauf. Alte Links dürfen nicht zu 404-Fehlern führen und müssen die Inhalte unter der neuen Adresse erreichen.

4.7.2 Zuständigkeit der Ebenen

Ebene Aufgabe Im Projekt
DNS-Auflösung Name → IP-Adresse. Verändert keine URL, entscheidet nur, welcher Server die Anfrage erhält. olddomain.de und newdomain.de zeigen beide auf die öffentliche IP und damit auf dieselbe OPNsense
HTTP-Redirect Der Server antwortet mit 301 und neuer URL; der Client stellt eine neue Anfrage. Die Adresszeile ändert sich. Caddy redir in newdomain-redirect.conf
Reverse Proxy Der Server leitet die Anfrage serverseitig weiter; der Client bemerkt nichts, die URL bleibt. Caddy reverse_proxy (Webserver-Sites; /nextcloud-DAV-Pfade der Alt-Domain)
URL-Rewriting interne Umschreibung des Pfads ohne Wissen des Clients Caddy uri path_regexp (Präfix entfernen); Apache mod_rewrite (index.php)
WordPress-interne URLs Basis-URL, in der WordPress seine Links und Asset-Adressen erzeugt WP_HOME/WP_SITEURL in wp-config.php; absolute URLs in Beiträgen (Datenbank)

4.7.3 Erkennung alter URLs

Alte URLs werden am Präfix des Pfads erkannt (/myblog, /www.myblog, /www.website1.de, /www.website2.de, /www.website3.de, /www.website4.de, /nextcloud). Der Präfix bestimmt die Ziel-Subdomain; der Rest des Pfads und die Query werden übernommen.

4.7.4 Vermeidung von 404

  • Jeder bekannte Präfix besitzt eine eigene Regel.
  • Die Auffangregel leitet alles Übrige auf die Blog-Subdomain.
  • Die Query wird bei jeder Regel mitgeführt ({uri}).
  • Nextcloud-Client-Pfade werden durchgereicht statt umgeleitet (Authorization-Header).

4.7.5 Änderungsstellen bei einem weiteren Domainumzug

Ort Änderung
deSEC/DNS neue Domain: A-Record und Wildcard-CNAME
os-acme-client Zertifikat für *. und
OPNsense/Caddy GUI Wildcard-Domain, Basisdomain und die Subdomain-Einträge
newdomain-redirect.conf Zeile import legacy_redirect ; Name des Site-Blocks, falls auch die Alt-Domain wechselt
nextcloud.conf ServerName nextcloud.
Nextcloud config.php trusted_domains (und gegebenenfalls overwrite.cli.url)
Apache-Makro, wp-config.php, .htaccess keine Änderung (domainunabhängig)

Optional ließe sich die Anzahl der Subdomain-Einträge in der Caddy-GUI durch einen Handler am Wildcard-Eintrag *.newdomain.de reduzieren. Diese Variante wurde nicht umgesetzt und nicht im Produktivsystem getestet.


Zurück zur Übersicht


5. WordPress und URL-Struktur

5.1 Grundsatz: Zuständigkeit der URL-Ebenen

Ebene Verarbeitet Nicht zuständig für
Caddy Domain/Host, Zertifikat, Backend-Auswahl, Weiterleitung alter Domain und alter Pfadpräfixe Inhalte, Permalinks, WordPress-Basis-URL
Apache VirtualHost-Auswahl (Host-Header), Alias (Direktzugriff per IP), mod_rewrite (.htaccess: Umleitung nicht existierender Pfade auf index.php) Basis-URL der Anwendung, Inhalte
WordPress Permalink-Auflösung, Erzeugung aller Links und Asset-Adressen aus WP_HOME/WP_SITEURL, kanonische Weiterleitung (redirect_canonical) auf die konfigurierte Basis-URL Auswahl des Backends, Auswahl des VirtualHosts

Wird eine Anfrage von einer früheren Ebene beantwortet (z. B. Redirect durch Caddy), erreicht sie die folgenden Ebenen nicht.

5.2 wp-config.php

Pfad je Site: /var/www/www.<websiteN>/wp-config.php.

Die Datei enthält Datenbankzugangsdaten, Schlüssel/Salts sowie die Logik zur Bestimmung von WP_HOME und WP_SITEURL abhängig von der Zugriffsart. WordPress lädt sie bei jedem Request vor wp-settings.php. Die Datei wird nur von PHP/WordPress über Apache verwendet; Caddy und Apache lesen sie nicht als Konfigurationsdatei.

Zugangsdaten sind Platzhalter. Die Schlüssel und Salts sind Beispielwerte und müssen bei einer Migration unverändert aus der bestehenden Installation übernommen werden.

Der URL-Block steht nach der ABSPATH-Definition und vor require_once(ABSPATH . 'wp-settings.php');. Nach dem Laden von wp-settings.php wäre es für define('WP_HOME', …) zu spät.

Frühere Debug-Zeilen der Form file_put_contents('/tmp/req.log', …) am Dateianfang werden für den Betrieb nicht benötigt und sind zu entfernen (Kapitel 7.8).

5.3 URL-Block

Der URL-Block legt fest, unter welcher öffentlichen Adresse WordPress betrieben wird. Er sorgt dafür, dass WordPress auch hinter einem Reverse Proxy die korrekte Domain und das richtige HTTPS-Schema verwendet und nicht auf interne Serveradressen oder alte Domains verweist.

Einzige site-spezifische Angabe ist $direct_path (Alias-Pfad aus 000-default.conf):

Bestandteil Funktion Folge ohne diese Einstellung
HTTP_X_FORWARDED_PROTO === 'https' → $_SERVER['HTTPS'] = 'on' HTTPS-Erkennung hinter dem Proxy. Apache sieht nur eine HTTP-Verbindung von Caddy; die ursprüngliche Verschlüsselung ist ausschließlich im Header erkennbar. WordPress erzeugt http://-URLs; Mixed Content, Weiterleitungen auf http://
Host aus HTTP_HOST Der vom Client (bzw. von Caddy durchgereichte) Host bestimmt die Basis-URL. Der Hostname wird nicht in der Datei hinterlegt. Domainwechsel erfordert Änderung jeder wp-config.php
$wp_direct (IP-Adresse oder Name ohne Punkt) Unterscheidung Direktzugriff ↔ Proxy-Zugriff. Bei Direktzugriff wird $direct_path angehängt. Beim Direktzugriff fehlen CSS und Links (Basis-URL ohne Alias-Pfad)
WP_HOME, WP_SITEURL überschreiben die in der Datenbank gespeicherten Optionen home und siteurl zur Laufzeit WordPress verwendet die Datenbankwerte (Alt-Domain) und leitet auf diese um
if ($wp_host !== '') kein HTTP_HOST bei WP-CLI oder Cron Warnungen/Fehler in CLI-Kontexten; ohne Host bleiben die Datenbankwerte wirksam

Syntaxprüfung und Kontrolle

Die ersten Links müssen mit https://websiteN.newdomain.de/ bzw. http://192.178.1.100/www.websiteN/ beginnen.

5.4 Permalinks und .htaccess

Pfad je Site: /var/www/www.websiteN/.htaccess

Funktion: mod_rewrite leitet alle Pfade, die weder Datei noch Verzeichnis sind, an index.php; WordPress löst den Permalink auf. Voraussetzung: AllowOverride All (Kapitel 2.4) und aktiviertes Modul rewrite.

Einheitlicher Block für alle Sites (Subdomain-Zugriff und Alias-Direktzugriff). Der Inhalt vorhandener .htaccess-Dateien ist durch diesen Block zu ersetzen oder bei vorhandener weiterer Konfiguration entsprechend anzupassen. Eventuell von Plugins ergänzte Abschnitte außerhalb von # BEGIN WordPress … # END WordPress bleiben unberührt.

Warum kein RewriteBase und keine absolute Substitution:

Variante Subdomain (DocumentRoot /) Alias-Direktzugriff (/www.websiteN/)
RewriteBase / + RewriteRule . /index.php (WordPress-Standard) funktioniert falsch: /index.php liegt im Default-DocumentRoot, nicht im Alias-Verzeichnis
RewriteBase /www.website3.de/ + RewriteRule . /www.websiteN/index.php falsch: dieser Pfad existiert im DocumentRoot der Subdomain nicht (404) funktioniert
RewriteRule . index.php ohne RewriteBase (relative Substitution) funktioniert funktioniert

Bei relativer Substitution ergänzt Apache das jeweilige URL-Präfix des Verzeichnisses selbst. Dadurch ist keine Angabe eines Hosts oder Pfads in der Datei erforderlich. Der frühere Sonderfall RewriteCond %{HTTP_HOST} !^websiteN\.<domain>$ (domainabhängig) entfällt vollständig.

Kontrolle:

Beide Aufrufe müssen den Status 200 (Permalink existiert) liefern; ein 404 kommt dann von WordPress selbst (Permalink existiert nicht), nicht von Apache.

5.5 Weiterleitungen innerhalb von WordPress

WordPress leitet Anfragen auf die kanonische URL um, wenn Host oder Pfad von WP_HOME abweichen (redirect_canonical). Mit dem URL-Block aus Kapitel 5.3 entspricht WP_HOME immer dem aufgerufenen Host; WordPress löst deshalb keine Weiterleitung auf die Alt-Domain mehr aus. Ohne den Block (Datenbankwerte = Alt-Domain) würde jede Anfrage über die neue Subdomain zurück auf die Alt-Domain umgeleitet und dort von Caddy erneut auf die neue Domain (Kapitel 7.2).

5.6 Alte Domainnamen in der Datenbank

  • Die Optionen home und siteurl (Tabelle wp_options) enthalten in der Regel die Alt-Domain. Solange WP_HOME/WP_SITEURL definiert sind, werden diese Werte zur Laufzeit überschrieben; eine Änderung in der Datenbank ist für die Funktion nicht erforderlich.
  • Absolute URLs in Beitragsinhalten, Widget-/Theme-Optionen und Plugin-Einstellungen bleiben unverändert in der Datenbank. Solche Links werden durch die Caddy-Weiterleitung (Kapitel 4.5) auf die neue Adresse umgeleitet, solange Pfadpräfix und Rest-Pfad mit den Regeln übereinstimmen.

Lesende Kontrolle (Zugangsdaten aus wp-config.php):

Serialisierte Werte in der Datenbank dürfen nicht per einfachem SQL-REPLACE geändert werden (gespeicherte Zeichenlängen würden ungültig). Eine Ersetzung ist, falls erforderlich, mit einem serialisierungsfähigen Werkzeug (z. B. WP-CLI search-replace) und vorheriger Sicherung vorzunehmen.

5.7 Statische Verweise in Dateien

Verweise auf die Alt-Domain können in Theme- und Plugin-Dateien stehen (z. B. fest eingetragene URLs in Templates).

5.8 Redirection-Plugin und alte Weiterleitungsregeln

  • Es ist im WordPress-Backend zu prüfen, ob auf einer der Websites ein Weiterleitungs-Plugin (z. B. „Redirection“) aktiviert ist und Weiterleitungsregeln enthält. Dazu sind die aktiven Plugins sowie die darin hinterlegten Weiterleitungsregeln zu kontrollieren.
  • Doppelte oder nicht mehr benötigte Redirects: Weiterleitungen der Alt-Domain gehören ausschließlich in newdomain-redirect.conf (Caddy). Weder Apache noch WordPress enthalten Regeln, die dieselbe Weiterleitung ein zweites Mal durchführen.

Kontrolle: Weiterleitungsregeln in .htaccess-Dateien und Apache-Konfiguration:

Erwartetes Ergebnis: Der Befehl liefert keine Ausgabe. Weiterleitungen von alten auf neue Domains werden ausschließlich in Caddy konfiguriert. Treffer außerhalb der Nextcloud-Dateien (/.well-known/carddav, /.well-known/caldav in der Nextcloud-.htaccess) sind einzeln zu bewerten.


Zurück zur Übersicht


6. Alte URLs und URL-Remapping

6.1 Reihenfolge der Ebenen

Eine Anfrage durchläuft die Ebenen in fester Reihenfolge. Die erste Ebene, die antwortet, beendet die Verarbeitung:

Datenbankeinträge und statische Verweise sind keine Verarbeitungsebenen; sie liefern lediglich die URLs, die in Antworten stehen und vom Client später erneut aufgerufen werden.

6.2 Übersicht

Nr. Ebene Einsatz Konfigurationsort Priorität Risiko bei doppelter Weiterleitung
1 HTTP-Redirect alte Domain/Pfadpräfix → neue Domain Caddy: caddy.d/newdomain-redirect.conf höchste (vor Apache und WordPress) Schleife, wenn eine spätere Ebene zurück auf die Alt-Domain leitet
2 Reverse Proxy Weiterleiten ohne sichtbare URL-Änderung (Webserver-Sites; /nextcloud-DAV-Pfade der Alt-Domain) Caddy: generierter Caddyfile, newdomain-redirect.conf wie 1 falscher Host-Header ⇒ falscher VirtualHost (Kapitel 3.5)
3 Apache Rewrite nicht existierende Pfade → index.php /var/www//.htaccess nach VirtualHost-Auswahl, vor WordPress absolute Substitution/RewriteBase ⇒ 404 bei Alias oder Subdomain (Kapitel 5.4)
4 WordPress Rewrite Permalink → Beitrag/Seite WordPress (Einstellungen → Permalinks) nach Apache bei fehlerhafter .htaccess nicht erreichbar
5 Plugin-Redirect einzelne Pfade → andere Pfade Plugin-Konfiguration im WordPress-Backend innerhalb WordPress, vor der Ausgabe Schleifen durch Regeln, die auf die Alt-Domain zeigen [Einsatz: zu ergänzen]
6 Datenbankeinträge absolute URLs in Inhalten/Optionen MySQL (wp_options, wp_posts, …) – alte Links erzeugen Aufrufe der Alt-Domain (werden von Ebene 1 abgefangen)
7 Statische Verweise URLs in Theme-/Plugin-Dateien /var/www//wp-content/… – wie 6

6.3 Regeln gegen Konflikte

  • Eine Weiterleitung, eine Ebene. Alt-Domain → Neu-Domain wird ausschließlich in Caddy umgesetzt.
  • WordPress erhält die aufgerufene Domain als Basis-URL (Kapitel 5.3). Dadurch erzeugt WordPress keine Weiterleitung zurück auf die Alt-Domain.
  • Apache enthält keine Host- oder Domainangaben in Rewrite-Regeln (Kapitel 5.4).
  • Nextcloud-Client-Pfade werden nicht umgeleitet, sondern durchgereicht (Kapitel 4.5).

6.4 Problem: mehrere Ebenen leiten dieselbe URL um

Konstellation Wirkung
Caddy leitet Alt → Neu, WordPress leitet Neu → Alt (Datenbankwert als Basis-URL) Endlosschleife; Browser meldet „zu viele Weiterleitungen“
Caddy und ein Plugin leiten dieselbe Alt-URL auf unterschiedliche Ziele Ergebnis abhängig davon, welche Ebene zuerst antwortet (immer Caddy); die Plugin-Regel bleibt wirkungslos
Caddy-Weiterleitung ohne Query Parameter (?p=, ?s=) gehen verloren (Kapitel 7.4)
Weiterleitung auf anderen Host für WebDAV Clients verlieren Authentifizierung (Kapitel 7.9)

Kontrolle auf Schleifen

Erwartet wird genau ein 301 und danach 200. Mehrere aufeinanderfolgende 301/302 oder der Abbruch durch --max-redirs zeigen eine Konfliktkonstellation.


Zurück zur Übersicht


7. Fehleranalyse und typische Probleme

Die folgenden Probleme können bei der Einrichtung auftreten. Jedes Problem ist nach dem Schema Ursache → Diagnose → Lösung → Kontrolle beschrieben. Soweit eine Ursache aus der Konfigurationsanalyse abgeleitet und nicht separat beobachtet wurde, ist dies vermerkt. Redirect-Schleifen wurden im Betrieb nicht protokolliert; die Konstellation ist in Kapitel 6.4 beschrieben.

7.1 Hartkodierte Domainnamen in Konfigurationsdateien

  • Ursache: Apache-VirtualHost-Dateien mit ServerName ., wp-config.php mit if ($host === '.') und .htaccess mit RewriteCond %{HTTP_HOST} !^\.$. Bei jedem Domainwechsel wären alle Dateien zu ändern.
  • Diagnose:

  • Lösung: Makro mit ServerAlias .* (Kapitel 2.4), dynamischer URL-Block (Kapitel 5.3), einheitlicher .htaccess-Block (Kapitel 5.4).
  • Kontrolle: Aufruf mit beliebiger Domain im Host-Header liefert 200:

7.2 wp-config.php ohne URL-Logik

  • Ursache: Die Datei enthält weder die HTTPS-Erkennung noch WP_HOME/WP_SITEURL. WordPress verwendet dann die Datenbankwerte (Alt-Domain) und leitet kanonisch dorthin um; Caddy leitet von dort wieder auf die neue Domain.
  • Diagnose:

Kein Treffer im ersten Befehl bzw. ein Location auf die Alt-Domain im zweiten zeigt den Fehler.

  • Lösung: URL-Block mit $direct_path = '/www' . '.websiteN.de' einfügen.
  • Kontrolle: curl -sIL --max-redirs 5 https://websiteN.newdomain.de/ liefert direkt 200.

7.3 .htaccess: RewriteBase und absolute Substitution

  • Ursache: Der WordPress-Standardblock (RewriteBase /, RewriteRule . /index.php) funktioniert nur bei Zugriff über das DocumentRoot. Bei einer Site war RewriteBase /www.websiteN.de/ mit absoluter Substitution gesetzt (funktioniert nur beim Alias-Direktzugriff); bei einer weiteren Site sorgte eine Host-Bedingung für den Direktzugriff.
  • Diagnose: Permalink-Aufruf liefert 404 oder den Inhalt eines falschen Verzeichnisses:
  • Lösung: einheitlicher Block aus Kapitel 5.2 in allen Sites (Website Pfad anpassen => $direct_path = ‘/www’ . ‘.websiteN’;)
  • Kontrolle: beide Aufrufe liefern denselben Status (200 bzw. von WordPress ausgegebenes 404).

7.4 Query-String geht bei der Weiterleitung verloren

  • Ursache (aus der Konfigurationsanalyse abgeleitet): Die frühere Regel für den Blog verwendete als Ziel nur den Pfad ({re..1}) ohne ?{query}. Parameter wie ?p=12 oder ?s=suche fielen weg.
  • Diagnose:

  • Lösung: (legacy_site)-Snippet mit {uri} (enthält Pfad und Query) statt {re..1}.
  • Kontrolle: Location: https://myblog.newdomain.de/?p=12&x=1.

7.5 Caddy: Präfix bleibt im Ziel-URL

  • Ursache: Caddy führt Direktiven nicht in Schreibreihenfolge aus, sondern in fester Reihenfolge; redir wird vor uri ausgeführt. Ohne route entstünde ein Ziel mit dem alten Präfix (…/myblog/category/…).
  • Diagnose: Location-Header enthält den alten Präfix.
  • Lösung: route @legacy_ { uri path_regexp … ; redir … } (Kapitel 4.5).

7.6 Fehlende Apache-Module

  • Ursache: Das Modul macro war nicht aktiviert.
  • Diagnose:

Ausgabe: AH00526: Syntax error on line 13 of /etc/apache2/sites-enabled/000-default.conf: Invalid command '<Macro', perhaps misspelled or defined by a module not included in the server configuration

  • Lösung:

  • Kontrolle: apache2ctl -M | grep -E 'macro|rewrite' listet beide Module; systemctl is-active apache2 meldet active.

7.7 Doppeltes www. im Direktzugriffspfad (Layout zerstört, 404)

  • Ursache: Der Wert von $direct_path in der wp-config.php einer Site (website2) war fehlerhaft (/www.www.websiteN.de). WordPress erzeugt alle URLs (Stylesheets, Skripte, Links) aus diesem Pfad. Die erste Seite lädt über den korrekten Alias; alle erzeugten Adressen laufen ins Leere.
  • Diagnose:

  • Lösung:
  • Kontrolle: Links beginnen mit http://192.178.1.100/www.websiteN/; Seite im Browser mit hartem Neuladen (Strg+F5) prüfen.

7.8 Fehlerhafte oder unvollständige wp-config.php

  • Ursache: Die Datei der Blog-Site enthielt eine Debug-Zeile file_put_contents('/tmp/req.log', … am Anfang, die in der vorliegenden Fassung unvollständig war (Syntaxfehler, falls tatsächlich so in der Datei), sowie einen durch Markdown-Umwandlung beschädigten Alias-Pfad (Kapitel 7.12). Ob die Zeile im Dateisystem oder nur in der Terminalanzeige abgeschnitten war, wurde nicht abschließend geklärt.
  • Diagnose:

  • Lösung: Ersatz durch eine vollständige wp-config.php nach dem Gerüst aus Kapitel 5.2 ohne Debug-Zeile.
  • Kontrolle: php -l meldet No syntax errors detected; die Site ist per Subdomain und IP erreichbar (bestätigt).

7.9 Alte WebDAV-/CalDAV-/CardDAV-URLs nach Redirect ohne Funktion

  • Ursache: Ein HTTP-Redirect auf einen anderen Host führt bei DAV-Clients üblicherweise dazu, dass die Authentifizierung nicht mit übernommen wird bzw. die Anfrage nicht erneut mit gleicher Methode gestellt wird. Ein Browser folgt dem Redirect, ein DAV-Client in der Regel nicht zuverlässig.
  • Diagnose: Access-Log auf der Alt-Domain (Kapitel 4.6) zeigt die Pfade, Methoden und Status des Clients:
  • Lösung: Client-Pfade (remote.php, ocs, status.php, public.php, .well-known) unter /nextcloud/ werden von Caddy mit unverändertem Pfad und Host: nextcloud. durchgereicht; der Alias /nextcloud des Nextcloud-VirtualHosts (Kapitel 2.6) ordnet den Pfad dem Nextcloud-Verzeichnis zu (Kapitel 4.5).
  • Kontrolle:

Erwartet werden HTTP/2 207 und /nextcloud/remote.php/dav/…. Beides ist im Projekt bestätigt. Im Caddy-Log erscheinen Anfragen eines CardDAV-Clients (Thunderbird) auf /nextcloud/remote.php/dav/addressbooks/users//… mit Status 207.

7.10 Nextcloud: Login-Schleife bei Direktzugriff über IP

  • Beobachtung: Beim Aufruf von http://192.178.1.100/nextcloud/… erscheint nach der Anmeldung erneut das Anmeldefenster. Über https://nextcloud.newdomain.de tritt der Fehler nicht auf. Naheliegend ist eine Einstellung in der Nextcloud-config.php, die HTTPS erzwingt (z. B. overwriteprotocol); Cookies mit dem Attribut Secure werden dann über HTTP nicht zurückgesendet.
  • Diagnose:

  • Lösung: Die Adresse des Direktzugriffs muss in trusted_domains stehen.
  • Kontrolle: Anmeldung über http://192.178.1.100/nextcloud/ bleibt angemeldet.

7.11 Nextcloud-Direktzugriff per IP liefert 404

  • Ursache: Beim Zusammenführen der VirtualHosts in 000-default.conf fehlte zunächst der Alias /nextcloud samt -Block des früheren Default-VirtualHosts.
  • Diagnose:

  • Lösung: Block aus Kapitel 2.4 (Alias, mit AllowOverride All, Dav off, SetEnv HOME, SetEnv HTTP_HOME) im Default-VirtualHost ergänzen; apache2ctl configtest && systemctl reload apache2.
  • Kontrolle: Anmeldeseite erreichbar (Status 200/302). Das Verhalten nach der Anmeldung betrifft 7.10.

7.12 Markdown-Links in kopierten Konfigurationsdateien

  • Ursache: Beim Kopieren aus gerenderten Chat- oder Webansichten wurden Zeichenfolgen wie www.myblog oder /var/www/www.* in Markdown-Links umgewandelt ([www.myblog](https://www.myblog)). Apache startet nicht oder liest Pfade mit Linksyntax; in einer wp-config.php entsteht ein unbrauchbarer Alias-Pfad.
  • Diagnose:

  • Lösung:

Dauerhaft: Dateien per scp oder Download übertragen, nicht aus der Ansicht kopieren; in wp-config.php den Alias-Pfad zerlegt schreiben ('/www' . '.myblog').

  • Kontrolle: grep -c '](http' liefert 0; apache2ctl configtest meldet Syntax OK.

7.13 Tests auf dem falschen Rechner

  • Ursache: Befehle mit 127.0.0.1 oder Log-Pfaden (/var/log/apache2/…) wurden auf der Arbeitsstation statt auf dem Webserver ausgeführt. Ergebnis: Failed to connect to 127.0.0.1 port 80 bzw. leere Log-Auswertung.
  • Diagnose: Der Shell-Prompt (user@workstation statt user@webserver) bzw.

  • Lösung: Befehle mit 127.0.0.1 und Apache-Logs auf dem Webserver, Caddy-Logs auf der OPNsense, externe Tests von einem Rechner außerhalb des Netzes ausführen.
  • Kontrolle: curl -sI -H 'Host: myblog.newdomain.de' http://127.0.0.1/ liefert auf dem Webserver eine HTTP-Antwort.

7.14 401 bei DAV-Abfragen mit Platzhalter-Zugangsdaten

  • Ursache: Der Test wurde mit den Platzhaltern der Anleitung (USER:APP-PASSWORT) oder mit einem anderen Benutzernamen als dem DAV-Benutzer ausgeführt (z. B. user statt user1).
  • Diagnose: -i zeigt HTTP/… 401 und WWW-Authenticate: Basic realm="Nextcloud". Die Antwort stammt dennoch von Apache/Nextcloud (Header Server: Apache/…); der Pfad wird also korrekt zugestellt.
  • Lösung: echten Benutzernamen und ein App-Passwort verwenden (in Nextcloud unter den Sicherheitseinstellungen erzeugbar). Zugangsdaten in Befehlszeilen verbleiben in der Shell-History; App-Passwörter nach dem Test widerrufen.
  • Kontrolle: HTTP/2 207.

7.15 404 für Adressbücher/Kalender nach der Migration

Siehe Kapitel 8 (abweichende Namen der Sammlungen).


Zurück zur Übersicht


8. CardDAV und Kalender

8.1 Technischer Zusammenhang

Nextcloud verwendet für Kalender und Adressbücher WebDAV-Erweiterungen (CalDAV, CardDAV). Kalender oder Adressbuch haben dabei einen eigenen URL-Pfad, der aus Benutzername und einem Kalender bzw. Adressbuchnamen (URI/„Slug“) besteht:

Der Name im Pfad ist nicht der Anzeigename, sondern ein beim Anlegen erzeugter Kurzname. Beobachtungen:

  • Standard-Sammlungen tragen feste Namen (personal für den Standardkalender, contacts für das Standard-Adressbuch).
  • Für selbst angelegte Sammlungen wird der Anzeigename in Kleinbuchstaben mit Bindestrichen umgesetzt; Sonderzeichen wie Umlaute werden entfernt (Beispiel: Anzeigename „Geschäftlich“ ⇒ Pfadname geschftlich).
  • Geteilte Sammlungen erhalten Pfadnamen nach dem Muster _shared_by_.

DAV-Clients (Thunderbird, DAVx5, iOS/macOS u. a.) speichern pro Sammlung den vollständigen Pfad. Ruft ein Client nach der Migration einen Pfad auf, den die neue Installation nicht kennt, antwortet Nextcloud mit 404. Ein Proxy-Fehler liegt dann nicht vor: Die Antwort trägt Nextcloud-Header, z. B. X-User-Id, und die Anfrage wurde korrekt zugestellt.

Beobachtung im Caddy-Log der Alt-Domain (Client Thunderbird, Basis-URL https://olddomain.de/nextcloud/remote.php/dav/; Namen anonymisiert):

Anfrage Status Bedeutung
REPORT /nextcloud/remote.php/dav/addressbooks/users/user1/addressbook-a/ 401, danach 207 erste Anfrage ohne Authorization wird abgelehnt (normale Challenge); die Wiederholung mit Authorization ist erfolgreich
REPORT /nextcloud/remote.php/dav/addressbooks/users/user1/old-contacts/ 404 (Nextcloud-Antwort) Sammlung mit diesem Namen existiert in der neuen Installation nicht
REPORT /nextcloud/remote.php/dav/addressbooks/users/user1/old-contacts_shared_by_/ 404 (Nextcloud-Antwort) wie oben, geteilte Sammlung
PROPFIND /nextcloud/remote.php/dav/ 207 Basis-URL erreichbar

Der Zugriff über die alte URL /nextcloud/… und über die neue Domain (https://nextcloud.newdomain.de/remote.php/dav/…) liefert für identische Pfade identische Ergebniss

8.2 Prüfung der vorhandenen Kontakte und Kalender

Auflistung der Kontakte und Kalender (Pfadnamen) einer Installation; je Installation (alt und neu) auszuführen:

  • Alt-Domain: = olddomain.de, <präfix> = nextcloud/
  • Neue Domain: = nextcloud.newdomain.de, <präfix> leer

8.3 Vorgehen bei künftigen Nextcloud-Migrationen

  1. Vor der Migration die Pfadnamen aller Kalender und Adressbücher aller Benutzer in der alten Installation erfassen (Kapitel 8.2) und sichern.
  2. Benutzernamen identisch halten. Der Benutzername ist Teil des Pfads (…//…).
  3. Sammlungsnamen identisch anlegen. In der neuen Installation Kalender und Adressbücher mit demselben Anzeigenamen anlegen, bevor Daten importiert werden, damit derselbe Pfadname entsteht. Danach Inhalte in die gleichnamigen Sammlungen importieren. Der Pfadname wird beim Anlegen erzeugt; eine spätere Umbenennung des Anzeigenamens ändert ihn nach bisherigem Kenntnisstand nicht (nicht eigens getestet).
  4. Standard-Sammlungen (personal, contacts) nicht umbenennen.
  5. Geteilte Sammlungen (…_shared_by_) erneut freigeben; ihre Pfadnamen hängen vom Besitzer und dem Namen der Freigabe ab.
  6. Nach der Migration die Auflistung (Kapitel 8.2) auf beiden Installationen vergleichen: Die Pfadnamen der Sammlungen müssen übereinstimmen.
  7. Clients mit bestehender Einrichtung (Alt-URL …/nextcloud/…) funktionieren nur bei übereinstimmenden Pfadnamen. Für Sammlungen ohne Entsprechung sind die Einträge im Client zu entfernen und neu hinzuzufügen.
  8. Zugriff über die alte Domain bleibt über die Durchreichung der /nextcloud/…-Pfade (Kapitel 4.5) und Alias /nextcloud (Kapitel 2.6) möglich. Der Zugriff nur über die Domain ohne Pfad (Erkennung per /.well-known/caldav bzw. /.well-known/carddav im Root der Alt-Domain) ist im Projekt nicht eingerichtet, da die beobachteten Clients den vollständigen Pfad /nextcloud/remote.php/dav/ verwenden.

Zurück zur Übersicht


9. Vollständige Konfigurationsübersicht

9.1 Webserver (Debian, Apache)

Pfad Zweck Relevante Konfiguration Abhängigkeiten Verwendet von
/etc/apache2/apache2.conf Hauptkonfiguration; bindet mods-enabled, ports.conf, conf-enabled, sites-enabled ein mit Require all granted, AllowOverride None; IncludeOptional sites-enabled/*.conf (alphabetisch) – Apache
/etc/apache2/ports.conf lauscht auf Port 80 Listen 80 – Apache
/etc/apache2/mods-enabled/ aktivierte Module macro, rewrite, headers, remoteip, env, setenvif, alias, … (Kapitel 2.1) a2enmod Apache
/etc/apache2/sites-available/000-default.conf Default-VirtualHost (Direktzugriff per IP), Makro WPSite, Aliase Kapitel 2.4 Module macro, rewrite, alias, env; Verzeichnisse unter /var/www/ Apache; indirekt Caddy (Host-Header) und direkte Clients
/etc/apache2/sites-available/nextcloud.conf VirtualHost für Nextcloud Kapitel 2.6 Module headers, remoteip, setenvif, env; /var/www/nextcloud Apache; Caddy (nextcloud.newdomain.de, /nextcloud-Durchreichung)
/etc/apache2/sites-enabled/ Symlinks der aktiven Sites mindestens 000-default.conf und nextcloud.conf a2ensite/a2dissite Apache
/etc/apache2/sites-available/default-ssl.conf Apache-Standarddatei für HTTPS Nicht benötigt, da SSL über Reverse Proxy verwaltet wird. – –
/var/log/apache2/error.log, access.log Logs des Default-VirtualHosts – – Apache
/var/log/apache2/-error.log, -access.log Logs je WordPress-Site (Makro) z. B. myblog-error.log – Apache
/var/log/apache2/yourdomain-error.log, …-access.log Logs des Nextcloud-VirtualHosts Namen aus nextcloud.conf – Apache

9.2 Webanwendungen

Pfad Zweck Relevante Konfiguration Abhängigkeiten Verwendet von
/var/www/www./wp-config.php Datenbankzugang, URL-Block Kapitel 5.2, ; Wert $direct_path je Site MySQL/MariaDB; Alias in 000-default.conf PHP/WordPress
/var/www/www./.htaccess Permalink-Rewrite Kapitel 5.3 Modul rewrite; AllowOverride All Apache
/var/www/www./wp-content/ Themes, Plugins, Uploads Prüfung auf alte URLs (Kapitel 5.7) – WordPress
/var/www/nextcloud/config/config.php Nextcloud-Konfiguration trusted_domains, overwrite*, htaccess.RewriteBase, trusted_proxies: Werte [zu ergänzen] nextcloud.conf Nextcloud
/var/www/nextcloud/.htaccess Nextcloud-Rewrite-Regeln (u. a. /.well-known/carddav, /.well-known/caldav) von Nextcloud verwaltet Modul rewrite Apache

9.3 OPNsense / Caddy

Pfad/Ort Zweck Relevante Konfiguration Abhängigkeiten Verwendet von
/usr/local/etc/caddy/Caddyfile automatisch generierter Caddyfile Kapitel 4.2 os-caddy-Einträge in der GUI Caddy
/usr/local/etc/caddy/caddy.d/newdomain-redirect.conf Weiterleitung und Durchreichung der Alt-Domain Kapitel 4.5 Backend 192.178.1.100:80; Apache-Alias /nextcloud Caddy (Import am Ende des Caddyfiles)
/usr/local/etc/caddy/caddy.d/*.global globale Zusatzoptionen derzeit nicht verwendet – Caddy
/usr/local/etc/caddy/certificates/.pem, .key Wildcard-Zertifikat aus dem Trust-Store – os-acme-client, deSEC-API Caddy
/var/log/caddy/caddy.log Caddy-Log – – Caddy
/var/log/caddy/newdomain-redirect-access.log temporärer Access-Log der Alt-Domain (Kapitel 4.6) – log-Block in newdomain-redirect.conf Caddy
OPNsense-GUI: os-caddy Domänen, Subdomänen, Handler Kapitel 4.2 – erzeugt den Caddyfile
OPNsense-GUI: os-acme-client Zertifikatsausstellung (DNS-01, deSEC) Kapitel 4.3 deSEC-API-Token erzeugt das Zertifikat im Trust-Store
Firewall/NAT der OPNsense Zugriff auf Caddy (80/443) und auf die Backends Regeln: siehe Tutorial Netzwerkisolation mit OPNsense auf Proxmox – OPNsense

9.4 DNS und Router

Ort Zweck Konfiguration
deSEC (newdomain.de) DNS der neuen Domain A-Record newdomain.de → öffentliche IP (automatisch aktualisiert); Wildcard-CNAME * → newdomain.de
DNS-Anbieter (olddomain.de) DNS der Alt-Domain zeigt auf die öffentliche IP
Internet-Router Portweiterleitung 80/443 auf die OPNsense https://www.youtube.com/watch?v=6dHoFVyHinU

Zurück zur Übersicht


10. Prüf- und Testverfahren

Alle Tests sind so gewählt, dass erkennbar ist, welche Komponente die Anfrage tatsächlich beantwortet:

Merkmal in der Antwort Bedeutung
Server: Apache/… Apache hat geantwortet
Via: 1.1 Caddy die Antwort lief über Caddy (Reverse Proxy)
Server: Caddy Caddy hat selbst geantwortet (z. B. Redirect; Standardverhalten von Caddy)
X-Powered-By/WordPress-spezifische Header, Link: <…/wp-json/> WordPress hat die Seite erzeugt
X-User-Id, Content-Security-Policy: default-src 'none' bei DAV-Antworten Nextcloud hat geantwortet

Ausführungsort beachten (Kapitel 7.13): Befehle mit 127.0.0.1 und Apache-Logs auf dem Webserver, Caddy-Logs auf der OPNsense, externe Tests außerhalb des Netzes.

10.1 Apache (auf dem Webserver)

Erwartet: Syntax OK; apache2ctl -S nennt den Default-Server (000-default.conf) und alle Sites; 200 für die bekannten Subdomains und für myblog.example.org (Domainunabhängigkeit); 403 für unbekannte FQDN.

10.2 Direkte IP-Aufrufe

Erwartet: 200/302; die Links beginnen mit http://192.178.1.100/www.website2.de/ (WordPress-Basis-URL, Kapitel 5.3). Zeigt der Link /www.www.…, liegt der Fehler aus Kapitel 7.7 vor.

10.3 Caddy (auf der OPNsense)

Eine Syntaxprüfung der Konfiguration ist zusätzlich möglich, sofern die caddy-Binärdatei auf dem System zur Verfügung steht:

Im Projekt wurde die Datei newdomain-redirect.conf zusammen mit dem generierten Caddyfile in einer Testumgebung mit caddy validate geprüft (Ergebnis: Valid configuration); auf der OPNsense erfolgte die Kontrolle über den Neustart und das Log. Ob caddy auf der OPNsense im Suchpfad liegt: [zu ergänzen].

10.4 HTTPS und Zertifikat (neue Domain)

Erwartet: Zertifikat für *.newdomain.de; HTTP/2 200; via: 1.1 Caddy und server: Apache/….

10.5 Alte Domain und Redirects

Erwartet: 301 mit Location: https://myblog.newdomain.de/category/smart-home/, Query und Rest-Pfad unverändert, Server: Caddy (Redirect durch Caddy; Apache ist nicht beteiligt). Der letzte Befehl muss genau ein 301 und danach 200 zeigen.

Weitere erwartete Ergebnisse: Kapitel 4.5, Tabelle „Getestete Zuordnungen“.

10.6 WordPress

Erwartet: No syntax errors detected; Links beginnen mit https://website1.newdomain.de/; der Zähler zeigt die Anzahl noch eingebetteter Alt-Domain-Verweise (0 ist der Zielwert, Kapitel 5.6/5.7).

10.7 Nextcloud, CardDAV und Kalender

Erwartet: 401 mit WWW-Authenticate: Basic realm="Nextcloud" ohne Zugangsdaten; 207 mit Zugangsdaten; bei der Alt-Domain beginnen die href-Werte mit /nextcloud/remote.php/dav/. Die Pfadnamen der Sammlungen müssen mit den im Client gespeicherten Pfaden übereinstimmen.

Auf dem Webserver zeigt das Nextcloud-Access-Log, welche Pfade ein Client tatsächlich abfragt:

Auf der OPNsense zeigt das Access-Log der Alt-Domain (Kapitel 4.6), ob die Anfrage Caddy erreicht und welchen Status der Client erhält.

10.8 Externe Erreichbarkeit

Von einem Rechner außerhalb des Heimnetzes (z. B. Mobilfunk):

Erwartet: beide Namen lösen auf dieselbe öffentliche IP auf; die Aufrufe liefern 200 bzw. 301. Schlägt ein Aufruf von außen fehl, funktioniert aber von innen, liegt der Fehler bei Portweiterleitung oder Firewall (Regeln: siehe Tutorial Netzwerkisolation mit OPNsense auf Proxmox).


Zurück zur Übersicht


11. Ablauf einer Anfrage

11.1 Neue Domain: https://myblog.newdomain.de/category/smart-home/

Schritt Komponente Vorgang
1 DNS Der Browser löst myblog.newdomain.de auf. Der Wildcard-CNAME * zeigt auf newdomain.de; der A-Record liefert die öffentliche IP.
2 Router / OPNsense Die Verbindung zu Port 443 wird an die OPNsense weitergeleitet. Die Firewall-Regeln lassen sie zu Caddy durch.
3 Caddy Caddy wählt den Site-Block myblog.newdomain.de anhand von SNI und Host-Header.
4 TLS Caddy beendet TLS mit dem Wildcard-Zertifikat *.newdomain.de (aus dem Trust-Store).
5 Reverse Proxy Der Handler reverse_proxy 192.178.1.100 öffnet eine neue HTTP-Verbindung zu 192.178.1.100:80.
6 HTTP-Request zum Apache GET /category/smart-home/ mit Host: myblog.newdomain.de, X-Forwarded-For: , X-Forwarded-Proto: https, X-Forwarded-Host: myblog.newdomain.de.
7 Host-Header Apache liest Host: myblog.newdomain.de aus dem Request.
8 VirtualHost-Auswahl Auf *:80 trifft ServerAlias myblog.* des Makros WPSite. Der Default-VirtualHost wird nicht verwendet.
9 DocumentRoot / Alias DocumentRoot /var/www/www.myblog. /category/smart-home/ existiert nicht als Datei; .htaccess leitet per RewriteRule . index.php [L] an WordPress.
10 WordPress wp-config.php setzt wegen X-Forwarded-Proto: https HTTPS=on und WP_HOME/WP_SITEURL auf https://myblog.newdomain.de. WordPress löst den Permalink auf und erzeugt die Seite mit URLs dieser Basis.
11 Rückgabe an Apache PHP übergibt die Antwort an Apache (Server: Apache/…).
12 Rückgabe an Caddy Apache sendet die Antwort an Caddy, das den Header Via: 1.1 Caddy ergänzt.
13 Rückgabe an den Browser Caddy sendet die Antwort über die TLS-Verbindung an den Browser.

11.2 Alte Domain: https://olddomain.de/myblog/category/smart-home/

Schritt Komponente Vorgang
1 DNS olddomain.de löst auf dieselbe öffentliche IP auf.
2 Router / OPNsense wie bei der neuen Domain
3 Caddy Der Site-Block olddomain.de aus newdomain-redirect.conf wird gewählt (SNI/Host).
4 TLS Caddy beendet TLS mit dem Zertifikat dieses Site-Blocks (Quelle: Kapitel 4.3)
5 Regelauswertung legacy_redirect prüft in fester Reihenfolge: /nextcloud/…-Client-Pfade (kein Treffer), dann legacy_site (?:www\.)?myblog (Treffer: Pfad beginnt mit /myblog/).
6 Umschreiben uri path_regexp entfernt den Präfix; {uri} lautet nun /category/smart-home/ (Query bleibt erhalten).
7 HTTP-Redirect Caddy antwortet selbst mit 301 und Location: https://myblog.newdomain.de/category/smart-home/. Apache und WordPress sind nicht beteiligt.
8 Browser Der Browser stellt eine neue Anfrage an die neue URL; ab hier gilt der Ablauf aus Kapitel 11.1. Die Adresszeile zeigt die neue Domain.

An dieser Stelle (Schritt 7) erfolgt die Weiterleitung auf die neue Domain. Der Pfad nach dem Präfix und die Query bleiben unverändert; unbekannte Pfade der Alt-Domain werden durch die Auffangregel auf die Blog-Subdomain umgeleitet.

11.3 Alte Nextcloud-Client-Anfrage: https://olddomain.de/nextcloud/remote.php/dav/…

Schritt Komponente Vorgang
1–4 DNS, OPNsense, Caddy, TLS wie in Kapitel 11.2
5 Regelauswertung Die erste Regel (@nextcloud_api) trifft: Pfad beginnt mit /nextcloud/remote.php/.
6 Reverse Proxy (kein Redirect) Caddy leitet an 192.178.1.100:80 weiter, Pfad unverändert (/nextcloud/remote.php/dav/…), Host: nextcloud.newdomain.de (header_up).
7 VirtualHost-Auswahl Apache wählt anhand von Host: nextcloud.newdomain.de den VirtualHost aus nextcloud.conf.
8 Alias Alias /nextcloud "/var/www/nextcloud/" ordnet den Pfad dem Nextcloud-Verzeichnis zu.
9 Nextcloud Nextcloud leitet seinen Webroot (/nextcloud) aus dem Skriptpfad ab und authentifiziert den Client. Antworten enthalten Pfade mit dem Präfix /nextcloud/remote.php/dav/….
10 Rückgabe Apache → Caddy → Client; der Client bemerkt keinen Hostwechsel.

Zurück zur Übersicht



Tutorials, Konfigurationen und Open-Source-Projekte sind mit regelmäßigem Aufwand für Tests, Pflege und Dokumentation verbunden. Wer unsere Arbeit unterstützen möchte, trägt dazu bei, dass neue Inhalte entstehen. Wir danken dafür.
  • Bitcoin (BTC): 33AXe8Z8XBuGKx9eHHmGnvbawrNYjSgDcM
  • Ethereum (ETH): 0xa61d178EA84C2200A8617b51B4bCf98F87ff59Ff
  • Solana (SOL): BDf5EgsN8fRUicYzeM8cuaNhL7zdty2qsEj2mC2jA4Fm
  • Ripple (XRP): rLHzPsX6oXkzU2qL12kHCH8G8cnZv1rBJh
  • USTether (USDT): 0xa61d178EA84C2200A8617b51B4bCf98F87ff59Ff

by Speefak
Back To Top