跳转到帖子
在手机APP中查看

一个更好的浏览方法。了解更多

PHP论坛人

主屏幕上的全屏APP,带有推送通知、徽章等。

在iOS和iPadOS上安装此APP
  1. 在Safari中轻敲分享图标
  2. 滚动菜单并轻敲添加到主屏幕
  3. 轻敲右上角的添加按钮。
在安卓上安装此APP
  1. 轻敲浏览器右上角的三个点菜单 (⋮) 。
  2. 轻敲添加到主屏幕安装APP
  3. 轻敲安装进行确认。

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

精选回复

適用環境: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 是否有新版本發布。

本帖最后于,由Jack编辑

创建帐户或登录后发表意见

帐户

导航

搜索

搜索

配置浏览器推送通知

Chrome (安卓)
  1. 轻敲地址栏旁的锁形图标。
  2. 轻敲权限 → 通知。
  3. 调整你的偏好。
Chrome (台式电脑)
  1. 点击地址栏中的挂锁图标。
  2. 选择网站设置。
  3. 找到通知选项并调整你的偏好。