網(wǎng) PHP 環(huán)境配置實(shí)戰(zhàn))
內(nèi)網(wǎng)機(jī)器不給外網(wǎng)、運(yùn)維只丟過來一臺(tái)裝了基礎(chǔ)系統(tǒng)的虛擬機(jī)、需求是搭個(gè)能跑 PHP 的測試環(huán)境——這事我前后干過四五次每次環(huán)境不一樣坑也不一樣。用包管理器一個(gè)個(gè)裝 Apache、PHP、MariaDB 是一條路但版本糾纏、依賴鏈長、離線環(huán)境下補(bǔ)包補(bǔ)到懷疑人生另一種更省事的做法是直接用 XAMPP 的自包含安裝包一個(gè).run文件拷進(jìn)去賦權(quán)執(zhí)行幾分鐘后/opt/lampp就能跑起來。這篇就把我在 Linux 下做 XAMPP 安裝與配置的整套流程講透重點(diǎn)放在離線安裝這條線上包從哪來、怎么校驗(yàn)、怎么帶進(jìn)內(nèi)網(wǎng)、裝完之后的權(quán)限與安全策略怎么收以及那些官方文檔不會(huì)寫、但一定會(huì)讓你卡住的細(xì)節(jié)。內(nèi)容面向兩類人一類是手上完全沒接觸過 XAMPP、只想快速把環(huán)境跑通的新手另一類是在隔離網(wǎng)絡(luò)里做交付、需要一套可復(fù)現(xiàn)流程的老手。新手按著步驟走能裝成老手可以直接跳到第 3、4、6 章看我踩過的具體坑。1. 離線環(huán)境里為什么還是選 XAMPP先把它能干什么、不能干什么說清楚在隔離網(wǎng)絡(luò)里搭 Web 環(huán)境選型邏輯和公網(wǎng)機(jī)器完全不一樣。公網(wǎng)機(jī)器上你隨手一個(gè)包管理命令就能拉齊依賴內(nèi)網(wǎng)機(jī)器上每一個(gè)缺失的so文件都意味著你要回到有網(wǎng)的地方去下載、拷貝、再試。這個(gè)來回成本決定了選型的第一原則不是哪個(gè)技術(shù)棧先進(jìn)而是哪個(gè)方案的依賴閉包最小、最可控。XAMPP 恰好在這個(gè)維度上有明顯優(yōu)勢但它的邊界也很硬先把這兩面都說清楚后面才不會(huì)做無用功。1.1 XAMPP 到底打包了哪些東西XAMPP 這個(gè)名字本身就是它的組件清單X跨平臺(tái)、AApache、MMySQL現(xiàn)在實(shí)際打包的是 MariaDB、PPHP、PPerl。Linux 版安裝完成后所有東西都落在/opt/lampp這一個(gè)目錄里/opt/lampp/binhttpd、mysqld、php、mysql 客戶端等二進(jìn)制/opt/lampp/etchttpd.conf、my.cnf、php.ini 等配置文件/opt/lampp/htdocs網(wǎng)站根目錄/opt/lampp/phpmyadmin自帶的數(shù)據(jù)庫管理界面/opt/lampp/var/mysql數(shù)據(jù)庫數(shù)據(jù)目錄與 socket 文件/opt/lampp/logs各服務(wù)的日志關(guān)鍵在于這些二進(jìn)制基本都是靜態(tài)鏈接得比較徹底的自帶電池版本不依賴系統(tǒng)里那套 Apache/PHP 包。這意味著它幾乎不會(huì)和系統(tǒng)已有的軟件產(chǎn)生版本沖突——除了端口和數(shù)據(jù)目錄這兩處后面會(huì)單獨(dú)講。對(duì)離線交付來說這種自包含是最大的價(jià)值你不需要在內(nèi)網(wǎng)機(jī)器上解壓幾十個(gè) RPM 的依賴樹一個(gè)安裝包解決全部問題。1.2 離線場景下它比逐個(gè)裝包強(qiáng)在哪我做過對(duì)比同樣是搭一個(gè) Apache PHP MySQL 的可用環(huán)境兩種路線的差異大概是這樣對(duì)比維度分組件安裝apt/yumXAMPP 離線安裝需要帶進(jìn)內(nèi)網(wǎng)的文件主包 依賴鏈幾十個(gè)包單個(gè) .run 安裝包版本一致性受發(fā)行版?zhèn)}庫限制容易錯(cuò)配官方已調(diào)好組合開箱可用安裝耗時(shí)依賴解析 逐個(gè)安裝較長解壓式安裝通常幾分鐘配置統(tǒng)一度配置分散在 /etc 各處集中在 /opt/lampp/etc卸載干凈度殘留分散清理麻煩停服后刪目錄即可當(dāng)然它不是萬能藥。生產(chǎn)環(huán)境我不建議拿 XAMPP 直接對(duì)外提供服務(wù)原因后面第 6 章會(huì)講——它默認(rèn)的安全姿態(tài)是方便開發(fā)不是面向公網(wǎng)。但作為內(nèi)網(wǎng)開發(fā)機(jī)、測試機(jī)、臨時(shí)演示環(huán)境它的性價(jià)比非常高。1.3 三條硬性前置檢查架構(gòu)、glibc、磁盤這三項(xiàng)檢查花你三分鐘能省掉一次失敗的內(nèi)網(wǎng)往返。我吃過虧所以現(xiàn)在把它固化成流程第一步。第一條是 CPU 架構(gòu)。執(zhí)行uname -m返回x86_64才繼續(xù)。XAMPP 官方提供的 Linux 包主要是 x86_64 架構(gòu)早期版本還有 32 位包如果你手上是 ARM 架構(gòu)的機(jī)器比如一些基于 ARM 平臺(tái)的工作站官方包里是沒有對(duì)應(yīng)版本的。這個(gè)必須提前確認(rèn)別等把幾百兆的文件拷進(jìn)內(nèi)網(wǎng)才發(fā)現(xiàn)跑不起來——ARM 平臺(tái)上更實(shí)際的做法是走發(fā)行版自帶的 LNMP 組件或者用容器化方案。第二條是 glibc 版本。執(zhí)行l(wèi)dd --version | head -1會(huì)打印類似ldd (GNU libc) 2.17的信息。官方并沒有給出精確的下限表但經(jīng)驗(yàn)上 glibc 2.17 及以上的發(fā)行版CentOS 7、Ubuntu 18.04 之后的版本跑 XAMPP 8.x 基本沒問題如果是很老的系統(tǒng)可能會(huì)在啟動(dòng)時(shí)直接報(bào)GLIBC_2.14 not found這類錯(cuò)誤那就只能換版本或換機(jī)器沒有繞過的好辦法。第三條是磁盤空間。XAMPP 8.x 完整安裝后加上初始數(shù)據(jù)目錄粗估占用在 500MB 到 700MB 之間而/opt通常掛在根分區(qū)上所以先跑一次df -h /opt建議預(yù)留 2GB 以上的余量。同時(shí)看一眼內(nèi)存free -h里如果可用內(nèi)存不到 512MB跑 MariaDB 加 Apache 會(huì)比較吃力。2. 安裝包怎么拿進(jìn)內(nèi)網(wǎng)獲取、校驗(yàn)、傳輸這三點(diǎn)別省這一步看著最沒技術(shù)含量實(shí)際上出錯(cuò)率最高。我遇到過的情況包括拷進(jìn)去的文件傳輸中斷導(dǎo)致體積不對(duì)、下載到的版本和實(shí)際需要的架構(gòu)不符、拷進(jìn)內(nèi)網(wǎng)之后忘了校驗(yàn)、以及文件拷到/tmp后被系統(tǒng)清理策略刪掉。所以把拿包當(dāng)成一個(gè)正式環(huán)節(jié)來做比裝的時(shí)候排錯(cuò)要省事得多。2.1 版本與文件名的對(duì)應(yīng)關(guān)系在有外網(wǎng)的環(huán)境上從官方渠道獲取 Linux 版安裝包。文件名大致長這樣xampp-linux-x64-8.2.12-0-installer.run拆開看linux-x64表示平臺(tái)和架構(gòu)8.2.12是版本號(hào)0是構(gòu)建號(hào)installer.run說明這是圖形/命令行二合一的安裝器。這里有兩個(gè)容易忽略的點(diǎn)名字里帶installer的是安裝器裝完會(huì)產(chǎn)生/opt/lampp如果你的目錄里還有別的后綴類型注意區(qū)分。另外版本不要盲目追最新先確認(rèn)你內(nèi)網(wǎng)里現(xiàn)有代碼和擴(kuò)展比如某些老框架依賴的 PHP 擴(kuò)展和目標(biāo) PHP 主版本是否兼容PHP 8.x 和 7.x 之間的差異不小。把安裝包放到一個(gè)固定的工作目錄比如~/soft不要丟在/tmp里——部分系統(tǒng)會(huì)定期清理臨時(shí)目錄等你去裝的時(shí)候文件已經(jīng)沒了。傳輸介質(zhì)推薦 U 盤或移動(dòng)硬盤如果是跨網(wǎng)段傳輸務(wù)必在拷貝完成后再做一次校驗(yàn)。2.2 下載后必須先做的完整性校驗(yàn)很多人跳過這一步然后在安裝時(shí)報(bào)一個(gè)莫名其妙的文件損壞或者不被識(shí)別為可執(zhí)行文件。校驗(yàn)只需要一行sha256sum xampp-linux-x64-8.2.12-0-installer.run把輸出和下載頁面公布的校驗(yàn)值比對(duì)。如果沒有官方校驗(yàn)值至少做一次兩次拷貝結(jié)果一致的自證外網(wǎng)機(jī)器上算一遍內(nèi)網(wǎng)機(jī)器上再算一遍兩個(gè)值相同說明傳輸過程沒出問題。這一步的價(jià)值在于把文件問題和配置問題分隔開——后面排錯(cuò)時(shí)你就知道該懷疑哪一邊。2.3 介質(zhì)傳輸與目錄落地內(nèi)網(wǎng)機(jī)器上建議先建一個(gè)專門的落地目錄權(quán)限收窄一點(diǎn)mkdir -p /home/yourname/soft chmod 700 /home/yourname/soft把安裝包拷進(jìn)去之后順手確認(rèn)三件事文件大小是否與來源一致ls -lh、屬主是不是你自己的賬號(hào)ls -l、掛載的 U 盤是否還有未同步的寫入sync一下再拔。最后一點(diǎn)特別容易翻車尤其是用 U 盤傳輸大文件時(shí)看著進(jìn)度條走完就拔盤實(shí)際上數(shù)據(jù)還在緩存里拷進(jìn)去的文件是殘缺的。養(yǎng)成sync之后再拔的習(xí)慣能省掉很多重新跑一趟的麻煩。3. 執(zhí)行 .run 安裝器每一步在做什么從這里開始進(jìn)入正式安裝。整個(gè)安裝過程本身的交互很少但每一步背后的含義值得講清楚因?yàn)槟愫竺嬗龅降乃新窂絾栴}、權(quán)限問題都能在這一步找到源頭。3.1 賦權(quán)與 sudo 的邊界.run文件從外網(wǎng)拷進(jìn)來時(shí)通常沒有執(zhí)行權(quán)限先加上cd /home/yourname/soft chmod x xampp-linux-x64-8.2.12-0-installer.run然后必須用sudo執(zhí)行原因很直接它要往/opt下寫目錄、要監(jiān)聽 80 和 3306 這類特權(quán)端口在 Linux 上小于 1024 的端口默認(rèn)只有 root 能綁定。這里有個(gè)經(jīng)驗(yàn)點(diǎn)——不要用sudo -i切到 root 再執(zhí)行而是保持在自己賬號(hào)下用sudo前綴這樣安裝器記錄的環(huán)境變量和當(dāng)前目錄是你自己的出問題時(shí)排查范圍更小。sudo ./xampp-linux-x64-8.2.12-0-installer.run3.2 安裝器交互項(xiàng)的取舍與 /opt/lampp 的由來執(zhí)行后會(huì)彈出基于終端的安裝向?qū)?。如果你的機(jī)器沒有圖形環(huán)境它會(huì)自動(dòng)走文本模式一路問下來大概是這樣幾項(xiàng)歡迎信息、許可協(xié)議選接受、安裝路徑確認(rèn)、以及最后的安裝進(jìn)度條。安裝路徑的建議是保持默認(rèn)的/opt/lampp不要改。為什么強(qiáng)調(diào)不要改因?yàn)?XAMPP 內(nèi)部的lampp控制腳本、各種配置文件里的相對(duì)路徑、以及 phpMyAdmin 的默認(rèn)配置大量硬編碼依賴這個(gè)路徑。你改到/usr/local/xampp啟動(dòng)腳本里有些地方不會(huì)自動(dòng)跟著變后面會(huì)莫名其妙報(bào)找不到文件。除非你有明確的目錄規(guī)范要求否則老老實(shí)實(shí)用默認(rèn)路徑。如果你希望無人值守安裝比如要批量部署到多臺(tái)機(jī)器可以試試帶靜默參數(shù)運(yùn)行但要先在本機(jī)跑一次交互模式確認(rèn)當(dāng)前版本的參數(shù)支持情況不同版本對(duì)--mode unattended這類參數(shù)的支持并不完全一致——這是我沒法一句話打包票的地方建議現(xiàn)場驗(yàn)證。3.3 安裝后的目錄地圖與自檢命令安裝完成后先別急著訪問頁面按順序做這幾個(gè)自檢ls -l /opt/lampp/ # 目錄結(jié)構(gòu)是否完整 sudo /opt/lampp/lampp status # 查看各服務(wù)狀態(tài) sudo /opt/lampp/lampp start # 啟動(dòng)lampp這個(gè)腳本是核心控制入口最常用的子命令整理如下子命令作用start/stop/restart啟動(dòng)、停止、重啟全部服務(wù)startapache/stopapache只操作 Apachestartmysql/stopmysql只操作 MariaDBstatus查看當(dāng)前各服務(wù)運(yùn)行狀態(tài)security交互式安全加固向?qū)nablessl生成自簽名證書并啟用 HTTPSpanel啟動(dòng)圖形化管理面板啟動(dòng)成功的標(biāo)志是看到類似 Starting XAMPP for Linux... 后面依次出現(xiàn) Apache、MySQL、ProFTPD 的啟動(dòng)信息。然后在瀏覽器里訪問http://本機(jī)IP能看到 XAMPP 的歡迎頁就說明主鏈路通了。注意訪問地址不要寫localhost去測局域網(wǎng)那是兩回事。4. 裝完啟動(dòng)就跑通了嗎端口、權(quán)限、SELinux 三道關(guān)卡真正讓新手卡住的不是安裝而是裝完了但訪問不了。絕大多數(shù)情況都落在這三類原因上端口被占用、權(quán)限不對(duì)、安全模塊攔截。把這三個(gè)按順序排查基本能覆蓋九成以上的啟動(dòng)失敗。4.1 端口占用80 和 3306 是最常見的攔路虎內(nèi)網(wǎng)機(jī)器上預(yù)裝了 Nginx、系統(tǒng)自帶的 httpd或者之前跑過別的數(shù)據(jù)庫都會(huì)導(dǎo)致 XAMPP 啟動(dòng)失敗。啟動(dòng)時(shí)看到類似 Another web server is already running 或者 mysqld 直接退出的提示第一件事是查端口ss -tlnp | grep -E :80|:443|:3306|:21這里特意用ss而不是netstat原因是精簡安裝的系統(tǒng)上net-tools包往往沒裝netstat命令根本不存在而ss屬于 iproute2基本都在。這在離線環(huán)境里是個(gè)很實(shí)用的習(xí)慣。確認(rèn)占用之后有兩條路停掉占用者或者給 XAMPP 換端口。如果那臺(tái)機(jī)器上的 Nginx 是別人在用的服務(wù)別去動(dòng)它直接改 XAMPP 的配置# 修改 Apache 監(jiān)聽端口在 /opt/lampp/etc/httpd.conf 中找到 Listen 80 sudo sed -i s/^Listen 80$/Listen 8080/ /opt/lampp/etc/httpd.conf # 修改 MariaDB 端口在 /opt/lampp/etc/my.cnf 中調(diào)整改完記得同步調(diào)整httpd-ssl.conf里的 443 端口否則啟用 HTTPS 時(shí)還會(huì)撞一次。改端口這件事的連鎖影響比看上去大站點(diǎn)里的硬編碼鏈接、反向代理配置都可能跟著要改所以優(yōu)先考慮騰出 80 端口。4.2 權(quán)限模型為什么命令前面要加 sudohtdocs 又該歸誰XAMPP 的權(quán)限模型有兩層理解它就明白為什么會(huì)出現(xiàn)文件傳上去了卻寫不進(jìn)去。第一層控制腳本lampp需要 root 權(quán)限因?yàn)樗獑?dòng)服務(wù)、綁定特權(quán)端口。所以所有l(wèi)ampp命令前面都要帶sudo。第二層Apache 實(shí)際運(yùn)行的身份由/opt/lampp/etc/httpd.conf里的User和Group指令決定默認(rèn)通常是非特權(quán)賬號(hào)。這就帶來一個(gè)常見的尷尬你用自己賬號(hào)把代碼傳到/opt/lampp/htdocs目錄屬主是你Apache 以另一個(gè)身份運(yùn)行遇到需要寫文件的操作上傳、緩存、日志就報(bào)權(quán)限錯(cuò)誤反過來PHP 程序創(chuàng)建的目錄屬主是 Apache 的運(yùn)行身份你又刪不掉。我的處理方式是把項(xiàng)目目錄的屬主改回自己權(quán)限設(shè)為 755目錄和 644文件讓 Apache 有讀權(quán)限即可需要寫入的子目錄單獨(dú)處理sudo chown -R yourname:yourname /opt/lampp/htdocs/myproject sudo chmod -R 755 /opt/lampp/htdocs/myproject sudo chmod -R 775 /opt/lampp/htdocs/myproject/uploads不要圖省事用chmod -R 777。在開發(fā)機(jī)上它確實(shí)能解決問題但會(huì)讓你的代碼在遷移到正式環(huán)境時(shí)立刻暴露出一堆權(quán)限設(shè)計(jì)缺陷等于把問題推遲到了更貴的階段。4.3 SELinux 與 AppArmor 的排查順序在 RHEL、CentOS、Rocky 這類系統(tǒng)上SELinux 是僅次于端口的第二大坑。表現(xiàn)是服務(wù)明明起來了端口也在監(jiān)聽但訪問頁面返回 403日志里看到權(quán)限拒絕而文件權(quán)限看起來完全正常。正確的排查順序是先確認(rèn)再動(dòng)手。第一步看狀態(tài)getenforce # 返回 Enforcing 或 Permissive如果是 Enforcing第二步做臨時(shí)驗(yàn)證——把它切到寬容模式看問題是否消失sudo setenforce 0如果切完立刻能訪問基本可以確認(rèn)是 SELinux 的上下文策略在攔。這時(shí)候你面臨選擇永久關(guān)閉改/etc/selinux/config設(shè)為 disabled是最省事但也最偷懶的做法在企業(yè)內(nèi)網(wǎng)機(jī)器上往往不允許更規(guī)范的做法是用ausearch和audit2allow從審計(jì)日志里提取被拒絕的操作生成針對(duì)性策略模塊sudo ausearch -m avc -ts recent sudo ausearch -m avc -ts recent | audit2allow -M xampp_local sudo semodule -i xampp_local.ppUbuntu/Debian 系的機(jī)器走 AppArmor一般默認(rèn)配置不會(huì)攔/opt下的自定義服務(wù)如果確實(shí)遇到用aa-status查看并針對(duì)性調(diào)整對(duì)應(yīng) profile。這一塊沒有萬能命令核心思路是先確認(rèn)攔截來源再?zèng)Q定是加白名單還是改策略不要一上來就關(guān)安全模塊。5. 把 XAMPP 調(diào)成一個(gè)趁手的開發(fā)環(huán)境服務(wù)能跑起來只是及格線。真正讓日常開發(fā)順手的是自啟、數(shù)據(jù)庫賬號(hào)、管理界面訪問控制和字符集這幾件事。這一章講我怎么配以及每個(gè)選擇背后的理由。5.1 開機(jī)自啟systemd 單元還是 rebootXAMPP 裝完默認(rèn)不會(huì)開機(jī)自啟重啟一次機(jī)器就得手動(dòng)lampp start。兩種方案可選。第一種是 systemd 單元寫到/etc/systemd/system/xampp.service[Unit] DescriptionXAMPP Control Panel Afternetwork.target [Service] Typeforking ExecStart/opt/lampp/lampp start ExecStop/opt/lampp/lampp stop RemainAfterExityes KillModenone [Install] WantedBymulti-user.target兩個(gè)參數(shù)要特別說明。RemainAfterExityes是因?yàn)閘ampp start執(zhí)行完就退出了但實(shí)際服務(wù)還在后臺(tái)跑systemd 需要被告知這個(gè)單元的狀態(tài)應(yīng)該保持為 active。KillModenone是為了防止 systemd 在停止單元時(shí)把控制腳本派生出來的 httpd、mysqld 一并殺掉——不加這一項(xiàng)systemctl stop xampp有時(shí)會(huì)留下孤兒進(jìn)程或者干脆停不干凈。即便如此這個(gè)方案在 stop/restart 的語義上依然不完美因?yàn)閘ampp腳本本質(zhì)是個(gè) shell 包裝器不是原生守護(hù)進(jìn)程。第二種更簡單也更穩(wěn)用 cron 的reboot。在 root 的 crontab 里加一行sudo crontab -e # 添加 reboot /opt/lampp/lampp start代價(jià)是啟動(dòng)順序不可控、沒有狀態(tài)查詢、失敗也沒有重試但對(duì)于一臺(tái)拿來開發(fā)的機(jī)器這點(diǎn)損失完全可以接受。我的實(shí)際選擇是開發(fā)機(jī)用reboot需要納入統(tǒng)一運(yùn)維的機(jī)器用 systemd 單元并接受它的那點(diǎn)不完美。5.2 MySQL/MariaDB 的 root 密碼與遠(yuǎn)程訪問收斂裝完之后的數(shù)據(jù)庫狀態(tài)是root 賬號(hào)在本地?zé)o密碼即可登錄這在開發(fā)機(jī)上尚可接受但只要機(jī)器能被局域網(wǎng)其他人訪問就必須改。最省事的做法是用官方加固向?qū)udo /opt/lampp/lampp security它會(huì)依次問你幾個(gè)問題是否給 XAMPP 頁面加訪問密碼、是否給 MySQL root 設(shè)置密碼、是否給 phpMyAdmin 設(shè)置額外的訪問控制。密碼設(shè)置完成后驗(yàn)證一下/opt/lampp/bin/mysql -u root -p關(guān)于遠(yuǎn)程訪問我的建議是默認(rèn)不要開。如果真的有從其他機(jī)器連數(shù)據(jù)庫的需求精確控制到來源主機(jī)而不是圖省事開%CREATE USER devuser192.168.1.% IDENTIFIED BY 一個(gè)足夠長的密碼; GRANT ALL PRIVILEGES ON mydb.* TO devuser192.168.1.%; FLUSH PRIVILEGES;按庫授權(quán)而不是*.*全庫授權(quán)是最低成本的止損設(shè)計(jì)。真要出事?lián)p失范圍是被限定的。5.3 phpMyAdmin 的訪問控制與漢化這件事先把一個(gè)容易誤解的點(diǎn)說清楚XAMPP 在 Linux 下的圖形管理面板是個(gè)編譯好的二進(jìn)制程序界面語言跟著它內(nèi)置的翻譯資源走我這幾年接觸到的版本里都沒有提供中文語言選項(xiàng)。所以如果你在網(wǎng)上搜XAMPP 漢化很多教程針對(duì)的是另一套圖形界面的環(huán)境機(jī)制不一樣照搬沒用。別在這上面耗時(shí)間。真正值得漢化、也確實(shí)能漢化的是 phpMyAdmin。改法是在/opt/lampp/phpmyadmin/config.inc.php里找到語言相關(guān)配置項(xiàng)指定為中文$cfg[Lang] zh_CN;或者更簡單——登錄頁右下角就有語言下拉框選一次中文即可。改配置文件的優(yōu)勢是對(duì)所有使用者生效。比漢化更重要的是訪問控制。默認(rèn)情況下 phpMyAdmin 對(duì)局域網(wǎng)是開放的任何能訪問 80 端口的人都能看到登錄框。加固思路有兩層一是用lampp security給 XAMPP 目錄整體加.htaccess認(rèn)證二是限制來源在httpd.conf對(duì)應(yīng)的目錄配置塊里用Require ip 192.168.1.0/24之類的方式收窄。兩層疊加比單獨(dú)改數(shù)據(jù)庫密碼更穩(wěn)妥。5.4 站點(diǎn)字符集與中文亂碼的根治辦法中文亂碼是另一類高頻問題它的根因通常在三個(gè)層面之一得分別處理。第一層是數(shù)據(jù)庫層。建庫時(shí)明確指定字符集不要依賴默認(rèn)值CREATE DATABASE mydb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;統(tǒng)一用utf8mb4而不是老的utf8原因是后者的實(shí)現(xiàn)最多只支持三字節(jié)編碼存不下一些符號(hào)。這個(gè)問題在新項(xiàng)目里踩一次就夠了。第二層是連接層。在應(yīng)用的數(shù)據(jù)庫連接配置里顯式聲明編碼命令行客戶端臨時(shí)調(diào)試時(shí)也要帶上/opt/lampp/bin/mysql -u root -p --default-character-setutf8mb4第三層是文件與傳輸層。如果解壓壓縮包之后中文文件名變成亂碼那是壓縮包本身的文件名編碼和當(dāng)前系統(tǒng) locale 不一致導(dǎo)致的先確認(rèn)locale輸出里的字符集設(shè)置再?zèng)Q定是解壓時(shí)指定編碼還是轉(zhuǎn)換文件名。這個(gè)現(xiàn)象在老項(xiàng)目遷移時(shí)特別常見跟 XAMPP 本身沒關(guān)系但很容易被誤判成環(huán)境問題。6. 我實(shí)際踩過的坑與排查鏈路復(fù)現(xiàn)前面講的都是應(yīng)該怎么做這一章講我當(dāng)時(shí)是怎么一步步找到原因的。排錯(cuò)思路比結(jié)論更值得學(xué)因?yàn)橄麓斡龅降膯栴}不會(huì)長得一模一樣。6.1 Another web server is already running 的完整排查第一次遇到的場景是一臺(tái)預(yù)裝了 Nginx 的測試機(jī)。執(zhí)行l(wèi)ampp start后 Apache 那一行直接失敗報(bào)錯(cuò)提示已有 Web 服務(wù)在運(yùn)行。我的排查鏈路是這樣的。第一步先確認(rèn)到底是誰占了 80 端口而不是憑直覺猜ss -tlnp | grep :80輸出里能看到進(jìn)程名和 PID。第二步確認(rèn)這個(gè)進(jìn)程的歸屬和用途——用ps -ef | grep PID看啟動(dòng)參數(shù)確認(rèn)它是系統(tǒng)服務(wù)還是某個(gè)同事手動(dòng)起的臨時(shí)進(jìn)程。這一步的意義在于避免誤停別人的服務(wù)。第三步判斷取舍如果那是正在被使用的服務(wù)就改 XAMPP 的 Listen 端口如果是歷史遺留的僵尸進(jìn)程直接停掉并設(shè)為不開機(jī)自啟。這里有個(gè)我踩過的細(xì)節(jié)改完httpd.conf的 Listen 端口后Apache 起來了但訪問頁面時(shí)頁面里的資源請(qǐng)求 404排查半天才發(fā)現(xiàn)站點(diǎn)里有硬編碼的 80 端口鏈接。所以改端口這件事必須連帶檢查應(yīng)用配置,不能只改服務(wù)端。6.2 MySQL 起不來從日志倒推數(shù)據(jù)目錄權(quán)限另一次是 MySQL 單獨(dú)啟動(dòng)失敗Apache 卻正常。這種情況別急著重裝先看日志tail -n 50 /opt/lampp/var/mysql/$(hostname).err日志里通常會(huì)給出比命令行更具體的原因。我那次看到的是數(shù)據(jù)目錄不可寫相關(guān)的報(bào)錯(cuò)。追溯下來是之前有人整體改過/opt/lampp的屬主和權(quán)限導(dǎo)致 MariaDB 無法初始化或?qū)懭霐?shù)據(jù)目錄。處理方式是先停服把數(shù)據(jù)目錄的屬主和權(quán)限恢復(fù)到服務(wù)運(yùn)行身份能訪問的狀態(tài)然后重啟。這里要提醒一點(diǎn)動(dòng)數(shù)據(jù)目錄的權(quán)限之前先備份一份。/opt/lampp/var/mysql里就是你的全部數(shù)據(jù)任何直接的文件操作都應(yīng)該先復(fù)制一份出來。如果是全新環(huán)境最干凈的方案反倒是備份后刪掉數(shù)據(jù)目錄重新初始化但這是在你確認(rèn)里面沒有重要數(shù)據(jù)的前提下。6.3 包安裝完命令卻找不到離線補(bǔ)依賴的清單離線環(huán)境里最耗時(shí)的往往不是主程序的安裝而是運(yùn)行時(shí)的依賴缺失。判斷方法很直接用ldd檢查二進(jìn)制缺哪些庫ldd /opt/lampp/bin/mysqld | grep not found ldd /opt/lampp/bin/httpd | grep not found有輸出就說明缺庫。在較新的企業(yè)級(jí)發(fā)行版上我遇到過幾次典型缺失整理成一份對(duì)照清單報(bào)錯(cuò)缺失的庫常見原因處理方向libnsl.so.1新版本把 NIS 相關(guān)庫拆出了兼容包離線安裝對(duì)應(yīng)的 libnsl 兼容包libcrypt.so.1加密庫版本升級(jí)老 ABI 不再內(nèi)置離線安裝 libxcrypt 兼容包GTK/X11 相關(guān)庫使用了圖形管理面板但系統(tǒng)沒裝桌面環(huán)境只跑命令行可忽略或補(bǔ)裝圖形庫補(bǔ)依賴的正確姿勢是在同版本同架構(gòu)的有網(wǎng)機(jī)器上用包管理器下載對(duì)應(yīng)的安裝包文件而不是直接在那些機(jī)器上安裝把文件拷進(jìn)內(nèi)網(wǎng)再用本地安裝方式裝。版本必須對(duì)得上否則會(huì)出現(xiàn)裝了但版本不兼容的更麻煩的局面。另外提醒一句圖形管理面板需要 X11 環(huán)境。服務(wù)器版系統(tǒng)通常沒有桌面lampp panel會(huì)啟動(dòng)失敗。這種情況下用命令行管理就夠了實(shí)在需要圖形界面的走 X11 轉(zhuǎn)發(fā)或者 VNC。這也說明一件事離線部署時(shí)優(yōu)先選最精簡的路徑能不依賴圖形界面就不依賴。6.4 一份能直接抄的安全加固清單最后把我每次裝完都會(huì)執(zhí)行的加固動(dòng)作列出來這部分比安裝本身更值得重視。XAMPP 的默認(rèn)安全級(jí)別明確是面向本地開發(fā)一旦這臺(tái)機(jī)器能被內(nèi)網(wǎng)其他機(jī)器訪問就該按下面的順序收一遍。第一跑一遍官方向?qū)Р⒃O(shè)置數(shù)據(jù)庫密碼sudo /opt/lampp/lampp security第二限制管理界面的訪問來源在httpd.conf中為 phpMyAdmin 目錄加上來源限制只允許可信網(wǎng)段。第三處理掉自帶的示例目錄。默認(rèn)的歡迎頁和示例程序在開發(fā)階段有點(diǎn)用一旦開始放真實(shí)項(xiàng)目建議移走或刪掉減少信息暴露面。第四給控制面板和 XAMPP 目錄本身加一層訪問認(rèn)證避免有人直接訪問目錄列表。第五明確這臺(tái)機(jī)器的定位。如果是純本地開發(fā)機(jī)考慮把 Apache 的監(jiān)聽地址限制在本地回環(huán)只在需要局域網(wǎng)聯(lián)調(diào)時(shí)臨時(shí)放開。第六建立備份習(xí)慣。開跑之前把/opt/lampp/var/mysql和數(shù)據(jù)文件定期復(fù)制出來。老版本的控制腳本里帶backup子命令可以試試是否可用如果不可用直接打包目錄也是可靠的辦法——畢竟所有東西都在一個(gè)目錄里這恰好是 XAMPP 結(jié)構(gòu)帶來的一個(gè)額外好處。關(guān)于卸載我一般不用官方腳本因?yàn)閳D形化的卸載器在無桌面環(huán)境里跑不起來。干凈的做法是先停服再刪目錄sudo /opt/lampp/lampp stop sudo rm -rf /opt/lampp如果之前做過自啟配置記得把 systemd 單元文件或者 crontab 里的reboot那行也一并清掉否則重啟后會(huì)出現(xiàn)一堆找不到路徑的報(bào)錯(cuò)。這個(gè)收尾動(dòng)作很容易被忘掉我就干過一次隔了一周才發(fā)現(xiàn)日志里一直在刷錯(cuò)誤。個(gè)人體會(huì)是XAMPP 在 Linux 上的價(jià)值九成體現(xiàn)在一個(gè)目錄裝完所有東西這個(gè)特性上尤其是離線交付場景而它全部的麻煩也基本都源自同一個(gè)特性——所有東西塞在一個(gè)目錄里所以路徑、屬主、安全上下文這三樣一旦有一處不對(duì)問題會(huì)集中爆發(fā)。把這三樣在裝完的第一時(shí)間就理清楚后面能省下大量時(shí)間。至于版本升級(jí)我的做法是在新目錄裝好新版、把htdocs和var/mysql遷過去驗(yàn)證通過之后再替換舊目錄比在原名目錄里原地升級(jí)穩(wěn)妥得多。