January 19Jan 19 適用環境:Debian 13 · Nginx · MariaDB 11.8.x · PHP 8.3.x VPS規格:2 vCPU / 2GB RAM 定位:論壇網站 phpMyAdmin 來源:官方下載版,非 Debian 套件版 --------------------- 前言與風險評估 --------------------- phpMyAdmin 是全球最廣泛使用的 MySQL/MariaDB 網頁管理工具。 正因知名度極高,攻擊者的自動掃描器會不斷尋找預設路徑(/phpmyadmin、/pma),並發動已知漏洞利用與字典暴力破解攻擊。 在 2GB RAM 的小型VPS上,一旦資料庫被入侵,論壇使用者的所有個資(帳號、密碼雜湊、Email、IP 等)將全數外洩,後果嚴重。 為何使用官方下載版而非 Debian 套件版? 本教學使用官方下載版 phpMyAdmin,而非 Debian 套件版(apt install phpmyadmin)。理由如下: Debian 套件版更新較慢,安全修補有延遲 官方版可自由控制安裝路徑,並能第一時間取得安全更新 官方版支援GPG簽章驗證,可確認下載來源的真實性 ------------------- 風險矩陣 ------------------- 風險項目:預設 URL 路徑公開暴露(/phpmyadmin) 嚴重性:高 常見程度:極高 本教學對策:自訂路徑 + IP白名單 風險項目:弱密碼 / 無密碼登入 嚴重性:嚴重 常見程度:高 本教學對策:強制強密碼,AllowNoPassword = false 風險項目:root 帳號允許遠端登入 嚴重性:嚴重 常見程度:中 本教學對策:unix_socket 認證,禁止 TCP 登入 風險項目:過時版本含已知 CVE 嚴重性:高 常見程度:高 本教學對策:官方版 + 訂閱安全公告 風險項目:未加密的 HTTP 傳輸 嚴重性:高 常見程度:中 本教學對策:TLS 1.3 + 自簽SSL憑證 風險項目:缺乏登入嘗試限制 嚴重性:高 常見程度:高 本教學對策:IP白名單(本教學未含 Fail2ban) 風險項目:過度開放的資料庫權限(GRANT ALL ON *.*) 嚴重性:嚴重 常見程度:高 本教學對策:最小權限原則 風險項目:未啟用稽核日誌 嚴重性:中 常見程度:極高 本教學對策:config.inc.php 預留稽核設定入口 風險項目:/setup 目錄未移除 嚴重性:嚴重 常見程度:高 本教學對策:安裝後立即移除,每次更新後再確認 風險項目:config.inc.php 權限過寬(644 而非 640) 嚴重性:中 常見程度:高 本教學對策:chmod 640 + chown root:www-data 風險項目:Session / 暫存目錄使用系統共用 /tmp 嚴重性:中 常見程度:高 本教學對策:獨立目錄 /var/lib/phpmyadmin 風險項目:open_basedir 設在 Nginx 導致升級異常 嚴重性:中 常見程度:高 本教學對策:移至獨立 PHP-FPM Pool 風險項目:Log 日誌無限增長(無 logrotate) 嚴重性:中 常見程度:極高 本教學對策:獨立 logrotate 設定 ----------------------- 防禦架構總覽 ----------------------- Internet │ ▼ [雲端安全群組 / WAF] ← 第零層:雲端層過濾(務必同步設定) │ ▼ [防火牆 / nftables] ← 第一層:網路層過濾(IP 白名單) │ ▼ [Nginx + TLS 1.3] ← 第二層:傳輸加密 + 自訂路徑隱藏 │ ▼ [HTTP Basic 驗證] ← 第三層:前置認證(本教學未實作) │ ▼ [phpMyAdmin 登入] ← 第四層:應用層認證(cookie 模式) │ ▼ [MariaDB 最小權限帳號] ← 第五層:資料庫層隔離 │ ▼ [Fail2ban + 稽核日誌] ← 第六層:偵測與回應(本教學未實作) 雲端主機安全群組必須同步設定 若你的 VPS 位於雲端平台(AWS EC2、GCP、Azure、Hetzner、Vultr、DigitalOcean 等), 雲端安全群組(Security Group)或防火牆規則也必須同步限制 888 port 僅允許管理員IP連入,才能形成完整的防護鏈。 單靠 nftables 或 Nginx 設定是不夠的,兩者必須同時到位。 部分雲端平台的安全群組在 VPS 作業系統層之前就已過濾流量,因此是不可或缺的第零層防禦。 ------------------------ 環境前置確認 ------------------------ 在執行任何操作前,先確認環境狀態 確認系統版本 lsb_release -a 預期輸出: Distributor ID: Debian Description: Debian GNU/Linux 13 (trixie) Release: 13 Codename: trixie 確認 Linux 核心版本 uname -r 預期輸出(以雲端 AMD64 映像為例): 6.12.90+deb13.1-cloud-amd64 確認各服務版本 php -v nginx -v mariadb --version 重要提醒:版本不符時請勿繼續。本教學的設定路徑與指令皆以 PHP 8.3 / Nginx / MariaDB 11.8.x 為準。 若 PHP 版本不同(如 8.4),需同步調整: Socket 路徑:php8.4-fpm.sock FPM 服務名稱:php8.4-fpm Pool 目錄:/etc/php/8.4/fpm/pool.d/ ---------------------------------------------------- 確認防火牆已開放 888 port ---------------------------------------------------- 在繼續之前,確認 nftables 已正確限制 888 port,僅允許管理員IP連入。 nft list ruleset | grep 888 若尚未設定,請先完成防火牆設定再繼續,避免安裝過程中 phpMyAdmin 短暫對外暴露。 同時確認雲端安全群組已同步限制,否則防護鏈不完整。 ----------------------------------------------- 自簽 TLS 憑證 ----------------------------------------------- 本教學使用 888 port 搭配 IP 直接存取,無申請正式 SSL 憑證,因此以自簽憑證提供傳輸加密。 瀏覽器會顯示安全警告,屬正常現象,點擊「進階」→「繼續前往」即可。 自簽憑證的作用:加密傳輸通道,防止帳號密碼在網路上明文傳輸。 雖然無法驗證伺服器身份,但在IP白名單保護下的管理入口已足夠安全。 若有獨立管理域名(如 admin.域名.com),可改用 acme.sh 申請正式憑證,並啟用 HSTS。 建立 SSL 目錄 mkdir -p /etc/nginx/ssl 產生自簽憑證(有效期 10年) 以下幾行一次貼上 openssl req -x509 -nodes -days 3650 \ -newkey rsa:2048 \ -keyout /etc/nginx/ssl/self-signed.key \ -out /etc/nginx/ssl/self-signed.crt \ -subj "/CN=Admin-Portal/O=Self-Signed" 說明:-nodes 參數代表不以密碼保護私鑰(No DES Passphrase),讓 Nginx 能在重啟時自動載入,無需人工輸入密碼。 這對伺服器自動重啟是必要的,但也意味著私鑰保護完全依賴檔案系統權限(下一步設定)。 設定憑證檔案權限 chmod 600 /etc/nginx/ssl/self-signed.key chmod 644 /etc/nginx/ssl/self-signed.crt chown root:root /etc/nginx/ssl/self-signed.key /etc/nginx/ssl/self-signed.crt 驗證憑證已正確建立 ls -lah /etc/nginx/ssl/ 預期輸出 -rw-r--r-- 1 root root ... self-signed.crt -rw------- 1 root root ... self-signed.key 驗證憑證內容 openssl x509 -noout -text -in /etc/nginx/ssl/self-signed.crt | grep -E 'Subject:|Not After' 預期輸出: Not After : [10年後日期] Subject: CN=Admin-Portal, O=Self-Signed ----------------------------------------- Nginx 設定檔(default.conf)優化 ----------------------------------------- 編輯 vi /etc/nginx/sites-available/default.conf 貼上以下完整內容(取代原有內容) # ============================================================ # default.conf 預設頁面,改為 phpMyAdmin 專用管理入口 # 使用 888 port + HTTPS(自簽憑證) # 防火牆限制:僅 管理員IP 可連入 # 以 伺服器IP 作為網址,不需要域名 # ============================================================ server { listen 888 ssl; # listen [::]:888 ssl; # 管理員有無IPv6(視需求取消註解) http2 on; # 使用 _ 萬用匹配所有IP,不設定具體IP # 避免IP變更時需同步修改此設定 server_name _; root /var/www/html; index index.html index.htm index.php; # 隱藏 Nginx 版本號(避免洩漏版本資訊給攻擊者) server_tokens off; # ── TLS 憑證 ────────────────────────────────────────────── # 自簽憑證(IP 直接存取使用) ssl_certificate /etc/nginx/ssl/self-signed.crt; ssl_certificate_key /etc/nginx/ssl/self-signed.key; # 若日後改用 acme.sh 申請正式憑證,替換為以下路徑並取消註解 # ssl_certificate /etc/nginx/ssl/fullchain.cer; # ssl_certificate_key /etc/nginx/ssl/your-domain.com.key; # ssl_trusted_certificate /etc/nginx/ssl/chain.cer; # ── TLS 協議與加密套件 ──────────────────────────────────── ssl_protocols TLSv1.3; ssl_prefer_server_ciphers on; # TLS 1.3 已內建強加密套件,通常無需額外指定 ssl_ciphers # 若需相容 TLS 1.2(舊版瀏覽器),可加入:TLSv1.2 # 並補充:ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'; ssl_ecdh_curve X25519:secp384r1; # ── SSL Session 快取 ────────────────────────────────────── ssl_session_cache shared:SSL_MGMT:20m; ssl_session_timeout 1d; ssl_session_tickets off; # 停用避免TLS session ticket重放攻擊 # ── OCSP Stapling(自簽憑證無需啟用) ──────────────────── ssl_stapling off; ssl_stapling_verify off; # ── DNS Resolver(供 OCSP / 外部請求使用,正式憑證時啟用) ────── # resolver 1.1.1.1 8.8.8.8 valid=300s; # resolver_timeout 10s; # ── 安全標頭 ────────────────────────────────────────────── # 注意:HSTS 在自簽憑證 + IP 直接存取環境下效果有限 # 改用正式憑證後,再取消 HSTS 的註解並啟用 # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "DENY" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer" always; add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always; # Content-Security-Policy:phpMyAdmin 使用大量 inline script, # 強制啟用 CSP 容易造成功能異常,建議暫不設定。 # 若日後啟用,需配合 phpMyAdmin 版本測試 nonce/hash 設定。 # ── 主要 location ───────────────────────────────────────── location / { try_files $uri $uri/ =404; } # ── PHP-FPM ──────────────────────────────────────────────── # open_basedir 已移至獨立 PHP-FPM Pool(phpmyadmin.conf) # 不再於此處設定 PHP_ADMIN_VALUE,避免升級後出現 # "No input file specified" 或 "open_basedir restriction in effect" 錯誤 location ~ \.php$ { try_files $uri =404; include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/phpmyadmin.sock; fastcgi_hide_header X-Powered-By; fastcgi_read_timeout 120; } # ── Gzip 壓縮 ───────────────────────────────────────────── gzip on; gzip_comp_level 5; gzip_min_length 256; gzip_proxied any; gzip_vary on; gzip_types text/plain text/css application/javascript application/json application/xml text/xml image/svg+xml; # ── 靜態檔案快取 ────────────────────────────────────────── location ~* \.(jpg|jpeg|png|bmp|gif|ico|webp|svg|css|js|woff|woff2|ttf)$ { expires 7d; add_header Cache-Control "public, immutable"; access_log off; } # ── 禁止存取隱藏檔(.htaccess、.git 等) ───────────────── location ~ /\. { deny all; access_log off; log_not_found off; } # ── 禁止存取設定檔與敏感副檔名 ─────────────────────────── location ~* \.(inc\.php|log|bak|sql|conf|ini|sh|env)$ { deny all; access_log off; log_not_found off; } } 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter ----------------------------------------------- 建立 phpMyAdmin 專用 PHP-FPM Pool ----------------------------------------------- 為何需要獨立 Pool? 將 open_basedir 設在 Nginx 的 fastcgi_param PHP_ADMIN_VALUE 雖可行, 但在 phpMyAdmin 升級後常因路徑變動而出現 No input file specified 或 open_basedir restriction in effect 錯誤,排查困難。 改為獨立 PHP-FPM Pool,可在升級後只修改 Pool 設定,不影響 Nginx 設定,且設定更集中、易於維護。 ---------------------------- 建立獨立 Pool 設定檔 ---------------------------- 建立 vi /etc/php/8.3/fpm/pool.d/phpmyadmin.conf 貼上以下完整內容 ; ============================================================ ; phpMyAdmin 專用 PHP-FPM Pool ; 與主站 Pool(www.conf)完全隔離,獨立 socket ; ============================================================ [phpmyadmin] user = www-data group = www-data ; 獨立 socket(Nginx fastcgi_pass 對應此路徑) listen = /var/run/php/phpmyadmin.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 ; ── 行程管理(2GB RAM VPS) ────────────────────────── pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 pm.max_requests = 500 ; ── open_basedir:限制 PHP 只能讀寫以下目錄 ─────────────── ; 防止路徑穿越攻擊(Directory Traversal) ; 升級 phpMyAdmin 後,若新版需要額外路徑,只需修改此處 php_admin_value[open_basedir] = /var/www/html/phpMyAdmin:/var/lib/phpmyadmin:/usr/share/php:/usr/share/javascript:/tmp ; ── Session 與暫存目錄(獨立,不使用系統 /tmp) ─────────── php_admin_value[session.save_path] = /var/lib/phpmyadmin/sessions php_admin_value[upload_tmp_dir] = /var/lib/phpmyadmin/tmp ; ── Session 有效時間(必須 ≥ config.inc.php 的 LoginCookieValidity) ── ; config.inc.php 設定 LoginCookieValidity = 1800(30 分鐘) ; 此處設為 1800 確保 PHP session 不會比 phpMyAdmin cookie 先過期 ; 若兩者不一致,phpMyAdmin 會在介面顯示「session.gc_maxlifetime 比 cookie 有效時間短」的警告 php_admin_value[session.gc_maxlifetime] = 1800 ; ── 安全強化 ────────────────────────────────────────────── php_admin_flag[expose_php] = Off php_admin_value[memory_limit] = 256M php_admin_value[max_execution_time] = 120 php_admin_value[post_max_size] = 64M php_admin_value[upload_max_filesize] = 64M ; ── 錯誤處理(生產環境不對外顯示錯誤) ─────────────────── php_admin_flag[display_errors] = Off php_admin_flag[log_errors] = On php_admin_value[error_log] = /var/log/php/phpmyadmin-error.log 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter --------------------------------------- 建立錯誤日誌目錄與日誌檔案 --------------------------------------- 背景知識:為何要分兩層設定? 這是許多教學最容易寫錯或寫漏的地方,務必先理解以下邏輯,再動手操作。 /var/log/php 目錄由 root 擁有(這是 Linux 系統日誌目錄的標準慣例),但日誌檔案本身必須由 www-data 擁有,原因如下: 層級:/var/log/php/(目錄) 擁有者:root:root 權限:755 說明:任何人可「進入」目錄,但只有 root 能在目錄中「直接新增檔案」 層級:phpmyadmin-error.log(檔案) 擁有者:www-data:www-data 權限:640 說明:PHP-FPM(以 www-data 執行)可寫入,其他使用者無法讀取 關鍵邏輯:目錄權限 755 允許 www-data 進入目錄,但不允許 www-data 在目錄中建立新檔案。 因此 PHP-FPM 執行時,日誌檔案必須已預先存在且歸 www-data 所有。 這正是後續「手動預建日誌檔案」步驟存在的核心原因。 常見錯誤:只建立目錄、不預建日誌檔案。 如此一來,PHP-FPM 首次嘗試寫入時因無法在 root:root 目錄中建立新檔案而靜默失敗; logrotate --force 測試也會回傳警告,令人誤以為 logrotate 設定有誤。 步驟一:建立錯誤日誌目錄 設定目錄擁有者為 root:root(遵循 /var/log 下系統目錄的標準慣例): mkdir -p /var/log/php chown root:root /var/log/php 設定目錄權限為 755 chmod 755 /var/log/php 755 權限說明: root(擁有者)可讀、寫、進入 同群組使用者可讀、進入 其他使用者(包含 www-data)可讀、進入 www-data 因此可以「進入」此目錄並「讀寫其中已存在的檔案」,但無法在目錄中自行建立新檔案。 這是下一步必須手動預建日誌檔案的原因。 步驟二:手動預建日誌檔案 這是許多教學遺漏的步驟,請勿省略。 PHP-FPM 在第一個 PHP 錯誤發生前不會嘗試自動建立日誌檔案; 而如前所述,即使嘗試,也因目錄屬 root:root 而無法建立,只會靜默失敗。 此外,logrotate 在輪替時也需要日誌檔案預先存在(即使是空白的), 否則 logrotate --force 測試時會出現 stat 警告,讓人誤以為設定有誤。 預先手動建立空白日誌檔案,可確保: 1. 目錄結構完整,服務啟動即可寫入 2. logrotate 驗證正常,不出現誤導性警告 3. 整個日誌鏈一致,權限清楚可稽核 touch /var/log/php/phpmyadmin-error.log 將日誌檔案的擁有者設為 www-data chown www-data:www-data /var/log/php/phpmyadmin-error.log 設定檔案權限為 640 chmod 640 /var/log/php/phpmyadmin-error.log 640 權限說明: www-data(擁有者)可讀寫 www-data 群組成員可讀 其他使用者無任何存取權(防止一般系統使用者讀取錯誤日誌內容) 步驟三:驗證 PHP-FPM 確實具有寫入權限 sudo -u www-data test -w /var/log/php/phpmyadmin-error.log && echo "OK" 若顯示 OK,表示 PHP-FPM(以 www-data 身份執行)確實具有寫入權限,設定正常。 若無任何輸出(靜默失敗):表示 www-data 無法寫入日誌檔案,請重新確認前兩步驟的 chown 與 chmod 是否正確執行。 步驟四:驗證目錄與檔案結構 ls -lah /var/log/php/ 預期輸出 drwxr-xr-x 2 root root 4.0K drwxr-xr-x 13 root root 4.0K -rw-r----- 1 www-data www-data 0 ... phpmyadmin-error.log 注意:目錄擁有者是 root root,而非 www-data www-data。 這是正確的設定。許多教學(與錯誤的預期輸出範例)將目錄擁有者誤寫為 www-data, 實際執行時前面的 chown root:root /var/log/php 就已確立了目錄歸屬。 日誌檔案本身才是 www-data www-data。 步驟五:驗證 PHP-FPM Pool 錯誤日誌設定已生效 確認 Pool 設定檔中的 error_log 指向正確路徑 grep error_log /etc/php/8.3/fpm/pool.d/phpmyadmin.conf 預期輸出 php_admin_value[error_log] = /var/log/php/phpmyadmin-error.log 驗證 PHP-FPM 語法 php-fpm8.3 -t 預期輸出: [...] NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful 重新載入 PHP-FPM 使設定生效 systemctl reload php8.3-fpm ---------------------------- 確認獨立 socket 已建立 ---------------------------- ls -la /var/run/php/phpmyadmin.sock 預期輸出: srw-rw---- 1 www-data www-data 0 ... /var/run/php/phpmyadmin.sock ------------------------- 驗證 Nginx 語法 ------------------------- 驗證語法 nginx -t 預期輸出: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful --------------------------------------------------- 確認 sites-enabled 符號連結 --------------------------------------------------- ls -la /etc/nginx/sites-enabled/ 預期顯示 default.conf -> /etc/nginx/sites-available/default.conf 若無 default.conf 連結,則執行(本教學之前步驟已做者,請勿重複執行,否則會報錯) ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf 重新載入 systemctl reload nginx --------------------------------------------- phpMyAdmin 下載、GPG驗證與安裝 --------------------------------------------- 前往官網確認目前最新穩定版本號 https://www.phpmyadmin.net/downloads/ 本教學以 phpMyAdmin 5.2.3 為例,請依官網公告替換版本號。 ----------------- 下載與GPG驗證 ----------------- 建立下載目錄 mkdir -p /root/downloads 進入該目錄 cd /root/downloads 下載 GPG 金鑰 wget https://files.phpmyadmin.net/phpmyadmin.keyring 匯入金鑰 gpg --import phpmyadmin.keyring 下載 phpMyAdmin 壓縮包 wget https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz 下載簽章檔 wget https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz.asc GPG 簽章驗證(必做,不可省略) gpg --verify phpMyAdmin-5.2.3-all-languages.tar.gz.asc 驗證結果判讀 若顯示 Good signature → 檔案完整且來源可信,可以繼續安裝 若顯示 BAD signature → 檔案已被竄改,立即停止,重新下載,絕不繼續 若顯示 WARNING: This key is not certified with a trusted signature! 且有 Good signature → 金鑰未加入信任鏈, 屬正常現象,可繼續安裝。 常犯錯誤:許多人跳過GPG驗證直接解壓縮。 GPG驗證是確認你下載到的是官方原版而非被惡意替換的版本,請務必執行,不可省略。 --------------------------------------- SHA256 校驗(強烈建議) --------------------------------------- sha256sum phpMyAdmin-5.2.3-all-languages.tar.gz 將輸出值與官網公佈的 SHA256 比對,確認完全相符後再繼續 https://files.phpmyadmin.net/phpMyAdmin/5.2.3/phpMyAdmin-5.2.3-all-languages.tar.gz.sha256 下載並開啟 phpMyAdmin-5.2.3-all-languages.tar.gz.sha256 檔案內容中有這一行 12ba1c425fa4071abbd4e7668c9ebdeac0b0755a467a6d6d5026122bb47c102b phpMyAdmin-5.2.3-all-languages.tar.gz 代表 官方雜湊值(5.2.3 版本) 說明: GPG 驗證確認來源真實性, SHA256 校驗確認下載完整性(防止下載中途損毀)。 兩者各有側重,建議同時執行。 ------------------ 解壓縮與安裝 ------------------ 建立目標目錄 mkdir -p /var/www/html/phpMyAdmin 解壓縮(--strip-components=1 去除頂層目錄名稱) tar xf phpMyAdmin-5.2.3-all-languages.tar.gz \ --strip-components=1 \ -C /var/www/html/phpMyAdmin 確認解壓縮成功(應看到 index.php、libraries/、sql/ 等核心檔案) ls -l /var/www/html/phpMyAdmin/ 複製設定檔範本 cp /var/www/html/phpMyAdmin/config.sample.inc.php \ /var/www/html/phpMyAdmin/config.inc.php -------------------------------------- 移除 setup 目錄 -------------------------------------- 移除 setup 目錄(非常重要!) rm -rf /var/www/html/phpMyAdmin/setup 確認已移除(以下幾行一起貼上,無警告輸出代表正確) ls -la /var/www/html/phpMyAdmin/setup 2>/dev/null \ && echo "警告:請立即移除!" \ || echo "setup 目錄已移除" 高風險提醒:/setup 目錄可被任何外部訪客用來重新設定 phpMyAdmin,是嚴重的攻擊入口。 即使已設有IP白名單,也應徹底移除,而不是僅依賴存取控制。 每次更新後同樣需要再次確認並移除。 ------------------- 清理下載暫存檔 ------------------- rm /root/downloads/phpMyAdmin-5.2.3-all-languages.tar.gz rm /root/downloads/phpMyAdmin-5.2.3-all-languages.tar.gz.asc rm /root/downloads/phpmyadmin.keyring ------------------------------------------------ phpMyAdmin config.inc.php 安全設定 ------------------------------------------------ 預先生成必要的金鑰與密碼 在編輯設定檔之前,先一次生成所有需要的隨機字串,並存入密碼管理器(如 Bitwarden、1Password)。 生成 Blowfish Secret(恰好32位元組,用於加密 Session cookie) openssl rand -base64 24 | head -c 32 生成 pma_control 的密碼(稍後建立帳號時使用) openssl rand -base64 24 生成 dbadmin 的密碼(稍後建立帳號時使用) openssl rand -base64 24 生成 xxxx_com(IPS論壇應用程式帳號)的密碼 openssl rand -base64 24 注意事項: 永遠不要在不同伺服器之間共用相同的 blowfish_secret 不要將 config.inc.php 提交至版本控制系統(Git) 每次重新安裝都應重新生成 4個輸出值請立即記錄,稍後分別填入設定檔 ---------------------------------------------------- 驗證 Blowfish Secret 長度(避免常見錯誤) ---------------------------------------------------- 生成後,務必確認恰好為 32個字元,多一個少一個都會觸發 phpMyAdmin 警告: echo -n '你生成的字串' | wc -c 預期輸出為 32 ------------------------------------------------------ 連線方式說明:為何使用 localhost + socket ------------------------------------------------------ 重要背景知識(請務必閱讀) 在 MariaDB / MySQL 中,localhost 與 127.0.0.1 是不同的連線方式 設定值:localhost 連線方式:Unix Domain Socket 對應的 MariaDB 帳號格式:'user'@'localhost' 設定值:127.0.0.1 連線方式:TCP/IP 對應的 MariaDB 帳號格式:'user'@'127.0.0.1' 本教學統一使用 localhost + socket,理由如下: Unix Socket 不經過網路堆疊,速度更快、延遲更低 不開放 TCP 端口,減少攻擊面 MariaDB 預設認證(unix_socket)即為 socket 連線 pma_control 與 xxxx_com 帳號均以 @'localhost' 建立,三方設定完全一致,不會出現混用導致的「Access denied」錯誤 混用 localhost 與 127.0.0.1 是大多數連線失敗的根本原因 -------------------- 編輯設定檔 -------------------- 編輯 vi /var/www/html/phpMyAdmin/config.inc.php 全部取代原有內容 <?php /** * phpMyAdmin 安全強化設定檔 * * 修改前必讀: * 1. blowfish_secret 必須替換為你自己生成的恰好32 bytes隨機字串 * 生成指令:openssl rand -base64 24 | head -c 32 * 驗證長度:echo -n '你的字串' | wc -c → 必須為 32 * 2. controlpass 必須替換為 pma_control 帳號的實際密碼 * 3. 本檔案儲存後須立即執行: * chown root:www-data /var/www/html/phpMyAdmin/config.inc.php * chmod 640 /var/www/html/phpMyAdmin/config.inc.php * 4. 切勿將本檔案提交至 Git 或任何版本控制系統 */ declare(strict_types=1); // ════════════════════════════════════════════════════════════════ // 安全金鑰 // 每台伺服器唯一,切勿共用或提交至 Git // 生成指令:openssl rand -base64 24 | head -c 32 // 長度必須恰好為 32 bytes,超過會顯示「longer than necessary」警告 // ════════════════════════════════════════════════════════════════ $cfg['blowfish_secret'] = '替換為恰好32字元的隨機字串'; // ← 必須替換 // ════════════════════════════════════════════════════════════════ // 伺服器連線設定 // ════════════════════════════════════════════════════════════════ $i = 0; $i++; // ── 主要連線(MariaDB 僅限本機,使用 Unix Socket) ────────────── $cfg['Servers'][$i]['host'] = 'localhost'; // Unix Socket 連線至本機 $cfg['Servers'][$i]['connect_type'] = 'socket'; // 明確指定 Unix Socket 連線方式 $cfg['Servers'][$i]['compress'] = false; // 本機連線不需壓縮 $cfg['Servers'][$i]['auth_type'] = 'cookie'; // cookie 模式:每次登入需輸入帳密 $cfg['Servers'][$i]['AllowNoPassword'] = false; // 嚴格禁止空白密碼登入 // ── phpMyAdmin 控制使用者(帳號 pma_control) ────────────────────────── // 此帳號用於儲存書籤、查詢歷史、關聯設定、使用者偏好等進階功能 // 注意:controlpass 必須與 MariaDB 中 pma_control@localhost 帳號的實際密碼一致 $cfg['Servers'][$i]['controluser'] = 'pma_control'; $cfg['Servers'][$i]['controlpass'] = '替換為pma_control帳號的密碼'; // ← 必須替換 $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin'; // ── 進階功能資料表(與 sql/create_tables.sql 對應) ───────────────────── // 這些資料表名稱為 phpMyAdmin 官方預設值 // 無特殊需求請勿修改,否則進階功能將無法正常運作 $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark'; $cfg['Servers'][$i]['relation'] = 'pma__relation'; $cfg['Servers'][$i]['table_info'] = 'pma__table_info'; $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords'; $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages'; $cfg['Servers'][$i]['column_info'] = 'pma__column_info'; $cfg['Servers'][$i]['history'] = 'pma__history'; $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs'; $cfg['Servers'][$i]['tracking'] = 'pma__tracking'; $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig'; $cfg['Servers'][$i]['recent'] = 'pma__recent'; $cfg['Servers'][$i]['favorite'] = 'pma__favorite'; $cfg['Servers'][$i]['users'] = 'pma__users'; $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups'; $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding'; $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches'; $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns'; $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings'; $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates'; // ════════════════════════════════════════════════════════════════ // Session 與 Cookie 安全 // ════════════════════════════════════════════════════════════════ // LoginCookieValidity 必須與 PHP-FPM Pool 的 session.gc_maxlifetime 一致(同為 1800) // 若 session.gc_maxlifetime < LoginCookieValidity,phpMyAdmin 介面會顯示: // 「在PHP設定參數 session.gc_maxlifetime 所設定的時間短於在 phpMyAdmin 設定的cookie有效時間, // 因此登入連線有效時間可能比在 phpMyAdmin 設定的時間要短。」 // 本教學已在 phpmyadmin.conf Pool 中設定 session.gc_maxlifetime = 1800,兩者一致。 $cfg['LoginCookieValidity'] = 1800; // 閒置 30 分鐘後自動登出(單位:秒) $cfg['LoginCookieStore'] = 0; // 0 = 關閉瀏覽器即清除 cookie(不持久化) $cfg['LoginCookieRecall'] = false; // 不在登入頁預填使用者名稱 $cfg['LoginCookieDeleteAll'] = true; // 登出時刪除所有伺服器的 Session $cfg['CookieSameSite'] = 'Strict'; // 防止 CSRF 跨站 cookie 傳送 // Session 存放在獨立目錄(不使用系統共用的 /tmp) $cfg['SessionSavePath'] = '/var/lib/phpmyadmin/sessions'; // ════════════════════════════════════════════════════════════════ // 安全功能限制 // ════════════════════════════════════════════════════════════════ // 禁止在登入頁填入任意伺服器位址(防止 SSRF 伺服器端請求偽造攻擊) $cfg['AllowArbitraryServer'] = false; $cfg['ArbitraryServerRegexp'] = ''; // 不對外檢查版本(避免讓攻擊者得知你使用的版本資訊) $cfg['VersionCheck'] = false; // 禁用佈景主題管理器(減少攻擊面) $cfg['ThemeManager'] = false; // 禁用 Web 介面上傳 SQL 檔案至伺服器目錄的功能 $cfg['UploadDir'] = ''; // 禁用伺服器端 SQL 儲存功能 $cfg['SaveDir'] = ''; // 啟用設定檔權限檢查 $cfg['CheckConfigurationPermissions'] = true; // 不傳送錯誤報告至 phpMyAdmin 官方伺服器 $cfg['SendErrorReports'] = 'never'; // 禁止顯示「全選」等批次危險操作 $cfg['ShowAll'] = false; // ════════════════════════════════════════════════════════════════ // 介面安全設定(隱藏敏感資訊) // ════════════════════════════════════════════════════════════════ // 不在介面顯示 PHP 詳細資訊(phpinfo) $cfg['ShowPhpInfo'] = false; // 不在介面顯示伺服器詳細資訊(版本、路徑、作業系統等) $cfg['ShowServerInfo'] = false; // 不在資料表結構頁顯示「建立時間」(減少系統資訊洩露) $cfg['ShowDbStructureCreation'] = false; // 禁止一般登入使用者刪除資料庫(需具備 DROP 權限才可刪除) $cfg['AllowUserDropDatabase'] = false; // 防止在 SQL 控制台按下 Enter 誤觸送出查詢(按 Ctrl+Enter 才執行) $cfg['ConsoleEnterExecutes'] = false; // 禁止將 phpMyAdmin 嵌入任何 iframe(防止 Clickjacking 點擊劫持攻擊) $cfg['FrameAllowedFrom'] = ''; // ════════════════════════════════════════════════════════════════ // 效能設定(針對 2GB RAM VPS 優化) // ════════════════════════════════════════════════════════════════ // PHP 記憶體限制 // phpMyAdmin 處理大型資料表時需要足夠記憶體 // 注意:此值不應超過 PHP 的 memory_limit(/etc/php/8.3/fpm/php.ini) $cfg['MemoryLimit'] = '256M'; // SQL 查詢執行逾時(單位:秒) // 匯入大型 SQL 檔案時可臨時調高至 600(10 分鐘),匯入完畢後改回 120 $cfg['ExecTimeLimit'] = 120; // 暫存目錄(不使用系統共用的 /tmp) $cfg['TempDir'] = '/var/lib/phpmyadmin/tmp'; // ════════════════════════════════════════════════════════════════ // 介面偏好 // ════════════════════════════════════════════════════════════════ $cfg['DefaultLang'] = 'zh_TW'; // 預設語言:繁體中文 $cfg['ServerDefault'] = 1; // 預設伺服器(對應上方 $i = 1) $cfg['MaxRows'] = 50; // 每頁顯示資料列數(可依個人習慣調整) // 匯出時預設使用的字元集 $cfg['Export']['charset'] = 'utf-8'; // ════════════════════════════════════════════════════════════════ // 稽核與日誌(Production 環境建議啟用) // ════════════════════════════════════════════════════════════════ // phpMyAdmin 層面的操作稽核(記錄登入、查詢等操作至 pma__history 等資料表) // $cfg['ActionLog'] = true; // 完整的資料庫操作稽核建議在 MariaDB 層面啟用 Audit Plugin: // INSTALL SONAME 'server_audit'; // SET GLOBAL server_audit_logging = ON; // SET GLOBAL server_audit_events = 'CONNECT,QUERY'; // 詳見:https://mariadb.com/kb/en/mariadb-audit-plugin/ 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter ---------------------------- 目錄與檔案權限設定 ---------------------------- 將所有權變更為 root chown -R root:root /var/www/html/phpMyAdmin 目錄權限設為 755 find /var/www/html/phpMyAdmin -type d -exec chmod 755 {} \; 檔案權限設為 644 find /var/www/html/phpMyAdmin -type f -exec chmod 644 {} \; config.inc.php 含有金鑰與密碼,必須特別保護 (僅允許 root 讀寫,www-data 群組唯讀,其他使用者無法存取) chown root:www-data /var/www/html/phpMyAdmin/config.inc.php chmod 640 /var/www/html/phpMyAdmin/config.inc.php ---------------------------------- 驗證 config.inc.php 權限 ---------------------------------- ls -lah /var/www/html/phpMyAdmin/config.inc.php 預期輸出: -rw-r----- 1 root www-data ... config.inc.php 權限說明:-rw-r----- 即 640 ----------------------------------------- 確認 無 777 危險權限 ----------------------------------------- find /var/www/html/phpMyAdmin -type f -perm 777 find /var/www/html/phpMyAdmin -type d -perm 777 無任何輸出,即代表沒有 777 權限的檔案或目錄。 ------------------------------------ 建立安全的暫存與 Session 目錄 ------------------------------------ phpMyAdmin 需要獨立的暫存目錄與 Session 目錄。 請勿使用系統共用的 /tmp,因為其他系統使用者可讀,存在Session洩露風險,且在安全稽核中會產生警告。 建立專用暫存目錄與 Session 目錄 mkdir -p /var/lib/phpmyadmin/tmp mkdir -p /var/lib/phpmyadmin/sessions 設定擁有者 chown -R www-data:www-data /var/lib/phpmyadmin 父目錄:750 = 擁有者完全控制,群組可讀,其他人無存取權 chmod 750 /var/lib/phpmyadmin 子目錄:700 = 僅 www-data 可存取,徹底隔離 chmod 700 /var/lib/phpmyadmin/tmp chmod 700 /var/lib/phpmyadmin/sessions ------------------- 驗證目錄結構 ------------------- ls -lah /var/lib/phpmyadmin/ 預期輸出 drwxr-x--- 4 www-data www-data 4.0K ... . drwxr-xr-x ... .. drwx------ 2 www-data www-data 4.0K ... sessions drwx------ 2 www-data www-data 4.0K ... tmp 常見遺漏: 若不建立此目錄,phpMyAdmin 會嘗試使用系統 /tmp, 可能導致 Session 衝突,或在安全稽核中產生警告。 ----------------------------------- 重開機後目錄持久性說明 ----------------------------------- /var/lib/phpmyadmin 位於持久性磁碟,重開機後不會消失,無需額外設定。 與之相對,/var/run/php/ 下的 socket 檔案位於 tmpfs(記憶體),每次重開機都會重新由 PHP-FPM 建立,這是正常行為。 --------------------------------------------- 確認 root 帳號僅允許本機連線 --------------------------------------------- 這是防止資料庫 root 帳號遭遠端登入的關鍵步驟,許多人因為跳過此步驟而導致資料庫被入侵。 進入資料庫 sudo mariadb 在 MariaDB 提示符號下,以下幾行一起貼上 -- 檢查目前 root 帳號的連線設定 SELECT User, Host, plugin FROM mysql.user WHERE User = 'root'; -- 刪除任何允許遠端連線的 root 帳號,只保留 localhost(Unix Socket) -- 注意:127.0.0.1 與 ::1 使用 TCP 連線,本教學不保留這兩個 DELETE FROM mysql.user WHERE User = 'root' AND Host NOT IN ('localhost'); FLUSH PRIVILEGES; -- 再次確認,應只剩 localhost 的 root 帳號 SELECT User, Host, plugin FROM mysql.user WHERE User = 'root'; EXIT; 預期查詢結果: | User | Host | plugin | |------|-----------|--------------| | root | localhost | unix_socket | 若 plugin 顯示為 mysql_native_password 而非 unix_socket,請進行以下修改。 --------------------------------------------------------------------------------- 將 mysql_native_password 修改為 unix_socket(給 MariaDB root 帳號用) --------------------------------------------------------------------------------- 注意:mysql_native_password 修改為 unix_socket 之後, MariaDB root 帳號將無法登入瀏覽器 phpMyAdmin 網頁頁面 進入資料庫 sudo mariadb 在 MariaDB 提示符號下,以下幾行一起貼上 -- 將 root 認證方式改為 unix_socket ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket; -- 若上面指令無效,試試以下指令 -- UPDATE mysql.user SET plugin='unix_socket' WHERE User='root' AND Host='localhost'; FLUSH PRIVILEGES; -- 確認修改結果 SELECT User, Host, plugin FROM mysql.user WHERE User = 'root'; EXIT; 注意:改成 unix_socket 後, .只能用系統的 root 使用者透過 sudo mariadb 登入 .無法用密碼登入(mysql -u root -p 會失敗,這是預期行為) .安全性較高(依賴系統使用者認證) ----------------------------------------- 建立IPS論壇資料庫與應用程式帳號 ----------------------------------------- -------------------- 帳號規劃原則 -------------------- 帳號名稱:xxxx_com 類型:IPS論壇應用程式帳號 用途:IPS論壇程式日常讀寫 建議權限:僅限IPS論壇資料庫的增刪改查與建表 帳號名稱:pma_control 類型:phpMyAdmin 控制帳號 用途:phpMyAdmin 本身運作 建議權限:僅限 phpmyadmin 控制庫 帳號名稱:dbadmin 類型:完整管理帳號 用途:phpMyAdmin 管理操作 建議權限:僅限指定資料庫的 ALL PRIVILEGES 帳號名稱:root 類型:資料庫超級使用者 帳號建立過程:在安裝 MariaDB 11.8.x,進行安全性設定 mariadb-secure-installation 時,所建立的root帳號 用途:SSH 命令列資料庫維護 建議權限:僅限本機 socket 連線 生產環境警告: dbadmin 的權限應縮減,切勿使用 GRANT ALL ON *.*(全域權限),等同於 root 等級。 務必指定資料庫名稱(ON xxxx_com.*),而非 *.*(所有資料庫)。 ------------------------------------------------------------- 建立 phpMyAdmin 控制使用者 pma_control 帳號 ------------------------------------------------------------- 使用前面步驟已生成的密碼,作為 pma_control 帳號的密碼 進入資料庫 sudo mariadb 在 MariaDB 提示符號下,替換密碼後,以下幾行一起貼上 -- 建立 phpMyAdmin 控制使用者 pma_control CREATE USER 'pma_control'@'localhost' IDENTIFIED BY '替換為強密碼至少16字元含大小寫數字符號'; -- 授予控制資料庫的必要權限 -- 注意:此時 phpmyadmin 資料庫尚未建立,GRANT 會先記錄,匯入資料表後即生效 GRANT SELECT, INSERT, UPDATE, DELETE ON phpmyadmin.* TO 'pma_control'@'localhost'; FLUSH PRIVILEGES; -- 驗證授權 SHOW GRANTS FOR 'pma_control'@'localhost'; EXIT; ---------------------------------------------- 修改 config.inc.php 並填入密碼 ---------------------------------------------- 編輯 vi /var/www/html/phpMyAdmin/config.inc.php 有2個地方需要填入實際值(在上面步驟中已生成並已記錄下) 第 1 處:搜尋 blowfish_secret 這一行並替換 $cfg['blowfish_secret'] = '替換為恰好32字元的隨機字串'; 第 2 處:搜尋 controlpass 這一行並替換 $cfg['Servers'][$i]['controlpass'] = '替換為pma_control帳號的密碼'; 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter --------------------------- 重新確認權限 --------------------------- chown root:www-data /var/www/html/phpMyAdmin/config.inc.php chmod 640 /var/www/html/phpMyAdmin/config.inc.php ---------------------------- 建立IPS論壇的資料庫 ---------------------------- 請先將 xxxx_com 改為你要的IPS論壇資料庫名 SSH 命令列,以下幾行一起貼上 sudo mariadb -e "CREATE DATABASE IF NOT EXISTS xxxx_com CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 注意:編碼務必選擇 utf8mb4_unicode_ci,而非舊版的 utf8_general_ci。 utf8mb4 才能正確儲存 Emoji 與完整的 Unicode 字元(包含中日韓文字的特殊字元)。 -------------------------------------------------- 建立IPS論壇應用程式帳號 -------------------------------------------------- 在前面步驟已生成,作為 xxxx_com 帳號的密碼 SSH命令列 進入資料庫 sudo mariadb 在 MariaDB 提示符號下,修改密碼與資料庫名後一起貼上 -- 建立應用程式帳號(IPS論壇程式使用) -- 請將 xxxx_com 替換為你的資料庫名 CREATE USER 'xxxx_com'@'localhost' IDENTIFIED BY '替換為強密碼至少16字元含大小寫數字符號'; -- 授予IPS論壇日常運作所需的權限 GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP, INDEX, LOCK TABLES, CREATE TEMPORARY TABLES ON xxxx_com.* TO 'xxxx_com'@'localhost'; FLUSH PRIVILEGES; -- 驗證授權 SHOW GRANTS FOR 'xxxx_com'@'localhost'; EXIT; ------------------------------------- 建立完整管理帳號 dbadmin ------------------------------------- MariaDB root 帳號使用 unix_socket 認證,無法透過瀏覽器 phpMyAdmin 登入(也不應允許)。 若確實需要透過 phpMyAdmin 執行完整管理操作,請建立專用管理帳號:dbadmin 在前面步驟已生成,作為 dbadmin 帳號的密碼 進入資料庫 sudo mariadb 在 MariaDB 提示符號下,修改密碼後,一起貼上 -- 建立 dbadmin 帳號 CREATE USER 'dbadmin'@'localhost' IDENTIFIED BY '替換為強密碼至少16字元含大小寫數字符號'; -- 生產環境建議:縮減至僅需管理的資料庫 -- 將 xxxx_com 改為你實際的論壇資料庫名 -- 切勿使用 ON *.* 全域授權 GRANT ALL PRIVILEGES ON xxxx_com.* TO 'dbadmin'@'localhost'; GRANT ALL PRIVILEGES ON phpmyadmin.* TO 'dbadmin'@'localhost'; FLUSH PRIVILEGES; -- 驗證授權 SHOW GRANTS FOR 'dbadmin'@'localhost'; EXIT; 補充說明:若日後新增了其他資料庫,也要補上對應的 GRANT: GRANT ALL PRIVILEGES ON 新資料庫名.* TO 'dbadmin'@'localhost'; FLUSH PRIVILEGES; ----------------------- 各帳號用途總覽 ----------------------- 帳號:xxxx_com 用途:填入IPS論壇程式的資料庫設定檔(conf_global.php 等) 登入方式:Unix Socket(應用程式自動連線) 帳號:pma_control 用途:填入 config.inc.php 的 controlpass,不直接用於登入 phpMyAdmin 登入方式:Unix Socket(phpMyAdmin 自動使用) 帳號:dbadmin 用途:透過瀏覽器 phpMyAdmin 介面進行資料庫管理操作 登入方式:Unix Socket + mysql_native_password(瀏覽器登入) 帳號:root 用途:透過 sudo mariadb 在 SSH 命令列進行資料庫維護,無法透過瀏覽器登入 phpMyAdmin (正確安全設計) 登入方式:Unix Socket(sudo mariadb 指令) ---------------------- 重新載入 ---------------------- nginx -t systemctl reload nginx systemctl status nginx ------------------------------- 清除瀏覽器 HSTS 快取 ------------------------------- 若瀏覽器曾記錄相同IP的HSTS 政策,可能造成環境切換異常。 請在Chrome瀏覽器的網址列輸入 chrome://net-internals/#hsts 請在「Delete domain security policies」輸入 VPS IP 並刪除。 ----------------------------------------- 建立 phpMyAdmin 控制資料庫 ----------------------------------------- 使用瀏覽器 進入 https://VPS的IP:888/phpMyAdmin/ 瀏覽器顯示自簽憑證警告 → 點擊「進階」→「繼續前往」(正常現象) 初次連入 phpMyAdmin 時,可能會看到提示: 尚未設定 phpMyAdmin 設定儲存空間,部份延伸功能將無法使用。了解原因。 或者前往任一個資料庫的「操作」分頁設定。 這個提示訊息,表示尚未建立 phpMyAdmin 用來存放自身設定的控制資料庫,需要匯入官方提供的建表 SQL。 ----------------------------------- 方法一:SSH命令列方式(建議) ----------------------------------- 建立控制資料庫(指定 utf8mb4 字元集) sudo mariadb -e "CREATE DATABASE IF NOT EXISTS phpmyadmin CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" 匯入 phpMyAdmin 控制資料表結構 sudo mariadb phpmyadmin \ < /var/www/html/phpMyAdmin/sql/create_tables.sql 驗證資料表已建立(預期看到約 19 個 pma__ 開頭的資料表) sudo mariadb -e "SHOW TABLES IN phpmyadmin;" -------------------------- 確認控制使用者權限 -------------------------- 在前面步驟建立的 pma_control 帳號,此時已可存取剛建立的 phpmyadmin 資料庫,無需額外操作 sudo mariadb -e "SHOW GRANTS FOR 'pma_control'@'localhost';" 預期輸出包含: GRANT SELECT, INSERT, UPDATE, DELETE ON `phpmyadmin`.* TO `pma_control`@`localhost` ---------------------------------------------------------------------------------------------------- 方法二:透過 phpMyAdmin 介面 (此方法須先「建立完整管理帳號 dbadmin」後才能操作) ---------------------------------------------------------------------------------------------------- 前往官網下載最新版壓縮包 https://www.phpmyadmin.net/downloads/phpMyAdmin-latest-all-languages.tar.gz 解壓縮 phpMyAdmin-latest-all-languages.tar.gz 尋找目錄中 /sql/create_tables.sql 找到 create_tables.sql 瀏覽器進入 phpMyAdmin 首頁(以 dbadmin 帳號登入) -> 匯入 -> 要匯入的檔案 -> 選擇檔案 -> create_tables.sql -> 匯入 完成後將顯示: 完成匯入,共執行了 19 個查詢指令。 (create_tables.sql) 返回 phpMyAdmin 首頁,「設定儲存空間」警告訊息應消失。 ---------------------- 重新載入 ---------------------- nginx -t systemctl reload nginx systemctl status nginx -------------------- 重開機驗證 -------------------- 重開機 reboot 重開機後,驗證所有服務正常啟動 驗證 Nginx 語法 nginx -t 確認 Nginx 運行 systemctl status nginx 確認 PHP-FPM 運行 systemctl status php8.3-fpm 確認 MariaDB 運行中 systemctl status mariadb 確認 phpMyAdmin 目錄存在且權限正確 ls -lah /var/www/html/phpMyAdmin/config.inc.php 確認暫存與 Session 目錄存在 ls -lah /var/lib/phpmyadmin/ 確認 PHP-FPM socket 存在(注意:phpMyAdmin 專用 socket) ls -la /var/run/php/phpmyadmin.sock 確認 setup 目錄已移除(無輸出代表正確) ls -la /var/www/html/phpMyAdmin/setup 2>/dev/null \ && echo "警告:setup 目錄仍存在,請立即移除!" \ || echo "setup 目錄已移除" ----------------- 功能驗證 ----------------- 1. 瀏覽器進入 https://伺服器IP:888/phpMyAdmin/ 2. 瀏覽器顯示自簽憑證警告 → 點擊「進階」→「繼續前往」(正常現象) 3. 應看到 phpMyAdmin 登入頁面(非空白頁或錯誤頁) 4. 以 dbadmin 帳號登入(root帳號無法登入phpMyAdmin瀏覽器頁面) 5. 登入後確認頁面無「設定儲存空間」警告 6. 確認頁面無 session 或 cookie 警告訊息 7. 點選上方「狀態」選項,確認伺服器資訊正常顯示 ------------------------------------- 若瀏覽器無法連線,請依序確認 ------------------------------------- 1. nftables 防火牆規則是否允許你的IP連入 888 port nft list ruleset | grep 888 2. WAF 雲端安全群組是否同步允許(請至雲端控制台確認) 3. nginx -t 語法是否正確 nginx -t 4. 888 port 是否正在監聽 ss -tlnp | grep 888 ---------------------------------- phpMyAdmin 快速開關管理 ---------------------------------- ----------------------------------- 建立快捷 Alias 並永久生效 ----------------------------------- Alias 是 Bash 的指令別名功能,讓你可以用簡短的自訂指令取代複雜的長指令。 Debian 預設的 /root/.bashrc 已內建載入 ~/.bash_aliases 的邏輯, 因此只需將 alias 定義寫入 /root/.bash_aliases 即可永久生效。 ------------------------------------- 確認 .bashrc 已內建載入邏輯 ------------------------------------- grep bash_aliases /root/.bashrc 若看到類似以下輸出,表示設定正確: if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi ----------------------------- 建立 Alias 定義檔 ----------------------------- 編輯 vi /root/.bash_aliases 貼上以下內容 # ── phpMyAdmin 快速開關 ──────────────────────────────────────── alias pma-open='mv /etc/nginx/sites-enabled/default.conf.disabled /etc/nginx/sites-enabled/default.conf 2>/dev/null; nginx -t && systemctl reload nginx && echo "[OK] phpMyAdmin 已開啟"' alias pma-close='mv /etc/nginx/sites-enabled/default.conf /etc/nginx/sites-enabled/default.conf.disabled 2>/dev/null; nginx -t && systemctl reload nginx && echo "[OK] phpMyAdmin 已關閉"' alias pma-status='ls /etc/nginx/sites-enabled/default.conf >/dev/null 2>&1 && echo "OPEN(phpMyAdmin 開啟中)" || echo "CLOSED(phpMyAdmin 已關閉)"' 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter ----------------------- 立即載入設定 ----------------------- source /root/.bashrc ------------------------- 驗證 Alias 已生效 ------------------------- alias | grep pma 預期輸出: alias pma-close='...' alias pma-open='...' alias pma-status='...' ---------------------- 使用方式 ---------------------- 開啟 phpMyAdmin pma-open 關閉 phpMyAdmin pma-close 查看目前開關狀態 pma-status 建議習慣 SOP:每次使用完畢,立即執行 pma-close -------------------------------------------------------------------- phpMyAdmin 自動關閉機制 -------------------------------------------------------------------- 本教學提供兩種互補的自動關閉機制,兩種方法都應設定,共同形成雙重保障。 ------------------------------ 機制說明與常見 Bug 分析 ------------------------------ 在設定前,必須理解各機制的作用範圍與已知限制: 機制:systemd 服務(方法一) 觸發時機:系統關機 / reboot 限制與盲點:需正確設定 Before= 依賴,否則執行時序不可靠 機制:.bash_logout(方法二) 觸發時機:root SSH 互動式登出 限制與盲點:僅對互動式 shell 有效;tmux/screen 內 exit 不觸發外層登出;非互動式SSH不觸發 重要: 兩種機制各有盲點,必須並用才能覆蓋大多數場景。 即便如此,仍建議養成手動執行 pma-close 的習慣,作為最後一道保障。 ---------------------------------------------------------------------- 方法一:systemd 服務(推薦,處理 reboot / shutdown) ---------------------------------------------------------------------- 這是最可靠的關機自動關閉方案。 systemd 服務在系統進入 shutdown 流程時執行 ExecStop, 確保 phpMyAdmin 在 reboot / shutdown 後保持關閉狀態。 建立 vi /etc/systemd/system/pma-autoclose.service 貼上以下完整內容 [Unit] Description=Auto-close phpMyAdmin on shutdown/reboot After=network.target nginx.service Before=shutdown.target reboot.target halt.target [Service] Type=oneshot RemainAfterExit=yes # 系統啟動時:確保 phpMyAdmin 處於關閉狀態(防禦性設計) # 若 default.conf 存在(開啟狀態),立即關閉 ExecStart=/bin/bash -c '\ if [ -f /etc/nginx/sites-enabled/default.conf ]; then \ mv /etc/nginx/sites-enabled/default.conf \ /etc/nginx/sites-enabled/default.conf.disabled && \ echo "pma-autoclose [start]: phpMyAdmin 已於開機時自動關閉"; \ else \ echo "pma-autoclose [start]: phpMyAdmin 已是關閉狀態,無需操作"; \ fi' # 系統關機 / reboot 時:確保 phpMyAdmin 處於關閉狀態 ExecStop=/bin/bash -c '\ if [ -f /etc/nginx/sites-enabled/default.conf ]; then \ mv /etc/nginx/sites-enabled/default.conf \ /etc/nginx/sites-enabled/default.conf.disabled && \ echo "pma-autoclose [stop]: phpMyAdmin 已於關機時自動關閉"; \ else \ echo "pma-autoclose [stop]: phpMyAdmin 已是關閉狀態,無需操作"; \ fi' [Install] WantedBy=multi-user.target 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter -------------------------- 啟用服務 -------------------------- systemctl daemon-reload systemctl enable pma-autoclose.service systemctl start pma-autoclose.service ------------------------ 驗證服務狀態 ------------------------ systemctl status pma-autoclose.service 預期輸出中應看到: Active: active (exited) ... pma-autoclose [start]: phpMyAdmin 已是關閉狀態,無需操作 ------------------------------------ 驗證服務已設定為開機自動啟動 ------------------------------------ systemctl is-enabled pma-autoclose.service 預期輸出:enabled -------------------------------------------------------- 方法二:SSH 登出時自動關閉(.bash_logout) -------------------------------------------------------- 若希望 root 透過 SSH登出時,自動關閉 phpMyAdmin。 -------------------------------------- .bash_logout 的作用與已知限制 -------------------------------------- 在繼續設定前,必須了解 .bash_logout 的執行條件: 會觸發的情境: 直接SSH連線後執行 exit 或 logout SSH連線中斷時(視 shell 設定而定) 不會觸發的情境: 在 tmux 或 screen session 內部執行 exit(只退出 tmux pane,外層SSH連線未結束) 非互動式SSH連線(如 ssh root@server "command") 使用 kill 強制終止 SSH session 透過 web terminal 或其他非標準SSH工具連線 因此:.bash_logout 不能作為唯一的自動關閉機制,必須與方法一(systemd)並用。 ------------------------------------ 建立 .bash_logout 設定 ------------------------------------ 以下幾行一起貼上 cat >> /root/.bash_logout << 'EOF' # 登出時自動關閉 phpMyAdmin # 注意:僅在互動式 SSH 直接登出時觸發;tmux/screen 內部退出不觸發 if [ -f /etc/nginx/sites-enabled/default.conf ]; then mv /etc/nginx/sites-enabled/default.conf \ /etc/nginx/sites-enabled/default.conf.disabled 2>/dev/null # -q 抑制正常輸出,只在錯誤時才顯示 nginx -t -q 2>/dev/null && systemctl reload nginx 2>/dev/null echo "[pma-autoclose] phpMyAdmin 已於登出時自動關閉" fi EOF 說明:nginx -t -q 中的 -q 旗標(quiet)會抑制 nginx -t 的正常測試通過訊息,僅在語法有誤時才顯示錯誤。 由於 .bash_logout 在終端機關閉前執行,使用 -q 可避免在登出時多一行多餘的提示,但不影響實際的語法檢查效果。 ------------------------- 驗證 ------------------------- cat /root/.bash_logout 確認內容已正確附加,應看到上述腳本片段。 ---------------------------------------------- 驗證登出自動關閉是否生效的正確方法 ---------------------------------------------- 以下是可靠的驗證流程: 1. 先執行 pma-open 開啟 phpMyAdmin 2. 確認已開啟:pma-status(應顯示 OPEN) 3. 直接關閉SSH連線(不是在 tmux/screen 內,而是直接結束 SSH session) 4. 重新SSH登入 5. 確認已關閉:pma-status(應顯示 CLOSED) 若在 tmux/screen 內測試,結果不會如預期,因為 tmux/screen 的 exit 不觸發外層 .bash_logout。 排查提醒:若確認是直接SSH登出,但 phpMyAdmin 仍未自動關閉,可嘗試重開機後再次測試。 原因是部分 shell 環境初始化狀態可能影響 .bash_logout 的執行。 重開機後,pma-autoclose.service 的 ExecStart 也會補救性地確保 phpMyAdmin 處於關閉狀態。 ------------------------------ 自動關閉機制完整驗證 ------------------------------ 完成兩種方法的設定後,執行以下完整驗證: 確認 systemd 服務已啟用且執行中 systemctl is-enabled pma-autoclose.service systemctl status pma-autoclose.service 確認 .bash_logout 已設定 cat /root/.bash_logout | grep pma 確認當前 phpMyAdmin 為關閉狀態 pma-status --------------------------------------------- 設定 Log 日誌 與 Logrotate --------------------------------------------- 為何需要 Logrotate? phpMyAdmin 與 Nginx 的日誌會持續累積。 在無人管理的生產環境中,數個月後日誌檔可能佔用 數百MB 乃至 數GB 的磁碟空間,造成磁碟滿載進而導致服務中斷。 兩個關鍵日誌路徑: /var/log/php/phpmyadmin-error.log:PHP-FPM Pool 錯誤日誌(由 phpMyAdmin 專用 Pool 產生) /var/log/nginx/error.log:Nginx 錯誤日誌(含所有 vhost 的錯誤) Debian 系統已預裝 logrotate,預設每天執行(由 /etc/cron.daily/logrotate 觸發)。 我們只需新增對應的設定檔即可。 ----------------------------------------------------- 建立 PHP phpMyAdmin 日誌 Logrotate 設定 ----------------------------------------------------- 建立 vi /etc/logrotate.d/php-phpmyadmin 貼上以下完整內容: /var/log/php/phpmyadmin-error.log { daily missingok rotate 30 compress delaycompress notifempty create 0640 www-data www-data sharedscripts postrotate # 通知 PHP-FPM 重新開啟日誌檔案句柄(零中斷,不重啟服務) # 使用 pid 檔案路徑,比 pkill 更精確 if [ -f /run/php/php8.3-fpm.pid ]; then kill -USR1 $(cat /run/php/php8.3-fpm.pid) 2>/dev/null || true fi endscript } 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter 設定說明: daily:每天輪替一次 rotate 30:保留最近30份(約 1 個月) compress / delaycompress:壓縮舊日誌(延遲一天,避免壓縮到當天才剛輪替的檔案) missingok:日誌檔不存在時不報錯(phpMyAdmin 不常用時可能無錯誤日誌,但本教學已預先建立空白檔案) notifempty:日誌為空時不輪替(避免產生大量無意義的空白壓縮檔) create 0640 www-data www-data:輪替後建立新空白日誌,擁有者為 www-data,權限 640 postrotate + kill -USR1:發送 USR1 訊號給 PHP-FPM,讓其重新開啟日誌檔案句柄(不重啟服務,零中斷) 補充說明: logrotate 以 root 執行,因此可以在 root:root 擁有的目錄中,建立指定擁有者(www-data)的新日誌檔案。 這與「PHP-FPM 無法自行在目錄中建立檔案」並不矛盾,因為執行者的身份不同(root vs. www-data)。 此設計確保: 每次日誌輪替後,新建立的空白日誌檔案自動繼承正確的 www-data:www-data 擁有權與 640 權限 無需在每次輪替後手動重設權限 整個日誌生命週期(初始建立 → 日常寫入 → 輪替壓縮 → 重新建立)的權限鏈一致 ------------------------------------------ 確認 Nginx 日誌 Logrotate 設定 ------------------------------------------ Debian 安裝 Nginx 後通常已自動建立 /etc/logrotate.d/nginx,請先確認是否存在: cat /etc/logrotate.d/nginx 若已存在且內容合理(有 rotate、compress、postrotate 等),則無需額外建立,直接確認設定即可。 本教學的使用者,在之前安裝Nginx的步驟中,已設置過 logrotate ------------------------------------ 驗證 Logrotate 設定語法 ------------------------------------ logrotate --debug /etc/logrotate.d/php-phpmyadmin logrotate --debug /etc/logrotate.d/nginx --debug 模式只模擬執行,不實際輪替,適合語法驗證。 輸出無 error,表示設定正確。 --------------------------------- 手動測試輪替(強制執行) --------------------------------- 確認設定正確後,可強制執行一次輪替測試: logrotate --force /etc/logrotate.d/php-phpmyadmin ls -lah /var/log/php/ 預期看到已輪替的壓縮檔(phpmyadmin-error.log.1 或 .gz)以及新建的空白 phpmyadmin-error.log。 常見遺漏:許多教學只設定 log 路徑,卻忘記同步設定 logrotate,導致日誌檔在數月後撐滿磁碟,觸發服務中斷。 磁碟滿載(No space left on device)是小型 VPS 最常見的故障原因之一。 --------------------------------- 更新 phpMyAdmin 版本流程 --------------------------------- phpMyAdmin 版本需定期關注,發現含已知 CVE 的舊版時應立即更新。 可訂閱官方安全公告:https://www.phpmyadmin.net/security/ ------------------------------ 步驟一:備份現有設定檔 ------------------------------ cp /var/www/html/phpMyAdmin/config.inc.php \ /root/pma_config_backup_$(date +%Y%m%d).inc.php 確認備份成功 ls -lah /root/pma_config_backup_*.inc.php ---------------------------------- 步驟二:下載並驗證新版本 ---------------------------------- cd /root/downloads 替換「新版本號」為實際版本(如 5.2.4) wget https://files.phpmyadmin.net/phpMyAdmin/新版本號/phpMyAdmin-新版本號-all-languages.tar.gz wget https://files.phpmyadmin.net/phpMyAdmin/新版本號/phpMyAdmin-新版本號-all-languages.tar.gz.asc GPG 驗證 gpg --verify phpMyAdmin-新版本號-all-languages.tar.gz.asc SHA256 校驗(與官網比對) sha256sum phpMyAdmin-新版本號-all-languages.tar.gz 將輸出值與官網公佈的 SHA256 比對,確認完全相符後再繼續 https://files.phpmyadmin.net/phpMyAdmin/新版本號/phpMyAdmin-新版本號-all-languages.tar.gz.sha256 下載並開啟 phpMyAdmin-新版本號-all-languages.tar.gz.sha256 檔案內容中有這一行 xxxxxxxxxxxxxxxxxx phpMyAdmin-新版本號-all-languages.tar.gz 代表 官方雜湊值(新版本號) ------------------------------------ 步驟三:解壓縮並覆蓋舊版本 ------------------------------------ tar xf phpMyAdmin-新版本號-all-languages.tar.gz \ --strip-components=1 \ -C /var/www/html/phpMyAdmin --------------------------- 步驟四:還原設定檔 --------------------------- 注意:使用 $(date +%Y%m%d) 時,必須是當天執行備份的日期。 若備份與還原跨天,請手動指定備份檔名。 查看備份檔名 ls /root/pma_config_backup_*.inc.php 替換 YYYYMMDD 為實際備份日期 cp /root/pma_config_backup_YYYYMMDD.inc.php \ /var/www/html/phpMyAdmin/config.inc.php ----------------------------- 步驟五:重設權限 ----------------------------- chown -R root:root /var/www/html/phpMyAdmin find /var/www/html/phpMyAdmin -type d -exec chmod 755 {} \; find /var/www/html/phpMyAdmin -type f -exec chmod 644 {} \; config.inc.php 特別保護 chown root:www-data /var/www/html/phpMyAdmin/config.inc.php chmod 640 /var/www/html/phpMyAdmin/config.inc.php --------------------------------------------------------- 步驟六:移除 setup 目錄(每次更新都必須確認) --------------------------------------------------------- rm -rf /var/www/html/phpMyAdmin/setup 確認已移除(無輸出代表正確) ls -la /var/www/html/phpMyAdmin/setup 2>/dev/null \ && echo "警告:請立即移除!" \ || echo "已移除" ------------------------------------------------- 步驟七:更新控制資料表結構(若有需要) ------------------------------------------------- 新版本可能新增控制資料表,使用 IF NOT EXISTS 重新匯入不會覆蓋現有資料: sudo mariadb phpmyadmin \ < /var/www/html/phpMyAdmin/sql/create_tables.sql -------------------------------------------------- 步驟八:驗證 open_basedir 是否需要更新 -------------------------------------------------- 升級後若出現 open_basedir 錯誤,優先檢查 vendor、libraries、templates、locale 等目錄。 grep open_basedir /etc/php/8.3/fpm/pool.d/phpmyadmin.conf 若需修改,編輯後重新載入 修改 vi /etc/php/8.3/fpm/pool.d/phpmyadmin.conf 重新載入 systemctl reload php8.3-fpm 查看 Nginx 錯誤日誌確認具體被拒絕的路徑: tail -n 50 /var/log/nginx/error.log tail -n 50 /var/log/php/phpmyadmin-error.log ----------------------------------------- 步驟九:快速檢查 PHP 語法錯誤 ----------------------------------------- find /var/www/html/phpMyAdmin \ -type f -name "*.php" \ -exec php -l {} \; 2>&1 | grep -v "No syntax errors" 無任何輸出代表沒有語法錯誤(此步驟需等待幾分鐘) ------------------------------- 步驟十:清理並驗證 ------------------------------- rm /root/downloads/phpMyAdmin-新版本號-all-languages.tar.gz rm /root/downloads/phpMyAdmin-新版本號-all-languages.tar.gz.asc nginx -t systemctl reload nginx 登入 phpMyAdmin 確認版本與功能正常。 ------------------------------------------------------------ 常見問題與排查 ------------------------------------------------------------ ---------------------------------------------- Q1:登入後顯示「設定儲存空間」警告 ---------------------------------------------- 原因:控制資料庫(phpmyadmin)或控制使用者(pma_control)設定不正確。 確認控制資料庫存在 sudo mariadb -e "SHOW DATABASES LIKE 'phpmyadmin';" 確認資料表已建立 sudo mariadb -e "SHOW TABLES IN phpmyadmin;" 確認 pma_control 帳號存在且有正確權限 sudo mariadb -e "SHOW GRANTS FOR 'pma_control'@'localhost';" 確認 config.inc.php 中的 controlpass 與實際密碼一致 grep controlpass /var/www/html/phpMyAdmin/config.inc.php --------------------------------------------------- Q2:phpMyAdmin 頁面顯示 403 Forbidden --------------------------------------------------- 原因:Nginx 設定或目錄權限問題。 ls -lah /var/www/html/phpMyAdmin/index.php stat /var/www/html/phpMyAdmin/ nginx -t cat /etc/nginx/sites-enabled/default.conf tail -n 50 /var/log/nginx/error.log ----------------------------------------- Q3:頁面顯示 502 Bad Gateway ----------------------------------------- 原因:PHP-FPM 未啟動或 socket 路徑錯誤。 確認 PHP-FPM 狀態 systemctl status php8.3-fpm 確認獨立 socket 存在 ls -la /var/run/php/phpmyadmin.sock 若 socket 不存在,重啟 PHP-FPM systemctl restart php8.3-fpm 注意:本教學將 Nginx 的 fastcgi_pass 改為 unix:/var/run/php/phpmyadmin.sock(獨立 Pool), 請確認 Pool 設定中 listen 路徑與 Nginx 設定一致。 ------------------------------------------------- Q4:無法以 root 帳號登入 phpMyAdmin ------------------------------------------------- 原因(預期行為):本教學的 MariaDB root 使用 unix_socket 認證, 無法透過 TCP 連線(包含 phpMyAdmin)登入,這是正確的安全設計。 解決方式:使用 dbadmin 帳號登入 phpMyAdmin。 ---------------------------------------------------------------------------------------- Q5:dbadmin 或 pma_control 帳號無法登入 phpMyAdmin(Access denied) ---------------------------------------------------------------------------------------- 原因:config.inc.php 中的 host / connect_type 設定與帳號建立時的 Host 不一致。 設定項目:config.inc.php 中 host 正確值:'localhost' 設定項目:config.inc.php 中 connect_type 正確值:'socket' 設定項目:MariaDB 帳號建立時的 Host 正確值:@'localhost' 確認 config.inc.php 的 host 設定 grep -E "host|connect_type" /var/www/html/phpMyAdmin/config.inc.php 背景知識:在 MariaDB / MySQL 中,localhost 使用 Unix Socket 連線,127.0.0.1 使用 TCP 連線, 兩者是不同的連線方式,對應的帳號也視為不同帳號。 混用是大多數連線失敗的根本原因。本教學全程統一使用 localhost ----------------------------------- Q6:匯入大型 SQL 時逾時 ----------------------------------- 解決方式一:臨時調高 config.inc.php 中的 ExecTimeLimit $cfg['ExecTimeLimit'] = 600; // 10分鐘 調高後記得匯入完畢再改回 120 解決方式二(建議大型資料庫):使用 SSH 命令列直接匯入 mariadb -u xxxx_com -p xxxx_com < 匯入檔案.sql --------------------------------------------------- Q7:更新 phpMyAdmin 後介面顯示功能異常 --------------------------------------------------- 原因:舊版 pma__ 資料表結構可能與新版不相容。 解決方式:重新匯入 create_tables.sql sudo mariadb phpmyadmin \ < /var/www/html/phpMyAdmin/sql/create_tables.sql -------------------------------------------------------- Q8:phpMyAdmin 顯示 config.inc.php 權限警告 -------------------------------------------------------- 原因:設定檔權限過於寬鬆(例如 644 而非 640)。 chmod 640 /var/www/html/phpMyAdmin/config.inc.php chown root:www-data /var/www/html/phpMyAdmin/config.inc.php ----------------------------------------------------- Q9:瀏覽器顯示「無法連線」或「連線被拒絕」 ----------------------------------------------------- 確認 Nginx 正在監聽 888 port ss -tlnp | grep 888 確認防火牆規則允許你的IP連入 888 port nft list ruleset | grep 888 nginx -t systemctl status nginx 若 VPS 位於雲端平台,請同時確認雲端安全群組已開放你的IP存取 888 port。 ---------------------------------------------- Q10:重開機後 phpMyAdmin 無法存取 ---------------------------------------------- 原因:這不是問題,而是本教學的安全設計。為了降低攻擊面, phpMyAdmin 預設是關閉的(pma-autoclose.service 的 ExecStart 在開機時會主動確認並關閉)。 解決:SSH 使用 pma-open 指令開啟 phpMyAdmin。 提醒:本教學的設計是「不使用時保持關閉」,重開機後 phpMyAdmin 預設為 關閉狀態 是正確行為,需要時再執行 pma-open 開啟。 --------------------------------------------------------------- Q11:pma-open / pma-close 指令不存在(alias 遺失) --------------------------------------------------------------- 確認 .bash_aliases 是否存在 ls -la /root/.bash_aliases 手動載入 source /root/.bashrc 確認 alias 已生效 alias | grep pma 若 /root/.bash_aliases 不存在,請重新執行 「建立快捷 Alias 並永久生效」 的步驟。 ------------------------------------------------------------- Q12:升級後出現 open_basedir restriction in effect ------------------------------------------------------------- 原因:新版 phpMyAdmin 需要存取的路徑不在 open_basedir 允許清單中。 解決方式:編輯 /etc/php/8.3/fpm/pool.d/phpmyadmin.conf,在 open_basedir 中新增所需路徑: 編輯 vi /etc/php/8.3/fpm/pool.d/phpmyadmin.conf 修改後重新載入: systemctl reload php8.3-fpm 查看 Nginx 錯誤日誌確認具體被拒絕的路徑: tail -n 50 /var/log/nginx/error.log tail -n 50 /var/log/php/phpmyadmin-error.log -------------------------------------------------------------------------------- Q13:/var/log/php/phpmyadmin-error.log 一直沒有產生新的錯誤內容 -------------------------------------------------------------------------------- 原因:phpMyAdmin 在正常運作且沒有 PHP 錯誤時,不會在日誌中產生新內容。 日誌檔雖已預先建立(空白),但只有在 PHP 錯誤發生時才會寫入內容,這是正常行為。 若想確認 PHP-FPM 日誌設定已正確載入: php-fpm8.3 -t systemctl status php8.3-fpm grep error_log /etc/php/8.3/fpm/pool.d/phpmyadmin.conf ------------------------ 安全訂閱建議 ------------------------ 建議每月定期檢查以下公告,發現影響你版本的 CVE 時立即更新: 項目:phpMyAdmin 安全公告 連結:https://www.phpmyadmin.net/security/ 項目:Debian 安全公告 連結:https://www.debian.org/security/ 項目:MariaDB 安全公告 連結:https://mariadb.com/kb/en/security/ 項目:CVE 資料庫 連結:https://cve.mitre.org/ 並每月定期確認 phpMyAdmin 是否有新版本發布。 Edited Wednesday at 01:23 PM2 days by Jack
Create an account or sign in to comment