[教學][Ubuntu 架站] 在 Ubuntu 22.04 上安裝 Linux、Nginx、MySQL、PHP(LEMP stack)

前言

LEMP 軟體堆疊是一組軟體,可以用來提供使用 PHP 編寫的動態網頁和網頁應用程式。這是一個縮寫,描述了一個包含 Linux 作業系統的系統,搭配著一個 Nginx(發音類似 “Engine-X”)網頁伺服器。後端數據儲存在 MySQL 資料庫中,而動態處理則由 PHP 處理。

這份指南示範了如何在 Ubuntu 22.04 伺服器上安裝 LEMP 堆疊。Ubuntu 作業系統負責整個堆疊中的 Linux 部分。我們將描述如何使其餘的元件運作起來。


預先準備

在開始操作此篇文章前,需要先準備好 Ubuntu 22.04 的主機,如果尚未準備好,可以參考此篇文章([教學][Ubuntu 架站] 如何在 Google Cloud Platform 架設 Ubuntu 22.04 伺服器)


1. 安裝 Nginx 網頁伺服器

1-1. 安裝 Nginx

因為 Nginx 在 Ubuntu 預設的軟體庫有提供,所以我們可以透過 apt 套件管理系統從這些軟體庫中安裝它。

既然這是我們在這次對話中第一次使用 apt 套件管理系統,我們要先更新一下我們本地的套件清單,這樣就能取得最新的套件資訊。然後,我們就可以開始安裝 nginx 了:

$ sudo apt update && sudo apt install nginx

當系統詢問你是否確認要安裝時,按下「Y」。如果系統詢問是否要重新啟動任何服務,直接按下「ENTER」接受預設設定並繼續。apt 會將 Nginx 及其所需的相依套件安裝到你的伺服器上。

1-2. 設置防火牆(Configure Firewall)

在測試 Nginx 之前,需要設定防火牆軟體,以允許訪問該服務。Nginx 在安裝時會在 ufw 中註冊自己作為一個服務,因此很容易允許 Nginx 訪問。

輸入以下指令列出 ufw 知道如何處理的應用程式配置:

$ sudo ufw app list


你應該會看到一個應用程式配置的清單:

Output
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

如輸出所示,Nginx 有三個可用的配置檔案:

  • Nginx Full:這個配置開啟了 80 號埠口(普通、未加密的網頁流量)和 443 號埠口(TLS/SSL 加密流量)
  • Nginx HTTP:這個配置僅開啟 80 號埠口(普通、未加密的網頁流量)
  • Nginx HTTPS:這個配置僅開啟 443 號埠口(TLS/SSL 加密流量)

建議你啟用最限制的配置,只要還能允許你所設定的流量。目前,我們只需要允許 80 號埠口上的流量。

我們將從為 SSH 添加防火牆規則開始,因為如果您遠程配置伺服器,您肯定不希望在啟用防火牆時被鎖定在外!

$ sudo ufw allow OpenSSH

你可以透過輸入以下指令來啟用 Nginx HTTP:

$ sudo ufw allow 'Nginx HTTP'

現在啟用防火牆

$ sudo ufw enable

如果看到「Command may disrupt existing ssh connections. Proceed with operation (y|n)?」,請按 y。

你可以透過輸入以下指令來驗證變更:

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP (v6)            ALLOW       Anywhere (v6)             
OpenSSH (v6)               ALLOW       Anywhere (v6)  

1-3. 測試 Nginx

在安裝過程結束時,Ubuntu 22.04 會啟動 Nginx。網頁伺服器應該已經運行起來了。

我們可以使用 systemd 啟動系統來檢查服務是否正在運行,只需輸入以下指令:

$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-09-05 06:24:14 UTC; 5min ago
       Docs: man:nginx(8)
    Process: 2793 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/S>
    Process: 2794 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 2888 (nginx)
      Tasks: 3 (limit: 4675)
     Memory: 5.3M
        CPU: 49ms
     CGroup: /system.slice/nginx.service
             ├─2888 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─2891 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
             └─2892 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >

Sep 05 06:24:14 ubuntu-22-ngunx systemd[1]: Starting A high performance web server and a reverse proxy server.>
Sep 05 06:24:14 ubuntu-22-ngunx systemd[1]: Started A high performance web server and a reverse proxy server.

從這個輸出可以確認服務已經成功啟動了。不過,最好的方式是實際從 Nginx 要求一個網頁。

你可以通過訪問預設的 Nginx 登陸頁面,來確認軟體運行正常。只需前往你伺服器的 IP 地址。如果你不知道伺服器的 IP 地址,你可以使用 icanhazip.com 工具來查找,它會給你從互聯網的其他位置接收到的公共 IP 地址:

$ curl -4 icanhazip.com

當你取得了伺服器的 IP 地址,就將它輸入到你瀏覽器的地址欄中:

http://your_server_ip

你應該會看到預設的 Nginx 登陸頁面:

如果你看到這個頁面,代表你的伺服器運行正常,已經可以開始進行管理了。


2. 安裝 MySQL

既然你已經讓一個網頁伺服器運行起來了,你需要安裝資料庫系統來儲存和管理你的網站數據。MySQL 是一個在 PHP 環境中常用的資料庫管理系統。

同樣地,使用 apt 來獲取並安裝這個軟體:

$ sudo apt install mysql-server

在提示時,按下 Y 鍵確認安裝,然後按下 ENTER。

當安裝完成後,建議你運行一個預先安裝在 MySQL 中的安全性腳本。這個腳本將移除一些不安全的預設設定,並加固對資料庫系統的訪問。啟動互動式腳本,請執行以下指令:

$ sudo mysql_secure_installation

你將會收到一個詢問,問你是否想要配置 VALIDATE PASSWORD PLUGIN。

回答 Y 表示是,或者輸入其他內容繼續而不啟用:

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No:

如果你回答「是」,你將會被要求選擇一個密碼驗證的等級。請記住,如果你選擇最強的等級 2,那麼在設定任何不包含數字、大寫和小寫字母以及特殊字符的密碼時,你將會收到錯誤訊息:

here are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 

無論你是否選擇設定 VALIDATE PASSWORD PLUGIN,你的伺服器都會要求你為 MySQL root 使用者選擇並確認密碼。請不要將其與系統 root 混淆。資料庫 root 使用者是一個擁有對資料庫系統完全權限的管理使用者。即使 MySQL root 使用者的預設認證方法不需要使用密碼,但即使設定了密碼,你仍應在這裡設定一個強密碼,作為額外的安全措施。我們一會兒會再談到這個。

如果你啟用了密碼驗證,你將會看到你輸入的 root 密碼的強度,並且伺服器會問你是否要繼續使用該密碼。如果你對目前的密碼滿意,請在提示中按下 Y 表示「是」:

stimated strength of the password: 100 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y

對於其餘的問題,每次在提示中按下 Y 鍵,然後按下 ENTER 鍵。這將會移除一些匿名使用者和測試資料庫,停用遠端 root 登入,並載入這些新的規則,讓 MySQL 立即遵循你所做的更改。

完成後,測試是否能夠登入 MySQL 控制台:

$ sudo mysql

這將會以管理資料庫使用者 root 身分連接到 MySQL 伺服器,這是透過執行此指令時使用 sudo 推斷的。你應該會收到以下輸出:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.34-0ubuntu0.22.04.1 (Ubuntu)

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

要退出 MySQL 控制台,輸入以下內容:

mysql> exit


注意,即使在執行 mysql_secure_installation 指令時已經設定了密碼,你在連接時並不需要提供 root 使用者的密碼。這是因為,在 Ubuntu 上安裝時,管理 MySQL 使用者的預設認證方法是 auth_socket,而不是使用密碼的方法。起初可能會感覺這是一個安全問題,但實際上這使得資料庫伺服器更安全,因為唯一被允許以 root MySQL 使用者登入的使用者是從終端機或具有相同特權的應用程式連接的系統使用者,具有 sudo 特權。實際上,這意味著你無法使用管理資料庫 root 使用者來從你的 PHP 應用程式進行連接。

為了增加安全性,最好為每個資料庫設定專用的使用者帳戶,並限制其特權,特別是如果你計劃在伺服器上托管多個資料庫的話。

你的 MySQL 伺服器現在已經安裝並進行了安全設置。接下來,你將安裝 PHP,這是 LEMP 堆疊的最後一個組件。


3. 安裝 PHP

你已經安裝了 Nginx 來提供內容,並安裝了 MySQL 來儲存和管理資料。現在你可以安裝 PHP 來處理程式碼,並為網頁伺服器生成動態內容。

儘管 Apache 在每個請求中嵌入了 PHP 解譯器,但 Nginx 需要一個外部程式來處理 PHP 處理並充當 PHP 解譯器本身和網頁伺服器之間的橋樑。這在大多數基於 PHP 的網站中能夠獲得更好的整體性能,但它需要額外的配置。你需要安裝 php8.1-fpm,這代表「PHP fastCGI process manager」,並使用目前的 PHP 版本(在撰寫本答案時)。這可以告訴 Nginx 將 PHP 請求傳遞給這個軟體進行處理。此外,你還需要 php-mysql,這是一個 PHP 模組,使 PHP 能夠與基於 MySQL 的資料庫進行通訊。核心的 PHP 套件將自動作為相依性安裝。

要安裝 php8.1-fpm 和 php-mysql 套件,執行以下指令:

 $ sudo apt install php8.1-fpm php-mysql

在提示時,按下 Y 鍵和 ENTER 鍵確認安裝。

現在你已經安裝好了 PHP 的相關組件。接下來,你將配置 Nginx 來使用它們。


4. 設定 Nginx 使用 PHP 處理器

在使用 Nginx 網頁伺服器時,我們可以創建伺服器區塊(類似於 Apache 的虛擬主機),來封裝設定詳情並在單個伺服器上托管多個域名。在本指南中,我們將使用 test3.ui-code.com 作為示範域名。

在 Ubuntu 22.04 上,Nginx 預設已啟用一個伺服器區塊,並且設定為從位於 /var/www/html 的目錄提供文件。雖然這對於單個站點來說很適用,但如果你要托管多個站點,管理起來可能會變得困難。我們將不修改 /var/www/html,而是在 /var/www 中為 test3.ui-code.com 網站創建一個目錄結構,同時保留 /var/www/html 作為預設目錄,以便在客戶端請求不符合其他站點時提供服務。

請按照以下方式創建 test3.ui-code.com 的目錄,使用 -p 標誌創建任何必要的上層目錄:

$ sudo mkdir -p /var/www/test3.ui-code.com/html

接下來,使用 $USER 環境變數來設定目錄的所有權:

$ sudo chown -R $USER:$USER /var/www/test3.ui-code.com/html

如果你沒有修改 umask 值(用於設定預設檔案權限),你的網站根目錄的權限應該是正確的。為確保權限正確,讓擁有者具有讀、寫和執行檔案的權限,同時僅允許群組和其他人擁有讀和執行權限,你可以輸入以下指令:

$ sudo chmod -R 755 /var/www/test3.ui-code.com

接下來,使用 nano 或你喜歡的編輯器來創建一個示範的 index.html 頁面:

$ sudo nano /var/www/test3.ui-code.com/html/index.html

在裡面,加入以下示範的 HTML 內容:

<html>
   <head>
     <title>Welcome to test3.ui-code.com</title>
   </head>
   <body>
      <h1>Welcome to test3.ui-code.com</h2>
   </body>
</html>

按下 Ctrl+X 離開並儲存檔案,然後當系統詢問是否要儲存時,按 Y,接著按 Enter。

為了讓 Nginx 提供這個內容,我們需要建立一個包含正確指令的伺服器區塊。我們不直接修改預設的配置檔案,而是在 /etc/nginx/sites-available/ 目錄下創建一個新的配置檔案,命名為 test3.ui-code.com

$ sudo nano /etc/nginx/sites-available/test3.ui-code.com


將以下的配置區塊貼入,這個配置和預設的類似,但已經根據我們的新目錄和域名進行了更新:

server {
    listen 80;
    server_name test3.ui-code.com www.test3.ui-code.com;
    root /var/www/test3.ui-code.com/html;

    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
     }

    location ~ /\.ht {
        deny all;
    }

}

請注意,我們已將根目錄的配置更新為新的目錄,並將 server_name 更新為我們的域名。

以下是這些指示和位置區塊的功能:

  • listen:定義 Nginx 監聽的埠號。在這個情況下,它會監聽 80 埠,這是 HTTP 的預設埠號。
  • root:定義此網站所提供檔案的文件根目錄。
  • index:定義 Nginx 為此網站優先選擇的索引檔案順序。通常的做法是將 index.html 檔案列在 index.php 檔案之前,以便在 PHP 應用程式中快速設置維護導引頁面。你可以調整這些設定以更好地適應你的應用程式需求。
  • server_name:定義此伺服器區塊應該回應的域名和/或 IP 地址。將此指示指向你的伺服器域名或公共 IP 地址。
  • location /:第一個位置區塊包含 try_files 指示,它會檢查是否存在與 URL 請求匹配的檔案或目錄。如果 Nginx 找不到適當的資源,將返回 404 錯誤。
  • location ~ .php$:此位置區塊通過將 Nginx 指向 fastcgi-php.conf 設定檔和 php8.1-fpm.sock 檔案,處理實際的 PHP 處理過程,後者宣告了與 php8.1-fpm 相關的插座。
  • location ~ /.ht:最後一個位置區塊處理 .htaccess 檔案,Nginx 不處理這些檔案。通過添加 deny all 指示,如果任何 .htaccess 檔案意外進入文件根目錄,它們將不會提供給訪客。

接下來,讓我們透過在 sites-enabled 目錄中創建一個連結,來啟用這個檔案,Nginx 在啟動時會從這個目錄讀取配置:

$ sudo ln -s /etc/nginx/sites-available/test3.ui-code.com /etc/nginx/sites-enabled/

然後,取消默認配置文件與 /sites-enabled/ 目錄的鏈接:

$ sudo unlink /etc/nginx/sites-enabled/default

現在已經啟用並配置了兩個伺服器區塊,根據它們的 listen 和 server_name 指令來回應請求(你可以在這裡閱讀更多有關 Nginx 如何處理這些指令的信息):

  • test3.ui-code.com:會回應 test3.ui-code.com 和 www.test3.ui-code.com 的請求。
  • default:會回應在 80 號埠口上不符合其他兩個區塊的任何請求。

為了避免可能由於添加額外的伺服器名稱而引起的哈希桶記憶體問題,我們需要在 /etc/nginx/nginx.conf 檔案中調整一個值。打開這個檔案:

$ sudo nano /etc/nginx/nginx.conf

找到 server_names_hash_bucket_size 指令,移除 # 符號以解除註解。如果你使用的是 nano 編輯器,你可以按下 Ctrl 和 w 鍵快速在檔案中搜尋詞語。

完成後,記得儲存並關閉檔案。

接下來,測試確保你的 Nginx 檔案中沒有語法錯誤:

$ sudo nginx -t

如果沒有出現任何問題,重新啟動 Nginx 以使你的變更生效:

$ sudo systemctl restart nginx

Nginx 現在應該正在提供你的域名。你可以通過前往 http://your_domain 來測試,你應該會看到類似這樣的內容:

你可以暫時將此檔案保留在原位,作為你的應用程式的臨時導引頁面,直到你建立一個 index.php 檔案來取代它。一旦你這麼做了,記得從你的文件根目錄中刪除或重新命名 index.html 檔案,因為它預設會優先於 index.php 檔案。

你的 LEMP 堆疊現在已經完全配置好了。在下一步中,你將創建一個 PHP 腳本,以測試 Nginx 是否能夠在新配置的網站內處理 .php 檔案。


5. 測試在 Nginx 中使用 PHP

你的 LEMP 堆疊現在應該已經完全設定好了。你可以進行測試,以驗證 Nginx 是否能夠正確地將 .php 檔案交給 PHP 處理器。

你可以通過在你的文件根目錄中創建一個測試的 PHP 檔案來進行測試。在你喜歡的文本編輯器中打開一個名為 info.php 的新檔案,放在你的文件根目錄中:

$ sudo nano /var/www/test3.ui-code.com/html/info.php

在新的檔案中添加以下幾行。這是有效的 PHP 程式碼,將返回有關你的伺服器的信息:

// in info.php
<?php
phpinfo();

完成後,請儲存並關閉這個檔案。

你現在可以通過在瀏覽器中輸入你在 Nginx 配置檔案中設置的域名或公共 IP 地址,後面加上 /info.php 來訪問這個頁面:

http://server_domain_or_IP/info.php

範例
http://test3.ui-code.com/info.php
http://35.229.234.157/info.php

在通過該頁面檢查你的 PHP 伺服器的相關信息後,最好刪除你創建的檔案,因為它包含有關你的 PHP 環境和 Ubuntu 伺服器的敏感信息。你可以使用 rm 命令來刪除該檔案:

$ sudo rm /var/www/test3.ui-code.com/html/info.php

6. 從 PHP 測試資料庫連線

如果你想要測試 PHP 是否能夠連線到 MySQL 並執行資料庫查詢,你可以創建一個帶有虛擬數據的測試表,然後從一個 PHP 腳本中查詢其內容。在這之前,你需要創建一個測試資料庫,以及一個新的 MySQL 使用者,正確地配置以訪問它。

我們將創建一個名為 example_database 的資料庫,以及一個名為 example_user 的使用者,但你可以用不同的值來取代這些名稱。

首先,使用 root 帳號連接到 MySQL 控制台:

$ sudo mysql

要創建一個新的資料庫,在你的 MySQL 控制台中執行以下指令:

mysql> CREATE DATABASE example_database;

現在你可以創建一個新的使用者,並給予他們對你所創建的自訂資料庫的完整權限。

以下指令將創建一個名為 example_user 的新使用者,使用 mysql_native_password 作為預設的身份驗證方法。我們將定義這個使用者的密碼為 !ExTest123,但你應該用自己選擇的安全密碼來取代這個值。

mysql> CREATE USER 'example_user'@'%' IDENTIFIED WITH mysql_native_password BY '!ExTest123';

現在我們需要給予這個使用者對 example_database 資料庫的權限:

mysql> GRANT ALL ON example_database.* TO 'example_user'@'%';

這將給予 example_user 使用者對 example_database 資料庫的完整權限,同時防止該使用者在你的伺服器上創建或修改其他資料庫。

現在,使用以下指令退出 MySQL shell:

mysql> exit

你可以透過再次使用自訂使用者的憑證登入 MySQL 控制台,來測試新使用者是否具有適當的權限。注意這個指令中的 -p 標誌,這將提示你輸入創建 example_user 使用者時使用的密碼:

$ mysql -u example_user -p

登入 MySQL 控制台後,確認你是否能夠訪問 example_database 資料庫:

mysql> SHOW DATABASES;

這將返回以下輸出:

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| example_database   |
| information_schema |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

接下來,我們將創建一個名為 todo_list 的測試資料表。在 MySQL 控制台中,執行以下語句:

mysql> CREATE TABLE example_database.example_data (
	item_id INT AUTO_INCREMENT,
	content VARCHAR(255),
	PRIMARY KEY(item_id)
);

在測試資料表中插入幾行內容。你可能想要重複執行下一個指令幾次,使用不同的值:

mysql> INSERT INTO example_database.example_data (content) VALUES ("第一筆測試資料");
mysql> INSERT INTO example_database.example_data (content) VALUES ("第二筆測試資料");
mysql> INSERT INTO example_database.example_data (content) VALUES ("第三筆測試資料");

為了確認資料是否成功保存到你的資料表中,執行以下指令:

mysql> SELECT * FROM example_database.example_data;

你的輸出應顯示如下:

mysql> SELECT * FROM example_database.example_data;
+---------+-----------------------+
| item_id | content               |
+---------+-----------------------+
|       1 | 第一筆測試資料        |
|       2 | 第二筆測試資料        |
|       3 | 第三筆測試資料        |
+---------+-----------------------+
3 rows in set (0.00 sec)

在確認你的測試資料表中有有效的資料後,你可以退出 MySQL 控制台:

mysql> exit

現在你可以創建一個連接到 MySQL 並查詢內容的 PHP 腳本。使用你喜歡的編輯器在你的自定義網站根目錄中創建一個新的 PHP 檔案。我們將使用 nano 進行這個操作:

$ sudo nano /var/www/test3.ui-code.com/html/example_data.php

以下的 PHP 腳本將連接到 MySQL 資料庫並查詢 example_data 表的內容,然後以列表的方式呈現結果。如果資料庫連接有問題,它會拋出一個例外。

將以下內容添加到你的 example_data.php 腳本中:

<?php
$user = "example_user";
$password = "!ExTest123";
$database = "example_database";
$table = "example_data";

try {
  $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
  echo "<h2>TODO</h2><ol>"; 
  foreach($db->query("SELECT content FROM $table") as $row) {
    echo "<li>" . $row['content'] . "</li>";
  }
  echo "</ol>";
} catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}

完成編輯後,記得儲存並關閉這個檔案。

你現在可以在網頁瀏覽器中輸入你設定的網站的域名或公共 IP 位址,然後加上 /example_data.php,來訪問這個頁面:

http://server_domain_or_IP/example_data.php

範例
http://35.229.234.157/example_data.php
http://test3.ui-code.com/example_data.php

應該收到如下所示的頁面,顯示您在測試表中插入的內容:

這表示你的 PHP 環境已經準備好可以連接並與你的 MySQL 伺服器互動了。


Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *