server { listen 80; listen [::]:80; server_name _; root /var/www/html/public; index index.php; charset utf-8; # ── Laravel health check ────────────────────────────────── location = /up { access_log off; fastcgi_pass app:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } # ── Aset statik — cache jangka panjang ─────────────────── location ~* \.(css|js|ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot|webp)$ { expires 1y; add_header Cache-Control "public, immutable"; access_log off; try_files $uri =404; } # ── Fail awam (storage/app/public) ──────────────────────── # Nota: laporan PDF disimpan di storage/app/private dan HANYA # boleh dimuat turun melalui laluan Laravel terlindung polisi. location /storage/ { alias /var/www/html/storage/app/public/; expires 30d; add_header Cache-Control "public"; access_log off; try_files $uri =404; } # ── Semua permintaan lain → Laravel ────────────────────── location / { try_files $uri $uri/ /index.php?$query_string; } # ── PHP-FPM ─────────────────────────────────────────────── location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass app:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param PHP_VALUE "upload_max_filesize=25M \n post_max_size=30M"; include fastcgi_params; fastcgi_connect_timeout 60s; fastcgi_send_timeout 300s; fastcgi_read_timeout 300s; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; } # ── Sekat fail tersembunyi/dot ──────────────────────────── location ~ /\.(?!well-known).* { deny all; access_log off; log_not_found off; } # ── Sekat fail sensitif ─────────────────────────────────── location ~* \.(env|log|git|gitignore|md|lock|json|yaml|yml)$ { deny all; access_log off; log_not_found off; } error_page 404 /index.php; error_page 500 502 503 504 /index.php; }