server { # Listen on port 80 for incoming HTTP requests. # Allow large file uploads (e.g., for flyers). This must be set here to prevent Nginx from rejecting large requests before they reach the Node.js backend. client_max_body_size 100M; # The root directory where your built application files are located. # This matches the destination in your rsync command. root /var/www/flyer-crawler.projectium.com; # The default file to serve if a directory is requested. index index.html; # The domain name this configuration applies to. server_name flyer-crawler.projectium.com; # Deny access to all dotfiles location ~ /\. { deny all; return 404; } location / { # This is the crucial part for a Single-Page Application (SPA). # 1. It first tries to serve the requested file ($uri). # 2. If it's a directory, it tries to serve the directory ($uri/). # 3. If neither exists, it falls back to serving /index.html. # This allows your React Router to handle the URL on the client-side. try_files $uri $uri/ /index.html; } # This new block is the reverse proxy for your backend API. # It tells Nginx that any request starting with /api/ should be # forwarded to your Node.js server running on port 3001. location /api/ { # Increase timeouts for long-running API requests, like AI processing. # The default is 60s, which is often too short for AI image analysis. # We'll set it to 300s (5 minutes) to be safe. proxy_connect_timeout 300s; proxy_send_timeout 300s; proxy_read_timeout 300s; # The trailing slash on the proxy_pass URL is crucial. # It tells Nginx to strip the `/api/` prefix from the request URI # before passing it to the backend server. proxy_pass http://localhost:3001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } # This block specifically targets requests for .mjs files. location ~ \.mjs$ { # It ensures that these files are served with the correct JavaScript MIME type. # The 'include' directive pulls in the standard MIME types, # and 'default_type' ensures our target type is set. include /etc/nginx/mime.types; default_type application/javascript; } # Optional: Add headers to improve security and prevent clickjacking. add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/flyer-crawler.projectium.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/flyer-crawler.projectium.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = flyer-crawler.projectium.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name flyer-crawler.projectium.com; return 404; # managed by Certbot }