
干運(yùn)維這一行的誰沒被Nginx折磨過兩回但說實(shí)話折騰多了你會(huì)發(fā)現(xiàn)Nginx的安裝壓根不是技術(shù)問題而是選擇問題。同一個(gè)Nginx在不同機(jī)器、不同場景下安裝方式差了十萬八千里后續(xù)的維護(hù)體驗(yàn)也完全不一樣。今天這篇就專門聊聊Nginx三種主流的安裝方式源碼編譯安裝、系統(tǒng)包管理器安裝、Docker容器化部署。我會(huì)把這三種方式從原理到實(shí)操、從優(yōu)缺點(diǎn)到坑點(diǎn)全部掰開揉碎講清楚順便把我這些年踩過的坑一并交代了。不管你是剛接觸Nginx的新手還是準(zhǔn)備在公司服務(wù)器上部署的老手這篇都有參考價(jià)值。1. 三種安裝方式的選擇邏輯先想清楚再動(dòng)手很多人一上來就敲命令裝完才發(fā)現(xiàn)模塊不夠、路徑不對、沒法平滑升級然后被迫重裝。Nginx安裝這事兒十有八九的問題都出在動(dòng)手前沒想明白。1.1 為什么安裝方式如此關(guān)鍵Nginx最強(qiáng)大的地方在于它的模塊化設(shè)計(jì)但這也恰恰是安裝時(shí)最需要?jiǎng)幽X子的地方。編譯安裝時(shí)多一個(gè)--with參數(shù)、少一個(gè)模塊到后面配置SSL證書、做TCP代理、加狀態(tài)監(jiān)控時(shí)差別立刻就體現(xiàn)出來了。舉個(gè)最典型的例子很多人用包管理器裝完Nginx配置HTTPS時(shí)發(fā)現(xiàn)缺少http_ssl_module只能干瞪眼。這時(shí)候無非兩條路要么找第三方源裝帶全模塊的版本要么重新編譯。無論哪條都比一開始就規(guī)劃好要費(fèi)事得多。再說升級問題。Nginx的漏洞和Bug修復(fù)頻率不算低如果你用的是編譯安裝升級時(shí)要重新走一遍編譯流程用包管理器則一條命令搞定用Docker就更簡單換個(gè)鏡像重新起容器就行。三種方式在運(yùn)維層面的成本差距越到后期越明顯。1.2 不同場景的選型建議根據(jù)我這幾年在測試環(huán)境和生產(chǎn)環(huán)境的部署經(jīng)驗(yàn)選型邏輯大致是這么個(gè)思路源碼編譯安裝適合需要定制模塊、追求極致性能、或者內(nèi)網(wǎng)環(huán)境沒有現(xiàn)成包的情況。比如你要加http_v2_module、stream模塊或者某些特殊第三方模塊編譯安裝是唯一靠譜的路子。缺點(diǎn)是對新手不太友好編譯參數(shù)錯(cuò)了、依賴缺了排查起來有點(diǎn)頭疼。系統(tǒng)包管理器安裝適合大多數(shù)常規(guī)場景尤其是剛上手Nginx的人。CentOS的yum、Ubuntu的apt都能直接裝裝完就是標(biāo)準(zhǔn)目錄結(jié)構(gòu)systemctl管理服務(wù)配置文件位置固定網(wǎng)上教程最多出了問題也好搜。缺點(diǎn)也很明顯——官方源里的版本經(jīng)常偏老模塊不全。Docker容器化部署適合微服務(wù)架構(gòu)、多環(huán)境快速復(fù)用、以及不想污染宿主機(jī)環(huán)境的場景。一條docker run命令就能起一個(gè)Nginx配置掛在宿主機(jī)上升級就是換鏡像的事兒。但對網(wǎng)絡(luò)模式、端口映射、掛載目錄不熟悉的話剛開始也容易繞暈。我個(gè)人的建議很簡單新手先用包管理器把Nginx跑起來理解它的工作方式和配置文件結(jié)構(gòu)等需要個(gè)性化定制了再嘗試編譯安裝等理解了Nginx的機(jī)制再上手Docker部署。循序漸進(jìn)比一步到位穩(wěn)得多。2. 源碼編譯安裝自由度和性能的極致追求源碼編譯是三種方式里最“原教旨主義”的一種也是最能體現(xiàn)Nginx本來面目的安裝方式。雖然步驟繁瑣但裝完之后你對Nginx的理解會(huì)上升一個(gè)層次。2.1 編譯前的準(zhǔn)備工作先說環(huán)境和依賴。不同發(fā)行版的依賴包名字不太一樣但核心就那幾個(gè)GCC編譯器、PCRE庫正則表達(dá)式支持、zlib庫gzip壓縮支持、OpenSSL庫HTTPS支持。# CentOS / RHEL 系列 yum install -y gcc gcc-c make pcre-devel zlib-devel openssl-devel # Ubuntu / Debian 系列 apt update apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev這些依賴缺了哪個(gè)./configure階段就會(huì)報(bào)相應(yīng)的錯(cuò)誤所以最好一次性裝全。這里有個(gè)經(jīng)驗(yàn)之談不要為了省空間跳過任何依賴特別是OpenSSL-devel。之前有個(gè)同事裝完Nginx才發(fā)現(xiàn)沒有SSL模塊后面補(bǔ)裝折騰了快一個(gè)小時(shí)完全沒必要。下載源碼的話建議直接去Nginx官網(wǎng)找到下載地址用wget拉下來。國內(nèi)機(jī)器訪問官網(wǎng)速度不穩(wěn)定可以考慮用國內(nèi)鏡像源。wget https://nginx.org/download/nginx-1.22.1.tar.gz tar -zxvf nginx-1.22.1.tar.gz cd nginx-1.22.1版本這里多說一句Stable版本偶數(shù)版本號比如1.22.x是生產(chǎn)環(huán)境的首選Mainline版本奇數(shù)版本號比如1.23.x功能更新但不建議生產(chǎn)用。這是很多老手血淚總結(jié)出來的不是隨便說說。2.2 configure參數(shù)解析與選擇./configure是整個(gè)編譯安裝的靈魂也是新手最容易迷茫的地方。網(wǎng)上的教程幾乎清一色都是--prefix/usr/local/nginx配上幾個(gè)默認(rèn)參數(shù)但實(shí)際工作里參數(shù)的選擇是要根據(jù)你的業(yè)務(wù)場景來的。我常用的一個(gè)配置參數(shù)組合是這樣的./configure \ --prefix/usr/local/nginx \ --usernginx \ --groupnginx \ --with-http_ssl_module \ --with-http_v2_module \ --with-http_stub_status_module \ --with-http_gzip_static_module \ --with-stream \ --with-stream_ssl_module \ --with-pcre \ --with-cc-opt-O2 \ --with-ld-opt-Wl,-E拆開解釋幾個(gè)關(guān)鍵的--prefix指定安裝目錄。這個(gè)決定了后面所有配置文件的路徑建議一開始就規(guī)劃好不然后面改起來特別麻煩。--user和--group指定Nginx運(yùn)行的用戶務(wù)必不要用root跑Nginx。安全風(fēng)險(xiǎn)太大正確做法是先創(chuàng)建nginx用戶讓worker進(jìn)程用普通用戶身份運(yùn)行。--with-http_ssl_moduleSSL模塊做HTTPS必須要默認(rèn)不編譯進(jìn)去這是新手最容易漏的。--with-http_v2_moduleHTTP/2支持現(xiàn)在網(wǎng)站性能優(yōu)化繞不開HTTP/2建議加上。--with-stream四層TCP/UDP代理模塊。如果你想用Nginx做TCP負(fù)載均衡比如代理MySQL、Redis沒有這個(gè)模塊是不行的。--with-http_stub_status_module提供/nginx_status頁面可以查看連接數(shù)、請求數(shù)等基礎(chǔ)監(jiān)控指標(biāo)。--with-cc-opt和--with-ld-opt這兩個(gè)是給編譯器和鏈接器的額外參數(shù)普通場景用我上面給的就夠了不需要深究。2.3 make install與啟動(dòng)配置configure都通過了編譯安裝就輕松了就是兩條命令make -j4 make installmake這一步是真正把源碼編譯成二進(jìn)制的環(huán)節(jié)-j4參數(shù)是啟用4個(gè)并行任務(wù)能顯著加快編譯速度。具體的數(shù)字根據(jù)你服務(wù)器的CPU核數(shù)來定如果是2核的機(jī)器就-j2別貪多。編譯安裝完成后Nginx會(huì)被裝到/usr/local/nginx目錄下二進(jìn)制文件在sbin/nginx配置文件在conf/nginx.conf默認(rèn)站點(diǎn)根目錄在html/。這里有個(gè)很多人會(huì)忽略的問題編譯安裝的Nginx系統(tǒng)不會(huì)自動(dòng)幫你創(chuàng)建init腳本或systemd服務(wù)。也就是說你沒法用systemctl start nginx來啟動(dòng)只能手動(dòng)執(zhí)行sbin/nginx。這會(huì)帶來兩個(gè)麻煩一是開機(jī)不會(huì)自啟二是進(jìn)程掛了不會(huì)自動(dòng)拉起。解決方案是自己寫一個(gè)systemd unit文件放到/etc/systemd/system/nginx.service[Unit] Descriptionnginx - high performance web server Afternetwork.target [Service] Typeforking 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 ExecStop/usr/local/nginx/sbin/nginx -s stop Usernginx Groupnginx [Install] WantedBymulti-user.target注意到Typeforking沒有這個(gè)很關(guān)鍵。因?yàn)镹ginx的master進(jìn)程啟動(dòng)后會(huì)自動(dòng)fork出worker進(jìn)程service要等master起來才算啟動(dòng)完成。如果不這么寫systemd可能會(huì)誤判啟動(dòng)狀態(tài)。寫完保存執(zhí)行systemctl daemon-reload然后用systemctl start nginx試試正常的話就說明服務(wù)配置好了。再用systemctl enable nginx設(shè)置開機(jī)自啟。3. 系統(tǒng)包管理器安裝高效省心的標(biāo)準(zhǔn)方案如果你不想編譯或者對Nginx的定制需求不高那直接用系統(tǒng)的包管理器裝就完事兒。這條路最省心五分鐘搞定但有幾個(gè)細(xì)節(jié)值得說道。3.1 CentOS/Ubuntu的安裝方式CentOS系列默認(rèn)的yum源里是有Nginx的但版本比較老。所以我更推薦先加一個(gè)Nginx官方源這樣裝到的版本比較新。# CentOS 7 rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm # CentOS 8/9 用 dn # 先創(chuàng)建一個(gè) nginx.repo 文件 vi /etc/yum.repos.d/nginx.repo # 填入以下內(nèi)容 [nginx] namenginx repo baseurlhttp://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck1 enabled1 gpgkeyhttps://nginx.org/keys/nginx_signing.key # 然后安裝 yum install -y nginxUbuntu/Debian系列的操作邏輯類似也是先加源再安裝# 先裝依賴 apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring # 導(dǎo)入官方GPG key curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg /dev/null # 添加源 echo deb [signed-by/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu lsb_release -cs nginx | tee /etc/apt/sources.list.d/nginx.list # 安裝 apt update apt install -y nginx裝完之后Nginx二進(jìn)制在/usr/sbin/nginx配置文件在/etc/nginx/下其中nginx.conf是主配置conf.d/目錄里可以放零散的子配置sites-available/和sites-enabled/是Debian系的傳統(tǒng)布局。注意一下這里和源碼編譯安裝的目錄區(qū)別后面操作容易搞混。3.2 包管理器的目錄結(jié)構(gòu)和配置習(xí)慣用包管理器裝的Nginx配置風(fēng)格和編譯安裝的版本差異挺大的。最大的區(qū)別是兩個(gè)目錄conf.d/你下發(fā)的額外配置可以放這里比如某個(gè)站點(diǎn)的server塊。sites-available/sites-enabled/Debian系特有的“可用配置”和“啟用配置”分離機(jī)制。配置文件先放到sites-available然后用軟鏈接的方式在sites-enabled里啟用。# 在 sites-available 里新建一個(gè)站點(diǎn)配置 vi /etc/nginx/sites-available/example.conf # 內(nèi)容示例 server { listen 80; server_name example.com; root /var/www/example; index index.html; } # 啟用這個(gè)站點(diǎn) ln -s /etc/nginx/sites-available/example.conf /etc/nginx/sites-enabled/example.conf # 測試配置并重載 nginx -t systemctl reload nginx很多新手容易在conf.d和sites-enabled哪個(gè)生效上懵掉。其實(shí)關(guān)鍵看nginx.conf里http塊下的include指令把include了哪個(gè)目錄打開看一眼就明白了。3.3 官方源和第三方源的選擇建議有時(shí)候官方源的版本還是不能滿足需求比如你用CentOS 7官方源里的是1.20.x但你想用1.22的新特性。這時(shí)候有兩個(gè)選擇方案一直接從官網(wǎng)下載新版RPM包來裝wget https://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.22.1-1.el7.ngx.x86_64.rpm rpm -Uvh nginx-1.22.1-1.el7.ngx.x86_64.rpm方案二折騰一下第三方維護(hù)的源。這里不太建議在生產(chǎn)環(huán)境用因?yàn)榈谌皆戳驾积R有些和系統(tǒng)的兼容性沒有經(jīng)過充分測試。我見過不止一次因?yàn)橛昧瞬豢孔V的源導(dǎo)致Nginx裝完沒法啟動(dòng)的情況。一句話總結(jié)能用系統(tǒng)自帶源就用系統(tǒng)源能加官方源就加官方源別為了一個(gè)模塊隨便試第三方源。4. Docker容器化部署隔離與復(fù)用的現(xiàn)代化利器Docker部署Nginx是這幾種方式里面最現(xiàn)代化的也是我最推薦在云原生架構(gòu)下用的方案。它最大的好處就是環(huán)境隔離、部署一致、升級方便。但也因?yàn)槎嗔艘粚尤萜鞒橄笥行┤顺跗跁?huì)覺得不太適應(yīng)。4.1 直接running一個(gè)Nginx容器如果你只是想快速體驗(yàn)一下Nginx一條命令就能搞定docker run -d --name mynginx -p 80:80 nginx這條命令做了什么-d表示后臺(tái)運(yùn)行--name給容器起個(gè)名字-p 80:80把宿主機(jī)的80端口映射到容器的80端口。跑完之后瀏覽器訪問宿主機(jī)IP看到Nginx歡迎頁就說明成功了。但這種方式有個(gè)問題容器刪了你在里面改的配置就全沒了。所以實(shí)際使用中一定要把配置文件掛載到宿主機(jī)上。一個(gè)標(biāo)準(zhǔn)的做法是# 先把 nginx 的默認(rèn)配置拷到宿主機(jī) mkdir -p /data/nginx/{conf.d,html,logs,ssl} docker cp mynginx:/etc/nginx/nginx.conf /data/nginx/nginx.conf docker cp mynginx:/etc/nginx/conf.d/default.conf /data/nginx/conf.d/default.conf # 刪掉剛才的測試容器重新以掛載方式運(yùn)行 docker rm -f mynginx docker run -d \ --name mynginx \ -p 80:80 \ -p 443:443 \ -v /data/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \ -v /data/nginx/conf.d:/etc/nginx/conf.d \ -v /data/nginx/html:/usr/share/nginx/html \ -v /data/nginx/logs:/var/log/nginx \ -v /data/nginx/ssl:/etc/nginx/ssl \ nginx:1.22-alpine幾個(gè)關(guān)鍵點(diǎn)解釋一下nginx:1.22-alpine是Alpine Linux版鏡像體積小只有幾十MB比完整版小了一個(gè)量級。生產(chǎn)環(huán)境推薦這么用既能滿足需求又減少了攻擊面。:ro表示只讀掛載主配置文件只讀是合理的防止容器里誤改。conf.d目錄別加ro因?yàn)楹罄m(xù)可能要往里丟配置。日志目錄一定要掛載出來。不然容器一刪日志全沒排查問題啥也看不到。4.2 docker-compose編排部署如果你一個(gè)項(xiàng)目要用到Nginx加后端服務(wù)單獨(dú)跑docker run就有點(diǎn)管不過來了這時(shí)候docker-compose是更優(yōu)雅的方案。我平時(shí)最常用的編排模板大概是這樣version: 3.8 services: nginx: image: nginx:1.22-alpine container_name: web-nginx restart: always ports: - 80:80 - 443:443 volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./conf.d:/etc/nginx/conf.d - ./html:/usr/share/nginx/html - ./logs:/var/log/nginx - ./ssl:/etc/nginx/ssl networks: - webnet depends_on: - app app: image: your-app:latest container_name: web-app restart: always expose: - 8080 networks: - webnet networks: webnet: driver: bridge注意這個(gè)編排里app服務(wù)用的是expose而不是ports。什么意思呢expose只暴露給Docker內(nèi)部網(wǎng)絡(luò)訪問宿主機(jī)訪問不到。Nginx通過proxy_pass http://app:8080就能訪問到后端的服務(wù)但外部流量只能從Nginx的80端口進(jìn)來。這種設(shè)計(jì)是標(biāo)準(zhǔn)的一道入口Nginx對多個(gè)內(nèi)部服務(wù)的架構(gòu)安全性比直接把每個(gè)服務(wù)端口都暴露出來好得多。啟動(dòng)方式就一條命令docker-compose up -d日常維護(hù)命令也放在這里# 重啟 Nginx 容器 docker-compose restart nginx # 重新加載配置通過信號 docker exec web-nginx nginx -s reload # 查看 Nginx 日志 docker-compose logs -f nginx # 更新鏡像后重建 docker-compose up -d --build4.3 容器化部署的注意事項(xiàng)Docker部署Nginx看起來簡單實(shí)際上有幾個(gè)容易踩的坑。第一個(gè)坑是容器里的時(shí)間問題。默認(rèn)情況下Docker容器用的是UTC時(shí)間而不是宿主機(jī)的本地時(shí)間。這會(huì)導(dǎo)致Nginx日志里記錄的時(shí)間比實(shí)際時(shí)間慢8個(gè)小時(shí)。排查問題的時(shí)候日志時(shí)間對不上能讓人瘋掉。解決辦法很簡單運(yùn)行的時(shí)候加上時(shí)區(qū)掛載-v /etc/localtime:/etc/localtime:ro或者通過環(huán)境變量指定-e TZAsia/Shanghai第二個(gè)坑是容器內(nèi)的Nginx用戶權(quán)限問題。官方Nginx鏡像默認(rèn)以root啟動(dòng)master進(jìn)程worker進(jìn)程切換為nginx用戶。如果你掛載配置文件目錄時(shí)權(quán)限設(shè)置不對比如宿主機(jī)的目錄所有者是root容器內(nèi)nginx用戶可能沒有權(quán)限讀取導(dǎo)致啟動(dòng)失敗或者404。我的習(xí)慣是直接在掛載的宿主機(jī)目錄上設(shè)置寬松權(quán)限chown -R 101:101 /data/nginx101是nginx在官方鏡像里的UID和GID這么設(shè)置保證容器內(nèi)可以正常讀寫。第三個(gè)坑是鏡像版本和宿主機(jī)內(nèi)核的兼容性。比如在CentOS 7上用比較新的nginx鏡像有時(shí)會(huì)遇到IPv6或防火墻相關(guān)的問題。這時(shí)候優(yōu)先檢查模塊加載情況不行就換用兼容性更穩(wěn)的Alpine系鏡像。5. 三種安裝方式的對比與切換指南把三種方式都跑通之后我在實(shí)際選擇時(shí)的參照系也就清晰了。這里做一個(gè)直接的橫向?qū)Ρ裙﹨⒖肌>S度源碼編譯包管理器Docker安裝速度慢需編譯快下載即裝快拉鏡像即用定制性高可加任意模塊低受限于源中可掛載定制升級難度高重編譯低yum update低換鏡像目錄結(jié)構(gòu)自定義標(biāo)準(zhǔn)路徑容器隔離對宿主機(jī)影響占用編譯依賴安裝系統(tǒng)包幾乎無影響適配新手程度不友好友好中等適合場景生產(chǎn)定制、內(nèi)網(wǎng)部署快速部署、學(xué)習(xí)微服務(wù)、云原生5.1 從包管理器遷移到編譯安裝的注意點(diǎn)很多人的成長路徑是先yum install裝了Nginx用了一段時(shí)間后發(fā)現(xiàn)需要加模塊于是決定遷移到編譯安裝。這個(gè)遷移過程有幾個(gè)坑需要注意端口沖突編譯版和包管理器版都監(jiān)聽80端口必須先停掉舊服務(wù)再啟動(dòng)新的。配置遷移包管理器版的主配置在/etc/nginx/nginx.conf編譯版在/usr/local/nginx/conf/nginx.conf直接把文件復(fù)制過去不一定可用。因?yàn)槁窂阶兞?、用戶可能不同、include的目錄結(jié)構(gòu)也不一樣。systemd管理切換包管理器版的Nginx自帶systemd服務(wù)編譯版需要手動(dòng)創(chuàng)建工作。遷移時(shí)要先把舊的systemd服務(wù)停掉并禁用再啟用新寫的unit文件。# 停掉舊的包管理器版 systemctl stop nginx systemctl disable nginx # 備份舊配置 cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak # 編譯安裝新版本然后啟動(dòng)新的 systemd 服務(wù) systemctl start nginx5.2 平滑升級與版本回退技巧Nginx最讓我喜歡的一個(gè)特性就是平滑升級這也是它在生產(chǎn)環(huán)境里地位不可撼動(dòng)的重要原因。用源碼編譯方式升級時(shí)這個(gè)優(yōu)勢體現(xiàn)得淋漓盡致。# 假設(shè)你是源碼編譯安裝當(dāng)前在 /usr/local/nginx/nginx-1.20 # 下載新版源碼比如 1.22解開后進(jìn)入目錄重新編譯 ./configure --prefix/usr/local/nginx --with-http_ssl_module make -j4 # 不要 make install先把新二進(jìn)制備份然后替換舊二進(jìn)制 cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old cp ./objs/nginx /usr/local/nginx/sbin/nginx # 給運(yùn)行中的舊 master 發(fā)送 USR2 信號讓它啟動(dòng)新的 master kill -USR2 $(cat /usr/local/nginx/logs/nginx.pid) # 關(guān)閉舊的 worker 進(jìn)程 kill -WINCH $(cat /usr/local/nginx/logs/nginx.pid.oldbin)執(zhí)行完這一套流程N(yùn)ginx進(jìn)程已經(jīng)被無縫切換到新版本期間不會(huì)中斷任何一個(gè)請求。這是Nginx設(shè)計(jì)最優(yōu)雅的地方比很多動(dòng)不動(dòng)就要重啟的服務(wù)不知道高到哪里去了。如果新版本有問題想回退就反過來# 給新的 master 發(fā)送 HUP 信號重載配置然后恢復(fù)舊二進(jìn)制 mv /usr/local/nginx/sbin/nginx.old /usr/local/nginx/sbin/nginx kill -HUP $(cat /usr/local/nginx/logs/nginx.pid)5.3 卸載Nginx要徹底說完了安裝和升級卸載也是繞不開的話題。尤其是你從包管理器版切到編譯版或者反過來卸載不徹底會(huì)留下各種暗坑。yum安裝的卸載yum remove nginx # 或者 rpm -e nginx編譯安裝的卸載由于沒有統(tǒng)一的卸載命令需要手動(dòng)清理# 停掉服務(wù) /usr/local/nginx/sbin/nginx -s stop # 或者 kill 掉 master 進(jìn)程 # 刪除安裝目錄 rm -rf /usr/local/nginx # 清理 systemd 服務(wù)文件 rm -f /etc/systemd/system/nginx.service systemctl daemon-reload # 清理 nginx 用戶 userdel nginxDocker部署的卸載就簡單多了docker stop mynginx docker rm mynginx docker rmi nginx:1.22-alpine卸載時(shí)最容易遺漏的就是殘留配置文件和日志。包管理器版刪掉之后/etc/nginx目錄可能還在編譯版刪掉后/usr/local/nginx目錄可能沒刪干凈。重新安裝時(shí)如果遇到奇怪的問題優(yōu)先檢查這些老配置是不是被新的實(shí)例加載了。6. 常見問題與排查技巧實(shí)錄最后這部分我根據(jù)自己的實(shí)踐和接觸過的案例把安裝Nginx時(shí)最容易遇到的問題整理成一個(gè)速查表希望能幫你省去一些排查時(shí)間。問題現(xiàn)象可能原因解決方法./configure報(bào)缺少PCRE/zlib/OpenSSL依賴包未安裝安裝pcre-devel zlib-devel openssl-devel編譯報(bào)undefined reference錯(cuò)誤模塊之間依賴關(guān)系沒處理好檢查--with參數(shù)去掉沖突模塊nginx -t報(bào)配置錯(cuò)誤配置文件語法有誤逐段檢查用nginx -t -c指定配置文件測試啟動(dòng)失敗端口被占用80端口被Apache或其他服務(wù)占用netstat -tlnp查占用進(jìn)程改Nginx監(jiān)聽端口想用HTTPS但配置報(bào)unknown directive sslnginx二進(jìn)制未編譯SSL模塊重新編譯加上--with-http_ssl_module或者換包管理器版Docker容器無法訪問外部端口防火墻未放行或端口未映射檢查docker -p參數(shù)firewall-cmd放行端口Docker掛載配置后404掛載目錄權(quán)限不對設(shè)置chown -R 101:101宿主機(jī)目錄日志時(shí)區(qū)差8小時(shí)容器默認(rèn)UTC時(shí)間掛載/etc/localtime或設(shè)TZAsia/Shanghaiaccess_log顯示Permission deniedNginx用戶無權(quán)限寫日志目錄檢查日志目錄權(quán)限改為nginx用戶或調(diào)整權(quán)限6.1 編譯安裝的依賴排查方法編譯安裝時(shí)報(bào)依賴缺失是最高頻的坑。排查的方法很簡單就是看./configure輸出的最后幾行錯(cuò)誤信息。比如這行checking for PCRE library ... not found ./configure: error: the HTTP rewrite module requires the PCRE library.它明確告訴你缺少PCRE。但這里有個(gè)迷惑性的點(diǎn)報(bào)的是“l(fā)ibrary”而不是“development headers”。有些時(shí)候你明明裝了pcre包但缺少pcre-devel也會(huì)報(bào)這個(gè)錯(cuò)。解決辦法就是把devel包一并裝上。還有一個(gè)技巧如果編譯時(shí)提示缺少某個(gè)lib但用yum install又找不到對應(yīng)的包可以用yum provides */頭文件來搜索哪個(gè)包提供了這個(gè)文件。yum provides *pcre.h這樣會(huì)列出所有包含pcre.h的軟件包找到對應(yīng)的devel包裝上去就行。6.2 systemd服務(wù)啟動(dòng)異常的處理思路編譯Nginx后手動(dòng)寫的systemd service啟動(dòng)時(shí)最容易出問題。我常用的排查流程是這樣的# 1. 查看服務(wù)狀態(tài)和錯(cuò)誤信息 systemctl status nginx # 2. 檢查日志 journalctl -u nginx # 3. 手動(dòng)執(zhí)行看具體報(bào)錯(cuò) /usr/local/nginx/sbin/nginx -t最常見的問題是PIDFile路徑寫錯(cuò)了。Nginx編譯安裝后默認(rèn)PID文件在logs/nginx.pid相對prefix路徑也就是/usr/local/nginx/logs/nginx.pid。systemd里寫錯(cuò)路徑會(huì)導(dǎo)致服務(wù)狀態(tài)判斷錯(cuò)誤。解決辦法就是在unit文件里和nginx.conf里都確認(rèn)PID路徑保持一致。6.3 Docker容器退出狀態(tài)排查實(shí)錄跑Docker版Nginx時(shí)如果容器啟動(dòng)就退出通常先看日志docker logs mynginx常見錯(cuò)誤有幾種端口占用宿主機(jī)80端口已經(jīng)有個(gè)Nginx在跑了Docker再綁定就會(huì)沖突。這時(shí)候要么停掉宿主機(jī)Nginx要么改Docker的端口映射。配置文件掛載錯(cuò)誤你掛載了宿主機(jī)上的一個(gè)nginx.conf但這個(gè)文件語法有問題Nginx啟動(dòng)時(shí)檢測失敗直接退出。解決方法是先在宿主機(jī)上用docker鏡像跑一下nginx -tdocker run --rm -v /data/nginx/nginx.conf:/etc/nginx/nginx.conf:ro nginx:1.22-alpine nginx -t這個(gè)命令很實(shí)用相當(dāng)于用容器內(nèi)的Nginx二進(jìn)制來校驗(yàn)掛載的配置有沒有語法錯(cuò)誤。文件權(quán)限問題掛載了日志目錄或證書文件但權(quán)限不夠容器的worker進(jìn)程無法寫入/讀取。這種情況日志里會(huì)有Permission denied類似的提示。寫在最后的經(jīng)驗(yàn)之談安裝Nginx這件事情本身沒有多難真正的價(jià)值在于搞清楚每條命令背后的邏輯和取舍。我自己從一開始只會(huì)yum install nginx到后來為了加模塊去學(xué)編譯參數(shù)再到用Docker做自動(dòng)化部署中間踩過不少坑但也正是這些坑讓我對Nginx的理解越來越深。如果讓我給一個(gè)最直接的建議那就是不管用哪種方式安裝先把nginx -t、reload、logs這幾個(gè)基本操作練熟。安裝只是開始后面的配置和運(yùn)維才是真正考驗(yàn)人的地方。配置文件的語法錯(cuò)誤排查、日志的解讀、反向代理的調(diào)試這些才是讓Nginx真正發(fā)揮價(jià)值的工作。一個(gè)新裝的Nginx跑起歡迎頁不算本事能穩(wěn)定承載線上流量才是水平。最后再分享一個(gè)我個(gè)人的小習(xí)慣安裝完Nginx后第一時(shí)間把nginx -V的輸出保存下來標(biāo)注好日期。這個(gè)命令會(huì)顯示編譯時(shí)用了哪些參數(shù)、添加了哪些模塊。等哪天忘了自己裝的是什么配置或者需要排查詭異問題的時(shí)候這串信息能省不少事。