SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-01

Ubuntu 24.04 安裝 LAMP 架構與 PHP-FPM 教學

在 Ubuntu 24.04 部署 Apache、MariaDB 與 PHP 8.3。本指南解決常見的空白頁面與權限錯誤,並包含使用 Certbot 設定 HTTPS 的完整步驟,確保您的伺服器安全且穩定運作。

您將建置的內容

LAMP 架構是在單一 Ubuntu 24.04 伺服器上運作的四個組件:底層的 Linux、負責處理 HTTP 的 Apache、儲存資料的 MariaDB,以及執行程式碼的 PHP 8.3。完成後,您將擁有一個基於名稱的虛擬主機來服務實際的應用程式目錄、一個具備最小權限專用使用者的資料庫、透過 PHP-FPM 連接至 Apache 的 PHP,以及一個頂層的免費 Let's Encrypt 憑證。

安裝過程僅需四個 apt 指令。本指南絕大部分內容在於組件間的串接,以及初學者常犯、導致新架構出現空白頁面、將原始碼以下載方式傳送至瀏覽器,或無法存取剛安裝之資料庫的錯誤。上述每個問題都有可辨識的特徵,下方列出了每個問題及其對應的確切錯誤訊息。

先決條件與注意事項

假設您已準備好一台全新的 Ubuntu 24.04 KVM VPS,並擁有 sudo 使用者權限或 root 權限,以及一個公開的 IPv4 位址。最小化堆疊在 1 GB RAM 下即可執行;若要部署實際的資料庫應用程式,請至少配置 2 GB RAM,因為 MariaDB 的預設緩衝區加上少量的 PHP-FPM 工作程序會迅速耗盡前 1 GB 記憶體。

在執行最後的 Certbot 步驟前,必須滿足以下兩項條件,請務必先行確認。您需要一個指向該 VPS 公開 IP 的 domain name A 記錄;Let's Encrypt 會透過 HTTP 驗證該網域名稱,僅使用裸 IP 位址無法取得憑證。此外,必須確保網際網路可連線至 80 與 443 連接埠;對於許多雲端服務供應商而言,這意味著除了在伺服器內部的 ufw 設定外,還必須在控制台的網路防火牆中開啟這些連接埠。DNS 變更生效可能需要長達 1 小時,請優先設定 A 記錄,待進行後續步驟時即可生效。

Step 1 - 安裝 Apache 並確認預設頁面

sudo apt update
sudo apt install -y apache2

apt 會為您啟動並啟用該服務。請檢查狀態:

systemctl status apache2

您應會看到一行顯示 active (running) 的內容。現在,請在瀏覽器中開啟 http://YOUR_SERVER_IP/。若看到帶有「It works!」大標題的 Apache2 Ubuntu Default Page,即代表安裝成功,這證明 Apache 正在運作且無錯誤。該頁面位於 /var/www/html/index.html,並由軟體內建的預設虛擬主機 000-default.conf 提供服務。您稍後會將其停用;目前它們的存在正是您預期看到的結果。

如果頁面無法載入,但 systemctl 顯示該程序正在執行,則表示防火牆阻擋了連線。這將是下一步要處理的問題。

步驟 2 - 開放 HTTP 與 HTTPS 的防火牆規則

apache2 套件會註冊三個 ufw 應用程式設定檔。請列出它們:

sudo ufw app list

您將會看到 ApacheApache FullApache SecureApache 僅針對 port 80,Apache Secure 僅針對 443,而 Apache Full 則包含兩者;由於您稍後會加入 TLS,因此這是您需要的設定檔。

sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enable

請務必在執行 ufw enable 之前 先允許 OpenSSHufw 預設會拒絕所有傳入流量;若未先設定 SSH 規則就啟用它,防火牆會在啟動瞬間切斷您的連線。雖然您能維持當前的連線階段,但之後將無法重新連線。請使用 sudo ufw status 進行確認;您應確保 OpenSSHApache Full 及其對應的 v6 版本皆顯示為 ALLOW

步驟 3 - 安裝並強化 MariaDB

sudo apt install -y mariadb-server
systemctl status mariadb

Ubuntu 24.04 隨附 MariaDB 10.11,這是一個長期支援版本,因此無需使用外部儲存庫。在服務執行後,請進行強化:

sudo mysql_secure_installation

建議仔細閱讀提示,而非直接按 Enter。當系統詢問 current root password 時,請按 Enter,因為目前尚未設定密碼。當詢問 "Switch to unix_socket authentication?" 時,由於此套件已預設啟用該功能,選擇任何選項皆無影響,請按 n。針對 "Change the root password?",請回答 n(原因詳見下一段),接著對其餘問題回答 Y:移除匿名使用者、禁止遠端 root 登入、刪除測試資料庫並重新載入權限資料表。

這是最容易讓人困惑的部分。在 Ubuntu 的 MariaDB 中,root 資料庫帳號使用 unix_socket 驗證,而非密碼。這代表資料庫會信任您已通過驗證的「作業系統使用者」。因此,從 root shell 執行以下指令即可運作:

sudo mysql

...系統會將您帶入 MariaDB [(none)]> 提示字元,且不會要求輸入密碼。若以無權限的使用者執行相同指令則會被拒絕,這正是其核心目的:資料庫 root 的存取權限與主機上的 sudo 綁定,且沒有密碼可供竊取、釣魚或暴力破解。這種方式比密碼更安全,請勿更動。由此衍生的規則為:絕對不要將應用程式指向 root 帳號。請為每個應用程式建立專屬使用者(步驟 7),因為透過 TCP 連線且使用帳號密碼的應用程式無法使用 socket 驗證,且您應將每個應用程式限制在其專屬的資料庫中。

步驟 4 - 安裝 PHP 8.3 與 PHP-FPM

Ubuntu 24.04 預設的 PHP 版本為 8.3。請安裝 FPM 進程管理器以及典型應用程式所需的擴充功能:

sudo apt install -y php8.3-fpm php8.3-mysql php8.3-cli \
  php8.3-curl php8.3-xml php8.3-mbstring php8.3-zip

請注意清單中未包含的項目:libapache2-mod-php。該舊版套件會將 PHP 直譯器嵌入每個 Apache 進程中。雖然配置簡單,但每個工作進程(worker)無論是處理腳本還是靜態圖片,都會攜帶一份 PHP 副本,且兩者共用生命週期;此外,它僅能與 Apache 效率最低的 prefork MPM 搭配使用。相對地,PHP-FPM 將 PHP 作為獨立的進程池執行,Apache 透過 Socket 與其通訊。如此一來,Apache 可使用多執行緒的 event MPM 處理靜態檔案,僅將 PHP 請求轉發給 FPM;進程池可獨立於網頁伺服器進行調校,且未來若改用 nginx 作為前端,這套 FPM 設定依然適用。這是目前作為預設方案的合理原因。

Apache 透過 proxy_fcgi 模組連接 FPM。請啟用該模組、啟用 FPM 套件提供的設定檔,並重新啟動服務:

sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2

a2enconf php8.3-fpm 會啟用 /etc/apache2/conf-available/php8.3-fpm.conf,其中包含將 PHP 檔案路由至 FPM Socket 的規則。其核心邏輯是比對所有 .php 檔案,並將其轉發至 /run/php/php8.3-fpm.sock 的 Socket:

<FilesMatch ".+\.ph(ar|p|tml)$">
    SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>

您無需編輯該檔案,其預設設定即為正確。但了解 Socket 路徑有助於診斷後續發生的「PHP 顯示為下載而非執行」以及「Primary script unknown」錯誤;這兩類問題通常皆源於 Apache 與 FPM 對此 Socket 或其後端檔案的設定不一致。

步驟 5 - 為您的應用程式設定名稱式虛擬主機

名稱式虛擬主機允許單一 IP 位址服務多個網站;Apache 會根據請求中的 Host: 標頭來選擇網站。請在遠離預設 /var/www/html 的位置為應用程式建立目錄:

sudo mkdir -p /var/www/testapp
sudo chown -R www-data:www-data /var/www/testapp
sudo chmod -R 755 /var/www/testapp

擁有權至關重要。在 Ubuntu 上,Apache 與 PHP-FPM 皆以 www-data 使用者身分執行,因此網頁伺服器必須讀取的檔案,以及應用程式必須寫入的目錄(例如上傳資料夾),其擁有者應設為 www-data。若您同時會以登入使用者身分編輯檔案,常見的做法是將檔案擁有權設為您自己,並將您的使用者加入 www-data 群組;若僅是單純部署,使用 www-data:www-data 是最不容易出錯的方式。

/etc/apache2/sites-available/testapp.conf 建立虛擬主機:

<VirtualHost *:80>
    ServerName app.example.com
    DocumentRoot /var/www/testapp

    <Directory /var/www/testapp>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/testapp-error.log
    CustomLog ${APACHE_LOG_DIR}/testapp-access.log combined
</VirtualHost>

ServerName 設定為您的真實網域。Options -Indexes 可防止 Apache 在沒有索引檔案時列出目錄內容,否則訪客將能瀏覽您的原始碼樹狀結構。AllowOverride All 可讓 .htaccess 檔案生效,大多數 PHP 應用程式皆依賴此功能來實現美觀的 URL;若您的應用程式不需要此功能,可將其設為 None 以獲得些微效能提升。啟用此網站、停用預設網站、檢查設定檔並重新載入:

sudo a2ensite testapp
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2

apache2ctl configtest 應顯示 Syntax OKa2dissite 000-default 這一行是人們最容易遺忘的部分,這也是為何預設頁面稍後會看起來像是卡住的原因,相關說明請參閱故障排除章節。

步驟 6 - 驗證 PHP 執行狀況並刪除測試檔案

在應用程式根目錄中建立一個單行的 PHP 檔案:

echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.php

瀏覽 http://app.example.com/info.php。若設定正確,您將會看到一個長條狀的紫色與灰色 PHP Version 8.3.x 表格,其中列出了已載入的模組,且 Server API 這一行應顯示 FPM/FastCGI。最後這一行確認了請求是透過 PHP-FPM 處理,而非 mod_php。

現在請立即刪除該檔案:

sudo rm /var/www/testapp/info.php

phpinfo() 會暴露您精確的 PHP 版本、所有已載入的擴充功能、檔案路徑以及環境詳細資訊,這對任何試圖探測伺服器是否存在已知漏洞的人來說是極大的便利。這僅是測試工具,而非功能。確認頁面後請務必立即刪除。若瀏覽器未顯示表格而是提示您 下載 info.php,代表 PHP 未正確連結至 Apache;請在進行任何其他操作前,先跳轉至故障排除章節。

步驟 7 - 建立應用程式資料庫與最小權限使用者

以 socket 驗證的 root 身分開啟資料庫:

sudo mysql

接著建立一個資料庫,並建立僅限於該資料庫的使用者:

CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

此處有三個刻意的選擇。utf8mb4 是真正的四位元組 UTF-8,舊有的 utf8 別名會無聲地截斷表情符號與部分 CJK 字元,因此請務必使用 utf8mb4。權限授予範圍為 appdb.*,而非 *.*:此使用者僅能存取其專屬資料庫,無法存取其他內容,因此即便應用程式出現 SQL 注入漏洞,也無法讀取其他網站的資料表。此外,'appuser'@'localhost' 將該帳號限制為僅能從本機發起的連線。

以該使用者身分進行測試:

mysql -u appuser -p appdb

系統會要求輸入密碼,並將您帶入 MariaDB [appdb]> 提示字元。請注意,此處沒有使用 -h 旗標;省略該旗標時,用戶端會透過本機 Unix socket 進行連線,這正是 MariaDB 所認定的 localhost。有一個值得注意的陷阱:對於 MySQL 與 MariaDB 而言,localhost 代表 Unix socket,而 127.0.0.1 代表 TCP 連線。 在標準的 Ubuntu 24.04 MariaDB 上,伺服器仍會將來自 127.0.0.1 的 TCP 連線解析回 localhost,因此兩者皆符合該帳號設定。但在啟用 skip-name-resolve 的伺服器上(這是一種常見的效能調整,也是許多容器映像檔的預設值),兩者會被視為不同的主機,若應用程式連線至 127.0.0.1,即使密碼正確也會被拒絕並顯示 ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' (using password: YES)

因此,請將您的應用程式指向主機 localhost、使用者 appuser、資料庫 appdb,切勿指向 root。當主機為字串 localhost 時,PHP 的 mysqli 與 PDO 皆會切換至 Unix socket,這與您剛建立的帳號相符。若框架強制要求使用數值 TCP 主機,請依照其實際連線方式建立使用者(例如 'appuser'@'127.0.0.1'),或僅在必須從其他機器存取資料庫時,才使用 @'%'(並搭配防火牆規則)。

步驟 8 - 使用 Certbot 加入 HTTPS

透過純 HTTP 傳輸登入表單會以明文發送密碼,且所有現代瀏覽器都會將該頁面標記為「不安全」。Certbot 可透過單一指令解決此問題。請使用 Apache 外掛程式進行安裝:

sudo apt install -y certbot python3-certbot-apache
sudo certbot --apache

Certbot 在此處使用兩個外掛程式。apache authenticator 會透過您正在執行的 Apache 短暫提供驗證檔案,以證明您擁有該網域的控制權;接著 apache installer 會重寫您的虛擬主機設定以加入 443 區塊,將其指向新的憑證,並預設將所有 HTTP 流量重新導向至 HTTPS。自 Certbot 2.0 起,系統不再詢問是否重新導向;若您需要繼續提供純 HTTP 服務,請傳入 --no-redirect。由於您已在步驟 5 設定了真實的 ServerName,Certbot 會自動偵測網域。憑證有效期為 90 天,安裝套件時會一併安裝一個 systemd 計時器以自動更新憑證;請使用 sudo certbot renew --dry-run 驗證該計時器,其輸出應以 Congratulations, all simulated renewals succeeded 結尾。

關於驗證流程、更新計時器以及 DNS 與防火牆需求的完整說明,請參閱隨附指南:在 Apache 上使用 Certbot 簽發免費 Let's Encrypt TLS 憑證

備份、升級與強化

備份兩項保存狀態的內容:資料庫與網頁根目錄。每日執行一次邏輯傾印(logical dump)是最簡單且可靠的方法,sudo sh -c 'mysqldump --all-databases --single-transaction | gzip > /root/db-$(date +%F).sql.gz',隨後將其複製到伺服器外部。將整個流程封裝在 sudo sh -c 中至關重要:若無此步驟,shell 會以您的使用者身分執行 > /root/... 重新導向,並因 Permission denied 而失敗,因為只有 mysqldump 繼承了 sudo--single-transaction 可在不鎖定資料表的情況下,取得 InnoDB 資料表的一致性快照。搭配 /var/www/etc/apache2/sites-availabletar,您即可利用這些檔案在全新的 VPS 上重建整個堆疊。

升級屬於常規的 sudo apt update && sudo apt upgrade 作業。最容易造成問題的是 PHP 版本升級,當未來的 Ubuntu 將預設值改為 PHP 8.4 時,apt 可能會同時安裝 php8.4-fpm 與 8.3 版本,導致 socket 變更為 /run/php/php8.4-fpm.sock,而您的 Apache 設定檔仍指向 8.3 的 socket。請啟用新的設定檔(sudo a2enconf php8.4-fpm)並停用舊的設定檔,否則您的網站會在常規升級後回傳 Primary script unknown 錯誤。由於 PHP 的發布速度快於 LTS 發行版,請查閱當前的 PHP 發行說明,而非鎖定特定的修補程式版本。

有兩項強化步驟建議在第一天就執行。首先,在伺服器上安裝 監控 SSH 的 Fail2Ban,公開的 VPS 在幾分鐘內就會遭到自動化登入嘗試,透過小型監獄(jail)機制,可將數千次嘗試縮減為幾次後即封鎖來源。其次,若您偏好透過瀏覽器管理 Apache 虛擬主機、MariaDB 資料庫與使用者,而非手動編輯檔案,Webmin 網頁控制面板 可架設在您剛建立的堆疊之上,並直接操作相同的設定檔。這兩者都無法取代對各組件的理解,但能減少日常維運的阻力。

失敗模式與對應訊息

預設頁面無法移除。 您已編輯虛擬主機並重新載入,但瀏覽器仍顯示 "Apache2 Ubuntu Default Page" 與其 "It works!" 橫幅。Apache 會提供第一個符合的虛擬主機,當沒有 ServerName 符合請求時,字母順序最前面的設定檔會勝出,000-default.conf 的排序優先於 testapp.conf。這可能是因為請求的主機名稱與您的 ServerName 不符,或是您未執行 sudo a2dissite 000-default。請停用預設設定 sudo systemctl reload apache2,並使用 apache2ctl -S 確認,該指令會列出虛擬主機對應表,顯示哪個設定檔擁有預設權限。同時請清除瀏覽器快取;舊頁面的快取 200 回應會持續存在。

.php 檔案被下載而非執行。 您開啟 info.php 時,瀏覽器下載了包含原始 <?php 程式碼的檔案,或將其顯示為純文字,而非執行它。這是因為 PHP 處理器未掛載,導致 Apache 將該檔案視為靜態資源處理;您可能跳過了 sudo a2enmod proxy_fcgisudo a2enconf php8.3-fpm,或者之後未重新啟動 Apache。請執行這三個步驟(步驟 4)並重新載入。使用 apache2ctl -M | grep fcgi 確認模組已載入,該指令應列出 proxy_fcgi_module。這屬於原始碼外洩,而非單純的顯示錯誤,請務必在伺服器部署實際內容前修復。

ERROR 1698 (28000): Access denied for user 'root'@'localhost' 您在沒有 sudo 的情況下執行了 mysql -u rootmariadb -u root。root 帳號使用 unix_socket 驗證,因此僅在您的作業系統使用者確實為 root 時才接受連線。解決方法是使用 sudo mysql,不需 -u root,也不需密碼。此訊息是 socket 驗證正常運作的預期行為,並非安裝損毀。

應用程式出現 ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1',但密碼正確。 該帳號以 'appuser'@'localhost' 存在,但您的應用程式正透過 TCP 連線至 127.0.0.1,且伺服器已停用主機名稱解析(skip-name-resolve),導致 MariaDB 將兩者視為不同主機:localhost 為 Unix socket,127.0.0.1 為 TCP。請將應用程式指向 localhost 以使用 socket 並符合帳號設定,若框架僅支援 TCP,則建立第二個帳號 'appuser'@'127.0.0.1'

/var/log/apache2/testapp-error.log 中出現 AH01071: Got error 'Primary script unknown',且瀏覽器顯示 File not found. Apache 已將請求轉交給 PHP-FPM,但 FPM 無法在 Apache 指定的路徑中找到該指令碼。常見原因有二:設定檔中的 FPM socket 指向了未安裝的 PHP 版本(例如升級後仍指向 php8.4 socket,但系統僅執行 8.3),或是因為 DocumentRoot 與實際目錄不符導致檔案確實不存在。請使用 ls -l /run/php/ 檢查 socket 是否存在,確認 DocumentRoot 與檔案實際位置相符,並重新啟動 php8.3-fpmapache2

每次重新啟動時出現 AH00558: apache2: Could not reliably determine the server's fully qualified domain name 這是無害的警告而非錯誤,Apache 提示您未設定全域 ServerName。若要消除此訊息,請將 ServerName your.domain 寫入 /etc/apache2/conf-available/servername.conf 並執行 sudo a2enconf servername

Apache 啟動時出現 (98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80 其他網頁伺服器已佔用 80 連接埠,通常是先前測試遺留的 nginx。請使用 sudo ss -ltnp | grep :80 找出該程序,並在啟動 Apache 前停止並停用該服務。

FAQ

mod_php 與 PHP-FPM - 我該使用哪一個?

請使用 PHP-FPM。mod_php 會將直譯器嵌入每個 Apache 程序中,並強制使用效能較差的 prefork MPM,導致 Apache 在處理靜態圖片時仍需承擔 PHP 的額外開銷。PHP-FPM 將 PHP 作為獨立且可單獨調整的程序池執行,Apache 透過 socket 與其通訊,並可搭配效能更佳的執行緒化 event MPM 使用,未來若需遷移至 nginx 也無需修改程式碼。這是現代的預設配置;mod_php 僅適用於依賴特定程序內行為的舊有應用程式。

為什麼瀏覽器下載了 PHP 檔案而不是執行它?

Apache 將 .php 檔案視為靜態下載,因為沒有為其掛載 PHP 處理器。在 Ubuntu 24.04 搭配 FPM 的環境中,這代表您遺漏了 sudo a2enmod proxy_fcgisudo a2enconf php8.3-fpm 或後續的 Apache 重啟步驟。請執行這三項指令並重新載入,接著使用 apache2ctl -M | grep fcgi 確認 proxy_fcgi_module 已被列出。在修復此問題前,伺服器會洩漏原始碼,請將其視為緊急事項處理。

為什麼即使密碼正確,MariaDB 仍拒絕 root 存取?

因為沒有設定密碼,Ubuntu 的 MariaDB 預設透過 unix_socket 驗證 root 帳號,將其與作業系統的 root 使用者綁定。從一般 shell 執行 mysql -u root 會依設計回傳 ERROR 1698 (28000): Access denied for user 'root'@'localhost'。請改用 sudo mysql 連線,並為應用程式建立獨立的密碼驗證使用者,而非重複使用 root。

如何為我的 LAMP 網站加入 HTTPS?

安裝 certbotpython3-certbot-apache,將網域的 A 紀錄指向伺服器,然後執行 sudo certbot --apache。Apache 驗證器會透過您運作中的 Apache 驗證網域控制權,安裝程式會重寫 port 443 的虛擬主機設定並建立自動續約機制。完整的 Certbot 與 Apache 設定教學 涵蓋了驗證挑戰、續約計時器以及常見的失敗模式。

#lamp#apache#mariadb#php-fpm#ubuntu