# deploy/nginx.conf
# Nginx virtual host for logistic.kapitano.shop
# Install to: /etc/nginx/conf.d/logistic.kapitano.shop.conf   (Alma/RHEL)
#
# Serving model: nginx + PHP-FPM (no Apache). Only the Laravel `public/` folder is the
# document root, so app/vendor/storage (except the public symlink) are unreachable by design.

# ------------------------------------------------------------------------------------
# HTTP -> HTTPS
# ------------------------------------------------------------------------------------
server {
    listen 80;
    server_name logistic.kapitano.shop;

    location /.well-known/acme-challenge/ {   # Let's Encrypt http-01 challenges
        allow all;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# ------------------------------------------------------------------------------------
# HTTPS server
# ------------------------------------------------------------------------------------
server {
    listen 443 ssl http2;
    server_name logistic.kapitano.shop;

    root /var/www/kapitano/api/public;
    index index.php;

    server_tokens off;
    etag on;

    # ------------------------------------------------------------------ TLS
    ssl_certificate     /etc/letsencrypt/live/logistic.kapitano.shop/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/logistic.kapitano.shop/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve X25519:secp384r1;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 24h;
    ssl_session_tickets off;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;  # add "preload" only after confirming readiness

    # ------------------------------------------------------------------ security headers
    # NOTE: an `add_header` inside a nested `location` replaces the server-level headers.
    # The static/cache locations below repeat the sensitive ones for that reason.
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;

    # ------------------------------------------------------------------ size + timeouts
    client_max_body_size 25m;        # covers the 5MB photo/profile licence multipart fields
    keepalive_timeout 65;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    open_file_cache max=1000 inactive=5m;
    open_file_cache_valid 2m;

    # ------------------------------------------------------------------ deny hidden/sensitive
    location ~ /\. { deny all; return 404; }

    # ------------------------------------------------------------------ front controller
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # ------------------------------------------------------------------ PHP
    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_pass unix:/run/php-fpm/kapitano.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param HTTPS on;
        fastcgi_read_timeout 120s;
        fastcgi_send_timeout 120s;
        fastcgi_connect_timeout 10s;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
    }

    # ------------------------------------------------------------------ served media (storage/public)
    location ^~ /storage/ {
        try_files $uri =404;
        add_header Cache-Control "public, max-age=2592000";      # 30 days
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    }

    # ------------------------------------------------------------------ versioned web assets
    location ~* \.(?:css|js|map|png|jpg|jpeg|gif|webp|avif|svg|ico|woff|woff2|ttf|eot|mp4|pdf)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header Referrer-Policy "strict-origin-when-cross-origin" always;
        try_files $uri =404;
    }

    # ------------------------------------------------------------------ gzip
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 1024;
    gzip_vary on;
    gzip_types
        text/plain
        text/css
        text/xml
        application/json
        application/javascript
        application/xml
        application/rss+xml
        application/xhtml+xml
        image/svg+xml
        font/woff
        font/woff2;

    # ------------------------------------------------------------------ brotli (optional)
    # Installed via: dnf install nginx-module-brotli   (EPEL)  -- then load at /etc/nginx/nginx.conf:
    #   load_module modules/ngx_http_brotli_filter_module.so;
    #   load_module modules/ngx_http_brotli_static_module.so;
    # brotli on;
    # brotli_comp_level 5;
    # brotli_static on;
    # brotli_types text/plain text/css application/json application/javascript application/xml image/svg+xml font/woff font/woff2;

    # ------------------------------------------------------------------ logging
    access_log /var/log/nginx/logistic-kapitano-shop.access.log;
    error_log  /var/log/nginx/logistic-kapitano-shop.error.log  warn;
}