當初使用 Ondřej Surý 的 PPA套件安裝(Apache / PHP )就是為了解決惱人的資安通報,果然網站上線沒多久通報就來了,這次主要有兩項要升級(Apache要高於2.4.64 / PHP要高於8.3.23),剛好來試看看傳說中的 PPA套件升級到底有多容易,以下是升級完整步驟紀錄
先備份檔案以防萬一(後續比對用)重要
sudo mkdir -p /root/apache_backup_$(date +%Y%m%d)
sudo cp /etc/php/8.3/apache2/php.ini /root/apache_backup_$(date +%Y%m%d)/
sudo cp /etc/apache2/sites-available/default-ssl.conf /root/apache_backup_$(date +%Y%m%d)/
sudo cp /etc/apache2/mods-available/ssl.conf /root/apache_backup_$(date +%Y%m%d)/
sudo cp /etc/apache2/apache2.conf /root/apache_backup_$(date +%Y%m%d)/
sudo cp /etc/apache2/conf-available/security.conf /root/apache_backup_$(date +%Y%m%d)/
sudo cp /etc/apache2/ports.conf /root/apache_backup_$(date +%Y%m%d)/
這樣所有重要設定就會備份到 /root/apache_backup_20251020/,如果升級後有任何異常,你只要:
sudo cp /root/apache_backup_20251020/* /etc/apache2/...
sudo systemctl reload apache2
就能一鍵復原(紅字為今天日期)
1、更新套件列表: sudo apt update
2、升級 Apache:sudo apt install --only-upgrade apache2
完成以上步驟繼續後面的流程
3、檢查版本是否更新成功:
apache2 -v
如果返回 Server version: Apache/2.4.64
或更高就沒問題
4、 檢查設定合併情況(diff):(或可省略跳過)
sudo diff /root/apache_backup_20251020/default-ssl.conf /etc/apache2/sites-available/default-ssl.conf
更新後的ssl.conf會被重置,找到檔案打開
sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf (示例)
<VirtualHost *:443>
略...................
SSLCertificateChainFile /etc/letsencrypt/live/您的網站網址/chain.pem //補一個chain.pem
</VirtualHost>
5、重新啟動 Apache:sudo systemctl restart apache2
到這裡就完成Apache 升級工作,原本的設定檔像是ssl也都沒被覆蓋,真的很方便
再來升級PHP
1、更新套件清單 + 升級 PHP
sudo apt update
sudo apt install --only-upgrade php8.3 php8.3-cli php8.3-common \ libapache2-mod-php8.3 php8.3-curl php8.3-gd php8.3-mbstring php8.3-mysql \ php8.3-sqlite3 php8.3-xml php8.3-zip php8.3-intl php8.3-bcmath php8.3-imagick
sudo apt install libapache2-mod-php8.3 php8.3-sqlite3
說明:
--only-upgrade php8.3:避免裝上其他版本(例如 8.4)
一次列出常用模組,確保升級後版本一致
如果你有安裝其他 extension(例如 imagick、redis 等),記得也一併加上。
2、重新載入 Apache(或 FPM)
讓 Apache 重新載入 libapache2-mod-php8.3.so
如果你是 mod_php:
sudo systemctl restart apache2
如果是 PHP-FPM:
sudo systemctl restart php8.3-fpm
說明:讓 Apache 重新載入 libapache2-mod-php8.3.so
清空舊版本 PHP 的快取、Opcache、模組記憶體
確保整個網站從這一刻起用的都是 最新 PHP
3、驗證版本是否升級成功
輸入指令:php -v
應該會顯示:
PHP 8.3.26 (cli) (built: Sep 25 2025 ...)
只要比原先版本大就是更新成功
PHP版本升級注意事項(實戰心得)
在使用 PPA 進行 PHP 套件升級時,即使指定使用 --only-upgrade php8.3,仍有可能因套件相依關係而被強制升級至最新版本(例如 PHP 8.4)。
但可用以下方法切換回 PHP 8.3新版,處理方式如下:
先查 php8.3是否還在:
dpkg -l | grep php8.3
如果還在直接切:
sudo update-alternatives --set php /usr/bin/php8.3
接者輸入
sudo a2dismod php8.4
sudo a2enmod php8.3
sudo systemctl restart apache2
最後再輸入php -v檢查PHP版本,如無意外因該會回到PHP8.3最新版
4、重新啟動 Apache
sudo systemctl restart apache2
5、php.ini資料回填
由於升級PHP後,php.ini強制都會被初始化,為了使之前的設定能恢復套用,建立一個執行腳本自動由新舊版php.ini比對後回填設定功能
先建立腳本
sudo nano /root/compare_phpini.sh
貼入以下內容:
#!/bin/bashset -euo pipefail
python3 - <<'PY'
from pathlib import Path
import shutil
import datetime
import sys
new = Path("/etc/php/8.3/apache2/php.ini")
#這裡是比對項目來源,可依實際情況擴充
"memory_limit",
"upload_max_filesize",
"post_max_size",
"max_execution_time",
"max_input_time",
"max_input_vars",
"max_file_uploads",
"date.timezone",
"display_errors",
"log_errors",
"error_reporting",
"session.save_path",
"file_uploads",
"allow_url_fopen",
"curl.cainfo",
"upload_tmp_dir",
]
#如來源資料不一致或無數據,填入預設數值(可擴充)
FORCE_VALUES = {
"curl.cainfo": "/usr/local/share/ca-certificates/cacert.pem",
"upload_max_filesize": "2000M",
"post_max_size": "2000M",
"max_execution_time": "600",
"memory_limit": "4G",
"max_input_time": "600",
"max_file_uploads": "500",
"upload_tmp_dir": "/var/www/html/uploads/php_tmp",
}
if not old.exists():
print(f"Old php.ini not found: {old}", file=sys.stderr)
sys.exit(1)
if not new.exists():
print(f"New php.ini not found: {new}", file=sys.stderr)
sys.exit(1)
backup = new.with_suffix(".ini.before_neil_restore_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S"))
shutil.copy2(new, backup)
def read_values(path):
values = {}
for line in path.read_text(errors="ignore").splitlines():
raw = line.strip()
if not raw or raw.startswith(";"):
continue
if "=" not in raw:
continue
key = raw.split("=", 1)[0].strip()
if key in keys:
values[key] = line
return values
old_values = read_values(old)
for key, value in FORCE_VALUES.items():
old_values[key] = f"{key} = {value}"
lines = new.read_text(errors="ignore").splitlines()
done = set()
out = []
for line in lines:
raw = line.strip()
key = None
if "=" in raw:
check = raw.lstrip(";").split("=", 1)[0].strip()
if check in old_values:
key = check
if key:
if key not in done:
out.append(old_values[key])
done.add(key)
else:
out.append(line)
else:
out.append(line)
for key in keys:
if key in old_values and key not in done:
out.append("")
out.append("; Restored from old php.ini by Neil restore script")
out.append(old_values[key])
new.write_text("\n".join(out) + "\n")
print("Backup:", backup)
print("Restored keys:")
for key in keys:
if key in old_values:
print(" -", key, "=>", old_values[key])
PY
sudo chmod 755 /root/compare_phpini.sh
執行:
sudo /root/compare_phpini.sh
sudo apache2ctl configtest
sudo systemctl restart apache2
sudo systemctl status apache2
確認 Apache PHP 設定值:
php -i | grep "Loaded Configuration File"
php -i | grep -E "curl.cainfo|upload_max_filesize|post_max_size|max_execution_time|memory_limit|max_input_time|max_file_uploads|upload_tmp_dir"
注意:
最準方式是暫時放 phpinfo() 檢查 Loaded Configuration File,看完立刻刪除,避免再次被弱掃抓到 info.php / phpinfo.php。
這樣就完成(Apache / PHP )升級工作,不用半小時,非常順利,這個 Ondřej Surý 的 PPA套件真的是非常非常的讚,大推!!
以上工作心得分享,有需要的朋友可參考看看
工作心得撰寫:徐嘉裕Neil hsu
留言
張貼留言