# Production nginx Config for React SPA + PocketBase ## Full Pattern ```nginx server { listen 443 ssl; server_name your-domain.com; ssl_certificate /etc/letsencrypt/live/your-domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your-domain/privkey.pem; root /path/to/spa/dist; index index.html; # SPA routing — all paths fall back to index.html location / { try_files $uri $uri/ /index.html; } # PocketBase SDK proxy (client uses /pb as base URL) location /pb/ { proxy_pass http://127.0.0.1:8091/; proxy_http_version 1.1; 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; } # PocketBase REST API proxy location /api/ { proxy_pass http://127.0.0.1:8091/api/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # DeepSeek AI API proxy location /deepseek/ { proxy_pass https://api.deepseek.com/; proxy_ssl_server_name on; proxy_set_header Host api.deepseek.com; proxy_set_header Authorization "Bearer sk-..."; proxy_buffering off; proxy_read_timeout 120s; } # Local LLM proxy (Ollama) location /llm/ { proxy_pass http://127.0.0.1:11434/; proxy_http_version 1.1; proxy_set_header Host "localhost"; proxy_buffering off; proxy_read_timeout 120s; } } ``` ## Key Details - **SPA routing**: `try_files $uri $uri/ /index.html;` is critical — without it, refreshing on a client-side route returns 404. - **PB proxy**: two locations (`/pb/` and `/api/`) — the PB JS SDK uses `/pb` as its base URL, but the SDK may also call `/api/` directly. - **SSL**: Use Let's Encrypt certbot — `sudo certbot --nginx -d your-domain.com`. - **Reload**: After editing, `sudo nginx -t && sudo systemctl reload nginx`. - **Dist path**: Point `root` at the Vite `dist/` folder, not the source.