Overview
Genie Helper uses Nginx as a reverse proxy to provide a seamless user experience without exposing internal ports or requiring users to remember multiple URLs. User-facing architecture:geniehelper.com/- React SPA (marketing, auth, dashboard)geniehelper.com/api/directus/- Directus API proxy (port 8055)geniehelper.com/api/llm/- AnythingLLM API + WebSocket proxy (port 3001)
cms.geniehelper.com- Directus admin panelagent.geniehelper.com- AnythingLLM admin UI
Plesk Setup
All Nginx configuration is managed via Plesk UI only. Direct editing of Nginx config files will be overwritten by Plesk.Critical Plesk Rules
-
NEVER add
location /- Plesk generates its ownlocation /for static file serving. Adding another causes: -
Safe location types:
- Sub-path locations:
location /api/llm/,location /app/ - Exact-match locations:
location = /exact-path - Regex locations:
location ~ /pattern/
- Sub-path locations:
-
SPA routing: Use
error_page 404 /index.html;for client-side routing -
WebSocket: Use literal
"upgrade"for Connection header, NOT$http_upgrade
Main Domain Configuration
Plesk Document Root Setup
Plesk > Domains > geniehelper.com > Hosting Settings-
Set Document root to:
-
This makes Plesk’s auto-generated
location /serve the built React SPA directly.
Additional Nginx Directives
Plesk > Domains > geniehelper.com > Apache & nginx Settings > Additional nginx directives Paste the following configuration:Testing the Configuration
Proxy Configuration Breakdown
SPA Fallback
- User navigates to
geniehelper.com/pricing - Nginx looks for file
dashboard/dist/pricing→ doesn’t exist - Instead of returning 404, returns
index.html - React Router loads and routes to
/pricingcomponent
Directus Proxy (/api/directus/)
proxy_pass: Strips/api/directus/prefix and forwards to Directus on port 8055X-Forwarded-*headers: Preserve client IP and protocol for Directus logsclient_max_body_size 100M: Allow media file uploadsproxy_read_timeout 120s: Prevent timeout on slow requests
- Browser:
GET https://geniehelper.com/api/directus/items/scraped_media - Nginx forwards to:
http://127.0.0.1:8055/items/scraped_media
AnythingLLM Proxy (/api/llm/)
UpgradeandConnection "upgrade"headers enable WebSocket connections- Required for streaming chat responses (SSE) and embed widget
"upgrade" for Connection header, NOT $http_upgrade:
- Correct:
Connection "upgrade" - Wrong:
Connection $http_upgrade(causes WebSocket failures in some cases)
proxy_buffering off: Required for streaming responsesproxy_read_timeout 300s: Long timeout for AI generation (5 minutes)client_max_body_size 3G: Allow large document uploads
- Browser:
GET https://geniehelper.com/api/llm/embed/anythingllm-chat-widget.min.js - Nginx forwards to:
http://127.0.0.1:3001/embed/anythingllm-chat-widget.min.js
Admin Subdomain Configuration (Optional)
CMS Admin Panel (cms.geniehelper.com)
Plesk > Domains > cms.geniehelper.com > Apache & nginx Settings > Additional nginx directives
- Visit
https://cms.geniehelper.com/open_sesameto unlock - Redirects to
/admin/(Directus panel) - Visit
https://cms.geniehelper.com/lock_sesameto lock
Agent Admin Panel (agent.geniehelper.com)
Plesk > Domains > agent.geniehelper.com > Apache & nginx Settings > Additional nginx directives
- Visit
https://agent.geniehelper.com/open_sesameto unlock - Redirects to
/chat/(AnythingLLM UI) - Visit
https://agent.geniehelper.com/lock_sesameto lock
SSL/TLS Configuration
Let’s Encrypt via Plesk
Plesk > Domains > geniehelper.com > SSL/TLS Certificates- Click Install next to Let’s Encrypt
- Enter email for renewal notifications
- Check Secure the domain name and Secure the www subdomain
- Click Get it free
- Certificate auto-renews via Plesk cron
cms.geniehelper.com and agent.geniehelper.com
Force HTTPS Redirect
Plesk > Domains > geniehelper.com > Hosting Settings- Check Permanent SEO-safe 301 redirect from HTTP to HTTPS
- Click OK
Iframe Embedding (Admin Panel)
The React admin panel (/admin route) embeds Directus and AnythingLLM in iframes. CSP headers must allow this.
AnythingLLM (server/.env)
Directus (cms/.env)
WebSocket Testing
Test WebSocket Connection
Common WebSocket Issues
Symptom: WebSocket connection fails with 400 or 502 Causes:- Missing
UpgradeorConnectionheaders - Incorrect
Connectionheader value (use"upgrade"not$http_upgrade) - Proxy buffering enabled (must be
off) - Timeout too short (increase
proxy_read_timeout)
Performance Tuning
Nginx Worker Processes
Plesk > Tools & Settings > Apache & nginx Settings > nginx settings Set worker processes to number of CPU cores:Connection Limits
Gzip Compression
Plesk enables gzip by default. Verify in Additional nginx directives (server context):Client Body Buffer
For large file uploads, increase buffer size:Security Hardening
Hide Nginx Version
Plesk > Tools & Settings > Security > Web Server Information Disclosure Check Hide. Or add to Additional nginx directives (http context):Rate Limiting (DDoS Protection)
Additional nginx directives (http context):rate=10r/s: Max 10 requests per second per IPburst=20: Allow bursts up to 20 requestsnodelay: Don’t delay excess requests, reject immediately
IP Allowlist (Admin Subdomains)
Additional nginx directives:Troubleshooting
502 Bad Gateway
Causes:- Backend service (Directus/AnythingLLM) is down
- Wrong port in
proxy_pass - Service not listening on 127.0.0.1
404 Not Found on SPA Routes
Cause: Missingerror_page 404 /index.html;
Fix: Add to Additional nginx directives and reload Nginx.
Nginx Won’t Reload
Cause: Syntax error in Additional nginx directives Debug:- Duplicate
location / - Missing semicolon
- Incorrect directive context (server vs http vs location)
WebSocket Upgrade Failed
Cause: Missing or incorrect WebSocket headers Fix: Ensure/api/llm/ location has:
Reference: Full Configs
Full reference configs available in source:docs/nginx/geniehelper.com.vhost_nginx.conf- Main domaindocs/nginx/cms.geniehelper.com.vhost_nginx.conf- CMS subdomaindocs/nginx/agent.geniehelper.com.vhost_nginx.conf- Agent subdomain
