Trang chủ
›
Chung
›
Bài viết
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.
Bài viết tương tự
Chung
Tại sao bảng dữ liệu và khóa chính quan trọng trong MySQL Khi xây dựng…
24/02
Chung
Docker trên VPS Free: Cách tối ưu hiệu năng và tiết kiệm chi phí Với…
14/03
Chung
Tận dụng free tier cloud 2026 để triển khai website cá nhân gần như không…
27/04
Chung
Mở đầu OpenClaw Free là một công cụ mạnh mẽ, được ưa chuộng nhờ khả…
18/03
Bình luận
Chưa có bình luận. Hãy là người đầu tiên!