Cấu hình domain Next.js trên VPS không lỗi từ A-Z

12/05/2026 · P T P · Chung

Cấu hình domain, subdomain cho Next.js trên VPS không lỗi: checklist thực chiến

Deploy Next.js lên VPS nghe đơn giản: build app, chạy Node, trỏ domain. Nhưng thực tế thường lỗi: domain không vào, subdomain sai route, SSL fail, refresh 404, API CORS, WebSocket chết, ảnh không load, redirect vòng lặp. Nguyên nhân đa số không nằm ở Next.js, mà ở DNS, reverse proxy, port, firewall, SSL, env.

Bài này → hướng dẫn cấu hình domain/subdomain cho dự án Next.js chạy trên VPS ổn định, dễ debug, ít lỗi production.


Mô hình chuẩn nên dùng

Kiến trúc phổ biến:

Domain chính: example.com
Subdomain app: app.example.com
Subdomain API: api.example.com
VPS: Ubuntu
Reverse proxy: Nginx
App Next.js: chạy port nội bộ 3000
Process manager: PM2
SSL: Let’s Encrypt + Certbot

Luồng req:

User → DNS → VPS IP → Nginx :80/:443 → Next.js :3000

Next.js không nên expose trực tiếp port 3000 ra internet. Nginx đứng trước → SSL, gzip, proxy, redirect, nhiều domain/subdomain.


Bước 1: Chuẩn bị VPS đúng cách

SSH vào VPS:

ssh root@YOUR_SERVER_IP

Update hệ thống:

apt update && apt upgrade -y

Cài package cần thiết:

apt install nginx certbot python3-certbot-nginx curl git ufw -y

Cài Node.js LTS. Ví dụ Node 20:

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

Kiểm tra:

node -v
npm -v
nginx -v

Cài PM2:

npm install -g pm2

Firewall:

ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
ufw status

Chỉ mở 22, 80, 443. Không cần mở 3000 public.


Bước 2: Trỏ DNS domain/subdomain

Vào trang quản lý DNS của nhà cung cấp domain.

Tạo record:

| Type | Name | Value |
|—|—|—|
| A | @ | YOUR_SERVER_IP |
| A | www | YOUR_SERVER_IP |
| A | app | YOUR_SERVER_IP |
| A | api | YOUR_SERVER_IP |

Nếu dùng Cloudflare:

– Proxy orange cloud: bật được, nhưng lúc cấp SSL lần đầu nên cân nhắc tắt proxy tạm.
– SSL/TLS mode: chọn Full hoặc Full (strict) sau khi có cert.
– Không dùng Flexible → dễ redirect loop.

Kiểm tra DNS:

dig example.com
dig app.example.com

Hoặc:

nslookup example.com

DNS propagation → có thể vài phút đến vài giờ.


Bước 3: Deploy Next.js lên VPS

Clone source:

cd /var/www
git clone https://github.com/your/repo.git next-app
cd next-app

Cài dependencies:

npm install

Tạo .env.production:

nano .env.production

Ví dụ:

NODE_ENV=production
NEXT_PUBLIC_SITE_URL=https://app.example.com
NEXT_PUBLIC_API_URL=https://api.example.com
DATABASE_URL=postgresql://user:pass@localhost:5432/db

Build:

npm run build

Chạy thử:

npm start

Mặc định Next.js chạy port 3000.

Nếu cần port khác:

npm start -- -p 3001

Khuyến nghị khai báo script trong package.json:

{
  "scripts": {
    "build": "next build",
    "start": "next start -p 3000"
  }
}

Bước 4: Chạy Next.js bằng PM2

Không chạy app bằng terminal thường. SSH disconnect → app chết. Dùng PM2.

pm2 start npm --name "next-app" -- start
pm2 save
pm2 startup

PM2 sẽ in ra command. Copy chạy command đó.

Kiểm tra:

pm2 status
pm2 logs next-app

Test nội bộ:

curl http://127.0.0.1:3000

Có HTML trả về → app OK. Nếu lỗi ở domain sau đó → lỗi Nginx/DNS/SSL, không phải Next.js.


Bước 5: Cấu hình Nginx cho domain chính

Tạo config:

nano /etc/nginx/sites-available/example.com

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; } }

Enable site:

ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

Vào:

http://example.com

Nếu thấy app → OK.


Bước 6: Cấu hình subdomain cho app

Nếu muốn app.example.com chạy cùng app port 3000:

nano /etc/nginx/sites-available/app.example.com
server {
    listen 80;
    server_name app.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; } }

Enable:

ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

Nếu mỗi subdomain là app riêng:

app.example.com → port 3000
admin.example.com → port 3001
api.example.com → port 4000

Nginx proxy từng server block riêng.


Bước 7: Cấp SSL HTTPS bằng Certbot

Cấp SSL cho domain:

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

Cấp SSL cho subdomain:

certbot --nginx -d app.example.com

Chọn redirect HTTP → HTTPS nếu Certbot hỏi.

Test auto-renew:

certbot renew --dry-run

Sau SSL, Nginx sẽ có block listen 443 ssl. Kiểm tra:

nginx -t
systemctl reload nginx

Lỗi thường gặp:

– DNS chưa trỏ đúng → Certbot fail.
– Port 80 bị chặn → challenge fail.
– Cloudflare Flexible → redirect loop.
– Nginx config sai server_name → cert cấp nhầm.


Bước 8: Xử lý lỗi thường gặp

Domain trỏ đúng IP nhưng không vào

Check Nginx:

systemctl status nginx
nginx -t

Check port:

ss -tulpn | grep nginx

Check firewall:

ufw status

Check DNS:

dig example.com

Nguyên nhân thường: DNS cache, record sai, Nginx chưa reload, firewall chưa mở 80/443.


502 Bad Gateway

Nginx sống, app chết.

Check PM2:

pm2 status
pm2 logs next-app

Check port:

curl http://127.0.0.1:3000

Fix:

pm2 restart next-app

Nếu build lỗi:

npm run build

502 → thường do proxy_pass sai port hoặc Next.js không chạy.


Refresh trang bị 404

Với Next.js chuẩn SSR/SSG, refresh không nên 404 nếu proxy vào Next.js. Nếu deploy static export (next export) mới dễ lỗi rewrite.

Kiểm tra bạn đang chạy:

next start

Không phải serve thư mục out nếu app có dynamic route/server features.

Nếu dùng output: 'export', dynamic route cần cấu hình fallback/static paths phù hợp.


HTTPS bị redirect vòng lặp

Hay gặp khi dùng Cloudflare SSL mode Flexible.

Fix:

– Cloudflare SSL/TLS → Full hoặc Full (strict).
– VPS có cert hợp lệ.
– Nginx nhận đúng X-Forwarded-Proto.

Trong Next.js, nếu tự redirect HTTP→HTTPS, tránh logic sai khi sau proxy.


API gọi sai domain

Ví dụ frontend ở app.example.com, API ở api.example.com.

Env đúng:

NEXT_PUBLIC_API_URL=https://api.example.com

Sau khi sửa env phải build lại:

npm run build
pm2 restart next-app

Biến NEXT_PUBLIC_* được đóng gói lúc build. Sửa env mà không rebuild → không đổi.


CORS lỗi giữa subdomain

app.example.com gọi api.example.com → khác origin.

API cần allow origin:

https://app.example.com

Không dùng * nếu có credentials/cookie.

Nếu dùng cookie auth:

– Cookie domain: .example.com
SameSite=None
Secure=true
– HTTPS bắt buộc

Sai cookie config → login được nhưng refresh mất session.


Ảnh Next.js không load

Nếu dùng next/image load ảnh từ domain ngoài, thêm vào next.config.js:

module.exports = {
  images: {
    domains: ['cdn.example.com', 'images.example.com']
  }
}

Hoặc dùng remotePatterns.

Sửa config → build lại:

npm run build
pm2 restart next-app

Bước 9: Cấu hình www, non-www, domain chính

Nên chọn một canonical domain:

https://example.com
– hoặc https://www.example.com

Ví dụ redirect www → non-www:

server {
    listen 80;
    server_name www.example.com;
    return 301 http://example.com$request_uri;
}

Sau SSL:

server {
    listen 443 ssl;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

Canonical rõ → SEO tốt hơn, tránh duplicate content, tránh cookie/session lẫn lộn.


Bước 10: Quy trình deploy an toàn

Mỗi lần update code:

cd /var/www/next-app
git pull
npm install
npm run build
pm2 restart next-app
pm2 logs next-app

Nếu dùng migration DB → chạy trước/sau build tùy app.

Checklist sau deploy:

curl http://127.0.0.1:3000
– Mở https://app.example.com
– Test login
– Test refresh route động
– Test API
– Test image
– Test mobile
– Check logs PM2/Nginx

Log Nginx:

tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log

Kết luận

Cấu hình domain/subdomain cho Next.js trên VPS không khó, nhưng cần đúng lớp: DNS trỏ đúng IP, Nginx proxy đúng port, PM2 giữ app sống, SSL hợp lệ, env build đúng, Cloudflare không cấu hình sai. Khi lỗi, debug theo chuỗi: DNS → Nginx → SSL → PM2 → Next.js → API/env.

Công thức ổn định nhất: Next.js chạy nội bộ 127.0.0.1:3000, Nginx nhận 80/443, Certbot cấp HTTPS, PM2 quản lý process, DNS A record trỏ về VPS. Làm đúng mô hình này → domain/subdomain chạy sạch, ít lỗi, dễ mở rộng thêm app, admin, API sau này.

#domain #hinh #khong #next #tren
Chia sẻ:
← Trước
Chọn VPS chạy Next.js ổn định, tiết kiệm: 7 kinh nghiệm vàng

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!