How to Deploy a Next.js Application with Nginx on Ubuntu
Step-by-step production deployment for Next.js on Ubuntu with Nginx, PM2, and Let's Encrypt SSL.
Why Nginx and Ubuntu work well for Next.js
Deploying a Next.js application on your own infrastructure gives you control over performance, cost, and compliance. Ubuntu LTS releases provide long support windows and predictable package behavior, while Nginx remains one of the most reliable reverse proxies for Node.js workloads. Together they form a stack that Vcom Web Tech uses frequently for client projects that outgrow managed platforms or need custom networking.
Before you SSH into the server, confirm your domain DNS A record points to the VPS public IP and that ports 80 and 443 are open in your cloud firewall. You will run the Next.js app on an internal port such as 3000 and expose only Nginx to the internet. This separation keeps TLS termination and rate limiting at the edge while your application focuses on rendering and API routes.
This guide assumes a production build using next build and a process manager such as PM2. Standalone output can reduce disk footprint on small VPS instances, but the Nginx and SSL steps remain the same regardless of how you package the Node process.
Prepare the Ubuntu server
Start with a fresh Ubuntu 22.04 or 24.04 instance. Update packages with apt update and apt upgrade, then create a non-root deploy user with sudo privileges. Disable password authentication for SSH once key-based login works, and enable UFW with allow OpenSSH, allow 80, and allow 443 before turning the firewall on.
Install Node.js using NodeSource or nvm so you receive a current LTS version compatible with your Next.js release. Install build-essential if native modules compile during npm ci. Clone or rsync your repository into a directory such as /var/www/myapp, install dependencies, copy environment variables into .env.production, and run the production build.
Set NODE_ENV to production in your process manager environment. Verify the app responds on localhost by running the start command once manually before delegating to PM2. A common mistake is binding only to localhost while Nginx expects 127.0.0.1 on the same port—keep upstream addresses consistent in both PM2 and Nginx configuration.
Configure PM2 for automatic restarts
PM2 keeps your Next.js server alive across crashes and reboots. Start the app with pm2 start npm --name myapp -- start, or point PM2 at a small ecosystem file that sets cwd, instances, and max memory restart thresholds. Run pm2 save and pm2 startup so systemd respawns PM2 after the server reboots.
For multi-core VPS hosts, consider cluster mode with instances set to max, but validate session affinity if you use in-memory caches. Next.js API routes and server components generally scale horizontally when the app is stateless and sessions live in a database or Redis.
Monitor pm2 logs during the first hour after deployment. Spikes in memory often indicate large page data or missing cache headers rather than Nginx misconfiguration.
Install and tune Nginx as a reverse proxy
Install Nginx with apt install nginx. Create a site file under sites-available that listens on port 80 for your domain and proxies to http://127.0.0.1:3000. Include proxy_http_version 1.1, proxy_set_header Upgrade and Connection for websocket upgrades, and standard headers such as Host, X-Real-IP, and X-Forwarded-For so Next.js sees correct client information.
Enable the site with a symlink into sites-enabled, run nginx -t, and reload Nginx. Request your domain over HTTP and confirm pages load. Only then proceed to TLS.
Add proxy_read_timeout and proxy_connect_timeout values suited to your slowest API routes. Admin dashboards and report exports sometimes exceed default sixty-second limits; raising timeouts at Nginx prevents false 502 errors while you optimize backend performance.
Issue Let's Encrypt certificates
Use Certbot with the Nginx plugin: certbot --nginx -d yourdomain.com -d www.yourdomain.com. Certbot modifies the server block to listen on 443 with managed certificates and can redirect HTTP to HTTPS automatically.
Confirm auto-renewal with certbot renew --dry-run. Schedule monitoring that alerts you if renewal fails, because expired certificates cause sudden outages that look like application bugs.
If you serve static assets from a CDN, keep origin certificates on the VPS even when public traffic hits the CDN first. Origin TLS protects traffic between the CDN and your Nginx layer.
Hardening and ongoing maintenance
Enable gzip or brotli at Nginx for text assets if not handled by Next.js. Set sensible client_max_body_size for upload endpoints. Restrict admin paths with IP allowlists or VPN access when projects require it.
Automate deployments with git pull, npm ci, npm run build, and pm2 reload. Use maintenance pages during migrations that change schema. Keep a rollback tag in git and snapshot the server before major upgrades.
Document upstream ports, environment variable names, and certificate renewal dates in your runbook. Future you—or the next engineer—will resolve incidents faster when Nginx, PM2, and DNS settings live in one place.
Additional operational notes
Operational excellence on Linux hosting requires documenting every change to Nginx, systemd, PM2, Docker, and DNS in a runbook your team shares. Vcom Web Tech clients benefit when staging environments mirror production firewall rules, TLS versions, and mail authentication so surprises appear before customers notice. Schedule quarterly reviews of backups, certificate expiry, DMARC reports, and monitoring alerts even when traffic feels stable.
When incidents occur, capture timelines and root causes in blameless postmortems. Patterns from past 502 errors, failed renewals, or bounce spikes inform checklists for the next deployment. Training new team members on SSH access, log locations, and escalation paths reduces dependency on single maintainers.
Security patches, dependency upgrades, and framework migrations should ride the same CI pipelines that deploy application code. Automate smoke tests that hit health endpoints and send test mail through staging SMTP relays. Small consistent investments beat heroic firefighting during launch weekends.
Capacity planning matters on VPS hosts where vertical scaling has limits. Watch disk inode usage, connection counts, and database connection pools as traffic grows. Proactive upgrades cost less than emergency migrations during peak sales or campaign sends.
Finally, communicate with stakeholders using plain language about risk, downtime windows, and deliverability metrics. Technical depth supports trust when email authentication or deployment strategy changes affect revenue-facing systems.