Nginx Virtual Hosts: Mehrere Websites auf einem Server hosten

Nutzen Sie die Leistungsfähigkeit von Nginx Virtual Hosts (Server-Blöcke), um effizient mehrere Websites oder Subdomains auf einem einzelnen Server zu hosten. Diese Anleitung bietet ein umfassendes, schrittweises Tutorial, das die Einrichtung von Verzeichnissen, die Erstellung von Konfigurationsdateien, das Aktivieren von Server-Blöcken und das Testen von Nginx abdeckt. Lernen Sie Best Practices für Subdomains, Standard-Server-Blöcke, HTTPS-Integration und dediziertes Logging kennen. Praktische Beispiele und wichtige Tipps zur Fehlerbehebung helfen Ihnen, das Multi-Site-Hosting mit Nginx zu meistern, die Ressourcennutzung zu optimieren und die Verwaltung des Webservers zu optimieren.

Nginx Virtual Hosts: Mehrere Websites auf einem Server hosten

Mehrere kleine Seiten von einem Server aus zu betreiben, ist eine normale Nginx-Aufgabe. Sie haben vielleicht eine Unternehmensseite, eine Dokumentationsseite, eine Staging-App und ein Kundenportal, die alle auf derselben Maschine landen. Nginx trennt sie mit server-Blöcken. Apache-Entwickler nennen dieselbe Idee oft Virtual Hosts, daher werden Sie beide Begriffe in Tutorials und Hosting-Panels sehen.

Der wichtige Teil ist einfach: Nginx betrachtet den Port, die IP-Adresse und den Host-Header und wählt dann den passenden server-Block aus. Wenn die falsche Seite geladen wird, ist das Problem normalerweise nicht mysteriös. Oft liegt es an einem fehlenden DNS-Eintrag, einem Tippfehler in server_name, einem Standard-Server, der die Anfrage abfängt, oder zwei Dateien, die denselben Namen beanspruchen.

Nginx Server-Blöcke (Virtual Hosts) verstehen

Im Kern ist ein Nginx Server-Block eine Konfigurationsdirektive, die innerhalb der Nginx-Konfigurationsdatei (nginx.conf oder eingebundenen Dateien) definiert wird. Jeder server-Block definiert die Konfiguration für einen bestimmten virtuellen Host und legt fest, wie Nginx auf Anfragen für eine bestimmte Domain oder eine Gruppe von Domains reagieren soll. Nginx verwendet die listen-Direktive, um die IP-Adresse und den Port anzugeben, auf dem es lauschen soll, und die server_name-Direktive, um zu identifizieren, auf welche Domainnamen oder Hostnamen dieser Server-Block antworten soll.

Wenn eine Anfrage eingeht, untersucht Nginx den Host-Header der HTTP-Anfrage und vergleicht ihn mit den server_name-Direktiven seiner konfigurierten Server-Blöcke. Dann wird der Inhalt aus dem passenden Server-Block ausgeliefert. Wenn kein server_name übereinstimmt, fällt Nginx normalerweise auf den Standard-Server-Block zurück (den ersten server-Block oder einen, der explizit als default_server markiert ist).

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Folgendes vorhanden ist:

  1. Nginx installiert: Nginx sollte auf Ihrem Server installiert und ausgeführt werden. Falls nicht, können Sie es in der Regel über den Paketmanager Ihres Systems installieren (z. B. sudo apt update && sudo apt install nginx unter Ubuntu/Debian, sudo yum install nginx unter CentOS/RHEL).
  2. Domainnamen: Sie benötigen mindestens zwei Domainnamen (z. B. example1.com und example2.com) oder Subdomains (z. B. blog.example.com und app.example.com), die Sie hosten möchten. Die DNS-A/AAAA-Einträge dieser Domains müssen auf die öffentliche IP-Adresse Ihres Servers zeigen.
  3. Grundlegende Verzeichnisstruktur: Ein Plan, wo Ihre Website-Dateien abgelegt werden sollen. Eine gängige Praxis ist /var/www/ihredomain.com/html.
  4. Sudo-Rechte: Sie benötigen sudo-Zugriff, um Nginx-Konfigurationsdateien zu ändern.

Schritt-für-Schritt-Einrichtungsanleitung

Richten wir zwei virtuelle Hosts ein: example1.com und example2.com.

Schritt 1: Verzeichnisstruktur für Websites erstellen

Erstellen Sie zunächst Stammverzeichnisse für jede Ihrer Websites. Hier werden ihre HTML-, CSS-, JavaScript- und anderen statischen Dateien gespeichert. Ein üblicher Ort ist /var/www/.

sudo mkdir -p /var/www/example1.com/html
sudo mkdir -p /var/www/example2.com/html

# Besitzer auf Ihren Benutzer setzen ($USER durch Ihren Benutzernamen ersetzen), um Bearbeitung zu ermöglichen
sudo chown -R $USER:$USER /var/www/example1.com/html
sudo chown -R $USER:$USER /var/www/example2.com/html

# Leseberechtigungen für den Webserver setzen
sudo chmod -R 755 /var/www

Erstellen Sie als Nächstes eine einfache index.html-Datei in jedem Verzeichnis, um die Einrichtung zu testen:

Für /var/www/example1.com/html/index.html:

<!-- /var/www/example1.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Willkommen bei Example1.com!</title>
</head>
<body>
    <h1>Erfolg! Dies ist Example1.com.</h1>
    <p>Dieser virtuelle Host funktioniert korrekt.</p>
</body>
</html>

Für /var/www/example2.com/html/index.html:

<!-- /var/www/example2.com/html/index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Willkommen bei Example2.com!</title>
</head>
<body>
    <h1>Erfolg! Dies ist Example2.com.</h1>
    <p>Dieser virtuelle Host funktioniert auch!</p>
</body>
</html>

Schritt 2: Nginx Server-Block-Konfigurationsdateien erstellen

Nginx lädt Server-Block-Konfigurationen normalerweise aus Dateien im Verzeichnis /etc/nginx/sites-enabled/. Diese Dateien sind in der Regel symbolische Links auf Konfigurationen, die in /etc/nginx/sites-available/ gespeichert sind. Diese Trennung ermöglicht es Ihnen, Konfigurationen zu speichern, die noch nicht aktiv sind, oder Seiten einfach zu aktivieren/deaktivieren.

Erstellen Sie eine neue Konfigurationsdatei für example1.com:

sudo nano /etc/nginx/sites-available/example1.com.conf

Fügen Sie den folgenden Inhalt hinzu:

# /etc/nginx/sites-available/example1.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example1.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example1.com www.example1.com;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/example1.com_access.log;
    error_log /var/log/nginx/example1.com_error.log;
}

Erklärung der Direktiven:

  • listen 80;: Nginx lauscht auf Port 80 (Standard-HTTP). listen [::]:80; ist für IPv6.
  • root /var/www/example1.com/html;: Gibt das Dokumentenwurzelverzeichnis für diesen Server-Block an. Nginx sucht in diesem Verzeichnis nach Dateien.
  • index index.html ...;: Definiert die Standarddatei, die Nginx ausliefern soll, wenn ein Verzeichnis angefordert wird (z. B. wenn jemand example1.com/ besucht).
  • server_name example1.com www.example1.com;: Dies ist entscheidend. Es teilt Nginx mit, auf Anfragen für example1.com oder www.example1.com mit der Konfiguration dieses Server-Blocks zu antworten.
  • location / { ... }: Ein Block, der definiert, wie Anfragen für bestimmte URIs behandelt werden. try_files versucht, eine Datei direkt ($uri), dann ein Verzeichnis ($uri/) auszuliefern und gibt schließlich einen 404 Not Found-Fehler zurück.
  • access_log und error_log: Gibt separate Logdateien für diese spezifische Seite an, was eine gute Praxis für einfachere Fehlerbehebung und Analyse ist.

Erstellen Sie nun eine ähnliche Konfigurationsdatei für example2.com:

sudo nano /etc/nginx/sites-available/example2.com.conf

Fügen Sie den folgenden Inhalt hinzu:

# /etc/nginx/sites-available/example2.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/example2.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name example2.com www.example2.com;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/example2.com_access.log;
    error_log /var/log/nginx/example2.com_error.log;
}

Schritt 3: Server-Blöcke aktivieren

Um diese Konfigurationen zu aktivieren, erstellen Sie symbolische Links vom Verzeichnis sites-available in das Verzeichnis sites-enabled. Dies teilt Nginx mit, diese Dateien beim Start einzubinden.

sudo ln -s /etc/nginx/sites-available/example1.com.conf /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example2.com.conf /etc/nginx/sites-enabled/

Schritt 4: Nginx-Konfiguration testen

Es ist entscheidend, Ihre Nginx-Konfiguration vor dem Neuladen auf Syntaxfehler zu testen. Dies verhindert, dass Nginx aufgrund eines Tippfehlers nicht neu startet.

sudo nginx -t

Sie sollten eine Ausgabe ähnlich der folgenden sehen, die den Erfolg anzeigt:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Wenn Sie Fehler sehen, korrigieren Sie diese in den entsprechenden Konfigurationsdateien und führen Sie sudo nginx -t erneut aus, bis es erfolgreich ist.

Schritt 5: Nginx neu starten

Wenden Sie die neue Konfiguration an, indem Sie Nginx neu starten oder neu laden. reload wird im Allgemeinen bevorzugt, da es Nginx ermöglicht, neue Konfigurationen zu laden, ohne aktive Verbindungen zu trennen.

sudo systemctl reload nginx
# Oder, falls reload nicht funktioniert oder bei Neuinstallationen:
sudo systemctl restart nginx

Schritt 6: DNS-Einträge aktualisieren

Stellen Sie sicher, dass die DNS-A-Einträge für example1.com, www.example1.com, example2.com und www.example2.com alle auf die IP-Adresse Ihres Nginx-Servers zeigen. Ohne korrekte DNS-Einträge weiß Ihr Browser nicht, wo er Ihre Websites finden soll.

Sobald die DNS-Propagation abgeschlossen ist (was einige Minuten bis mehrere Stunden dauern kann), sollten Sie in Ihrem Webbrowser http://example1.com und http://example2.com aufrufen und die entsprechenden index.html-Seiten sehen können.

Erweiterte Szenarien und Best Practices

Subdomains hosten

Das Hosten von Subdomains (z. B. blog.example.com, shop.example.com) funktioniert genauso wie das Hosten separater Domains. Sie definieren einfach einen neuen Server-Block mit der Subdomain als server_name.

Beispiel für blog.example.com:

# /etc/nginx/sites-available/blog.example.com.conf
server {
    listen 80;
    listen [::]:80;

    root /var/www/blog.example.com/html;
    index index.html;

    server_name blog.example.com;

    location / {
        try_files $uri $uri/ =404;
    }
}

Denken Sie daran, das Verzeichnis (/var/www/blog.example.com/html) zu erstellen, eine index.html zu erstellen, den symbolischen Link zu erstellen und Nginx neu zu laden.

Der Standard-Server-Block

Es ist gute Praxis, einen Standard-Server-Block zu haben, der Anfragen für Domainnamen abfängt, die mit keiner anderen server_name-Direktive auf Ihrem Server übereinstimmen. Dies verhindert, dass unbekannte Anfragen vom "ersten" virtuellen Host bedient werden, den Nginx findet, oder ermöglicht es Ihnen, eine generische "Seite nicht gefunden"-Seite auszuliefern.

Typischerweise ist der erste server-Block in Ihrer nginx.conf oder sites-enabled implizit der Standard. Sie können einen explizit mit default_server festlegen:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    server_name _;
    # Der Unterstrich `_` ist ein nicht existierender Domainname, der niemals mit einer echten Anfrage übereinstimmt.
    # Sie können auch localhost verwenden.

    root /var/www/default_site/html;
    index index.html;

    location / {
        return 444; # Gibt einen Nginx-spezifischen 444-Fehler (keine Antwort) für unbekannte Hosts zurück
        # Oder, liefern Sie eine generische Landingpage:
        # try_files $uri $uri/ =404;
    }
}

Warnung: Wenn Sie einen default_server-Block definieren, stellen Sie sicher, dass nur ein server-Block auf einem bestimmten listen-Port das default_server-Flag hat, da Nginx sonst eine Warnung protokolliert.

Virtuelle Hosts mit HTTPS (SSL/TLS) absichern

Für Produktionswebsites ist die Aktivierung von HTTPS unerlässlich. Dies beinhaltet das Einholen eines SSL/TLS-Zertifikats (z. B. über Let's Encrypt mit Certbot) und die Konfiguration von Nginx, um auf Port 443 mit dem Zertifikat zu lauschen.

Ein typischer HTTPS-Server-Block sieht so aus (nachdem Zertifikate eingeholt wurden):

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example1.com www.example1.com;

    root /var/www/example1.com/html;
    index index.html;

    ssl_certificate /etc/letsencrypt/live/example1.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example1.com/privkey.pem;

    # Andere SSL-Konfigurationen einfügen (Chiffren, Protokolle usw.)
    include /etc/nginx/snippets/ssl-params.conf;

    location / {
        try_files $uri $uri/ =404;
    }
}

# Optional: HTTP-zu-HTTPS-Weiterleitung für diese Domain
server {
    listen 80;
    listen [::]:80;
    server_name example1.com www.example1.com;
    return 301 https://$host$request_uri;
}

Es ist üblich, einen separaten HTTP-Server-Block zu haben, dessen einziger Zweck es ist, den gesamten Traffic auf sein HTTPS-Gegenstück umzuleiten.

Wenn Sie Certbot verwenden, erstellt oder bearbeitet es möglicherweise diese Blöcke für Sie. Das ist praktisch, aber Sie sollten die resultierende Datei trotzdem lesen. Automatisierte Zertifikatstools fügen manchmal Weiterleitungslogik an einer Stelle hinzu, die Sie selbst nicht gewählt hätten, und doppelte Weiterleitungen können die Fehlerbehebung erschweren.

Logging für jede Seite

Wie in den Beispielen gezeigt, ist die Verwendung separater access_log- und error_log-Dateien für jeden virtuellen Host eine bewährte Methode. Dies erleichtert das Debuggen von Problemen und die Analyse des Datenverkehrs für einzelne Websites erheblich, ohne kombinierte Logs durchsuchen zu müssen.

Struktur der Konfigurationsdateien

Für größere Bereitstellungen sollten Sie Ihre Nginx-Konfigurationsdateien wie folgt organisieren:

  • nginx.conf: Hauptkonfiguration, bindet conf.d/*.conf und sites-enabled/* ein.
  • conf.d/: Allgemeine serverweite Einstellungen (z. B. Gzip, Caching).
  • snippets/: Wiederverwendbare Nginx-Konfigurationsschnipsel (z. B. SSL-Parameter, gemeinsame location-Blöcke).
  • sites-available/: Einzelne server-Blöcke für jede Website.
  • sites-enabled/: Symbolische Links zu aktiven Konfigurationen in sites-available/.

Fehlerbehebung bei häufigen Problemen

  • 403 Forbidden Error: Dies bedeutet normalerweise, dass Nginx keinen Lesezugriff auf die Dateien oder Verzeichnisse Ihrer Website hat. Überprüfen Sie die Datei- und Verzeichnisberechtigungen (z. B. sudo chmod -R 755 /var/www/ihredomain.com/html und stellen Sie sicher, dass der Nginx-Benutzer, normalerweise www-data oder nginx, sie lesen kann).
  • 404 Not Found Error: Überprüfen Sie, ob die root-Direktive in Ihrem Server-Block auf das richtige Verzeichnis zeigt und ob Ihre index.html-Datei an diesem Ort vorhanden ist. Stellen Sie außerdem sicher, dass try_files korrekt konfiguriert ist.
  • Falsche Seite wird geladen: Dies deutet oft auf ein Problem mit der server_name-Direktive hin. Stellen Sie sicher, dass der server_name genau mit dem Domainnamen übereinstimmt, den Sie aufrufen möchten (einschließlich www. oder Subdomains). Überprüfen Sie auch Ihre DNS-Einträge.
  • Nginx startet/lädt nicht neu: Verwenden Sie immer sudo nginx -t, um Ihre Konfiguration zu testen, bevor Sie versuchen, Nginx neu zu laden oder neu zu starten. Fehlermeldungen zeigen die Zeile und Datei an, in der der Syntaxfehler aufgetreten ist.
  • DNS-Probleme: Wenn Sie Ihre Seite über die IP-Adresse, aber nicht über den Domainnamen erreichen können, liegt es fast sicher an einem DNS-Problem. Verwenden Sie dig oder nslookup, um zu überprüfen, ob die A-Einträge Ihrer Domain auf die richtige Server-IP zeigen.

Testen, bevor DNS bereit ist

Sie müssen nicht auf das öffentliche DNS warten, um die Nginx-Seite zu testen. Sie können eine Anfrage mit einem benutzerdefinierten Host-Header senden:

curl -H "Host: example1.com" http://203.0.113.10/
curl -H "Host: example2.com" http://203.0.113.10/

Ersetzen Sie 203.0.113.10 durch Ihre Server-IP. Wenn jeder Befehl die richtige Testseite zurückgibt, funktioniert der Server-Block-Matching. Wenn beide Befehle dieselbe Seite zurückgeben, überprüfen Sie, ob beide Dateien aktiviert sind, ob server_name korrekt ist und ob ein Standard-Block die Anfrage abfängt.

Für HTTPS ist der Test etwas anders, da TLS SNI verwendet, bevor der HTTP-Host-Header verarbeitet wird:

curl --resolve example1.com:443:203.0.113.10 https://example1.com/

Dieser Befehl teilt curl mit, eine Verbindung zu Ihrer Server-IP herzustellen, während für TLS und HTTP weiterhin example1.com verwendet wird. Dies ist eine der schnellsten Möglichkeiten, einen neuen HTTPS-Virtual-Host zu testen, bevor DNS geändert wird.

Ein wartbares Multi-Site-Muster

Für eine Handvoll statischer Seiten reichen die obigen Beispiele aus. Sobald Sie mehrere Anwendungen hosten, wiederholen Sie weniger und zentralisieren Sie nur die Teile, die wirklich gemeinsam genutzt werden. Legen Sie beispielsweise gemeinsame Sicherheitsheader, Komprimierung und SSL-Parameter in Snippets ab, aber behalten Sie root, server_name, Upstream und Logs jeder Seite in ihrer eigenen Datei sichtbar.

Vermeiden Sie es, einen großen Produktionsblock von einer Domain in eine andere zu kopieren, ohne jede Zeile zu lesen. So schleichen sich server_name-Fehler, falsche Zertifikatspfade und gemeinsame Logdateien ein. Eine praktische Überprüfungsliste ist kurz:

  • Enthält server_name jeden Hostnamen, den Benutzer eingeben werden?
  • Zeigt root oder proxy_pass auf diese Seite, nicht auf die vorherige?
  • Sind Zugriffs- und Fehlerlogs ausreichend getrennt, um diese Seite allein debuggen zu können?
  • Besteht nginx -t vor dem Neuladen?
  • Gibt curl -H "Host: ..." oder curl --resolve die erwartete Seite zurück?

Abschließende Bemerkungen

Nginx Virtual Hosts sind zuverlässig, wenn jede Seite einen klaren Server-Block, einen korrekten server_name und einen vorhersehbaren Standard-Fallback hat. Halten Sie die Dateien langweilig. Testen Sie jede Änderung vor dem Neuladen. Verwenden Sie dedizierte Logs, wenn die Seiten wichtig sind. Die meisten Multi-Site-Nginx-Probleme lassen sich leicht lösen, sobald Sie nachweisen können, ob DNS, TLS/SNI oder das Server-Block-Matching der fehlgeschlagene Teil ist.