Setup NGINX + Next.js Standalone: Hướng dẫn từ thực chiến
Hướng dẫn chi tiết cách setup NGINX làm reverse proxy cho Next.js standalone mode, kèm tips từ kinh nghiệm deploy thực tế.
Nguyen Nhat Long
@longnn
Mình từng mất nguyên một buổi chiều debug lỗi 502 Bad Gateway chỉ vì thiếu một dòng config NGINX. Chuyện deploy Next.js nghe thì đơn giản, nhưng khi kết hợp với NGINX ở chế độ standalone, có kha khá thứ dễ sai nếu bạn chưa quen. Bài này mình chia sẻ lại toàn bộ flow setup từ đầu đến cuối, kèm những lỗi mình từng dính để bạn khỏi phải đạp lại vết xe đổ.
Tại sao lại là Standalone + NGINX?
Mặc định khi bạn npm run build một app Next.js, output sẽ phụ thuộc vào toàn bộ node_modules — nặng, chậm copy, và không tối ưu cho production. Chế độ standalone giải quyết đúng pain point này: Next.js sẽ bundle ra một thư mục .next/standalone chứa đúng những gì cần thiết để chạy, bao gồm cả một Node.js server tối giản.
Còn NGINX? Nó đóng vai trò reverse proxy đứng trước, lo việc handle SSL, serve static files, load balancing, và bảo vệ app Node.js phía sau. Theo kinh nghiệm của mình, combo này chạy cực kỳ ổn định trên các VPS từ 1GB RAM trở lên.
Build Next.js ở chế độ Standalone
Bước đầu tiên, mở file next.config.js và thêm một dòng duy nhất:
1module.exports = {2 output: 'standalone',3 // các cấu hình khác nếu có4};
Sau đó build như bình thường:
1npm run build
Khi build xong, bạn sẽ thấy thư mục .next/standalone xuất hiện. Thư mục này chứa file server.js và tất cả dependencies đã được bundle sẵn. Bạn chỉ cần copy thư mục này lên server — không cần chạy `npm install` trên server nữa.
Điều mình thấy hay là output standalone nhẹ hơn đáng kể so với cách deploy truyền thống. Một app Next.js trung bình mà mình từng làm giảm từ ~400MB (với node_modules) xuống còn ~50MB. Deploy nhanh hơn rất nhiều.
Lưu ý quan trọng: Thư mục.next/staticvàpublickhông được copy tự động vào standalone. Bạn cần copy thủ công hoặc để NGINX serve trực tiếp — mà cách sau mới là best practice.
Cài đặt môi trường trên Server
Mình giả sử bạn đang dùng Ubuntu/Debian. Đầu tiên, cài NGINX:
1sudo apt update2sudo apt install nginx -y
Tiếp theo, cài PM2 để quản lý process Node.js. Đừng chạy node server.js trần — app sẽ chết khi bạn tắt terminal hoặc khi có lỗi runtime.
1npm install -g pm2
Di chuyển vào thư mục chứa app standalone trên server và start với PM2:
1cd /duong/dan/den/ung/dung/cua/ban2pm2 start "npm run start" --name nextjs-app3# hoặc nếu bạn muốn chỉ định port khác:4# pm2 start "npm run start -- -p 4000" --name nextjs-app
Mình hay thêm pm2 startup và pm2 save để PM2 tự khởi động lại app khi server reboot. Nhiều bạn quên bước này rồi thắc mắc sao restart server xong app không lên — mình cũng từng vậy.
Cấu hình NGINX làm Reverse Proxy
Đây là phần quan trọng nhất. Tạo file config mới:
1sudo nano /etc/nginx/sites-available/nextjs.conf
Thêm nội dung sau:
1server {2 listen 80;3 server_name your_domain_or_ip www.your_domain_or_ip;45 # Reverse proxy tới Next.js6 location / {7 proxy_pass http://localhost:3000;8 proxy_http_version 1.1;9 proxy_set_header Upgrade $http_upgrade;10 proxy_set_header Connection 'upgrade';11 proxy_set_header Host $host;12 proxy_cache_bypass $http_upgrade;13 }1415 # Serve static files trực tiếp qua NGINX — nhanh hơn nhiều so với qua Node.js16 location /_next/static/ {17 alias /duong/dan/den/ung/dung/cua/ban/.next/static/;18 expires 1y;19 access_log off;20 }2122 # Serve public assets23 location /static/ {24 alias /duong/dan/den/ung/dung/cua/ban/public/static/;25 expires 1y;26 access_log off;27 }28}
Mấy dòng proxy_set_header không phải để cho đẹp đâu — thiếu Upgrade và Connection là WebSocket sẽ không hoạt động, và thiếu Host thì Next.js sẽ không nhận đúng hostname, ảnh hưởng đến các tính năng như next/image hay middleware.
Kích hoạt config và restart NGINX:
1sudo ln -s /etc/nginx/sites-available/nextjs.conf /etc/nginx/sites-enabled/2sudo rm /etc/nginx/sites-enabled/default3sudo nginx -t4sudo systemctl restart nginx
Luôn chạy `nginx -t` trước khi restart. Mình đã thấy không ít trường hợp anh em restart NGINX mà không test trước, config sai → NGINX chết → toàn bộ site down. Một thói quen nhỏ nhưng cứu mạng.
Thêm HTTPS với Let's Encrypt
Năm 2025 rồi, không có lý do gì để chạy HTTP thuần cả. Certbot làm việc này cực kỳ đơn giản:
1sudo apt install certbot python3-certbot-nginx -y2sudo certbot --nginx -d your_domain -d www.your_domain
Certbot sẽ tự động sửa file config NGINX của bạn, thêm các block SSL và redirect HTTP → HTTPS. Nó cũng tự setup cron job để renew certificate trước khi hết hạn.
Những lỗi mình từng gặp
502 Bad Gateway: 90% là do app Next.js chưa chạy hoặc chạy sai port. Kiểm tra pm2 status và đảm bảo port trong config NGINX khớp với port app đang listen.
Static files trả về 404: Đường dẫn alias trong NGINX phải trỏ chính xác đến thư mục .next/static/ — thiếu dấu / cuối cùng là đủ để lỗi.
App chạy nhưng CSS/JS không load: Bạn quên copy thư mục .next/static lên server, hoặc đường dẫn alias sai.
Permission denied: NGINX chạy dưới user www-data. Đảm bảo user này có quyền đọc thư mục chứa static files.
Những điều nên nhớ
- Standalone mode giảm đáng kể dung lượng deploy — không cần
node_modulestrên server - PM2 là must-have để giữ app luôn sống, đừng chạy
nodetrần - NGINX serve static files trực tiếp sẽ nhanh hơn rất nhiều so với để Node.js xử lý
- Luôn chạy `nginx -t` trước khi restart
- HTTPS không phải optional — Certbot setup trong 2 phút, không có lý do bỏ qua
- Nhớ copy `.next/static` và `public` lên server vì standalone không bundle chúng
Setup này mình đã dùng cho cả dự án cá nhân lẫn production của công ty, handle vài nghìn concurrent users mà không vấn đề gì. Nếu bạn đang deploy Next.js lần đầu, hy vọng bài này giúp bạn tiết kiệm được vài giờ debug. Có gì thắc mắc thì cứ trao đổi thêm nhé!
Nguyen Nhat Long
@longnnThấy hay? Chia sẻ cho bạn bè!
Bài viết liên quan
Có thể bạn cũng thích

30 khái niệm Frontend mà bạn phải nắm trước khi đi phỏng vấn
Frameworks thay đổi, tools tiến hóa, nhưng 30 concepts này cứ xuất hiện hoài trong mọi buổi phỏng vấn frontend. Nắm chắc chúng, bạn sẽ khác biệt.

TanStack Start — Khi Next.js không còn là lựa chọn mặc định
Next.js đã thống trị 5 năm qua, nhưng sự phức tạp ngày càng tăng khiến nhiều dev tìm kiếm lựa chọn khác. TanStack Start có phải là câu trả lời?

Docker cho người mới: Hiểu đúng, dùng đúng từ ngày đầu
Tất cả những gì bạn cần biết về Docker để bắt đầu — không lý thuyết suông, có ví dụ thực tế và góc nhìn từ người đã dùng Docker hàng ngày.