Deploy Next.js trên VPS với PM2 và Nginx: Chuẩn thực chiến SEO

09/05/2026 · P T P · Chung

Vì sao nhiều team chọn VPS + PM2 + Nginx cho Next.js?

Deploy Next.js lên Vercel rất nhanh. Nhưng khi cần toàn quyền kiểm soát server, tối ưu chi phí, gắn nhiều service trên cùng máy, hoặc phải đáp ứng yêu cầu nội bộ về hạ tầng, mô hình VPS + PM2 + Nginx gần như là lựa chọn thực chiến nhất.

Bộ ba này phổ biến vì khá “chuẩn bài”:

Next.js → app SSR/SSG/API.
PM2 → giữ tiến trình Node.js luôn sống, tự restart, log rõ ràng.
Nginx → reverse proxy, SSL, cache tĩnh, gzip, bảo vệ lớp ngoài.

Nếu cấu hình đúng, bạn sẽ có một stack vừa ổn định, vừa dễ vận hành, dễ mở rộng. Bài viết này đi theo hướng thực chiến: từ chuẩn bị VPS, build app, chạy bằng PM2, tới cấu hình Nginx “sạch”, ít lỗi, dễ bảo trì.


Kiến trúc triển khai chuẩn

Luồng cơ bản:

– User truy cập domain.
Nginx nhận request ở cổng 80/443.
– Nginx reverse proxy vào app Next.js đang chạy ở 127.0.0.1:3000.
PM2 quản lý tiến trình Next.js.
– SSL do Nginx xử lý.

Kiểu này có vài lợi ích rõ:

Ẩn port app nội bộ → an toàn hơn.
Restart app không ảnh hưởng public endpoint nhiều.
Dễ thêm SSL, redirect, rate limit, cache.
Thuận tiện deploy nhiều app trên cùng VPS.


Chuẩn bị VPS trước khi deploy

Một VPS Ubuntu LTS là đủ. Tối thiểu:

– RAM: 1GB–2GB cho app nhỏ/vừa.
– CPU: 1–2 vCPU.
– OS: Ubuntu 22.04 LTS hoặc tương đương.

Cài các gói cần thiết:

sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx git curl ufw

Cài Node.js LTS. Nên dùng Node 18 hoặc 20:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs

Kiểm tra:

node -v
npm -v

Cài PM2 global:

sudo npm install -g pm2

Thiết lập firewall:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Best practice:

– Tạo user riêng để deploy, không chạy app bằng root.
– Dùng SSH key thay vì password.
– Tách thư mục app rõ ràng, ví dụ: /var/www/my-next-app.


Deploy mã nguồn Next.js lên VPS

Clone source:

cd /var/www
sudo mkdir my-next-app
sudo chown -R $USER:$USER /var/www/my-next-app
cd /var/www/my-next-app

git clone <repo-url> .

Cài dependency:

npm install

Nếu app dùng biến môi trường, tạo file .env.production hoặc .env tùy cách bạn thiết kế:

nano .env.production

Ví dụ:

NODE_ENV=production
PORT=3000
NEXT_PUBLIC_API_URL=https://api.example.com

Build app:

npm run build

Chạy thử local trên VPS:

npm run start

Mặc định Next.js sẽ lắng nghe ở port 3000. Test nhanh:

curl http://127.0.0.1:3000

Nếu app lên đúng, dừng tiến trình thử nghiệm bằng Ctrl + C.


Dùng PM2 để chạy Next.js ổn định

Điểm yếu lớn nhất khi chạy npm run start trực tiếp: thoát SSH hoặc app lỗi → process chết. PM2 xử lý đúng bài toán này.

Chạy app bằng PM2:

pm2 start npm --name "my-next-app" -- start

Kiểm tra:

pm2 list
pm2 logs my-next-app

Lưu cấu hình để server reboot vẫn tự chạy lại:

pm2 save
pm2 startup

PM2 sẽ in ra một lệnh. Copy và chạy đúng lệnh đó.

Cách cấu hình PM2 “chuẩn hơn” bằng ecosystem file

Thay vì chạy lệnh rời, nên dùng file ecosystem.config.js:

module.exports = {
  apps: [
    {
      name: "my-next-app",
      script: "npm",
      args: "start",
      cwd: "/var/www/my-next-app",
      instances: 1,
      exec_mode: "fork",
      env: {
        NODE_ENV: "production",
        PORT: 3000
      }
    }
  ]
};

Chạy:

pm2 start ecosystem.config.js
pm2 save

Ưu điểm:

– Dễ đọc.
– Dễ version control.
– Dễ scale sau này.

Một số lệnh PM2 nên nhớ

pm2 restart my-next-app
pm2 stop my-next-app
pm2 delete my-next-app
pm2 logs my-next-app
pm2 monit

Cấu hình Nginx reverse proxy đúng chuẩn

Tạo file config:

sudo nano /etc/nginx/sites-available/my-next-app

Nội dung:

server {
    listen 80;
    server_name example.com www.example.com;

location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1;

proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;

proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

proxy_cache_bypass $http_upgrade; }

location /_next/static/ { alias /var/www/my-next-app/.next/static/; access_log off; expires 30d; add_header Cache-Control "public, immutable"; }

location /favicon.ico { log_not_found off; access_log off; } }

Kích hoạt site:

sudo ln -s /etc/nginx/sites-available/my-next-app /etc/nginx/sites-enabled/

Kiểm tra syntax:

sudo nginx -t

Reload:

sudo systemctl reload nginx

Vì sao config này “thực chiến”?

proxy_pass → forward req vào Next.js.
X-Forwarded-* → giữ đúng IP, protocol, host.
Upgrade/Connection → hỗ trợ websocket, hot path cần nâng cấp kết nối.
/_next/static/ → Nginx phục vụ static asset trực tiếp, giảm tải cho Node.
expires + immutable → tối ưu cache client rất tốt.


Gắn SSL bằng Let’s Encrypt

Sau khi domain đã trỏ A record về VPS, cài Certbot:

sudo apt install -y certbot python3-certbot-nginx

Cấp SSL:

sudo certbot --nginx -d example.com -d www.example.com

Certbot thường tự sửa config Nginx cho bạn, gồm:

– redirect HTTP → HTTPS
– khai báo certificate path
– tự renew định kỳ

Test renew:

sudo certbot renew --dry-run

SSL xong → app chuyên nghiệp hơn, bảo mật hơn, SEO tốt hơn.


Quy trình deploy cập nhật phiên bản mới

Khi có code mới, quy trình an toàn thường là:

1. SSH vào VPS.
2. Pull code mới.
3. Cài lại dependency nếu cần.
4. Build lại.
5. Restart PM2.

Lệnh mẫu:

cd /var/www/my-next-app
git pull origin main
npm install
npm run build
pm2 restart my-next-app

Nếu app có migration DB, hãy chèn bước migration trước restart.

Gợi ý giảm downtime

Với app lớn hơn, bạn có thể:

– dùng pm2 reload thay vì restart.
– bật nhiều instances nếu app không phụ thuộc memory local.
– cân nhắc CI/CD qua GitHub Actions.


Các lỗi phổ biến khi deploy Next.js trên VPS

1. Nginx báo 502 Bad Gateway

Nguyên nhân thường gặp:

– PM2 chưa chạy app.
– App chạy sai port.
proxy_pass trỏ sai.
– Build lỗi nhưng chưa kiểm tra log.

Cách debug:

pm2 logs my-next-app
sudo journalctl -u nginx
sudo nginx -t

2. App chạy local được, qua domain không lên

Khả năng cao:

– domain chưa trỏ đúng IP.
– firewall chưa mở 80/443.
– Nginx config chưa enable.
– quên reload Nginx.

3. Static file lỗi 404

Hay xảy ra khi:

– sai đường dẫn alias.
– build chưa tạo .next/static.
– deploy xong nhưng chưa npm run build.

4. Sau reboot server app không tự lên

Nguyên nhân:

– chưa chạy pm2 save.
– chưa cấu hình pm2 startup.


Một số tinh chỉnh nên có trong môi trường production

Để hệ thống “bền” hơn, nên bổ sung:

log rotation cho PM2:

pm2 install pm2-logrotate

giới hạn upload/body trong Nginx nếu app có upload file.
gzip/brotli để giảm bandwidth.
fail2ban nếu VPS public internet.
monitoring: Netdata, Uptime Kuma, Grafana, hoặc ít nhất alert ping.

Nếu traffic tăng mạnh:

– VPS nhỏ → CPU/RAM nghẽn.
– SSR nặng → response chậm.
– DB remote → latency tăng.

Lúc đó cần tối ưu sâu hơn:

– cache layer.
– giảm SSR không cần thiết.
– dùng CDN cho ảnh/tĩnh.
– scale app hoặc tách service.


Kết luận

Deploy Next.js trên VPS với PM2 + Nginx là mô hình rất đáng dùng khi bạn muốn chủ động hạ tầng, chi phí hợp lý, vận hành linh hoạt. Cấu hình chuẩn thực chiến không nằm ở việc “app chạy được”, mà ở chỗ:

– process sống ổn định với PM2
– request đi qua Nginx đúng chuẩn reverse proxy
– static asset được phục vụ tối ưu
– SSL đầy đủ
– deploy/update đơn giản, dễ rollback, dễ debug

Nếu làm đúng ngay từ đầu, bạn sẽ tránh được phần lớn lỗi kinh điển như 502 Bad Gateway, app chết sau reboot, hay domain hoạt động chập chờn. Với team nhỏ hoặc sản phẩm đang tăng trưởng, đây là setup cân bằng rất tốt giữa đơn giản, kiểm soát, hiệu năng.

Muốn đi xa hơn, bạn có thể bổ sung CI/CD, Docker, monitoring và chiến lược zero-downtime. Nhưng nền móng vẫn là: Next.js chạy gọn trong PM2, Nginx đứng ngoài làm lớp bảo vệ và tối ưu truy cập. Đây là cấu hình đủ thực chiến để chạy production nghiêm túc.

#chuan #deploy #next #nginx #tren
Chia sẻ:
← Trước
Next.js trên VPS: Giảm CPU, Tăng Tốc Phản Hồi Vượt Trội

Bài viết tương tự

Bình luận

Chưa có bình luận. Hãy là người đầu tiên!