Node.js 程式能在 http://127.0.0.1:3000 回應,只代表應用本身啟動了;要讓正式網域穩定提供服務,還需要程序管理、Nginx 反向代理、正確 Header、日誌與 HTTPS。這篇從「內部 port 已經能用」開始,帶你把 Node.js 服務接到正式網域。
這篇會完成什麼
- 確認 Node.js 應用只監聽本機或指定內部介面。
- 用 systemd 管理啟動、重啟與日誌。
- 安裝 Nginx 並設定
proxy_pass。 - 保留 Host、來源 IP 與原始連線協定資訊。
- 用
nginx -t、curl、systemctl 逐層驗證。 - 排查 502、504、404 與 Redirect loop。
架構先看懂
使用者瀏覽器
↓ HTTPS / 443
Nginx
↓ HTTP / 127.0.0.1:3000
Node.js 應用
Node.js 不一定要直接開放 3000 給全網。讓 Nginx 對外處理網域、Header、連線與憑證,應用只監聽本機 port,通常比較容易維護。
動手前先確認
- Ubuntu / Debian VPS 已可使用 SSH。
- 網域 DNS 已指向 VPS,或你準備用 curl
--resolve測試。 - Node.js 應用已經能在主機本機回應。
- 你知道程式目錄、啟動檔與執行帳號。
- 防火牆已允許真正需要的 80、443 與 SSH port。
先在 VPS 上確認應用:
curl -i http://127.0.0.1:3000/
sudo ss -lntp | grep :3000
如果這一步就失敗,先修 Node.js 應用,不要先改 Nginx。
用 systemd 管理 Node.js 程序
正式服務不適合靠 SSH 視窗裡的 node server.js 長期執行。SSH 斷線、主機重開機或程式崩潰後,服務都可能消失。
先確認 Node.js 的絕對路徑:
command -v node
readlink -f "$(command -v node)"
如果你使用 NVM,systemd 不會自動讀取互動式 shell 的 .bashrc。請把上面查到的實際路徑填進 ExecStart,並在升級 Node.js 後重新確認。
建立 /etc/systemd/system/myapp.service:
[Unit]
Description=My Node.js application
After=network.target
[Service]
Type=simple
User=deploy
WorkingDirectory=/srv/myapp
Environment=NODE_ENV=production
ExecStart=/usr/bin/node /srv/myapp/server.js
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
請把 User、WorkingDirectory、Node 路徑與啟動檔換成你的實際值。不要為了省事直接用 root 執行一般 Web 應用。
套用並啟動:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
sudo systemctl status myapp --no-pager
sudo journalctl -u myapp -n 100 --no-pager
再次確認內部 port:
curl -i http://127.0.0.1:3000/
安裝並確認 Nginx
sudo apt update
sudo apt install nginx
sudo systemctl enable --now nginx
sudo nginx -t
如果系統使用 UFW,先確認 SSH 規則存在,再開放網站連線:
sudo ufw status verbose
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
不要直接把應用的 3000 port 對外開放,除非你有明確的網路與存取控制需求。
建立 Nginx reverse proxy 設定
建立 /etc/nginx/sites-available/myapp:
server {
listen 80;
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_connect_timeout 10s;
proxy_read_timeout 60s;
}
}
這幾個 Header 的用途:
| 設定 | 用途 |
|---|---|
Host | 讓應用知道使用者原本要求的網域 |
X-Real-IP | 傳遞目前連線來源 IP |
X-Forwarded-For | 保留經過代理鏈的來源 IP 資訊 |
X-Forwarded-Proto | 告訴應用原始請求是 HTTP 還是 HTTPS |
啟用站台:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp
sudo nginx -t
sudo systemctl reload nginx
nginx -t 成功後才 reload。若 symbolic link 已存在,不要重複建立;直接檢查它是否指向正確檔案。
驗證正式網域
curl -I http://app.example.com/
curl -sS -o /dev/null -w "%{http_code}\n" http://app.example.com/
DNS 尚未切換時,可以指定新主機 IP:
curl -I --resolve app.example.com:80:203.0.113.10 http://app.example.com/
完整用法請看 curl HTTP 與 API 排錯教學。
HTTPS 要在什麼時候處理
先確認以下項目都正確,再設定 HTTPS:
- DNS 指向正確主機。
- Nginx HTTP 設定通過
nginx -t。 - 內部 Node.js port 正常回應。
- 正式網域能透過 Nginx 取得預期內容。
不要在憑證與代理 Header 尚未確認時就疊加多層強制 Redirect,否則很容易形成 HTTP / HTTPS 無限循環。若應用框架需要判斷安全連線,必須正確信任反向代理提供的 X-Forwarded-Proto,而不是一律把請求視為 HTTP。
如果你不想自行處理憑證申請、設定與到期管理,可以查看侃瑞的 SSL 憑證全程代管;網站搬遷或切換前,也建議先跑一次 網站上線檢查表。
WebSocket 要額外注意什麼
聊天、即時通知或部分開發工具會使用 WebSocket。這類服務需要正確傳遞 Upgrade Header,而且應用、Nginx 與前端 CDN 都要支援。不要在不確定需求時把所有連線一律設定成 upgrade;先確認你的應用框架與實際路徑,再依官方文件增加對應設定。
502 Bad Gateway 怎麼排查
依序檢查:
sudo systemctl status myapp --no-pager
sudo journalctl -u myapp -n 100 --no-pager
sudo ss -lntp | grep :3000
curl -i http://127.0.0.1:3000/
sudo tail -100 /var/log/nginx/error.log
常見原因:
- Node.js 程式沒啟動或持續崩潰。
proxy_passport 寫錯。- 應用只監聽另一個 IP 或 Socket。
- systemd 的
ExecStart使用了錯誤 Node.js 路徑。 - SELinux、容器網路或額外防火牆阻擋內部連線。
504、404 與 Redirect loop
504 Gateway Timeout
Nginx 找得到上游,但上游太久沒有回應。查看應用、資料庫、外部 API 與慢查詢,不要只把 proxy_read_timeout 無限加長。
404 Not Found
先比較內部與外部結果:
curl -i http://127.0.0.1:3000/test
curl -i http://app.example.com/test
內部成功、外部失敗,通常是 Nginx location、proxy_pass 尾端斜線或路徑重寫問題。
Redirect loop
檢查:
curl -IL http://app.example.com/
curl -IL https://app.example.com/
常見是 CDN、Nginx 與 Node.js 三層都在做 HTTPS Redirect,或應用不信任 X-Forwarded-Proto。
部署後的固定檢查
sudo nginx -t
systemctl is-active nginx
systemctl is-active myapp
curl -sS -o /dev/null -w "%{http_code}\n" https://app.example.com/
另外要定期確認:
- Nginx 與應用日誌沒有持續錯誤。
- 系統與 Node.js 版本仍在維護範圍。
- 備份包含應用設定、必要資料與還原說明。
- 監控不是只看「主機有開」,而是會打實際健康檢查 URL。
下一步
- Node.js 版本管理:NVM 安裝與版本切換
- 程序不斷重啟:Linux 程序管理教學
- 服務日誌排查:systemctl、journalctl 教學
- 需要一台可部署 API 或 Node.js 的主機:VPS 方案與價格