伺服器維運

Nginx 啟動命令:啟動、停止、重啟與 reload 怎麼選

Nginx 啟動命令分兩套:由 systemd 管理時用 systemctl start、stop、restart、reload nginx;直接控制程序時執行 nginx 啟動,用 nginx -s stop、quit、reload 停止或過載。改了配置先 nginx -t 檢查再 reload,不必 restart;只有升級了 Nginx 程式、改了 systemd 引數或程序狀態異常時才需要 restart。

作者 頂聯產品團隊發布於 6 分鐘閱讀

Nginx 啟動命令取決於它是怎麼裝上的。用 apt、dnf 從發行版軟體源或 nginx.org 官方倉庫安裝的,由 systemd 管理,啟動執行 systemctl start nginx;原始碼編譯或解壓即用的版本,直接執行 Nginx 程式本身,例如 /usr/local/nginx/sbin/nginx。停止、重啟、過載也是兩套寫法:systemctl stop|restart|reload nginx,或者 nginx -s stop|quit|reload。日常改配置只需要 nginx -t 檢查透過後 reload,正在存取的使用者不會斷開;restart 會讓整個程序退出再啟動,留給少數幾種必須用它的情況。

所有寫法一張表:啟動、停止、重啟、過載

操作 systemd 管理時 直接控制程序 對應訊號 效果
啟動 systemctl start nginx nginx — 啟動 master 程序和若干 worker 程序
快速停止 systemctl stop nginx(具體訊號由 unit 檔案決定) nginx -s stop TERM 或 INT 立即退出,正在傳輸的請求被切斷
優雅停止 — nginx -s quit QUIT 不再接受新連線,處理完手頭的請求再退出
過載配置 systemctl reload nginx nginx -s reload HUP 用新配置啟動新 worker,舊 worker 處理完再退出
重啟 systemctl restart nginx nginx -s quit 之後再執行 nginx — 整個程序退出後重新啟動,master 的 PID 改變
重新開啟日誌 — nginx -s reopen USR1 日誌被輪轉改名後,讓 Nginx 寫入新檔案
檢查配置 nginx -t nginx -t — 只檢查語法和引用的檔案,不影響正在執行的程序
檢視狀態 systemctl status nginx pgrep -a nginx — —

日常用到的命令:

# systemd 管理的 Nginx(發行版軟體源或 nginx.org 官方倉庫安裝)
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
sudo nginx -t && sudo systemctl reload nginx    # 檢查透過才過載
sudo systemctl enable --now nginx               # 設為開機自啟並立即啟動
systemctl status nginx --no-pager

# 直接控制程序(原始碼編譯預設裝在 /usr/local/nginx)
sudo /usr/local/nginx/sbin/nginx                # 啟動
sudo /usr/local/nginx/sbin/nginx -s quit        # 優雅停止
sudo /usr/local/nginx/sbin/nginx -s stop        # 快速停止
sudo /usr/local/nginx/sbin/nginx -t && sudo /usr/local/nginx/sbin/nginx -s reload

幾個容易踩的細節:

  • nginx -s 靠 pid 檔案找 master 程序。 它先讀配置裡的 pid 指令,拿到 pid 檔案裡的程序號再發訊號。啟動時用 -c 指定了別的配置檔案,發訊號時也要帶上同一個 -c,例如 nginx -c /opt/nginx/conf/nginx.conf -s reload,否則會報 open() ".../nginx.pid" failed 或 invalid PID number。
  • 提示 nginx: command not found。 原始碼編譯的程式不在 PATH 裡。執行 ps -ef | grep "nginx: master",master 程序的命令列會顯示完整路徑和配置檔案,例如 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf;常用的話做一個軟連結:ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/nginx。寶塔面板裝的 Nginx 在 /www/server/nginx/sbin/nginx,一般透過面板或它提供的服務指令碼控制。
  • service 寫法。 CentOS 6 這類老系統用 service nginx restart 或 /etc/init.d/nginx reload;在 systemd 系統上執行 service 命令,會被轉交給 systemctl,效果相同。
  • 直接用 kill 發訊號也可以。 kill -HUP $(cat /run/nginx.pid) 等價於 reload,kill -QUIT 等價於 quit。pid 檔案的位置以 grep -E '^\s*pid' /etc/nginx/nginx.conf 查到的為準。

reload 和 restart 的區別:什麼時候必須 restart

收到 reload 後,master 程序先檢查新配置並開啟新的連接埠和日誌檔案;檢查透過,就用新配置啟動一批新的 worker,再通知舊 worker 不再接收新連線、處理完手頭的請求後退出。整個過程中監聽連接埠一直開著,使用者感知不到。新配置有錯時,master 把錯誤寫進 error.log,拒絕載入,繼續用舊配置執行。restart 則是先停止、再啟動:兩步之間連接埠關閉,新連線會被拒絕;如果新配置有錯,啟動失敗,網站就停在那裡了。

對比項 reload restart
master 程序 不變,PID 不變 退出後重新啟動,PID 改變
正在處理的請求 舊 worker 處理完再退出 取決於停止訊號:TERM 立即切斷,QUIT 等請求處理完(受超時限制)
監聽連接埠 一直在監聽,不會拒絕新連線 停止到啟動之間連接埠關閉
新配置有錯 拒絕載入,按舊配置繼續執行 啟動失敗,網站中斷
是否換成磁碟上的新程式 不會,仍執行原來的程式 會
適用場景 絕大多數配置修改:server、location、upstream、證書、日誌格式、限流 升級 Nginx 程式、改 systemd 引數、程序狀態異常

換證書也屬於配置修改,reload 就能讓新證書生效。真正需要 restart 的是下面三種情況:

  1. 升級了 Nginx 軟體包。 apt upgrade 或 dnf update 替換的是磁碟上的程式檔案,正在執行的 master 還是舊程式,reload 只換配置不換程式。nginx -v 顯示的是磁碟上的新版本,不能說明執行中的是哪個版本。確認方法是看 master 程序對應的程式檔案:ls -l /proc/$(cat /run/nginx.pid)/exe,末尾帶 (deleted) 說明程式已被替換,需要 restart 才會用上新版本。部分發行版的軟體包在升級時會自行處理,以這條命令的結果為準。
  2. 改了 systemd 的引數。 在 unit 檔案或 systemctl edit nginx 裡改的 LimitNOFILE、環境變數等,只在程序啟動時生效,要先 systemctl daemon-reload,再 systemctl restart nginx。
  3. 程序狀態異常。 例如 pid 檔案被誤刪、master 被 kill 後殘留 worker、reload 報 invalid PID number。先用 pgrep -a nginx 看清有哪些程序,必要時全部結束,再用 systemctl 重新啟動。

確認 reload 是否成功,看程序啟動時間:

ps -o pid,ppid,lstart,cmd -C nginx

reload 成功後,master 的 PID 和啟動時間不變,worker 都是剛啟動的新程序。如果還有標著 worker process is shutting down 的舊 worker 遲遲不退,通常是 WebSocket、大檔案下載這類長連線還沒結束。頻繁 reload 時這些舊程序會越積越多、佔用記憶體,可以在 nginx.conf 的最外層加 worker_shutdown_timeout 30s;,讓舊 worker 最多等 30 秒就關閉剩餘連線退出。

至於 restart 時正在處理的請求會不會被切斷,要看 unit 檔案怎麼寫。不同來源的 unit 寫法不同:有的停止時發 QUIT 並等待幾秒,超時再強制結束;有的直接發 TERM。執行 systemctl cat nginx,看 ExecStop、KillSignal、TimeoutStopSec 這幾行就清楚了。

如果升級 Nginx 程式也不能接受斷連,Nginx 官方文件提供了不停機替換程式的訊號流程:給舊 master 發 USR2 啟動新程式,再用 WINCH 讓舊 worker 退出,確認新程序正常後對舊 master 發 QUIT。由 systemd 管理時,systemd 跟蹤的是 pid 檔案裡記錄的主程序,手工做這套流程前先確認 unit 檔案的 PIDFile 設定;沒把握的話,在業務低峰期 restart 更省事。

原始碼編譯的 Nginx 怎麼交給 systemd 管理

原始碼編譯裝的 Nginx 沒有 unit 檔案,systemctl start nginx 會提示 Unit nginx.service not found。可以自己寫一個,儲存為 /etc/systemd/system/nginx.service:

[Unit]
Description=nginx web server
After=network-online.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed

[Install]
WantedBy=multi-user.target

要點有三個:PIDFile 必須和 nginx.conf 裡 pid 指令的路徑一致(原始碼編譯預設是安裝目錄下的 logs/nginx.pid);ExecStartPre 先跑一遍 nginx -t,配置有錯時直接拒絕啟動;停止用 QUIT 訊號優雅退出,5 秒內沒退完再強制結束。不建議用 ExecStop=nginx -s quit 代替 KillSignal:這條命令發完訊號立即返回,systemd 隨即認為停止動作已經完成,按 KillMode 和 KillSignal 處理剩餘程序,KillSignal 保持預設的 TERM 時,等於又發了一次快速停止,優雅退出就失去了意義。

寫好後先把手動啟動的程序停掉,再交給 systemd:

sudo /usr/local/nginx/sbin/nginx -s quit
sudo systemctl daemon-reload
sudo systemctl enable --now nginx
systemctl status nginx --no-pager

Windows 下怎麼啟動、停止、重啟 Nginx

Windows 版 Nginx 是 nginx.org 下載的 zip 包,解壓即用,不是系統服務。它把執行時所在的目錄當作相對路徑的起點,所以所有命令都要先進入 Nginx 目錄再執行,否則會報找不到 conf\nginx.conf 或 logs\nginx.pid。在命令提示符(cmd)裡:

cd /d C:\nginx
start nginx
nginx -t
nginx -s reload
nginx -s quit
nginx -s stop
tasklist /fi "imagename eq nginx.exe"
taskkill /f /im nginx.exe
  • 用 start nginx 啟動,它會在後台另開程序;直接執行 nginx.exe 會佔住當前視窗。預設配置下工作管理員裡會看到兩個 nginx.exe,一個 master、一個 worker,這是正常的。
  • Windows 上的重啟就是 nginx -s quit 之後再 start nginx;只是改了配置,用 nginx -s reload。
  • 在 PowerShell 裡要寫成 .\nginx.exe -s reload、Start-Process .\nginx.exe,PowerShell 預設不從當前目錄查詢命令,直接寫 nginx 會提示找不到。
  • taskkill /f 是強制結束,用於 -s 命令失效、程序殘留的情況,平時不要用它代替 quit。

Windows 上幾個特有的啟動報錯:

報錯 原因 處理
bind() to 0.0.0.0:80 failed (10048: ...) 連接埠已被佔用,常見是之前啟動的 Nginx 沒退出,或者 IIS 在用 80 連接埠 netstat -ano | findstr :80 查 PID,再用 tasklist /fi "pid eq 1234" 看是哪個程式;PID 為 4 表示被系統的 HTTP.sys(IIS 等)佔用
bind() to 0.0.0.0:80 failed (10013: ...) 連接埠被系統保留,或者被其他程式以獨佔方式佔用 執行 netsh interface ipv4 show excludedportrange protocol=tcp 檢視保留的連接埠範圍(開啟 Hyper-V、WSL 後常見),換一個不在範圍內的連接埠
CreateFile() ... failed (1113: ...) Nginx 所在路徑或配置裡的路徑含中文 放到全英文路徑下,例如 C:\nginx

Nginx 啟動失敗怎麼排查

systemctl start nginx 失敗時,螢幕上只有一句 Job for nginx.service failed because the control process exited with error code。按這個順序找原因:

sudo nginx -t                               # 1. 配置有沒有錯,報錯會給出檔案和行號
systemctl status nginx --no-pager -l        # 2. 最近幾行啟動日誌
journalctl -u nginx -n 30 --no-pager        # 3. 更完整的啟動日誌
sudo tail -n 30 /var/log/nginx/error.log    # 4. Nginx 自己的錯誤日誌
sudo ss -lntp | grep -E ':(80|443)\b'       # 5. 80、443 連接埠被誰佔著

常見報錯與處理:

報錯 原因 處理
bind() to 0.0.0.0:80 failed (98: Address already in use) 連接埠被佔用:Apache(httpd)、面板自帶的 Web 服務,或者一個手動啟動、不歸 systemd 管的 Nginx 用 ss -lntp 找到佔用的程序;如果佔用者就是 nginx,先 nginx -s quit 停掉它,再 systemctl start nginx
bind() to [::]:80 failed (97: Address family not supported by protocol) 系統關閉了 IPv6,配置裡卻有 listen [::]:80 刪除或註釋 IPv6 的 listen 行
bind() to 0.0.0.0:連接埠 failed (13: Permission denied) 用普通使用者啟動、監聽 1024 以下的連接埠;或者 SELinux 不允許 Nginx 監聽 8088 這類非標準連接埠 用 root 或 systemd 啟動;SELinux 環境執行 semanage port -a -t http_port_t -p tcp 8088 放行該連接埠
unknown directive "proxy_passs" 指令拼錯,或用了沒編譯進來的模組的指令 核對拼寫;用 nginx -V 檢視編譯了哪些模組
directive "server_name" is not terminated by ";" 漏了分號 按報錯給出的檔案和行號修改,行號可能指向下一行
unexpected "}" 或 unexpected end of file, expecting "}" 花括號不配對 檢查報錯位置前面最近的幾個塊
cannot load certificate "...": BIO_new_file() failed 證書路徑寫錯,或檔案沒有讀許可權 用 ls -l 核對路徑和許可權
報錯中含 key values mismatch 證書和私鑰不是一對 分別執行 openssl x509 -in 證書.pem -noout -pubkey | openssl sha256 和 openssl pkey -in 私鑰.key -pubout | openssl sha256,兩個結果相同才是一對
could not build server_names_hash, you should increase server_names_hash_bucket_size 域名太長或太多 在 http 塊加 server_names_hash_bucket_size 128;

連接埠占用裡最常見的一種是“兩種啟動方式混用”:有人直接執行過 nginx,程序在執行,systemctl status 卻顯示 inactive;這時再 systemctl start nginx 必然報 98 連接埠占用,而網站其實一直在跑。解決辦法是停掉手動啟動的那個,以後統一用 systemctl。

另外,systemctl status 裡出現 Can't open PID file /run/nginx.pid (yet?) after start 一般只是 systemd 讀取 pid 檔案早了一點,服務狀態顯示 active (running) 就不用處理。啟動顯示成功、網頁卻打不開,先在伺服器本機執行 curl -I http://127.0.0.1 區分問題出在 Nginx 還是出在防火牆和安全組。

SSH 連不上時怎麼重啟 Nginx

有兩種情況會讓你在 SSH 裡處理不了 Nginx:改防火牆規則時連 22 連接埠一起封掉了,或者伺服器負載過高、SSH 遲遲登入不上。這時只能從伺服器的“螢幕”進去。在 Toplink DCIM 裡,維運人員從 IPMI 遠端管理開啟基於 BMC 的 VNC 控制檯,業務網路斷了也能看到系統的登入提示符,用 root 登入後先 nginx -t,再按需要 reload 或 restart,防火牆規則也可以在這裡改回來。如果機器已經租給客戶,服務商開放相應許可權後,客戶在客戶自助端也能開啟同樣的控制檯自行處理;系統確實卡死、控制檯沒有回應時,才需要重啟或進入救援模式。

常見問題

nginx -s reload 和 systemctl reload nginx 有區別嗎?

效果一樣,都是讓 master 程序重新讀取配置。區別在管理歸屬:由 systemd 啟動的 Nginx 統一用 systemctl 操作,systemctl status 顯示的狀態才準確;手動執行 nginx 啟動的程序不歸 systemd 管,是“明明在執行、status 卻顯示 inactive”這類混亂的主要來源。

怎麼設定 Nginx 開機自啟?

Linux 上執行 systemctl enable nginx,想同時立即啟動就用 systemctl enable --now nginx,再用 systemctl is-enabled nginx 確認結果為 enabled。Windows 版 Nginx 不是系統服務,開機自啟要藉助 WinSW、NSSM 這類把程式包裝成服務的工具,或者放進計劃任務。

reload 之後配置沒生效怎麼辦?

先看 error.log 裡 reload 那一刻有沒有 emerg 報錯,新配置有錯時 Nginx 會繼續按舊配置執行。沒有報錯,就用 nginx -T 列印實際載入的完整配置,確認改的檔案確實被 include 進來,以及請求有沒有被另一個 server_name 相同或帶 default_server 的 server 塊先匹配走。

Docker 裡的 Nginx 怎麼重啟和過載?

過載執行 docker exec 容器名 nginx -s reload,改配置前同樣可以先 docker exec 容器名 nginx -t 檢查;重啟用 docker restart 容器名。容器裡的 Nginx 以 daemon off 方式在前台執行,是容器的主程序,在容器裡執行 nginx -s stop 或 quit 會讓整個容器退出。

想看看在你的機房裡怎麼用?

從一次產品示範開始,梳理你的業務鏈路。

查看價格
服務熱線 400-112-2951

讓我們聊聊你的 IDC 業務

掃碼新增企業微信,預約產品示範或申請試用。

Toplink 企業微信二維碼

長按儲存或使用企業微信 / 微信掃描

也可致電
400-112-2951
Telegram
@TopLink88