---
# System prepended metadata

title: Apache Web Server

---

# Apache Web Server

- WWW 是依據 HTTP 這個協定而來的，分為伺服器端與用戶端；
- Apache 是一個伺服器端的軟體，前身從 NCSA 的 HTTPd 伺服器發展而來，可用於網站搭建與管理，是一個最常見且最穩定的HTTP server之一，可支援靜態與動態網站（動態網站需搭配PHP）

- 主要另一個常見的為Microsoft的IIS (internet information services) server
{%preview https://ithelp.ithome.com.tw/articles/10291454 %}

---
# LAMP 平台說明：
常見的兩大平台設計系統：
1. 在Linux系統上 => `Apache + MySQL + PHP` (主要)
2. 在Windows系統上 => `IIS + MSSQL + ASP(.NET)`

## www (LAMP) 基本設定：
- Apache => 只提供基本靜態網頁資料
- 搭配PHP / MySQL => 整合成動態網頁


## LAMP 架站所需軟體
- `apache2` -> Apache2 網頁伺服器 
- `mysql-server or mariadb-server` -> MySQL 伺服器
- `mysql-client` -> MySQL 客戶端工具 
- `php / libapache2-mod-php` -> PHP 模組
- `php-mysql` -> PHP & MySQL 連線工具 
- `php-dev` -> PHP 開發工具


## Apache 各種設定檔
![截圖 2025-05-03 下午4.21.08](https://hackmd.io/_uploads/BJ1fzLXeee.png)

- `error.log` -> 記錄 Apache 發生的錯誤（如設定錯誤、找不到檔案、權限問題等）
預設路徑：`/var/log/apache2/error.log`

- CGI 網頁程式存放 -> `/usr/lib/cgi-bin/` 
(需啟用mod_cgi -> `sudo a2enmod cgi`)

- `access.log` -> 記錄每一次對網站的請求（誰連進來、存取了什麼、狀態碼）
預設路徑：`/var/log/apache2/access.log`

- Apache密碼工具 -> 可生成網頁登錄時的密碼
預設路徑：`/usr/bin/htpasswd`

- **CGI (Common Gateway Interface) 網頁程式**
-> 是一種讓 Web 伺服器能夠執行外部程式（通常稱為 CGI 腳本）並與之互動的標準介面。


## Apache 基本設定
1. 設定測試用主機Hostname -> 尚未從no-ip申請HostName時的設定
```
alex@lin:~$ sudo vim /etc/hosts
=> 127.0.0.1 localhost 

請修改為以下
=> 127.0.0.1 localhost.localdomain localhost
```
-> （仍建議從No-ip申請一個HostName）

2. 網站首頁（/var/www/html）相關設定
=> `cd /etc/apache2/apache2.conf` 找出apache.conf

```
<Directory "/var/www/html">
    Options Indexs FollowSymLinks
    AllowOverride None
    Require all denied
</Directory>
```
---
### :gear: Options（目錄參數）
=> 針對Apache的權限設定，如果有列出則表示開啟該功能

- `Indexes` -> 若在此目錄下找不到index.html檔案時，則顯示該目錄下的所有檔名。
- `FollowSymLinks` -> 讓連結檔生效，預設在/var/www/html下要連結到非此目錄的地方，該連結檔會失效，但此設定可讓其生效。
- `ExecCGI` -> 讓此目錄具有執行CGI程式的權限。
- `Includes` -> 讓一些server-side Include程式可以運作 （通常建議加上！）
- `MultiViews` -> 讓系統可根據使用者的語系，自動回傳相對應的檔案給client端（如台灣使用者就回傳 => index.zh-tw.html）

---
### :gear: AllowOverride （允許覆寫參數的功能）
=> 讓使用者以目錄底下的 `.htaccess` 檔案內覆寫 `<Directory>` 內的某些功能參數。 用來規定 `.htaccess` 可以覆寫的權限類型有哪些。

常見的有：
![截圖 2025-05-04 下午4.34.52](https://hackmd.io/_uploads/rkd38sNeeg.png)

=> 預設可能沒有這個檔案，可以在/var/www/html/.htaccess中撰寫。 

---
### :gear: Require（存取權限）
=> 設定使用者在此目錄下的存取權限。

![截圖 2025-05-04 下午4.38.01](https://hackmd.io/_uploads/S1NdwsNxlx.png)

---
### :gear: DirectoryIndex（首頁檔名設定）
範例： `DirectoryIndex index.html index.html.var`
=> 若此目錄下找不到index.html，系統會自動照順序往後找，若列出的檔案都找不到，則會參考 Indexes的設定。
- `有設定Indexes` -> 則列出所有目錄下檔案
- `未設定Indexes` -> 則用戶端會顯示403 Forbidden錯誤

---
### :gear: Alias（檔案路徑映射 -> 類似連結檔）
=> 允許你將網站的 URL 路徑映射到伺服器上的實際目錄。

設置方法：
1. 編輯配置文件
`sudo nano /etc/apache2/sites-available/000-default.conf`
2. 在 `<VirtualHost>`標籤內添加
```
Alias /images /var/www/html/my_images

<Directory /var/www/html/my_images>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>
```
3. 儲存並重啟Apache
`sudo systemctl restart apache2`

=> 這樣設定後，當訪問 `http://你的伺服器IP/images/` 時，實際會訪問到伺服器上的 `/var/www/html/my_images`。
(目錄實際上images目錄並不在/var/www/html/下）


## Apache 針對伺服器環境的設定

### :gear: ServerTokens OS 
=> 告知用戶端我們伺服器的版本與作業系統
- 可以將 `OS` 改成 `prod` -> 隱藏Apache版本資訊，提高安全性
- 檔案路徑：`sudo vim /etc/apache2/conf-available/security.conf`
- 修改後
-> 重啟Apache2
`sudo systemctl restart apache2`
-> 測試回應
`curl -I http://localhost`
![截圖 2025-05-04 下午5.09.17](https://hackmd.io/_uploads/SyY60iEglx.png)
- 可設定參數如下：
![截圖 2025-05-04 下午5.12.18](https://hackmd.io/_uploads/ry-tyh4gle.png)

---
### :gear: ServerRoot
=> 定義 Apache 伺服器的根目錄路徑，預設為 `/etc/apache2/`。

---
### :gear: PidFile
=> 指定 Apache 伺服器主進程的進程 ID (PID) 儲存位置。
- 檔案路徑：/etc/apache2/apache2.conf
=> `PidFile ${APACHE_PID_FILE}`
透過環境變數設置，連結到/etc/apache2/envvars

---
### :gear: TimeOut
=> `TimeOut 60` -> 當持續連線等待超過 60 秒則該次連線就中斷，預設通常為300秒。

---
### :gear: KeepAlive
=> 是否允許持續性的連線，設定 `KeepAlive On` 即一個 TCP 連線可以將所有資料傳送完（預設為off）。

---
### :gear: MaxKeepAliveRequests
=> 當 KeepAlive 設定為 On 時，則此數值可決定該次連線的最大傳輸數量。
- `MaxKeepAliveRequests 500` -> 單一TCP連線可以處理的最大HTTP請求次數為 500 次
- 設定為 0 => 代表不限制

---
### :gear: KeepAliveTimeout
=> 指定 Apache 在關閉連接前等待下一個請求的最大秒數。
- 例如：`KeepAliveTimeout 5` 表示等待 5 秒

---
## 多工處理設定（與記憶體效能管理有關！）
- prefork
- worker
- event（預設）

設定檔路徑：`/etc/apache2/mods-available/` 找到`mpm_worker.conf / mpm_prefork.conf / mpm_event.conf`



## worker.conf參數說明 (prefork / event 比照)
- `startServers:2` => 預建立2個process來處理請求，每個process包含多個threads。
- `MinSpareThreads:25` => 空閒threads少於25條時，Apache會啟用新的threads or process。
- `MaxSpareThreads:75` => 空閒thread超過75條時，Apache會關閉不必要的 thread，避免資源浪費。
- `ThreadLimit:64` => `ThreadsPerChild` 的上限限制，保護 Apache 不會設定過高造成系統負荷。
- `ThreadsPerChild:25` => 每個process在啟動時會建立25條thread來處理請求。
- `MaxRequestWorkers:150` => 最多可同時處理 150 個 client 請求（注意會耗用實體記憶體）-> 若所有process都在處理請求，則新的請求會被放到等待序列中。
- `MaxConnectionsPerChild:0` => 若設為 0，代表不限制，process 會永久存在直到 Apache 重啟。若設定1000，則 process 在處理完1000個請求後會自動退出，Apache會再重啟一個新的process（可避免記憶體洩漏）。

![截圖 2025-05-04 下午5.47.59](https://hackmd.io/_uploads/BycAP2Elex.png)

## 補充：多工處理模組安裝與設定（ prefork / worker / event ）

### 安裝PHP-FPM（PHP8.4），並停用mod_php模組

- 安裝PHP-FPM
`sudo apt install php8.4-fpm`

- 啟用 proxy_fcgi & setenvif 模組
`sudo a2enmod proxy_fcgi setenvif`

- 啟用 php8.4-fpm
`sudo a2enconf php8.4-fpm`

- 停用 `mod_php`（prefork 專用的 PHP 模組）：
`sudo a2dismod php8.4`

### 切換MPM多工處理模組
- 停用 `mpm_prefork`，啟用 `mpm_event`：
`sudo a2dismod mpm_prefork`
`sudo a2enmod mpm_event`

- 重新啟動 Apache：
`sudo systemctl restart apache2`

- 查詢目前是用的MPM模組
`apache2ctl -M | grep mpm`

![截圖 2025-05-03 晚上7.01.54](https://hackmd.io/_uploads/Sy6oDdXgxl.png)

### 備註：
- `proxy_fcgi` 模組
讓 Apache 能夠透過 FastCGI 協定，把來自用戶的 PHP 請求「轉送」給 PHP-FPM。
=> `將PHP請求代理給PHP-FPM處理`


- `setenvif` 模組
根據請求的標頭、來源、User-Agent 等設定特定的環境變數。
=> `設定環境變數，幫助伺服器識別請求`

---
### 其他Server環境設定參數
- `Listen 80`
=> 告訴 Apache 監聽所有網路介面上的 80 端口，這是 HTTP 協議的預設端口。
=> 設定檔路徑：`/etc/apache2/ports.conf`

- `User apache / Group apache`
=> Apache 伺服器的主要 process 將會以 `apache` 這個群組帳號的權限來運行。

- `ServerAdmin`
=> 設定自己的Email，當網站出錯時，錯誤訊息會回報到設定的Email。

- `ServerName`
=> 自行設定HostName（如：網域ddns.net之前的alexlin1127 -> hostname），若無指定則預設以hostname 的輸出為依據

- `UseCanonicalName`
=> 若設定On（預設） -> 告訴Apache只接受上頭 serverName 指定的主機名稱連線。
=> 如果有設定virtualHost，建議設定off。

## 針對中文 big5 語系編碼的設定參數修改
=> Apache2預設為UTF-8編碼格式，有些舊的www網站為Big5格式，則會出現亂碼。

解決方法：
1. 修改`/etc/apache2/apache2.conf`預設的UTF-8編碼設定，將`AddDefaultCharset UTF-8`進行註解
2. 清除瀏覽器的快取

---
### 補充：網頁首頁及目錄相關之權限設定 (DocumentRoot 與 Directory)
![截圖 2025-05-03 晚上9.41.58](https://hackmd.io/_uploads/rkd4pqXlee.png)


# 其他補充：
### 1. 異常大量請求處理
- `mod_evasive` 是 Apache 的一個防禦模組，**用來防止 DDoS（分散式阻斷服務攻擊）與暴力爬蟲等大量惡意連線行為**。 
- 當偵測到某個 IP 在短時間內發出異常大量請求時，**暫時封鎖該 IP**，保護伺服器資源不被耗盡。
- 安裝`mod_evasive`模組：
`sudo apt-get install libapache2-mod-evasive`
- 相關參數設定：
![截圖 2025-05-03 下午6.17.56](https://hackmd.io/_uploads/rJ3Ypvmeee.png)

---
### 2. 虛擬主機 (virtual host)
- 若要將首頁目錄建立在其他地方，可使用VirtualHost -> 新增.conf檔案 -> `sudo vim /etc/apache2/site-available/你的網站名稱.conf`
- 新增內容如下：
```html=
<VirtualHost *:80>
    ServerName alexlin120.ddns.net
    DocumentRoot /var/www/html/自己的網頁資料夾
    <Directory /var/www/html/自己的網頁資料夾>
    AllowOverride All
    Options Indexes FollowSymLinks MultiViews
    Order allow,deny
    allow from all
    </Directory>
</VirtualHost>
```
- 啟用虛擬主機服務
`sudo a2ensite 自己的網頁資料夾.conf`
- 重新啟動 apache2  
`sudo systemctl restart apache2`

---
### 3. 防火牆（ufw）設定
- 讓外部使用者連線 -> 監聽 80 port
- 防火牆開啟80 port
`sudo ufw allow 80/tcp`
- 開啟防火牆
`sudo ufw enable`
- 查看狀態
`sudo ufw status`
- 確認Apache是否有在監聽80port
`netstat -tnpl | grep :80`

![image](https://hackmd.io/_uploads/HyUCVqHxxl.png)

==> 開啟防火牆設定及80 port監聽後，應能從外部裝置登入/var/www/html(需在同一個內網之下)

---
### 4. 檢查 AppArmor 設定
- 查看 AppArmor 狀態
`sudo aa-status`
- 查看 AppArmor 日誌
`sudo less /var/log/syslog`
- 禁用 AppArmor（僅用於測試）
`sudo systemctl stop apparmor`

--- 
### 5. 若無法從外部網路裝置連線到網站
檢查流程：
- 檢查防火牆
- 確認 Apache 配置 -> 檢查 Apache 的配置文件 `/etc/apache2/ports.conf`，確認 80 端口被設置為開放：
![image](https://hackmd.io/_uploads/SJmZocBgxg.png)
- 檢查 Apache 伺服器的錯誤日誌
![image](https://hackmd.io/_uploads/BkW4sqHxll.png)
- 測試本地連接
![image](https://hackmd.io/_uploads/HyaBs9Bxeg.png)
- 確認 Linux IP 設置
![image](https://hackmd.io/_uploads/rJ25i5Bxgg.png)
