Nginx powinien wystawiać wyłącznie public Laravela, przekazywać ścieżki aplikacji do index.php i odmawiać ukrytych plików oraz arbitralnego wykonania PHP. W nginx 1.25.1+ używaj http2 on;, nie listen ... http2.
server {
listen 443 ssl;
http2 on;
server_name example.com;
root /var/www/current/public;
index index.php;
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
location ~ /\. { deny all; }
}
Przed systemctl reload nginx uruchom nginx -t. TLS, redirecty i wartości FastCGI trzymaj w przejrzanych include'ach. Gdy TLS kończy się wyżej, skonfiguruj trusted proxies w Laravelu; forwarded header od klienta nie jest zaufany.
Reverse proxy i cache
WebSocket potrzebuje HTTP/1.1 oraz nagłówków upgrade. Cache'uj agresywnie niezmienne assety, ale nie zalogowany HTML, strony zależne od cookies ani odpowiedzi autoryzacji bez jawnego klucza i invalidacji.
location /app/ {
proxy_pass http://reverb:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
Pełny TLS, cache i limitowanie
Port 80 powinien tylko przekierowywać, zaś host TLS jest jedynym miejscem obsługi Laravela. $realpath_root rozwiązuje symlink wydania przed przekazaniem skryptu do PHP-FPM.
server { listen 80; server_name example.com; return 301 https://$host$request_uri; }
server {
listen 443 ssl;
http2 on;
server_name example.com;
root /var/www/current/public;
index index.php;
client_max_body_size 20m;
add_header X-Content-Type-Options nosniff always;
location / { try_files $uri $uri/ /index.php?$query_string; }
location ~ \\.php$ { try_files $uri =404; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_pass unix:/run/php/php8.5-fpm.sock; }
location ~ /\\.(?!well-known).* { deny all; }
}
Cache'uj tylko assety z hashem URL, nie HTML zależny od cookies. limit_req stosuj na loginie; to nie zastępuje autoryzacji ani weryfikacji podpisu webhooka.
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;
location = /login { limit_req zone=login burst=10 nodelay; try_files $uri $uri/ /index.php?$query_string; }
sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/health
Kiedy tego NIE używać
Nie wklejaj tego do shared hostingu ani platformy zarządzającej Nginxem: użyj wspieranej integracji. Build obrazów Docker, lokalny cache i wdrożenie należą do osobnych przewodników, ponieważ ich awarie i rollback różnią się od produkcyjnego proxy.