Deploy your Next.js site to your own Linux server step‑by‑step and keep it running smoothly
Before We Start: What You'll Walk Away With
When you finish this guide you’ll have a fully‑functional Next.js site answering requests at your own domain name.
You’ll be able to point Nginx at your Node process the same way you’d set a restaurant’s front door to the kitchen, then hand out HTTPS certificates from Let’s Encrypt like a maître d’ handing out napkins.
PM2 will keep the app alive and restart it automatically, just like a reliable dishwasher that never lets a plate slip through.
Everything works on a fresh Ubuntu or Debian VPS, and you only need the command line you already use for git pulls and npm installs.
Install system dependencies and your code.
Configure Nginx as a reverse proxy.
Obtain and install a free SSL certificate.
Set up PM2 to manage the Node process.
Verify the site is live and secure.
Prerequisite: SSH access to a VPS with root or sudo rights.
Tools:
nginx,certbot,pm2,git,node/npm.Tip: Keep a copy of your
nginxconfig file; you’ll revert to it if something goes wrong, just like you’d keep a spare key.
By the time you close the terminal you’ll have a production‑ready deployment you can point friends at and trust to stay up.
What Deploying a Next.js App Actually Is (No Jargon)
Deploying a Next.js app simply means taking the code you ran locally, copying it to a remote Linux box, and configuring that box so the site stays online and responds to visitors.
First you run npm run build to turn your React pages into static files and server‑side bundles. Then you move the .next folder, package.json, and any static assets to the VPS. The server needs Node installed, a process manager like pm2 to keep the app alive, and a web server (usually Nginx) that hands incoming HTTP requests to your Node process.
Think of your app as a restaurant kitchen. The build step is the recipe you write down—without it the chef can’t cook. The VPS is the dining room where guests sit; it must be clean, have power, and stay open. The reverse proxy (Nginx) and SSL are the waitstaff and health inspector: they take orders, deliver plates securely, and make sure everything complies with safety standards.
When the kitchen (your Next.js code) follows the recipe, the waitstaff (Nginx) routes each order (request) to the right chef (Node process), and the health inspector (SSL) guarantees the food travels over a safe, encrypted path. If any part fails—say the kitchen closes early—the guests leave disappointed, just like a site that crashes or shows “not secure”.
In short, deploy next.js self hosted is about moving the recipe, setting up the dining room, and hiring the right staff so the experience runs smoothly every night.
The 3 Mistakes Everyone Makes With Next.js Deployments
Here’s what trips most people up when they try to deploy next.js self hosted for the first time.
Skipping
next buildon the server. It’s like ordering a pizza and forgetting to bake it before delivery – the crust arrives, but there’s no cheese. Without runningnext buildon the VPS, the.nextfolder never gets populated, so static assets and server‑side bundles are missing. The result? 404s on every page that should be pre‑rendered.Running the default Node server directly. Think of it as driving a sports car on city streets without traffic lights – you’ll get somewhere, but you’ll hit a lot of red lights (slow performance) and you’ll have no protection from the elements (no HTTPS). A reverse proxy like Nginx or Caddy handles SSL termination and serves static files efficiently, leaving Node to focus on rendering React.
Not installing a process manager. Imagine packing a suitcase for a trip and leaving the zipper open; a sudden gust will blow everything away. Without a tool such as
pm2orsystemd, your app disappears after a reboot or after an uncaught error, forcing you to manually restart it each time.Quick fix: Add
npm run build && npm startto your deployment script.Proxy tip: Use Nginx with
proxy_pass http://localhost:3000;and enablessl_certificatedirectives.Stay alive: Install
pm2and runpm2 start npm --name "next-app" -- start, thenpm2 save.
Fix these three, and your Next.js app will stay up, run fast, and actually show the pages you built.
How to Deploy a Next.js App: Step‑by‑Step
Grab a fresh Ubuntu 22.04 VPS, log in, and create a regular user so you don’t run everything as root.
Create a non‑root user and give it sudo rights.
adduser deployer
usermod -aG sudo deployer
Switch to that user, install nvm, then pull the LTS Node version.
su - deployer
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash
source ~/.bashrc
nvm install --lts
node -v
npm -v
Clone your repository into the web directory and install exact dependencies.
git clone https://github.com/yourname/your-app.git /var/www/your-app
cd /var/www/your-app
npm ci
Build the production bundle – think of it like packing a suitcase before a trip.
npm run build
Run the app with PM2. Imagine PM2 as a reliable restaurant manager who keeps the kitchen open 24/7.
npm i -g pm2
pm2 start npm --name "my-next" -- start
- Save the process list and make PM2 start on boot, just like setting an alarm that never forgets.
Install Nginx, then create a server block that forwards traffic to http://localhost:3000.
sudo apt-get update
sudo apt-get install -y nginx
sudo nano /etc/nginx/sites-available/your-app
Inside, set
proxy_pass http://localhost:3000;Enable with
ln -s /etc/nginx/sites-available/your-app /etc/nginx/sites-enabled/Test and reload:
nginx -t && systemctl reload nginx
Secure the site with a free Certbot certificate – it’s like getting a lock for your front door.
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com
Verify everything works, set up automatic renewal, and keep an eye on logs.
Renewal:
sudo certbot renew --dry-runPM2 logs:
pm2 logsVisit
https://yourdomain.comto confirm the app serves correctly.
Now your Next.js app is live, managed, and ready for traffic.
A Real Example: Deploying a SaaS Dashboard for “Acme Corp”
Maya just finished coding the Acme Corp dashboard and now it’s time to push it to her DigitalOcean droplet.
- She clones the repo:
git clone https://github.com/maya/acme-dashboard.git
cd acme-dashboard
Think of this like picking up a take‑out order before heading home.
- Install dependencies and build the production bundle:
npm ci
npm run build
- Start the app with PM2 so it survives crashes and reboots:
pm2 start npm --name "acme-dashboard" -- start
She then runs pm2 status and sees the process listening on port 3000 – like checking that the kitchen has finished cooking.
- Configure Nginx to act as a reverse proxy for
acme-dashboard.com:
server {
listen 80;
server_name acme-dashboard.com www.acme-dashboard.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Now Nginx is the traffic cop, sending visitors to the right lane.
- Obtain a free TLS certificate with Certbot:
sudo certbot --nginx -d acme-dashboard.com -d www.acme-dashboard.com
Result: HTTPS is active, and the browser shows a green lock.
Persistence:
pm2 savewrites the current process list so it restarts on boot.
With these steps, Maya’s dashboard is live at https://acme-dashboard.com and will stay up even after the server reboots. That’s how you deploy next.js self hosted in a real‑world scenario.
The Tools That Make This Easier
Grab these five tools and the deployment process feels as smooth as ordering take‑out.
nvm – Node Version Manager lets you pull the exact LTS Node release you need, then switch back with a single command. Think of it as a kitchen drawer where each drawer holds a different version of the same utensil.
PM2 – A process manager that watches your Next.js server, restarts it if it crashes, and keeps logs tidy. It works like a reliable delivery driver who never leaves the restaurant until the order is completed.
Certbot – The free helper that talks to Let’s Encrypt, fetches SSL certificates, and renews them automatically. It’s the equivalent of a self‑service kiosk that hands you a fresh ticket every 90 days without you lifting a finger.
DigitalOcean Droplets (or any Ubuntu VPS) – A low‑cost, single‑click Ubuntu machine that gives you full control over the stack. Picture it as a rented studio apartment: you bring the furniture (your app) and set up the utilities (Node, Nginx) yourself.
Git – Version control that pushes code over SSH, eliminating passwords during deployment. It’s like having a trusted courier who knows the exact address and never asks for a PIN.
Quick cheat sheet:
nvm install --lts – get the latest LTS Node.
pm2 start npm --name "my-next-app" -- start – launch Next.js under PM2.
certbot --nginx -d yourdomain.com – obtain and install SSL.
git push origin main – update the server code.
With these tools in place, deploying a Next.js app self‑hosted becomes a repeatable, low‑maintenance routine.
Quick Reference: Next.js Deployment Cheat Sheet
Here’s the entire workflow in bite‑size steps, like a recipe you can follow every time you need to deploy Next.js self hosted:
Provision an Ubuntu VPS and create a non‑root user. Think of it as getting a new kitchen and assigning a chef.
Install
nvmand runnvm install --lts. This gives you the right version of Node, just like choosing the right oven temperature.Clone your repository with
git clone …. It’s the same as picking up the ingredients you’ll cook with.Install dependencies using
npm ci. This locks the recipe exactly as you tested locally.Build the app:
npm run build. Imagine packing a suitcase; everything you need is now neatly folded.Start the process with PM2:
pm2 start npm --name "app" -- start. PM2 acts like a reliable sous‑chef that keeps the stove on.Save the PM2 process list and enable startup:
pm2 save && pm2 startup. This ensures your app restarts automatically after a power cut.Install Nginx and configure it as a reverse proxy. Nginx is the front‑door guard, directing visitors to the right room.
Secure the site with Certbot:
certbot --nginx -d yourdomain.com. It’s like handing out ID badges so only trusted guests get in.Test everything, monitor with
pm2 logs, and set up automatic certificate renewals.Quick tip: Keep your SSH keys handy; they’re the master key to your VPS.
Safety net: Run
pm2 statusafter each change to verify the app is alive.Future updates: Pull new code, run
npm ciandnpm run build, thenpm2 restart app.
What to Do Next
Start small, then level up as you get comfortable.
-
Easy: Add a health‑check endpoint (
/api/health) and let a service like UptimeRobot ping it. Think of it as leaving a “doorbell” on your app so you know it’s home before anyone else knocks.
Medium: Wire a CI/CD pipeline (GitHub Actions works fine). On every push run
npm ci && npm run build && pm2 reload all
. It’s like setting up a coffee machine that brews a fresh cup automatically whenever you order a new blend.
- Hard: Containerize the app with Docker and orchestrate with Docker Compose, adding services like a database or Redis. Imagine packing a suitcase where each item (app, DB, cache) has its own compartment, all ready for a quick grab‑and‑go.
Tools/Tips
Health‑check: return
{status:"ok"}and a 200 status.UptimeRobot: free tier checks every 5 minutes.
GitHub Actions: store
PM2_HOMEas a secret.Docker: keep
.dockerignorelean to speed builds.
Got stuck or have a better tip? Drop a comment below – I’d love to hear how your deployment went!
About the Author
Abdullah Sheikh is the Founder & CEO at Exteed, where he leads a team of skilled developers specializing in Web2 and Web3 applications, Custom Smart Contracts, and Blockchain solutions.
With 6+ years of experience, Abdullah has built CRMs, Crypto Wallets, DeFi Exchanges, E-Commerce Stores, HIPAA Compliant EMR Systems, and AI-powered systems that drive business efficiency and innovation.
His expertise spans Blockchain, Crypto & Tokenomics, Artificial Intelligence, and Web Applications; building reliable and smooth web apps that fit the client’s goals and requirements.
📧 info@abdullah-sheikh.com · 🔗 LinkedIn · 🌐 abdullah-sheikh.com











