DocHub
Production server configuration on OVH3 with nginx, PM2, and SSL

Server Setup and Deployment

Server History

Ricoya was deployed to three different servers during development:

  1. Home Server (192.168.1.157) — Initial attempt. PM2 process worked but Cloudflare tunnel config required sudo access the dev user didn’t have. Abandoned.
  2. n8n-worker-1 (159.203.80.93) — DigitalOcean. Successfully deployed with nginx + self-signed SSL. Discovered Turbopack production bundling bug here.
  3. OVH3 Worker (15.204.11.95) — Final production server. Rebuilt deployment under ubuntu user. This is the current production environment.

Current Production Environment

  • Server: OVH3 Worker (16 vCPU, 61GB RAM, 339GB disk)
  • OS: Ubuntu
  • App Path: /opt/ricoya/
  • Process Manager: PM2 (process name: ricoya, port 3000)
  • Reverse Proxy: nginx with SSL
  • Domain: ricoya.ipnoelp.com
  • DNS: Cloudflare-proxied A record

Deployment Process

No git repository on server. Code is synced directly via rsync:

  1. rsync local code to server (excluding node_modules, .next, .git)
  2. Run pnpm build on server (with --no-lint flag for Next.js 16 compatibility)
  3. pm2 restart ricoya

Turbopack Production Bug

Next.js 16 mandates Turbopack for builds. A production-only bug was discovered:

Problem: React error #310 (“Rendered more hooks than during the previous render”) on the root page. Only occurred in production builds, not dev mode.

Root cause: The root page used next/navigation redirect(), which throws internally. Turbopack’s production bundling placed this throw between hook calls in the router component, causing React to see inconsistent hook counts.

Fix: Replaced throw-based redirect with Next.js middleware redirect. Created src/middleware.ts to handle the root redirect via NextResponse.redirect(). The root page now returns null (middleware handles routing before it renders).

nginx Configuration

  • SSL configured with certificates (Cloudflare Full mode requires HTTPS on origin)
  • Proxies port 443 to localhost:3000 (PM2/Next.js)
  • Also proxies n8n traffic on worker1.ipnoelp.com to localhost:5678

Supabase Navigator Lock Fix

Problem: Console errors about acquiring exclusive Navigator LockManager lock with 10-second timeout. Multiple concurrent Supabase queries all competed for the same browser lock during getSession() calls.

Fix: Replaced the default Navigator LockManager with a no-op lock function in the Supabase browser client. Since there’s a single client instance, the lock is unnecessary. Queries execute without blocking each other.

Environment Variables

The server requires these environment variables in .env.local:

  • Supabase URL and keys (anon + service role)
  • Google Maps API key
  • CyberSource credentials (sandbox)
  • VAPID keys for web push notifications
  • PayPal configuration
  • CASH_ONLY flag (enables cash-only mode when payment providers aren’t configured)