Deploy Next.js on Ubuntu with Git, PM2, Nginx, and Certbot
Production-ready guide to deploy a Next.js app on Ubuntu using Git for code, PM2 for process management, Nginx as reverse proxy, and Certbot for HTTPS.
This guide walks through a production-ready deployment of a Next.js app on Ubuntu using:
- Git for pulling code
- PM2 for process management and restarts
- Nginx as reverse proxy
- Certbot (Let's Encrypt) for HTTPS
Replace placeholders like
<domain>,<repo_url>, and<project_name>with your values.
1) Install Node.js and PM2
sudo apt-get update
# If Node is missing, install from NodeSource (recommended) or apt
# NodeSource example for Node 20 (optional, better than old apt repo):
# curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# sudo apt-get install -y nodejs
# Or use apt's nodejs (ensure it's recent enough for Next.js)
sudo apt-get install -y nodejs npm
# PM2 global
sudo npm install -g pm2
pm2 --version
2) Pull Your Project from Git
cd /var/www
sudo mkdir -p /var/www/<project_name>
sudo chown $USER:$USER /var/www/<project_name>
cd /var/www/<project_name>
git clone <repo_url> .
3) Install Dependencies and Build
npm install
npm run build
4) Start with PM2
pm2 start "npm run start" --name <project_name>
pm2 save
pm2 status
# (Optional) Enable startup at boot
pm2 startup systemd
# Follow PM2's printed command to enable the service, then:
pm2 save
- Default Next.js
npm run startlistens on port 3000. You can setPORT=3000in your env if needed.
5) Install and Configure Nginx
sudo apt install -y nginx
Create a site config (e.g., /etc/nginx/conf.d/<domain>.conf):
server {
root /var/www/html;
server_name <domain>;
location /doc {
try_files $uri $uri/ =404;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
}
Test and reload Nginx:
sudo nginx -t
sudo systemctl reload nginx
If you used
/etc/nginx/sites-available/+ symlink tosites-enabled/, place the file there instead.
6) Get HTTPS with Certbot (Let's Encrypt)
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <domain>
Certbot will inject SSL directives and create a redirect server block automatically. A typical HTTPS config looks like:
server {
root /var/www/html;
server_name <domain>;
location /doc {
try_files $uri $uri/ =404;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/<domain>/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/<domain>/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = <domain>) {
return 301 https://$host$request_uri;
} # managed by Certbot
server_name <domain>;
listen 80;
return 404; # managed by Certbot
}
Test and reload:
sudo nginx -t
sudo systemctl reload nginx
7) Firewall and Health Checks
# UFW examples
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
# or specifically ports: sudo ufw allow 80, sudo ufw allow 443
sudo ufw enable
sudo ufw status
Verify:
curl -I http://<domain>should return301to HTTPS.curl -I https://<domain>should return200.pm2 logs <project_name>shows app output.
8) Updates and Zero‑Downtime Restarts
cd /var/www/<project_name>
git pull
npm install
npm run build
pm2 reload <project_name>
pm2 save
Troubleshooting Tips
- Blank page / 502: ensure PM2 app is listening on 127.0.0.1:3000 and Nginx proxy points to the same port.
- Permissions: ensure project dir ownership is correct for the deploy user.
- SSL renewal: Certbot installs a systemd timer/cron for auto-renewal; verify with
sudo systemctl list-timers | grep certbot. - Environment variables: place them in a
.envfile and load via your start script or PM2 ecosystem file.
You're now running Next.js in production with process supervision, reverse proxy, and HTTPS. 🎉
Post Details
Navigation
Related posts
Essential Security Practices to Protect Your Web Applications
Practical, easy-to-apply security improvements for any online project — from security headers, rate limiting, login protection, to safe file uploads and more.
Read more →Generate a Self‑Signed SSL Certificate on Ubuntu (Nginx)
Step-by-step guide to creating a self-signed certificate with OpenSSL and configuring Nginx with secure defaults.
Read more →Answer Engine Optimization for Next.js: Schema, llms.txt, and Proving It Shipped
A practical pass at making a Next.js site legible to AI answer engines: allowing the crawlers, publishing llms.txt, adding FAQPage and HowTo schema without hand-maintaining it, and asserting in the build output that all of it actually rendered.
Read more →