Case Study ยท Next.js ยท FastAPI ยท DevOps

CareJourney Multi-Environment Deployment

Getting a Next.js frontend and FastAPI backend running cleanly across Dev, QA, and Production on a shared VPS โ€” untangling JWT secrets, Nginx routing conflicts, cookie stripping, and Node.js version hell.

RoleDevOps & Backend Engineer
PlatformHostinger VPS ยท Nginx ยท PM2
DomainHealthcare SaaS
TypeMulti-Env Deployment & DevOps

Three environments, one VPS, and nothing talking to each other correctly

CareJourney needed Dev, QA, and Production environments running simultaneously on a single Hostinger VPS. The initial deployment had authentication completely broken โ€” users could log in but were immediately redirected back to the login page on every page load.

Three independent bugs compounding each other: mismatched JWT secrets, Nginx stripping Set-Cookie headers, and Node.js v22 conflicting with the system Node.js v18 used by PM2.

Peeling the onion โ€” three bugs masking each other

1
Node.js version conflict โ€” PM2 running wrong binaryPM2 installed under system Node v18 but the app required v22. Fixed by installing PM2 inside nvm-managed v22 and updating ecosystem.config.js to lock the runtime path.
2
JWT secret mismatch between Next-Auth and FastAPINext-Auth signed JWTs with NEXTAUTH_SECRET; FastAPI read a different JWT_SECRET. Fixed by unifying to a single shared secret injected via GitHub Actions secrets on every deploy.
3
Nginx stripping Set-Cookie on proxied auth responsesNext-Auth issues session cookies via Set-Cookie headers that Nginx was dropping on proxy. Fixed with proxy_cookie_domain and proxy_cookie_path directives.
4
Routing conflict โ€” /api/auth hijacked before Next.js handled itNginx forwarded ALL /api/* to FastAPI, but /api/auth/* belongs to Next-Auth. Fixed by adding a specific location block for /api/auth/ pointing to the Next.js port, placed before the generic /api/ block.
# Nginx routing fix location /api/auth/ { proxy_pass http://localhost:3000; proxy_cookie_domain localhost app.carejourney.com; } location /api/ { proxy_pass http://localhost:8000; } location / { proxy_pass http://localhost:3000; }

Three clean environments, one-command deploys

3
Independent environments on one VPS
0
Auth failures post-fix
CI/CD
GitHub Actions per-branch deploy
SSL
Let's Encrypt on all 3 subdomains

Back to all projects