💡 Hinweis: Dieses Tutorial setzt voraus, dass du einen normalen Benutzer mit sudo-Rechten verwendest — wie im Tutorial Debian 13 Server absichern beschrieben.
Einleitung — Was ist Nginx und warum nicht Apache?
Nginx (ausgesprochen „Engine-X“) ist einer der beliebtesten Webserver weltweit — und das aus gutem Grund. Ursprünglich 2004 von Igor Sysoev entwickelt, um das C10K-Problem zu lösen (10.000 gleichzeitige Verbindungen), hat sich Nginx zum Standard für moderne Webinfrastruktur entwickelt.
Im Vergleich zu Apache bietet Nginx einige entscheidende Vorteile:
- Event-basierte Architektur — Nginx nutzt ein asynchrones, nicht-blockierendes Modell. Apache erstellt standardmäßig einen Thread/Prozess pro Verbindung, was bei vielen gleichzeitigen Anfragen schnell Ressourcen frisst.
- Geringerer Speicherverbrauch — Bei statischen Inhalten braucht Nginx einen Bruchteil des RAMs im Vergleich zu Apache.
- Hervorragend als Reverse Proxy — Nginx ist die erste Wahl, wenn du Anwendungen wie Node.js, Python oder Docker-Container hinter einem Webserver betreiben willst.
- Einfache Konfiguration — Die Konfig-Syntax ist klar, deklarativ und leicht lesbar.
Das heißt nicht, dass Apache schlecht ist — für bestimmte Use Cases (z.B. .htaccess-basierte Konfiguration) hat Apache seine Berechtigung. Aber für moderne Self-Hosting-Setups, APIs und statische Seiten ist Nginx die bessere Wahl.
In diesem Tutorial installieren wir Nginx auf Debian 13 (Trixie), verstehen die Verzeichnisstruktur, erstellen unsere erste Konfiguration und härten den Server mit Security Headers und Gzip-Kompression.
Voraussetzungen
Bevor wir starten, stelle sicher, dass Folgendes gegeben ist:
- Debian 13 (Trixie) — frisch installiert oder bestehendes System. Falls noch nicht geschehen, folge Tutorial #1: Debian 13 Server Grundkonfiguration
- Root-Zugang oder ein User mit
sudo-Rechten - Port 80 muss von außen erreichbar sein (Firewall prüfen)
- Eine Domain (optional, aber empfohlen für die Server-Block-Konfiguration)
Alle Befehle in diesem Tutorial werden mit sudo ausgeführt.
Nginx installieren
Nginx ist in den offiziellen Debian-Repositories enthalten. Die Installation ist denkbar einfach:
sudo apt update
sudo apt install nginx -yNach der Installation startet Nginx automatisch. Prüfe den Status:
sudo systemctl status nginxDu solltest active (running) sehen. Öffne jetzt deinen Browser und navigiere zu http://deine-server-ip — die Nginx-Standardseite („Welcome to nginx!“) sollte erscheinen.
Falls du UFW als Firewall nutzt, gib den HTTP-Traffic frei:
sudo ufw allow 'Nginx HTTP'
sudo ufw statusDie Nginx-Verzeichnisstruktur verstehen
Bevor wir konfigurieren, solltest du wissen, wo was liegt. Nginx unter Debian organisiert sich so:
/etc/nginx/
├── nginx.conf # Hauptkonfiguration
├── sites-available/ # Alle verfügbaren Server-Blöcke
│ └── default # Standard-Konfiguration
├── sites-enabled/ # Aktive Server-Blöcke (Symlinks)
│ └── default → ../sites-available/default
├── conf.d/ # Zusätzliche Konfig-Snippets
├── snippets/ # Wiederverwendbare Konfig-Teile
├── mime.types # MIME-Type-Zuordnungen
└── modules-enabled/ # Geladene ModuleDas wichtigste Prinzip: sites-available enthält alle Konfigurationen, sites-enabled nur die aktiven (als Symlinks). So kannst du Seiten aktivieren und deaktivieren, ohne Dateien zu löschen.
Erste Konfiguration — Ein Server-Block erstellen
Ein Server-Block (bei Apache „Virtual Host“ genannt) definiert, wie Nginx auf Anfragen für eine bestimmte Domain reagiert. Erstellen wir einen für example.com:
sudo nano /etc/nginx/sites-available/example.comFüge folgende Konfiguration ein:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}Erstelle das Webroot-Verzeichnis und eine Test-Seite:
sudo mkdir -p /var/www/example.com/html
echo '<h1>Willkommen auf example.com!</h1>' | sudo tee /var/www/example.com/html/index.html
sudo chown -R www-data:www-data /var/www/example.comAktiviere den Server-Block und deaktiviere die Standardseite:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/defaultTeste und lade die Konfiguration neu:
sudo nginx -t
sudo systemctl reload nginxWenn sudo nginx -t meldet syntax is ok und test is successful, ist alles korrekt.
Eine statische Website hosten
Nginx ist perfekt für statische Websites — HTML, CSS, JavaScript, Bilder. Lege deine Dateien einfach in das root-Verzeichnis deines Server-Blocks.
Ein typisches Setup für eine statische Seite:
/var/www/example.com/html/
├── index.html
├── about.html
├── css/
│ └── style.css
├── js/
│ └── app.js
└── images/
└── logo.pngFür Single-Page Applications (SPAs) wie React oder Vue ändere die try_files-Direktive:
location / {
try_files $uri $uri/ /index.html;
}So werden alle Routen auf index.html umgeleitet — perfekt für Client-Side Routing.
Wichtige Nginx-Direktiven im Überblick
Hier die Direktiven, die du kennen solltest:
worker_processes
Definiert die Anzahl der Worker-Prozesse. Setze es auf auto, damit Nginx die Anzahl der CPU-Kerne automatisch erkennt:
# In /etc/nginx/nginx.conf
worker_processes auto;server_name
Bestimmt, auf welche Domain(s) der Server-Block reagiert:
server_name example.com www.example.com;
server_name *.example.com; # Wildcard
server_name _; # Catch-all (Default-Server)location
Definiert, wie Nginx auf bestimmte URL-Pfade reagiert:
location / { } # Alles
location /images/ { } # Alles unter /images/
location ~ \.php$ { } # Regex: PHP-Dateien
location = /favicon.ico { } # Exakter Matchroot vs. alias
# root: Pfad + URI
location /static/ {
root /var/www; # Sucht in /var/www/static/
}
# alias: Ersetzt den Location-Pfad
location /static/ {
alias /var/www/files/; # Sucht in /var/www/files/
}index
Welche Datei als Index geladen wird:
index index.html index.htm index.php;Security Headers konfigurieren
Security Headers schützen deine Besucher vor gängigen Angriffen wie Clickjacking, XSS und MIME-Sniffing. Füge sie in deinen Server-Block oder in eine zentrale Snippet-Datei ein:
sudo nano /etc/nginx/snippets/security-headers.conf# Verhindert Clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;
# Verhindert MIME-Type-Sniffing
add_header X-Content-Type-Options "nosniff" always;
# XSS-Schutz (für ältere Browser)
add_header X-XSS-Protection "1; mode=block" always;
# Referrer-Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions-Policy (ehemals Feature-Policy)
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
# Content-Security-Policy (anpassen!)
# add_header Content-Security-Policy "default-src 'self';" always;Binde das Snippet in deinen Server-Block ein:
server {
listen 80;
server_name example.com;
root /var/www/example.com/html;
include snippets/security-headers.conf;
location / {
try_files $uri $uri/ =404;
}
}Tipp: Teste deine Headers mit securityheaders.com — Ziel ist mindestens ein A-Rating.
Gzip-Kompression aktivieren
Gzip reduziert die Größe von Textdateien (HTML, CSS, JS) um 60-80%. Das beschleunigt die Ladezeit massiv. Bearbeite die Hauptkonfiguration:
sudo nano /etc/nginx/nginx.confFüge im http-Block hinzu (oder entkommentiere vorhandene Zeilen):
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
application/xml+rss
image/svg+xml
font/woff2;Erklärung:
gzip_comp_level 5— Guter Kompromiss zwischen CPU-Last und Kompression (1-9 möglich)gzip_min_length 256— Dateien unter 256 Bytes werden nicht komprimiert (Overhead wäre größer als der Gewinn)gzip_vary on— Setzt denVary: Accept-EncodingHeader für korrektes Caching
Logs verstehen — access.log und error.log
Nginx schreibt standardmäßig zwei Log-Dateien:
/var/log/nginx/access.log— Jeder Request wird hier protokolliert (IP, URL, Status-Code, User-Agent)/var/log/nginx/error.log— Fehlermeldungen und Warnungen
Nützliche Befehle für die Log-Analyse:
# Live-Logs verfolgen
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
# Die 10 häufigsten IP-Adressen
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# Alle 404-Fehler finden
sudo awk '$9 == 404' /var/log/nginx/access.log
# Requests pro Stunde zählen
sudo awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-2 | sort | uniq -cDu kannst auch eigene Log-Formate pro Server-Block definieren:
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;Tipp: Logrotate ist auf Debian standardmäßig für Nginx konfiguriert (/etc/logrotate.d/nginx). Die Logs werden automatisch rotiert und komprimiert.
Konfiguration testen und Nginx neu laden
Die wichtigsten Befehle für den Alltag mit Nginx:
# Konfiguration auf Syntaxfehler prüfen (IMMER vor reload!)
sudo nginx -t
# Nginx neu laden (ohne Downtime — bevorzugt)
sudo systemctl reload nginx
# Nginx komplett neu starten (kurze Unterbrechung)
sudo systemctl restart nginx
# Nginx stoppen
sudo systemctl stop nginx
# Nginx starten
sudo systemctl start nginx
# Status prüfen
sudo systemctl status nginx
# Nginx beim Boot automatisch starten
sudo systemctl enable nginxGoldene Regel: Führe sudo nginx -t immer vor reload oder restart aus. Ein Syntaxfehler in der Konfiguration würde Nginx sonst nicht starten und deine Seiten wären offline.
PHP mit Nginx (PHP-FPM)
Nginx kann von Haus aus kein PHP ausführen — anders als Apache mit mod_php. Stattdessen nutzt Nginx PHP-FPM (FastCGI Process Manager), einen eigenständigen PHP-Prozess, der Anfragen über das FastCGI-Protokoll entgegennimmt. Das hat handfeste Vorteile:
- Bessere Performance — PHP-FPM läuft als eigener Daemon mit Worker-Pools, unabhängig von Nginx
- Geringerer Speicherverbrauch — Nginx bedient statische Dateien direkt, nur PHP-Requests gehen an FPM
- Bessere Skalierbarkeit — PHP-FPM Pools können pro Anwendung konfiguriert werden
- Sicherheit — Nginx und PHP laufen als getrennte Prozesse mit eigenen Berechtigungen
PHP-FPM installieren
Debian 13 (Trixie) liefert PHP 8.4 in den offiziellen Repositories. Installiere PHP-FPM zusammen mit den wichtigsten Erweiterungen:
sudo apt install php-fpm php-mysql php-xml php-mbstring php-curl php-zip php-gd php-intl -yPrüfe die installierte Version und den Status des FPM-Dienstes:
php -v
sudo systemctl status php8.4-fpmDie Ausgabe sollte PHP 8.4.x zeigen und der Dienst als active (running) gemeldet werden. PHP-FPM erstellt automatisch einen Unix-Socket unter /run/php/php8.4-fpm.sock, über den Nginx die Anfragen weiterleitet.
Nginx für PHP konfigurieren
Damit Nginx PHP-Dateien an PHP-FPM weiterleitet, musst du einen location-Block in deiner Server-Konfiguration ergänzen. Öffne die Config deiner Seite:
sudo nano /etc/nginx/sites-available/example.comFüge innerhalb des server { }-Blocks folgenden PHP-Location-Block hinzu:
server {
listen 80;
server_name example.com;
root /var/www/example.com/html;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
# PHP-Dateien an PHP-FPM weiterleiten
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
# Zusätzliche FastCGI-Parameter
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Zugriff auf .htaccess und versteckte Dateien blockieren
location ~ /\.ht {
deny all;
}
}Die wichtigsten Direktiven erklärt:
location ~ \.php$— Fängt alle Anfragen an.php-Dateien ab (Regex-Match)include snippets/fastcgi-php.conf— Lädt Debians Standard-FastCGI-Konfiguration (prüft ob die Datei existiert, setztPATH_INFOetc.)fastcgi_pass unix:/run/php/php8.4-fpm.sock— Leitet die Anfrage an den PHP-FPM Unix-Socket weiterSCRIPT_FILENAME— Teilt PHP-FPM mit, welche Datei ausgeführt werden soll
Teste die Konfiguration und lade Nginx neu:
sudo nginx -t
sudo systemctl reload nginxPHP testen mit phpinfo()
Erstelle eine Test-Datei, um zu prüfen, ob PHP korrekt funktioniert:
echo '<?php phpinfo(); ?>' | sudo tee /var/www/example.com/html/info.phpRufe http://example.com/info.php im Browser auf. Du solltest die vollständige PHP-Informationsseite sehen — mit PHP-Version, geladenen Modulen und Konfiguration.
⚠️ Wichtig: Lösche die Datei nach dem Test sofort wieder! phpinfo() zeigt sensible Server-Informationen an, die ein Angreifer nutzen könnte.
sudo rm /var/www/example.com/html/info.phpPHP-FPM Pool-Konfiguration
PHP-FPM organisiert seine Worker-Prozesse in Pools. Der Standard-Pool heißt www und wird unter /etc/php/8.4/fpm/pool.d/www.conf konfiguriert:
sudo nano /etc/php/8.4/fpm/pool.d/www.confDie wichtigsten Einstellungen:
[www]
; Benutzer und Gruppe, unter der PHP-FPM läuft
user = www-data
group = www-data
; Socket-Pfad (muss zum Nginx fastcgi_pass passen!)
listen = /run/php/php8.4-fpm.sock
; Process Manager Modus:
; - static: Feste Anzahl Worker (gut für dedizierte Server)
; - dynamic: Skaliert zwischen min/max (Standard, empfohlen)
; - ondemand: Startet Worker nur bei Bedarf (gut für wenig Traffic)
pm = dynamic
; Maximale Anzahl gleichzeitiger Worker-Prozesse
pm.max_children = 10
; Worker die beim Start erstellt werden
pm.start_servers = 3
; Minimum an idle Workern
pm.min_spare_servers = 2
; Maximum an idle Workern
pm.max_spare_servers = 5
; Nach X Requests wird ein Worker neu gestartet (gegen Memory Leaks)
pm.max_requests = 500Für einen kleinen VPS mit 1–2 GB RAM sind die Standardwerte meist ausreichend. Bei mehr Traffic oder größeren Anwendungen (WordPress, Laravel) solltest du pm.max_children an den verfügbaren RAM anpassen. Faustregel: Verfügbarer RAM / durchschnittlicher PHP-Prozess-Speicher (typisch 30–50 MB pro Prozess).
Nach Änderungen PHP-FPM neu starten:
sudo systemctl restart php8.4-fpmWichtige php.ini-Einstellungen
Die PHP-Konfiguration für FPM findest du unter /etc/php/8.4/fpm/php.ini. Einige Einstellungen solltest du je nach Anwendungsfall anpassen:
sudo nano /etc/php/8.4/fpm/php.iniWichtige Werte:
; Maximale Upload-Größe (Standard: 2M — für WordPress/CMS deutlich erhöhen)
upload_max_filesize = 64M
; Maximale POST-Größe (muss >= upload_max_filesize sein)
post_max_size = 64M
; Speicherlimit pro PHP-Prozess
memory_limit = 256M
; Maximale Ausführungszeit in Sekunden (für lange Imports/Backups erhöhen)
max_execution_time = 300
; Maximale Input-Zeit
max_input_time = 300
; Zeitzone setzen
date.timezone = Europe/BerlinNach Änderungen an der php.ini muss PHP-FPM neu gestartet werden:
sudo systemctl restart php8.4-fpmSicherheit: cgi.fix_pathinfo
Eine wichtige Sicherheitseinstellung betrifft cgi.fix_pathinfo. Standardmäßig steht dieser Wert auf 1, was dazu führen kann, dass PHP-FPM auch Dateien ausführt, die keine PHP-Dateien sind — ein potenzielles Sicherheitsrisiko.
Öffne die php.ini und setze:
; Sicherheit: Verhindert, dass PHP beliebige Dateien als PHP interpretiert
; MUSS auf 0 stehen, wenn Nginx mit try_files arbeitet
cgi.fix_pathinfo = 0In Kombination mit dem snippets/fastcgi-php.conf von Debian (das try_files nutzt) ist dein Setup damit gegen Path-Traversal-Angriffe auf PHP geschützt.
sudo systemctl restart php8.4-fpmTroubleshooting — Häufige Probleme und Lösungen
Port 80 ist bereits belegt
sudo ss -tlnp | grep :80Falls Apache oder ein anderer Dienst Port 80 nutzt, stoppe ihn oder ändere den Port.
403 Forbidden
Häufige Ursachen:
- Falsche Dateiberechtigungen:
sudo chown -R www-data:www-data /var/www/example.com - Kein
index.htmlvorhanden undautoindexist deaktiviert - SELinux oder AppArmor blockiert den Zugriff
502 Bad Gateway
Tritt auf, wenn Nginx als Reverse Proxy konfiguriert ist, aber das Backend nicht erreichbar ist. Prüfe:
- Läuft der Backend-Dienst? (
sudo systemctl status dein-dienst) - Stimmt der
proxy_pass-Port? - Prüfe
/var/log/nginx/error.logfür Details
Konfigurationsänderungen greifen nicht
- Hast du
sudo nginx -tundsudo systemctl reload nginxausgeführt? - Ist der Server-Block in
sites-enabled/verlinkt? - Browser-Cache leeren (oder mit
curl -Itesten)
nginx -t zeigt Fehler
Die Fehlermeldung von sudo nginx -t ist meist sehr hilfreich — sie zeigt die Datei und Zeilennummer. Häufige Fehler:
- Fehlende Semikolons am Zeilenende
- Geschweifte Klammern nicht geschlossen
- Doppelte
server_name-Einträge in verschiedenen Blöcken
Zusammenfassung & Checkliste
Du hast jetzt einen vollständig konfigurierten Nginx-Webserver auf Debian 13. Hier die Checkliste:
- ✅ Nginx installiert und gestartet
- ✅ Verzeichnisstruktur verstanden (sites-available → sites-enabled)
- ✅ Eigenen Server-Block erstellt
- ✅ Statische Website gehostet
- ✅ Wichtige Direktiven kennengelernt
- ✅ Security Headers konfiguriert
- ✅ Gzip-Kompression aktiviert
- ✅ Logs verstanden und analysiert
- ✅ nginx -t als Gewohnheit etabliert
Wie geht es weiter?
Dein Webserver läuft — aber ohne HTTPS ist er noch nicht produktionsreif. Im nächsten Tutorial richten wir kostenlose SSL-Zertifikate mit Let’s Encrypt ein, damit deine Seiten verschlüsselt und vertrauenswürdig sind.
Außerdem werden wir Nginx später als Reverse Proxy nutzen, um Docker-Container, Node.js-Apps und andere Dienste sicher hinter Nginx zu betreiben.
Schreibe einen Kommentar