Skip to content
View in the app

A better way to browse. Learn more.

PHP论坛人

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

phpMyAdmin 安裝、設置與 Nginx default.conf 優化

Featured Replies

適用環境: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 by Jack

Create an account or sign in to comment

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.