April 14Apr 14 Debian 13 安裝 PHP 8.3 環境:Debian 13 VPS規格:2 vCPU / 2GB RAM 用途:LNMP 論壇網站 ----------------- 前置確認 ----------------- 在開始之前,請先確認以下事項,避免後續安裝失敗或設定衝突 確認OS版本 cat /etc/os-release 預期輸出應包含:PRETTY_NAME="Debian GNU/Linux 13 (trixie)" 注意:sury.org 的套件來源會依 lsb_release -sc 取得代號(trixie),若OS版本不符,後續 apt update 會出現 404 錯誤 確認目前是否已安裝其他PHP版本 dpkg -l | grep php 若已有舊版 PHP(如 PHP 7.x / 8.1 / 8.2),請評估是否先移除,避免多版本衝突 列出所有已安裝的 PHP 套件(僅查詢,不執行移除) dpkg -l | grep '^ii' | grep php 確認系統時間正確 憑證驗證與 log 時間戳均依賴系統時間,請先確認 timedatectl status ----------------------------- 加入 sury.org PHP套件來源 ----------------------------- Debian官方倉庫的PHP版本通常落後官方發佈數個月,安裝最新 PHP 8.3 需加入 sury.org 第三方來源 此來源由Debian PHP維護者 Ondřej Surý 長期維護,穩定性與安全性有保障,是Debian社群的主流選擇 更新系統並安裝必要工具 apt update -y && apt upgrade -y apt install -y wget curl vim gnupg dpkg apt-transport-https lsb-release ca-certificates 下載 GPG 金鑰 curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg 驗證 GPG 金鑰指紋 (資安關鍵,請勿略過) gpg --show-keys --with-fingerprint /usr/share/keyrings/deb.sury.org-php.gpg 預期輸出: pub rsa3072 2019-03-18 [SC] [expires: 2028-02-04] 1505 8500 A023 5D97 F5D1 0063 B188 E2B6 95BD 4743 uid DEB.SURY.ORG Automatic Signing Key <deb@sury.org> sub rsa3072 2019-03-18 [E] [expires: 2028-02-04] 安全提醒:若指紋不符,請立即停止安裝 可能代表金鑰遭竄改或下載來源異常,這是防範供應鏈攻擊的重要步驟,切勿略過 加入套件來源 echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list 確認內容是否正確 cat /etc/apt/sources.list.d/php.list 預期輸出:deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ trixie main 更新套件清單,執行升級 apt update -y && apt upgrade -y 安裝 PHP 8.3 核心與擴展 以下3行一次複製貼上 apt install -y php8.3 php8.3-cli php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd \ php8.3-mbstring php8.3-xml php8.3-zip php8.3-imap php8.3-soap php8.3-gmp \ php8.3-bcmath php8.3-redis php8.3-exif php8.3-imagick php8.3-intl 各擴展用途說明 php8.3-fpm:PHP FastCGI 處理程序 (搭配 Nginx 必要) php8.3-mysql:連接 MySQL / MariaDB 資料庫 php8.3-curl:發送 HTTP 請求 (呼叫 API 等) php8.3-gd:圖片處理 (縮圖、浮水印等基本功能) php8.3-mbstring:多位元組字串處理 (中文、日文等) php8.3-xml:XML解析與生成 php8.3-zip:壓縮與解壓縮ZIP檔 php8.3-imap:收發 Email (IMAP 協定) php8.3-soap:SOAP Web Service 支援 php8.3-gmp:大數運算 (加密相關) php8.3-bcmath:高精度數學運算 (金融計算常用) php8.3-redis:連接 Redis 快取伺服器 php8.3-exif:讀取圖片 EXIF 後設資料 (相機拍攝資訊) php8.3-imagick:進階圖片處理 (需搭配 imagemagick) php8.3-intl:國際化 (Internationalization, i18n) 擴展模組,用於處理 多語言文字、Unicode、地區格式化、排序、轉換等功能 說明: 若論壇未來有發送簡訊驗證或整合第三方支付需求,php8.3-curl 與 php8.3-soap 均屬必要,建議一併安裝 安裝 PEAR、ImageMagick 與 Redis 服務 apt install -y php-pear imagemagick redis 說明 php-pear:PHP套件管理工具,部分函式庫安裝時需要 imagemagick:系統層級的圖片處理程式,php8.3-imagick 的依賴套件 redis:Redis 伺服器本體,提供快取與Session儲存服務 重啟 systemctl restart php8.3-fpm 確認 PEAR 安裝 pear version 預期輸出 PEAR Version: 1.10.16 PHP Version: 8.3.31 Zend Engine Version: 4.3.31 Running on: Linux xxxx 6.12.86+deb13-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.86-1 (2026-05-08) x86_64 搜尋其他可用的 PHP 8.3 擴展 若未來有其他功能需求,可先查詢是否有對應套件: apt-cache search php8.3 | grep php8.3 安全強化:關閉 cgi.fix_pathinfo 防止跨目錄攻擊 / 防止路徑攻擊 cgi.fix_pathinfo cgi.fix_pathinfo 預設值為 1(啟用),在此模式下,攻擊者可藉由偽造路徑(如 /uploads/evil.jpg/nonexistent.php)讓伺服器嘗試執行惡意腳本,必須關閉 使用 sed 自動修改(推薦:快速且不易出錯) sed -i 's@^;*cgi.fix_pathinfo=.*@cgi.fix_pathinfo=0@' /etc/php/8.3/fpm/php.ini 確認修改成功,預期輸出 cgi.fix_pathinfo=0 grep cgi.fix_pathinfo /etc/php/8.3/fpm/php.ini ------------------------------- 修改 php.ini(FPM) ------------------------------- 範圍說明:本文僅修改 PHP-FPM 使用的 php.ini,路徑為 /etc/php/8.3/fpm/php.ini CLI 使用獨立設定檔 /etc/php/8.3/cli/php.ini,兩者彼此獨立,互不影響 編輯 vi /etc/php/8.3/fpm/php.ini 使用Xshell 8軟體上面的選項,編輯 -> 尋找 -> 尋找目標,將能快速找到以下這些要修改的地方 停用危險函數,修改為 (請依實際需求調整) ; IPS論壇用 disable_functions = exec, proc_open, passthru, system, chroot, chgrp, chown, shell_exec, popen, ini_alter, ini_restore, dl, readlink, symlink, popepassthru, stream_socket_server, pcntl_exec ; 執行時間與記憶體 max_execution_time = 300 max_input_time = 300 memory_limit = 512M ; 錯誤顯示,正式環境關閉,請設 display_errors = Off,避免洩漏程式碼與路徑資訊 display_errors = Off ; 開啟錯誤記錄 log_errors = On ; Production 正式環境用 error_reporting = E_ALL & ~E_DEPRECATED ; 錯誤記錄檔路徑 ; 放在 error_reporting = E_ALL & ~E_DEPRECATED 的底下 error_log = /var/log/php8.3-fpm-error.log ; 上傳與傳輸設定 ; upload_max_filesize 必須小於 post_max_size,否則上傳會靜默失敗 post_max_size = 220M upload_max_filesize = 200M max_file_uploads = 100 default_socket_timeout = 180 ; Session 安全強化 ; 論壇高度依賴 Session 管理登入狀態,以下設定可有效防範常見攻擊 ;Session 儲存位置(常被忽略) session.save_path = "/var/lib/php/sessions" ; 防止 Session Fixation 攻擊 session.use_strict_mode = 1 ; 只允許透過 HTTPS 傳送 Cookie(需已部署 HTTPS) ; 僅在 HTTPS 環境下有效;若伺服器尚未配置 SSL,請先暫時設為 0,待 HTTPS 部署完成後再改回 1 session.cookie_secure = 1 ; 僅允許使用 Cookie 保存 Session ID(防止 URL 洩漏) session.use_only_cookies = 1 ; 禁止 JavaScript 讀取 Session Cookie(防止 XSS 竊取) session.cookie_httponly = 1 ; 防止跨站請求偽造(CSRF) session.cookie_samesite = Lax ; Session 過期時間(秒),1440 = 24 分鐘 session.gc_maxlifetime = 1440 ; Session ID 長度(較長的 ID 更難被暴力猜測) session.sid_length = 48 ; Session ID 每字元的熵值位元數(6 = 使用 base64url 字元集) session.sid_bits_per_character = 6 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter 說明 upload_max_filesize 必須小於 post_max_size,否則上傳會靜默失敗 若使用 Nginx,同時需在 Nginx 設定中調整 client_max_body_size,兩者需對應 -------------------------------- Session 儲存位置 (常被忽略) -------------------------------- 確認目錄是否存在 ls -ld /var/lib/php/sessions 若目錄不存在,需手動建立 mkdir -p /var/lib/php/sessions 確認權限,預期權限應為 drwx-wx-wt(即 1733) ls -ld /var/lib/php/sessions 若權限不正確,執行 chown root:www-data /var/lib/php/sessions chmod 1733 /var/lib/php/sessions 說明:權限 1733 中的 Sticky bit 可防止不同使用者互相刪除彼此的 Session 檔案 www-data 群組需有寫入權限,PHP-FPM 才能正常建立 Session 檔案 ------------------------- 驗證並重啟 ------------------------- 檢查 php.ini 語法,預期顯示 No syntax errors detected in /etc/php/8.3/fpm/php.ini php -l /etc/php/8.3/fpm/php.ini 驗證 PHP-FPM 設定語法,預期顯示 NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful php-fpm8.3 -t 重啟 systemctl restart php8.3-fpm 確認服務狀態,預期輸出 Active: active (running) systemctl status php8.3-fpm ------------------------------- 確認擴展載入狀態 ------------------------------- 某些擴展可能在安裝過程中未被正確啟用,建議逐一確認 /bin/php8.3 -m 輸出清單中應可看到:exif、gmp、imagick、redis、intl 以及其他已安裝的擴展 若清單中缺少某個擴展,重新安裝對應套件 apt install --reinstall php8.3-擴展名稱 systemctl restart php8.3-fpm -------------------------- 設定系統預設 PHP 版本 -------------------------- 若伺服器上安裝了多個PHP版本,需明確指定預設使用的版本,避免版本衝突 查看目前已登錄的PHP版本 update-alternatives --list php 設定預設版本為PHP 8.3 update-alternatives --set php /usr/bin/php8.3 互動式選擇 (若有多個版本可供切換) update-alternatives --config php 確認目前PHP版本 php -v 預期輸出 PHP 8.3.31 (cli) 補充:update-alternatives 只影響 CLI 的 php 指令預設版本,不影響 PHP-FPM 的運作版本 PHP-FPM 的版本由安裝的 php8.3-fpm 套件本身決定,兩者彼此獨立 --------------------------- 設定開機自動啟動 --------------------------- 開機自動啟動 systemctl enable php8.3-fpm 立即重啟 systemctl restart php8.3-fpm 確認服務狀態,應顯示 Active: active (running) systemctl status php8.3-fpm ------------------------- 同步確認 Redis 服務 ------------------------- systemctl enable redis-server systemctl start redis systemctl status redis 常見疏失: 安裝 Redis 後忘記設定開機自啟動,重開機後論壇 Session 快取失效,導致用戶被強制登出 ----------------------------------- PHP-FPM Pool 效能調整 ----------------------------------- PHP-FPM 的行程池設定檔位於 /etc/php/8.3/fpm/pool.d/www.conf,可依伺服器規格調整參數 以下適合 VPS 2C/2G 優化參數 編輯 vi /etc/php/8.3/fpm/pool.d/www.conf 搜尋以下內容,並替換 ; 行程管理模式(dynamic 閒置時縮減行程,節省記憶體) pm = dynamic ; 最大子行程數 (依據記憶體調整,每行程約 128~256MB) pm.max_children = 8 ; 啟動時建立的行程數 pm.start_servers = 3 ; 最少待機行程數 (保留少量應付瞬間流量) pm.min_spare_servers = 2 ; 最多待機行程數 (避免過多閒置行程浪費記憶體) pm.max_spare_servers = 5 ; 每個子行程最多處理請求次數 (防止記憶體洩漏,超過後自動回收並重建行程) pm.max_requests = 500 ; 逾時設定。單一請求最長執行時間 (需與 php.ini 的 max_execution_time 對應) request_terminate_timeout = 300s ; 在 www.conf 末尾 加入錯誤記錄設定 ; Pool 設定檔的優先權高於 php.ini,適合多網站不同 log 路徑的情境 ; 正式環境關閉 display_errors 後,務必確保錯誤訊息被記錄 ; 自訂錯誤記錄路徑 php_flag[log_errors] = on php_value[error_log] = /var/log/php8.3-fpm-error.log 儲存檔案並離開vi編輯器 按 Esc,輸入 :wq,按 Enter --------------------------------- 建立錯誤記錄與 logrotate --------------------------------- 建立記錄檔 touch /var/log/php8.3-fpm-error.log 設定擁有者 (與 PHP-FPM 執行使用者一致) chown www-data:www-data /var/log/php8.3-fpm-error.log 設定權限 (640 = 擁有者可讀寫,群組可讀,其他人無權限) chmod 640 /var/log/php8.3-fpm-error.log 設定 logrotate (避免 log檔 過大) 以下這幾行一起貼上 cat > /etc/logrotate.d/php-fpm << 'EOF' /var/log/php8.3-fpm-error.log { daily rotate 30 compress delaycompress missingok notifempty create 640 www-data www-data sharedscripts postrotate systemctl reload php8.3-fpm > /dev/null 2>&1 || true endscript } EOF --------------------------- 測試 logrotate 設定 --------------------------- logrotate --debug /etc/logrotate.d/php-fpm 預期輸出不應有 error,若有錯誤請依訊息修正路徑或權限設定 常見疏失:logrotate 設定後從未測試,直到 log 檔長到 數GB 才發現問題。建議設定完成後立即執行一次除錯測試 ------------------------- 驗證並重新載入 ------------------------- 驗證 PHP-FPM 設定語法,預期顯示 NOTICE: configuration file /etc/php/8.3/fpm/php-fpm.conf test is successful php-fpm8.3 -t 重新載入 systemctl reload php8.3-fpm ----------------------------------------- 如何計算適合的 pm.max_children? ----------------------------------------- 執行以下指令測量單個 PHP 行程平均佔用記憶體 : ps --no-header -o rss -C php-fpm8.3 | awk '{sum+=$1} END {print sum/NR/1024" MB"}' 計算公式 pm.max_children = 可分配給 PHP-FPM 的記憶體 ÷ 單個行程平均記憶體用量 範例: 可用 RAM 約 1 GB(2 GB 扣除 Nginx、MySQL、Redis 後的餘量) 單個行程平均用量 128 MB pm.max_children = 1024 ÷ 128 = 8 提醒:2GB RAM 的VPS需同時運行 Nginx、MySQL、Redis 等服務,不要將全部記憶體分配給PHP-FPM 初始建議值為 6~10,上線後依實際流量與記憶體監控再調整 --------------------------- 監控實際記憶體用量 --------------------------- 查看所有 PHP-FPM 行程的總記憶體用量 ps --no-header -o rss -C php-fpm8.3 | awk '{sum+=$1} END {print sum/1024" MB total"}' 查看整體可用記憶體 free -h ---------------- 重開機驗證 ---------------- 重開機 reboot 確認PHP-FPM已自動啟動,應顯示 Active: active (running) systemctl status php8.3-fpm 確認Redis已自動啟動 systemctl status redis 再次確認PHP版本 php -v 確認 Session 目錄權限仍正確 ls -ld /var/lib/php/sessions 確認錯誤記錄檔存在 ls -lh /var/log/php8.3-fpm-error.log --------------- 常見問題排查 --------------- PHP-FPM 啟動失敗 查看詳細錯誤訊息 journalctl -xe | grep php 語法檢查 php-fpm8.3 -t 語法檢查輸出 FAILED 時,依錯誤訊息修正 php.ini 或 www.conf 擴展載入失敗 確認特定擴展是否載入 php8.3 -m | grep 套件名稱 確認 conf.d 目錄是否有對應 .ini 檔 ls /etc/php/8.3/fpm/conf.d/ 若 .ini 檔不存在,重新安裝對應套件 apt install --reinstall php8.3-擴展名稱 systemctl restart php8.3-fpm 記憶體不足導致 504 逾時 查看整體可用記憶體 free -h 查看 PHP-FPM 各行程記憶體用量 ps --no-header -o rss -C php-fpm8.3 | awk '{sum+=$1} END {print sum/1024" MB total"}' 處理方式:適當降低 pm.max_children,並確認 memory_limit 設定合理 Nginx 與 PHP-FPM 連線失敗(502 Bad Gateway) 確認 PHP-FPM socket 路徑 grep "^listen" /etc/php/8.3/fpm/pool.d/www.conf 預設 socket 路徑為 /run/php/php8.3-fpm.sock,Nginx 設定中的 fastcgi_pass 必須對應此路徑 fastcgi_pass unix:/run/php/php8.3-fpm.sock; 確認 socket 檔案存在 ls -lh /run/php/php8.3-fpm.sock 上傳檔案失敗(無錯誤訊息) 請同時確認以下三個設定的一致性 php.ini upload_max_filesize 200M php.ini post_max_size 220M nginx.conf client_max_body_size 220M 關鍵:upload_max_filesize 必須小於 post_max_size;client_max_body_size 必須大於或等於 post_max_size 三者任一設定過小都會導致靜默失敗 PHP 錯誤不記錄到 log 檔 確認以下條件全部成立 1. 確認 log 檔存在且權限正確 ls -lh /var/log/php8.3-fpm-error.log 2. 確認 www-data 可寫入 sudo -u www-data touch /var/log/php8.3-fpm-error.log 確認 php.ini 設定 php -i | grep -E 'log_errors|error_log|error_reporting' Edited June 3Jun 3 by Jack
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.