
改 OpenResty 配置之前我做了備份。備份包躺在目錄里1.5K。這臺(tái)機(jī)器不是我一個(gè)人的。1Panel 面板上掛著 9 個(gè)站點(diǎn)我自己的 3 個(gè)別人的 6 個(gè)。我那三個(gè)域名是 h5.example.com、api.example.com、admin.example.com。在這種機(jī)器上任何一次 nginx -s reload 都在同時(shí)動(dòng) 9 個(gè)業(yè)務(wù)。所以我先備份再改配置。給的那條命令是這一條。tar-czf$BK$(dirname$(find /opt/1panel-name*.conf-path*conf.d*2/dev/null|head-1))跑完 ls -lh 一看。-rw-r--r-- 1 root root 1.5K Sep 22 20:41 openresty_backup.tar.gz九個(gè)站點(diǎn)的配置壓縮完 1.5K。這個(gè)數(shù)字本身就在報(bào)警??晌耶?dāng)時(shí)接下去做的事是改配置不是打開(kāi)包看看。這條命令我是怎么想出來(lái)的拆開(kāi)看里頭疊了三層錯(cuò)。單看每一層都像個(gè)好習(xí)慣。第一層出在 -path “conf.d”。我一開(kāi)始想的是「站點(diǎn)配置都在 conf.d 里」就先拿 -path 篩了一遍???/opt/1panel 下面不止一個(gè) conf.d面板自己的、鏡像默認(rèn)的、各個(gè)應(yīng)用目錄里都有。這個(gè)條件沒(méi)能幫我定位到站點(diǎn)配置只是把候選集縮成了一堆同名目錄。第二層是 | head -1。這層最致命。find 的輸出順序取決于文件系統(tǒng)怎么遍歷不是按重要性排的也不保證穩(wěn)定。第一條是誰(shuí)不知道。第三層是 $(dirname …)。它把「一個(gè)文件」換成了「一個(gè)目錄」然后只備份這一個(gè)目錄。三層疊起來(lái)的結(jié)果是find 找到的第一個(gè) .conf 所在的那個(gè)目錄被打包其余全都不進(jìn)包。而它實(shí)際取到的是面板或者鏡像自帶的那個(gè)默認(rèn) conf.d里面是出廠配置不含任何站點(diǎn)配置。兩個(gè)目錄的掛載關(guān)系是這樣。宿主 /opt/1panel/www ── 容器內(nèi) /www 宿主 /opt/1panel/www/conf.d ── 容器內(nèi) /usr/local/openresty/nginx/conf/conf.d真正要備份的站點(diǎn)配置在 /opt/1panel/www/… 這一支上我取到的是另一支。還有第四層也是最該記住的一層。我沒(méi)驗(yàn)證。tar 不報(bào)錯(cuò)ls 顯示文件存在退出碼是 0。一個(gè)空備份和一份有效備份在命令行回顯上長(zhǎng)得一模一樣。哪一刻確認(rèn)它等于沒(méi)備份讓我確認(rèn)的是這條命令。tar-tzf$BK|grep-Eexample\.com沒(méi)有任何輸出。tar -tzf 列出包內(nèi)文件清單grep 拿域名關(guān)鍵字去篩一個(gè)站點(diǎn)都沒(méi)有。那時(shí)候我正準(zhǔn)備改一個(gè) OpenResty 配置改錯(cuò)就要回滾而回滾依據(jù)的那個(gè)包里一片空白。同機(jī) 6 個(gè)別人的站點(diǎn)正跑著。驗(yàn)收標(biāo)準(zhǔn)只有一個(gè)我要保的域名在不在包里這件事給我的教訓(xùn)不是「命令寫(xiě)錯(cuò)了」。一個(gè) 1.5K 的包確實(shí)存在可它承諾不了任何東西。所以驗(yàn)收動(dòng)作得回答一個(gè)具體問(wèn)題我要保的那幾個(gè)域名在包里嗎正確打包是把 find 的結(jié)果整體交給 tar而不是取一條再 dirname。BK/opt/1panel/backup;TS$(date%Y%m%d_%H%M%S);mkdir-p$BK# ① 全量打包find 的結(jié)果通過(guò) -T - 從 stdin 交給 tar繞開(kāi)參數(shù)展開(kāi)與空格問(wèn)題find/opt/1panel-name*.conf-typef2/dev/null\|tar-czf$BK/openresty_all_$TS.tar.gz-T-ls-lh$BK/openresty_all_$TS.tar.gz# ② 必須驗(yàn)證列得出域名才算備份成立tar-tzf$BK/openresty_all_$TS.tar.gz|grep-Eexample\.com-T - 這處是關(guān)鍵。tar 從標(biāo)準(zhǔn)輸入讀文件列表繞開(kāi)了 $(…) 展開(kāi)帶來(lái)的參數(shù)個(gè)數(shù)上限和文件名空格問(wèn)題。如果路徑里可能有空格用 -print0 與 --null 配對(duì)。find/opt/1panel-name*.conf-typef-print02/dev/null\|tar-czf$BK/openresty_all_$TS.tar.gz--null-T-驗(yàn)證這一步不是可選項(xiàng)它是備份的一部分。只做打包、不做驗(yàn)證和那條 head -1 命令沒(méi)有本質(zhì)區(qū)別你只是換了一種方式不知道自己備份了什么。還有一點(diǎn)不顯眼但很要命備份包要帶時(shí)間戳命名就是上面命令里的 $TS。它不是為了歸檔整齊而是為了不覆蓋上一份。你永遠(yuǎn)不知道上一份是不是唯一一份還有效的。順帶一條怎么確認(rèn)真正生效的配置在哪個(gè)文件面板托管的 Nginx配置文件位置不一定是你以為的那個(gè)。這條命令能 dump 全部生效配置并把每一段配置的來(lái)源文件打出來(lái)。dockerexec面板web容器nginx-T21\|sed-ns/^# configuration file \(.*\):$/\1/p|sort-u兩點(diǎn)要注意。輸出的是容器內(nèi)路徑要對(duì)照掛載關(guān)系換算成宿主路徑比如 /www/… 換回 /opt/1panel/www/…。它回答的是「哪些文件被真正加載了」這正好就是你的備份清單該覆蓋的集合。固化成幾條能復(fù)用的判據(jù)打包這一步做法是 find 根路徑 -name “*.conf” -type f -print0 交給 tar -czf 包 --null -T -。不用 head也不用 dirname 取單條。驗(yàn)證內(nèi)容這步是 tar -tzf 包 再 grep -E “域名關(guān)鍵字”列得出生效域名才算過(guò)列不出來(lái)就回到打包那步重來(lái)。驗(yàn)證可解是 tar -xzf 包 -C /tmp/verify 之后 ls /tmp/verify看能不能解出目錄樹(shù)。確認(rèn)配置來(lái)源還是用 docker exec 進(jìn)面板 web 容器跑 nginx -T。再 sed 出 # configuration file 那幾行去重。改前基線要逐個(gè)域名 curl 一遍參數(shù)是 -s -o /dev/null -w “%{http_code}” --max-time 8。再帶上 Host 頭打 http://127.0.0.1/全 200 或者 301 就記錄下來(lái)。改后用同一條 for 循環(huán)再跑一次跟基線對(duì)照掉了就立刻回滾。語(yǔ)法門(mén)禁是 docker exec 進(jìn)容器跑 nginx -t看到 syntax is ok 才 reload?;€和改后對(duì)照這兩步在這臺(tái)機(jī)器上尤其重要。它的粒度不是「我這個(gè)站點(diǎn)」而是「這臺(tái)機(jī)上全部 9 個(gè)」。grep 的關(guān)鍵字要覆蓋他人站點(diǎn)的域名不能只 grep 自己的。你動(dòng)的這份配置影響的是整臺(tái)機(jī)。剩下的幾條我一起放在這里。find 加 head -1 取到的不是「一個(gè)代表」它是個(gè)「未知」備份要全量用 -T - 把清單整體交給 tar。1.5K 這個(gè)數(shù)字本身就是信號(hào)備份體積和常識(shí)不匹配的時(shí)候先停下來(lái)。nginx -T 能打出每一段配置的來(lái)源文件這是該備份哪些文件的權(quán)威清單。備份不做驗(yàn)證那張包就是空的。