Zum Inhalt springen
DevOps

Nginx vs Apache - Produktive Webserver-Konfiguration

Veröffentlicht am:
·4 Min. Lesezeit·Autor: MDS Software Solutions Group

Nginx Apache Produktive

devops

Nginx vs Apache - Produktive Webserver-Konfiguration

Die Wahl des richtigen Webservers ist eine der wichtigsten Infrastrukturentscheidungen in jedem Webprojekt. Nginx und Apache dominieren den Markt seit Jahren, unterscheiden sich aber grundlegend in ihrer Architektur, der Verarbeitung von Anfragen und den Szenarien, in denen sie jeweils ihre Staerken ausspielen. In diesem Artikel bieten wir einen umfassenden Vergleich beider Server, praesentieren produktionsreife Konfigurationen, Performance-Optimierungen und Empfehlungen, wann welcher Server die bessere Wahl ist.

Architektur - Event-Driven vs Process-Based#

Der fundamentale Unterschied zwischen Nginx und Apache liegt in der Art und Weise, wie eingehende Verbindungen verarbeitet werden. Das Verstaendnis dieses Unterschieds ist entscheidend fuer eine korrekte Produktionskonfiguration.

Nginx - Event-Driven-Architektur#

Nginx verwendet ein asynchrones, ereignisgesteuertes Modell zur Verbindungsverarbeitung. Ein einzelner Worker-Prozess kann dank nicht-blockierender I/O und einer Event-Schleife (epoll unter Linux, kqueue unter BSD) Tausende gleichzeitiger Verbindungen verarbeiten.

# /etc/nginx/nginx.conf - Hauptkonfiguration
user www-data;
worker_processes auto;          # Ein Worker pro CPU-Kern
worker_rlimit_nofile 65535;     # Limit fuer offene Dateideskriptoren
pid /run/nginx.pid;

events {
    worker_connections 4096;    # Verbindungen pro Worker
    multi_accept on;            # Mehrere Verbindungen gleichzeitig akzeptieren
    use epoll;                  # Event-Mechanismus unter Linux
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;          # Serverversion verbergen

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # Protokollierung
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

In diesem Modell kann ein einzelner Worker-Prozess mit 4096 Verbindungen bei 4 CPU-Kernen theoretisch bis zu 16.384 gleichzeitige Verbindungen verarbeiten - ohne einen neuen Prozess oder Thread fuer jede Anfrage zu erstellen.

Apache - Process/Thread-basierte Architektur#

Apache verwendet traditionell das Prefork-Modell (ein separater Prozess pro Anfrage) oder Worker/Event MPM (eine Kombination aus Prozessen und Threads). In modernen Installationen wird das Event MPM empfohlen:

# /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
    StartServers             4
    MinSpareThreads          25
    MaxSpareThreads          75
    ThreadLimit              64
    ThreadsPerChild          25
    MaxRequestWorkers        400
    MaxConnectionsPerChild   10000
    ServerLimit              16
</IfModule>

Apache mit Event MPM ist deutlich effizienter als Prefork, benoetigt aber immer noch mehr Ressourcen pro Verbindung als Nginx. Jeder MaxRequestWorkers-Slot entspricht einer gleichzeitig bedienten Anfrage.

Nginx als Reverse Proxy#

Nginx wird am haeufigsten als Reverse Proxy vor Anwendungsservern eingesetzt. Hier ist eine vollstaendige Produktionskonfiguration:

# /etc/nginx/sites-available/app.conf
upstream backend_app {
    least_conn;                              # Load Balancing - wenigste Verbindungen
    server 127.0.0.1:3000 weight=3;          # Primaere Instanz
    server 127.0.0.1:3001 weight=2;          # Sekundaere Instanz
    server 127.0.0.1:3002 backup;            # Backup - nur wenn Primaere ausfallen

    keepalive 32;                            # Keep-Alive-Verbindungspool
}

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

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # SSL - Konfiguration unten
    include /etc/nginx/snippets/ssl-params.conf;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # Anfrage-Body-Groesse
    client_max_body_size 64M;
    client_body_buffer_size 128k;

    # Proxy zum Backend
    location / {
        proxy_pass http://backend_app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Proxy-Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;

        # Pufferung
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }

    # Statische Dateien direkt ueber Nginx
    location /static/ {
        alias /var/www/app/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    location /_next/static/ {
        alias /var/www/app/.next/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}

Apache - Virtual Hosts und .htaccess#

Apache bietet ein leistungsstarkes Konfigurationssystem basierend auf Virtual Hosts und .htaccess-Dateien:

# /etc/apache2/sites-available/app.conf
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/app/public

    # SSL
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    # Protokollierung
    ErrorLog ${APACHE_LOG_DIR}/app-error.log
    CustomLog ${APACHE_LOG_DIR}/app-access.log combined

    # Dokumentenstamm-Verzeichnis
    <Directory /var/www/app/public>
        AllowOverride All
        Require all granted
        Options -Indexes +FollowSymLinks
    </Directory>

    # Proxy zu Node.js / Next.js
    ProxyPreserveHost On
    ProxyPass /api http://127.0.0.1:3000/api
    ProxyPassReverse /api http://127.0.0.1:3000/api

    # Statische Dateien
    <LocationMatch "^/static/">
        ExpiresActive On
        ExpiresDefault "access plus 1 year"
        Header set Cache-Control "public, immutable"
    </LocationMatch>

    # Sicherheits-Header
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-XSS-Protection "1; mode=block"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</VirtualHost>

Die .htaccess-Datei fuer eine PHP/Laravel-Anwendung:

# /var/www/app/public/.htaccess
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    # Weiterleitung auf HTTPS
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

    # Trailing Slash entfernen
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Front Controller - Laravel
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

# Kompression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/css
    AddOutputFilterByType DEFLATE text/javascript application/javascript
    AddOutputFilterByType DEFLATE application/json application/xml
    AddOutputFilterByType DEFLATE image/svg+xml
</IfModule>

# Browser-Caching
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
    ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

SSL/TLS mit Let's Encrypt#

Die SSL-Konfiguration ist sowohl fuer die Sicherheit als auch fuer SEO entscheidend. Hier sind die optimalen Einstellungen fuer beide Server.

Nginx - SSL-Snippet#

# /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# SSL-Sitzungen
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;

# HSTS - Strict Transport Security
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

# Diffie-Hellman-Parameter
ssl_dhparam /etc/nginx/dhparam.pem;

DH-Parameter generieren:

openssl dhparam -out /etc/nginx/dhparam.pem 4096

Automatische Zertifikatserneuerung#

# Certbot mit automatischer Erneuerung
sudo certbot --nginx -d example.com -d www.example.com

# Crontab - alle 12 Stunden erneuern
0 */12 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"

PHP-FPM - Konfiguration fuer Nginx und Apache#

PHP-FPM (FastCGI Process Manager) ist die empfohlene Methode zum Ausfuehren von PHP sowohl mit Nginx als auch mit Apache.

PHP-FPM-Pool-Konfiguration#

; /etc/php/8.3/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data

; UNIX-Socket - schneller als TCP
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data

; Prozessverwaltung
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 1000

; Slow-Log zum Debuggen
slowlog = /var/log/php-fpm/slow.log
request_slowlog_timeout = 5s

; Limits
request_terminate_timeout = 120s
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M

; OPcache
php_admin_value[opcache.enable] = 1
php_admin_value[opcache.memory_consumption] = 256
php_admin_value[opcache.max_accelerated_files] = 20000
php_admin_value[opcache.validate_timestamps] = 0

Nginx mit PHP-FPM#

server {
    listen 443 ssl http2;
    server_name laravel-app.com;
    root /var/www/laravel/public;
    index index.php;

    include /etc/nginx/snippets/ssl-params.conf;
    ssl_certificate /etc/letsencrypt/live/laravel-app.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/laravel-app.com/privkey.pem;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;

        # FastCGI-Pufferung
        fastcgi_buffering on;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 16 16k;

        # Timeouts
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 120;
        fastcgi_read_timeout 120;
    }

    # Zugriff auf versteckte Dateien blockieren
    location ~ /\.(?!well-known) {
        deny all;
    }

    # Zugriff auf sensible Dateien blockieren
    location ~* \.(env|log|git|sql|bak)$ {
        deny all;
        return 404;
    }
}

Apache mit PHP-FPM#

<VirtualHost *:443>
    ServerName laravel-app.com
    DocumentRoot /var/www/laravel/public

    # PHP-FPM ueber Proxy
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
    </FilesMatch>

    <Directory /var/www/laravel/public>
        AllowOverride All
        Require all granted
        Options -Indexes
    </Directory>

    # Zugriff auf versteckte Dateien blockieren
    <DirectoryMatch "/\.">
        Require all denied
    </DirectoryMatch>
</VirtualHost>

Load Balancing#

Nginx - Erweitertes Load Balancing#

upstream php_backend {
    # Algorithmus - ip_hash sorgt fuer Sticky Sessions
    ip_hash;

    server 10.0.0.10:9000 weight=5 max_fails=3 fail_timeout=30s;
    server 10.0.0.11:9000 weight=3 max_fails=3 fail_timeout=30s;
    server 10.0.0.12:9000 weight=2 max_fails=3 fail_timeout=30s;
    server 10.0.0.13:9000 backup;

    keepalive 64;
}

upstream node_backend {
    least_conn;

    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;

    keepalive 32;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    location /api/ {
        proxy_pass http://php_backend;
        proxy_next_upstream error timeout http_500 http_502 http_503;
        proxy_next_upstream_tries 3;
    }

    location / {
        proxy_pass http://node_backend;
        proxy_next_upstream error timeout http_502;
    }
}

Apache - mod_proxy_balancer#

<Proxy "balancer://app_cluster">
    BalancerMember "http://10.0.0.10:8080" route=node1 loadfactor=5
    BalancerMember "http://10.0.0.11:8080" route=node2 loadfactor=3
    BalancerMember "http://10.0.0.12:8080" route=node3 loadfactor=2 status=+H
    ProxySet lbmethod=byrequests stickysession=JSESSIONID
</Proxy>

<VirtualHost *:443>
    ServerName app.example.com

    ProxyPreserveHost On
    ProxyPass / "balancer://app_cluster/"
    ProxyPassReverse / "balancer://app_cluster/"

    # Load-Balancer-Verwaltungspanel
    <Location "/balancer-manager">
        SetHandler balancer-manager
        Require ip 10.0.0.0/8
    </Location>
</VirtualHost>

Caching-Konfiguration#

Nginx - FastCGI Cache und Proxy Cache#

# Cache-Zonendefinition (im http-Block)
fastcgi_cache_path /var/cache/nginx/fastcgi
    levels=1:2
    keys_zone=PHPCACHE:100m
    max_size=2g
    inactive=60m
    use_temp_path=off;

proxy_cache_path /var/cache/nginx/proxy
    levels=1:2
    keys_zone=PROXYCACHE:100m
    max_size=5g
    inactive=24h
    use_temp_path=off;

server {
    # FastCGI-Cache fuer PHP
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        include fastcgi_params;

        fastcgi_cache PHPCACHE;
        fastcgi_cache_valid 200 301 302 60m;
        fastcgi_cache_valid 404 1m;
        fastcgi_cache_key "$scheme$request_method$host$request_uri";
        fastcgi_cache_use_stale error timeout updating http_500 http_503;
        fastcgi_cache_bypass $cookie_nocache $arg_nocache;

        add_header X-Cache-Status $upstream_cache_status;
    }

    # Proxy-Cache fuer oeffentliche API
    location /api/public/ {
        proxy_pass http://backend_app;
        proxy_cache PROXYCACHE;
        proxy_cache_valid 200 10m;
        proxy_cache_key "$request_uri";
        add_header X-Cache-Status $upstream_cache_status;
    }
}

Apache - mod_cache#

# Cache-Module aktivieren
# a2enmod cache cache_disk headers

CacheQuickHandler off
CacheLock on
CacheLockPath /tmp/mod_cache-lock
CacheLockMaxAge 5

<VirtualHost *:443>
    CacheEnable disk /
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheDefaultExpire 3600
    CacheMaxExpire 86400
    CacheIgnoreNoLastMod On

    # Admin-Panel nicht cachen
    CacheDisable /admin
    CacheDisable /api/auth

    # Cache-Header
    <LocationMatch "^/static/">
        Header set Cache-Control "public, max-age=31536000, immutable"
    </LocationMatch>
</VirtualHost>

Gzip- und Brotli-Kompression#

Nginx#

# Gzip
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;

# Brotli (erfordert ngx_brotli-Modul)
brotli on;
brotli_comp_level 6;
brotli_static on;          # Vorkomprimierte .br-Dateien ausliefern
brotli_types
    text/plain
    text/css
    text/javascript
    application/javascript
    application/json
    application/xml
    image/svg+xml
    font/woff2;

Apache#

# mod_deflate (gzip)
<IfModule mod_deflate.c>
    SetOutputFilter DEFLATE
    DeflateCompressionLevel 5

    AddOutputFilterByType DEFLATE text/html text/plain text/css
    AddOutputFilterByType DEFLATE text/javascript application/javascript
    AddOutputFilterByType DEFLATE application/json application/xml
    AddOutputFilterByType DEFLATE image/svg+xml font/woff2

    # Bereits komprimierte Dateien nicht komprimieren
    SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|webp|gz|zip|br)$ no-gzip
</IfModule>

# Brotli (erfordert mod_brotli - Apache 2.4.26+)
<IfModule mod_brotli.c>
    AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css
    AddOutputFilterByType BROTLI_COMPRESS text/javascript application/javascript
    AddOutputFilterByType BROTLI_COMPRESS application/json application/xml
    BrotliCompressionQuality 5
</IfModule>

Sicherheits-Header#

Nginx - Vollstaendige Security-Headers-Konfiguration#

# /etc/nginx/snippets/security-headers.conf
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' https://api.example.com;" always;

# Header entfernen, die den Technologie-Stack verraten
proxy_hide_header X-Powered-By;
fastcgi_hide_header X-Powered-By;

Rate Limiting#

Nginx#

# Rate-Limiting-Zonendefinitionen (im http-Block)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    # Allgemeines Rate Limit fuer API
    location /api/ {
        limit_req zone=api burst=20 nodelay;
        limit_req_status 429;
        proxy_pass http://backend_app;
    }

    # Strenges Rate Limit fuer Login
    location /api/auth/login {
        limit_req zone=login burst=3 nodelay;
        limit_req_status 429;
        proxy_pass http://backend_app;
    }

    # Gleichzeitige Verbindungsbegrenzung
    location /downloads/ {
        limit_conn addr 5;
        limit_rate 1m;          # 1MB/s pro Verbindung
        alias /var/www/downloads/;
    }
}

Apache - mod_ratelimit und mod_evasive#

# mod_ratelimit - Bandbreitenbegrenzung
<Location "/downloads">
    SetOutputFilter RATE_LIMIT
    SetEnv rate-limit 1024       # 1024 KB/s
</Location>

# mod_evasive - DDoS-Schutz
<IfModule mod_evasive20.c>
    DOSHashTableSize 3097
    DOSPageCount 5               # Max. 5 Anfragen pro Seite/s
    DOSSiteCount 50              # Max. 50 Anfragen pro Website/s
    DOSPageInterval 1
    DOSSiteInterval 1
    DOSBlockingPeriod 60         # 60s sperren
    DOSEmailNotify admin@example.com
</IfModule>

WebSocket-Proxying#

Nginx#

# Map fuer WebSocket-Upgrade-Verarbeitung
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    location /ws/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # WebSocket-Timeout (laenger als Standard)
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

Apache#

# Erforderliche Module: mod_proxy_wstunnel
# a2enmod proxy_wstunnel

<VirtualHost *:443>
    # WebSocket-Proxy
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /ws/(.*) ws://127.0.0.1:3000/ws/$1 [P,L]

    ProxyPass /ws/ ws://127.0.0.1:3000/ws/
    ProxyPassReverse /ws/ ws://127.0.0.1:3000/ws/

    # WebSocket-Timeout
    ProxyTimeout 3600
</VirtualHost>

Performance-Vergleich#

Im Folgenden praesentieren wir typische Benchmark-Ergebnisse fuer beide Server in verschiedenen Szenarien:

| Metrik | Nginx | Apache (Event MPM) | |--------|-------|---------------------| | Statische Dateien (Req/s) | ~25.000 | ~10.000 | | Reverse Proxy (Req/s) | ~18.000 | ~8.000 | | PHP-FPM (Req/s) | ~3.500 | ~3.200 | | RAM-Verbrauch (1.000 Verb.) | ~50 MB | ~200 MB | | RAM-Verbrauch (10.000 Verb.) | ~80 MB | ~1,5 GB | | Antwortzeit p99 | ~2 ms | ~8 ms | | Max. gleichzeitige Verbindungen | ~100.000+ | ~10.000 |

Nginx dominiert in Szenarien mit vielen gleichzeitigen Verbindungen und beim Ausliefern statischer Dateien. Bei dynamischen PHP-FPM-Anfragen verringert sich der Abstand, da PHP selbst zum Flaschenhals wird.

Nginx fuer Next.js / Node.js#

# Produktive Nginx-Konfiguration fuer Next.js
upstream nextjs {
    server 127.0.0.1:3000;
    keepalive 64;
}

server {
    listen 443 ssl http2;
    server_name app.example.com;

    include /etc/nginx/snippets/ssl-params.conf;
    include /etc/nginx/snippets/security-headers.conf;

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

    # Next.js statische Assets - aggressives Caching
    location /_next/static/ {
        proxy_pass http://nextjs;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Next.js Bildoptimierung
    location /_next/image {
        proxy_pass http://nextjs;
        proxy_cache PROXYCACHE;
        proxy_cache_valid 200 24h;
        proxy_cache_key "$request_uri";
    }

    # Oeffentliche Assets
    location /public/ {
        alias /var/www/app/public/;
        expires 30d;
        add_header Cache-Control "public";
        access_log off;
    }

    # Alles andere an Next.js weiterleiten
    location / {
        proxy_pass http://nextjs;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Apache fuer PHP / Laravel#

# Produktive Apache-Konfiguration fuer Laravel
<VirtualHost *:443>
    ServerName laravel.example.com
    DocumentRoot /var/www/laravel/public

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/laravel.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/laravel.example.com/privkey.pem

    # PHP-FPM
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
    </FilesMatch>

    # Dokumentenstamm
    <Directory /var/www/laravel/public>
        AllowOverride All
        Require all granted
        Options -Indexes +FollowSymLinks -MultiViews
    </Directory>

    # Zugriff auf sensible Verzeichnisse blockieren
    <DirectoryMatch "^/var/www/laravel/(storage|vendor|bootstrap/cache)">
        Require all denied
    </DirectoryMatch>

    # .env-Dateien blockieren
    <FilesMatch "^\.env">
        Require all denied
    </FilesMatch>

    # Sicherheits-Header
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

    # Kompression
    SetOutputFilter DEFLATE
    AddOutputFilterByType DEFLATE text/html text/css application/javascript application/json

    # Protokollierung
    ErrorLog ${APACHE_LOG_DIR}/laravel-error.log
    CustomLog ${APACHE_LOG_DIR}/laravel-access.log combined
</VirtualHost>

Wann Nginx und wann Apache waehlen?#

Waehlen Sie Nginx wenn:#

  • Sie eine Node.js- / Next.js-Anwendung entwickeln - Nginx ist der natuerliche Reverse Proxy fuer Node-Anwendungen
  • Viele gleichzeitige Verbindungen benoetigt werden - WebSocket, SSE, Long Polling
  • Viele statische Dateien ausgeliefert werden - Nginx ist deutlich effizienter
  • Load Balancing - integrierte Load-Balancing-Algorithmen sind flexibel und performant
  • Microservices - als API-Gateway mit Routing zu mehreren Backends
  • Begrenzte Ressourcen - geringerer RAM- und CPU-Verbrauch
  • Containerisierung (Docker/K8s) - kleinerer Footprint, schnellerer Start

Waehlen Sie Apache wenn:#

  • Shared Hosting - .htaccess ermoeglicht verzeichnisbasierte Konfiguration ohne Server-Neustart
  • PHP/Laravel-Anwendungen - native Integration mit mod_php (obwohl PHP-FPM empfohlen wird)
  • Dynamische Konfiguration erforderlich - .htaccess ermoeglicht Aenderungen ohne Neustart
  • Komplexe Rewrite-Regeln - mod_rewrite ist umfangreicher
  • Mehrere Websites auf einem Server - Konfigurationsisolierung durch .htaccess
  • Bestehende Infrastruktur - die Migration von Apache zu Nginx ist nicht immer kosteneffizient

Hybridloesung#

In vielen Produktionsumgebungen ist die Kombination beider Server die beste Loesung:

Client -> Nginx (Reverse Proxy, SSL, Cache, statische Dateien)
            |-- Node.js / Next.js (Port 3000)
            |-- Apache + PHP-FPM (Port 8080)
            |-- Andere Microservices

Nginx dient als Frontend-Proxy und uebernimmt SSL-Terminierung, Kompression, Caching und statische Dateien, waehrend Apache PHP-Anwendungen mit der vollen Leistungsfaehigkeit von .htaccess und mod_rewrite verarbeitet.

Fazit#

Sowohl Nginx als auch Apache sind ausgereifte, zuverlaessige Webserver. Nginx dominiert in Szenarien, die hohe Leistung, eine grosse Anzahl gleichzeitiger Verbindungen und Reverse-Proxy-Workloads erfordern. Apache bietet groessere Konfigurationsflexibilitaet und bleibt die traditionelle Wahl fuer PHP-Anwendungen. In modernen Architekturen ist der Einsatz von Nginx als Frontend-Proxy mit Apache als PHP-Backend ein bewaehrter Ansatz, der die Staerken beider Server vereint.


Benoetigst du eine professionelle Webserver-Konfiguration? Das Team von MDS Software Solutions Group ist auf die Optimierung von Web-Infrastruktur spezialisiert. Von der Nginx- und Apache-Konfiguration ueber CI/CD-Deployments bis hin zur Skalierung von Cloud-Anwendungen - wir helfen dir, eine leistungsfaehige und sichere Infrastruktur aufzubauen. Kontaktiere uns, um dein Projekt zu besprechen.

Autor
MDS Software Solutions Group

Team von Programmierexperten, die sich auf moderne Webtechnologien spezialisiert haben.

Nginx vs Apache - Produktive Webserver-Konfiguration | MDS Software Solutions Group | MDS Software Solutions Group