Nginx 啟動命令:啟動、停止、重啟與 reload 怎麼選
Nginx 啟動命令分兩套:由 systemd 管理時用 systemctl start、stop、restart、reload nginx;直接控制程序時執行 nginx 啟動,用 nginx -s stop、quit、reload 停止或過載。改了配置先 nginx -t 檢查再 reload,不必 restart;只有升級了 Nginx 程式、改了 systemd 引數或程序狀態異常時才需要 restart。
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 的是下面三種情況:
- 升級了 Nginx 軟體包。
apt upgrade或dnf update替換的是磁碟上的程式檔案,正在執行的 master 還是舊程式,reload 只換配置不換程式。nginx -v顯示的是磁碟上的新版本,不能說明執行中的是哪個版本。確認方法是看 master 程序對應的程式檔案:ls -l /proc/$(cat /run/nginx.pid)/exe,末尾帶(deleted)說明程式已被替換,需要 restart 才會用上新版本。部分發行版的軟體包在升級時會自行處理,以這條命令的結果為準。 - 改了 systemd 的引數。 在 unit 檔案或
systemctl edit nginx裡改的LimitNOFILE、環境變數等,只在程序啟動時生效,要先systemctl daemon-reload,再systemctl restart nginx。 - 程序狀態異常。 例如 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 會讓整個容器退出。