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_IPUpdate hệ thống:
apt update && apt upgrade -yCài package cần thiết:
apt install nginx certbot python3-certbot-nginx curl git ufw -yCài Node.js LTS. Ví dụ Node 20:
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
apt install nodejs -yKiểm tra:
node -v
npm -v
nginx -vCài PM2:
npm install -g pm2Firewall:
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
ufw statusChỉ 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.comHoặc:
nslookup example.comDNS 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-appCài dependencies:
npm installTạo .env.production:
nano .env.productionVí 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/dbBuild:
npm run buildChạy thử:
npm startMặc định Next.js chạy port 3000.
Nếu cần port khác:
npm start -- -p 3001Khuyế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 startupPM2 sẽ in ra command. Copy chạy command đó.
Kiểm tra:
pm2 status
pm2 logs next-appTest nội bộ:
curl http://127.0.0.1:3000Có 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.comNộ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 nginxVào:
http://example.comNế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.comserver {
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 nginxNế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.comCấp SSL cho subdomain:
certbot --nginx -d app.example.comChọn redirect HTTP → HTTPS nếu Certbot hỏi.
Test auto-renew:
certbot renew --dry-runSau SSL, Nginx sẽ có block listen 443 ssl. Kiểm tra:
nginx -t
systemctl reload nginxLỗ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 -tCheck port:
ss -tulpn | grep nginxCheck firewall:
ufw statusCheck DNS:
dig example.comNguyê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-appCheck port:
curl http://127.0.0.1:3000Fix:
pm2 restart next-appNếu build lỗi:
npm run build502 → 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 startKhô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.comSau khi sửa env phải build lại:
npm run build
pm2 restart next-appBiế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.comKhô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-appBướ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-appNế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.logKế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ình luận (0)
Chưa có bình luận. Hãy là người đầu tiên!