---
# System prepended metadata

title: 網頁伺服器 Nginx
tags: [docker, nginx, ncnu, container, lsa]

---

# 網頁伺服器 Nginx

###### tags: `ncnu`, `lsa`, `nginx`

[TOC]

---


## 網頁伺服器概論

### 什麼是 Server？


伺服器（Server）這個名詞，最早的意涵其實很直白——「提供服務的人或東西」。在電腦網路世界中，凡是能接收請求並回應資料的實體，都可以被稱為伺服器。不論它是一台電腦、一個軟體，甚至是一個雲端平台，重點在於它「提供服務（Service）」這件事。

以實際例子來說：
當你打開瀏覽器輸入 `https://www.google.com` 時，你的電腦會向 Google 的伺服器發出請求，伺服器接收到後回傳網頁內容——這整個過程中，Google 的主機就是伺服器，而你的電腦則是「客戶端（Client）」。

常見伺服器種類如下：

* **網頁伺服器（Web Server）**：回應使用者的網頁請求，提供 HTML、CSS、圖片等內容。
* **資料庫伺服器（Database Server）**：儲存與管理資料，供其他系統查詢。
* **檔案伺服器（File Server）**：集中管理檔案與資料夾，支援上傳與下載。
* **郵件伺服器（Email Server）**：處理電子郵件的寄送、接收與儲存。
* **DNS 伺服器（Domain Name Server）**：把我們輸入的網域名稱（如 `google.com`）轉換成實際的 IP 位址，讓網路找到正確的目標主機。




#### 什麼是 Web Server？

Web Server 是一種提供網頁相關服務的伺服器。它的主要功能是讓使用者能夠透過瀏覽器，在世界各地任何連上網路的地方顯示自己的網頁內容。

Web Server 存放著網路伺服器軟體以及網站檔案，例如 HTML、CSS、JavaScript、圖片、影片等。當客戶端 (Client)，通常是瀏覽器（如 Chrome、Firefox），主動向伺服器發送請求 (request) 時，Web Server 會接收並處理這些請求，然後回傳一個回應 (response) 給客戶端，使客戶端能夠呈現這些資訊。

##### Client-Server 架構

```mermaid
graph TD
    A[Client 瀏覽器] <-->|HTTP Request/Response| B[Web Server]
    B --> C[網站檔案]
```

<p style="text-align: center;">Client-Server 架構示意圖</p>

Web Server 通常會在主機上開啟一個預設為 80 的 Port，其他電腦即可透過該主機的 IP 和這個 Port 與其建立連線。

```mermaid
flowchart TB
    A1[Client]
    A2[Client]
    A3[Client]
    B[獨立IP]
    C[主機 Nginx Port 80]

    A1 --> B
    A2 --> B
    A3 --> B
    B --> C
```

<p style="text-align: center;">Web Server 開啟 80 Port 示意圖</p>



### HTTP（Hypertext Transfer Protocol）

HTTP，全名 **H**yper**t**ext **T**ransfer **P**rotocol，「超文本傳輸協定」。
它是 **TCP/IP 模型**中的「應用層（Application Layer）」協定，用來規範 **Client** 與 **Server** 之間，如何發送請求（Request）與接收回應（Response）。
HTTP 預設使用的埠號（Port）是 **80**，但這是慣例設定，協定本身並不限定埠號。

#### 🌐 協定比較表

| 協定    | 所屬層級 (TCP/IP 模型) | 是否加密 | 預設埠號 | 備註                                    |
| ----- | ---------------- | ---- | ---- | ------------------------------------- |
| HTTP  | 應用層              | 否    | 80   | 傳輸明文，安全性低                             |
| HTTPS | 應用層（經 TLS 加密）    | 是    | 443  | 需要向CA 機構申請憑證，自簽名的憑證大多不被信任 |

---

#### 📌 重點整理

* HTTP 的核心在於定義「請求／回應」的溝通格式與行為，而**不是**定義 Port。
* HTTP 使用 TCP 進行資料傳輸，確保資料封包可靠、有序抵達。
* HTTPS 是 HTTP 加上 **TLS（Transport Layer Security）** 加密後的安全版本。
* **Let's Encrypt** 提供免費憑證服務，使加密網站普及化，推動整個網路從「HTTP」邁向「HTTPS」。


telnet moli.lsa.tw 80
```bash!
GET / HTTP/1.0
Host: moli.lsa.tw


```



### Port (通訊埠ㄅㄨˋ)

![TCP/IP](https://miro.medium.com/v2/resize:fit:1266/format:webp/0*H0QvGqEB4OxOQML9)

![TCP/IP Layer](https://kagi.com/proxy/OSI-vs-TCP-vs-Hybrid-2.webp?c=NEWVyEx4NuEJxKkAg7KeAU6NxdCIjRRfJBKa7ghmgDxZRY2keOf3_jtXOFZbdxvW0R_0XupzrcttxqnP-WsgQQHJ8Z77JHqYEzCyUUXfnvewl61iYV9TICrultVf9hOukW-BssLxL2PnNLPgAWpkTQ%3D%3D)

Port 用於區分同一個 IP 地址下的不同服務。每個 Port 提供特定的服務，例如 SSH 使用 22 Port，網頁瀏覽預設使用 80 Port。

#### 為什麼需要 Port？

當電腦傳輸和接收來自網路的資料時（例如來自 Chrome、Telegram、遊戲等），電腦需要區分這些混合的資料應該傳送到哪個服務處理。Port 的作用就像郵局的窗口，封包在回傳到電腦時會標記要給哪個 Port，電腦便會將封包分配給目前佔用該 Port 的服務，從而確保資料傳送給正確的應用程式。

#### Port 號範圍

Port 號以 16 位元表示，範圍從 0 到 65535。

- **0**：保留 Port，通常不會啟用。
- **1 ~ 1023 (Well-Known Ports)**：這些 Port 需要超級使用者 (root) 權限才能佔用和使用，主要用於一些常見的通訊服務。由 IANA (Internet Assigned Numbers Authority) 進行管理和分配。

常見的 Well-Known Ports：

- **20/21**: FTP (檔案傳輸協定)
- **22**: SSH (安全遠端登入)
- **23**: Telnet
- **25**: SMTP (郵件傳送)
- **53**: DNS (網域名稱系統)
- **80**: HTTP (網頁瀏覽)
- **110**: POP3 (郵件接收)
- **143**: IMAP (郵件接收)
- **443**: HTTPS (加密網頁瀏覽)


**1024 ~ 49151 (Registered Ports)**：公司或組織可以向 IANA 申請註冊這些 Port。它們不需要超級使用者權限，用於特定的服務，例如 MySQL 資料庫服務的 3306 Port。



**49152 ~ 65535 (Private/Dynamic Ports)**：這些 Port 未向 IANA 註冊，可以在本地或由應用程式動態使用。



#### `/etc/services` 檔案

`/etc/services` 檔案記錄了各種服務會佔用的 Port 號，包含服務名稱、Port 號、使用的協定以及別名。

```bash
$ cat /etc/services
```

你可以在這個檔案中查看系統預設的服務與 Port 對應關係。

#### 檢查開啟的 Port

可以使用 `ss` 指令來查看目前開啟的 Port 和網路連線狀態。

```bash
sudo ss -ntupl
```

可以帶入哪些參數:

- `-a`: 顯示所有的網路連線狀態(包含監聽中和已建立的連線)
- `-t`: 顯示 TCP 連線
- `-u`: 顯示 UDP 連線
- `-p`: 顯示此連線的 PID(Process ID)和程式名稱。若沒有 `sudo` 權限,則無法顯示 PID/Program name
- `-l`: 只顯示處於 LISTEN(監聽)狀態的連線
- `-n`: 以數字顯示 IP 位址和 Port 號,而不轉換成主機名和服務名

輸出欄位說明:

- `Netid`: 協定類型(tcp 或 udp)
- `State`: 連線狀態,`LISTEN` 表示服務正在監聽 Port,`ESTAB` 表示連線已建立
- `Recv-Q` / `Send-Q`: 接收和傳送佇列中的資料量
- `Local Address:Port`: 本地 IP 和 Port,`0.0.0.0` 或 `*` 表示可接受來自任何位址的請求
- `Peer Address:Port`: 遠端位址和 Port,`*:*` 表示尚未建立具體連線(監聽狀態)
- `Process`: 程序 ID 和程式名稱

---

## 網頁伺服器，以 Nginx 為例

在了解 Nginx 之前，讓我們先認識一下網頁伺服器的發展脈絡。

### 網頁伺服器市占率演變

![CleanShot 2025-10-09 at 13.00.13@2x](https://hackmd.io/_uploads/ByXKWaVTxe.png)



根據歷年市場調查數據：

- **2010 年代初期**：Apache 獨占鰲頭，市占率超過 60％  
- **2019 年**：Nginx 首次超越 Apache，成為市占率最高的網頁伺服器  
- **2024 年最新數據**：  
  - Nginx 約占 39.36%
  - Apache 約占 25.72％  
  - Microsoft 約佔 9.63%
  - 其他伺服器（包含 Lighttpd、Caddy、 等）約占60％  

### 主要網頁伺服器介紹

#### 1. Apache HTTP Server
- **架構特性**：採用「一個請求、一個 Process」的處理模式  
- **優勢**：歷史悠久、模組豐富、設定靈活  
- **劣勢**：記憶體使用較多、高並行處理能力有限  
- **現況**：目前主要用於維護舊系統，新專案較少採用  

#### 2. Lighttpd（讀作 lighty）
- **架構特性**：輕量級設計  
- **優勢**：靜態檔案處理效率高，**靜態內容效能強於 Apache**  
- **劣勢**：動態內容處理能力有限、社群相對較小  
- **適用場景**：靜態網站、資源受限環境  

#### 3. Nginx（發音同「engine X」）

**誕生背景**：為了解決 **C10K 問題**（同時處理一萬個並行連線）而設計，目標是超越 Apache 的效能極限。

**核心特性**：

- **事件驅動架構**：不像 Apache 每個請求都開一個 Process，而是用事件循環處理多個連線  
- **非同步非阻塞**：能同時處理大量並行請求而不占用過多資源  
- **模組化設計**：功能透過模組擴充，保持核心輕量  

**效能表現**（2024 年數據）：

- 高並發情況下效能優於 Apache **2.5 倍**  
- 記憶體占用比 Apache 少約 **40％**  
- 可穩定承受大流量衝擊  

**適用場景**：

- 高流量網站  
- 反向代理與負載均衡  
- 靜態檔案伺服  
- API Gateway  

### 為什麼上課選擇 Nginx？

1. **產業主流**：自 2019 年超越 Apache 後持續成長，是現代網站架構的首選  
2. **效能卓越**：解決了傳統伺服器的並行處理瓶頸  
3. **資源友善**：記憶體占用少、穩定性高  
4. **應用廣泛**：不只是網頁伺服器，更常用於反向代理、負載均衡等進階架構  
5. **學習價值**：理解事件驅動架構，對未來系統設計很有幫助  


---

#### 安裝 Nginx

```bash
# 更新套件資訊
sudo apt update

# 安裝 Nginx
sudo apt install nginx

# 檢查服務狀態
sudo systemctl status nginx

# 或使用更現代的 ss 指令
sudo ss -tulnp | grep nginx
```

#### Web Server 服務操作指令

在實際操作 Web Server 時，有多種指令格式可以使用。了解這些指令的差異很重要。



```bash
# 方式 1：使用 service 指令
sudo service <service_name> <操作>

# 方式 2：使用 systemctl 指令（推薦）
sudo systemctl <操作> <service_name>
```

**說明**：
- `service` 是較舊的指令，但仍然常用且簡潔
- `systemctl` 是 systemd 系統的標準指令，功能更完整（推薦使用）

#### 常用操作指令

- **`status`**：查看服務狀態
  ```bash
  sudo systemctl status nginx
  ```

- **`start`**：開啟服務
  ```bash
  sudo systemctl start nginx
  ```
- **`stop`**：關閉服務
  ```bash
  sudo systemctl stop nginx
  ```

- **`reload`**：不停止服務，重載設定檔，使更改生效
  ```bash
  sudo systemctl reload nginx
  ```
  **重點**：`reload` 不會中斷現有服務，適合在生產環境更新設定

- **`restart`**：停止服務後重新開啟
  ```bash
  sudo systemctl restart nginx
  ```
  **重點**：`restart` 會中斷現有服務，但確保設定完全重新載入

### reload vs restart 的差異

| 操作 | 中斷服務 | 適用場景 |
|------|----------|----------|
| **reload** | 否 | 修改設定檔後平滑更新 |
| **restart** | 是 | 重大更新、安裝新模組 |

**實務建議**：除非必要，優先使用 `reload` 來更新設定，避免影響使用者。

#### systemctl 額外功能

`systemctl` 提供比 `service` 更多的操作：

```bash
# 檢查服務是否失敗
sudo systemctl is-failed nginx

# 如果可以就 reload，否則 restart
sudo systemctl reload-or-restart nginx

# 啟用服務（開機自動啟動）
sudo systemctl enable nginx

# 停用服務（開機不自動啟動）
sudo systemctl disable nginx
```


### Nginx 設定檔結構

Nginx 的設定檔主要集中在 `/etc/nginx/` 目錄下，方便管理並避免系統更新時覆蓋使用者自定義設定：

```text!
/etc/nginx/
├── nginx.conf                    # 主設定檔
├── mime.types                    # MIME 類型對應檔
├── fastcgi_params                # FastCGI 參數設定
├── uwsgi_params                  # uWSGI 參數設定
├── scgi_params                   # SCGI 參數設定
├── proxy_params                  # 代理伺服器參數設定
├── sites-available/              # 可用站點設定檔
│   ├── default                   # 預設站點設定
│   └── example.com.conf          # 其他站點設定檔
├── sites-enabled/                # 已啟用站點(軟連結 symlink)
│   └── default -> ../sites-available/default
├── conf.d/                       # 額外設定檔(自動載入 *.conf)
│   └── custom.conf               # 自訂設定檔
├── modules-available/            # 可用模組
├── modules-enabled/              # 已啟用模組(軟連結)
└── snippets/                     # 可重複使用的設定片段
    ├── fastcgi-php.conf
    └── snakeoil.conf
```

- **`nginx.conf`**：主設定檔，包含 Nginx 的全域設定，例如 `worker_processes` (工作程序數量)、Log 路徑等。一般情況下不建議直接修改主設定檔，以免影響系統更新。
- **`sites-available`**：所有可用的 Web Server設定檔的集中地，方便管理。這些檔案本身不會生效。
- **`sites-enabled`**：實際讓服務運作的設定檔。此目錄中的檔案是從 `sites-available` 目錄中的檔案軟連結過來的。當 Nginx 啟動或重載時，會載入此目錄中的設定檔。

### Nginx 主設定檔

#### nginx.conf 全域設定

```nginx
# 工作程序數量,auto 會根據 CPU 核心數自動設定
worker_processes auto;

# 錯誤 Log 位置和等級
error_log /var/log/nginx/error.log warn;

# PID 檔案位置
pid /run/nginx.pid;

events {
    # 每個 worker 程序可處理的最大連線數
    worker_connections 1024;
}

http {
    # 包含 MIME 類型定義
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    
    # 存取日誌格式和位置
    access_log /var/log/nginx/access.log;
    
    # 包含其他設定檔
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}
```

**重點說明**：
- `worker_processes auto`：讓 Nginx 自動根據 CPU 核心數調整工作程序數量，是最佳實踐
- 日誌檔案對於除錯和監控非常重要



#### sites-available 默認設定檔

`/etc/nginx/sites-available`

在 Nginx 的 `server` 區塊中，包含以下重要參數：

- **`listen`**：伺服器監聽的 Port
  ```nginx
  listen 80;              # IPv4
  listen [::]:80;         # IPv6
  ```

- **`default_server`**：當沒有其他 `server_name` 符合時，會連到此 `server` 區塊。每個 Port 只能有一個 `default_server`。
  ```nginx
  listen 80 default_server;
  ```


- **`root`**：設定網站的根目錄，Nginx 會從這裡提供檔案給存取者
  ```nginx
  root /var/www/html;
  ```

- **`index`**：設定預設首頁檔案的名稱
  ```nginx
  index index.html index.htm index.nginx-debian.html;
  ```
  當使用者存取目錄時，Nginx 會按順序查找並載入第一個名稱成功配對到的檔案，如果沒有，就回傳 404。

- **`server_name`**：根據客戶端請求的 `Host` 標頭 (Domain Name) 選擇正確的 `server` 區塊
  ```nginx
  server_name example.com www.example.com;
  server_name _;  # 底線表示預設伺服器
  ```

- **`location`**：定義對特定路徑或 URL 模式的操作

#### try_files 指令詳解

`try_files` 是 Nginx 中非常重要的指令，它定義了處理請求的優先順序。

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

**處理流程**（以請求 `/example` 為例）：

```mermaid
flowchart TD
    A[請求 /example] --> B{檢查檔案<br/>$uri}
    B -->|存在| C[提供 /example 檔案]
    B -->|不存在| D{檢查目錄<br/>$uri/}
    D -->|存在| E[進入 /example/ 目錄<br/>尋找 index 檔案]
    D -->|不存在| F[回傳 404 錯誤]
```

**步驟說明**：
1. **檢查檔案 (`$uri`)**：先檢查 `root` 目錄下是否存在名為 `example` 的檔案。若存在，則提供該檔案。
2. **檢查目錄 (`$uri/`)**：若 `example` 檔案不存在，則檢查是否有名為 `example` 的目錄 (即 `/example/`)。若存在，則進入此目錄，並依照 `index` 欄位查找指定的檔案。
3. **回傳 404**：如果 `example` 既不是檔案也不是目錄，Nginx 會回傳 `404 Not Found` 錯誤。

#### location 區塊範例

```nginx
# 基本路徑匹配
location / {
    try_files $uri $uri/ =404;
}

# 禁止存取隱藏檔案
location ~ /\. {
    deny all;
}

# 靜態檔案快取
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}
```

### 基本配置範例

```nginx
# /etc/nginx/sites-available/default
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    
    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    
    server_name _;
    
    location / {
        try_files $uri $uri/ =404;
    }
}
```

### 更改 Port 範例

如果需要讓 Nginx 監聽不同的 Port（例如 8080）：

```bash
# 1. 停止 Nginx
sudo systemctl stop nginx

# 2. 編輯設定檔
sudo vim /etc/nginx/sites-available/default
```

修改 `listen` 參數：

```nginx
server {
    listen 8080 default_server;
    listen [::]:8080 default_server;
    
    # ... 其他設定
}
```

```bash
# 3. 測試設定檔語法
sudo nginx -t

# 4. 啟動 Nginx
sudo systemctl start nginx

# 5. 驗證 Port
sudo ss -tulpn | grep nginx
```
---

## 虛擬主機 (Virtual Host)

虛擬主機允許一台伺服器提供多個網站或網頁應用程式，且每個網站可以有自己的 Domain Name 和網頁內容。這樣可以最大化利用伺服器資源，節省硬體成本。伺服器會依據使用者的請求資訊（如 Domain Name, IP, Port）來提供不同的內容。

### 虛擬主機的三種類型

#### 1. 基於域名的虛擬主機 (Name-Based Virtual Host)

使用不同的 Domain Name 來區分不同的網站。

**情境**：多個網站共享同一個 IP 地址，伺服器根據請求中的 Domain Name (Host header) 來分配請求。

**範例**：`example1.com` 和 `example2.com` 都執行在同一台伺服器的相同 IP 上。

```mermaid
flowchart TB
    AA[Client 客戶端<br/>瀏覽器輸入網址] --> |HTTP Request<br/>包含 Host header| A[Web Server<br/>Apache/Nginx<br/>Port 80/443]
    A --> VH{Virtual Host<br/>判斷機制<br/>讀取 Host header}
    VH -->|Host: site-a.com| B[內部轉發<br/>192.168.1.100:80]
    VH -->|Host: site-b.com| C[內部轉發<br/>192.168.1.101:80]
    B --> D[網站 A<br/>回傳內容]
    C --> E[網站 B<br/>回傳內容]
    D --> AA
    E --> AA
```

**優點**：
- 節省 IP 位址
- 設定簡單
- 最常用的方式

**缺點**：
- 需要註冊 Domain Name

#### 2. 基於 IP 的虛擬主機 (IP-Based Virtual Host)

使用不同的 IP 地址來區分網站。

**情境**：每個網站分配一個專屬的 IP 地址。在一台主機上，可以將多個 IP 位址綁定在同一張網卡上，並針對不同 IP 監聽。

```mermaid
flowchart LR
    AA[Client] -->|連接到 192.168.1.100:80| A[Nginx 伺服器]
    AA -->|連接到 192.168.1.101:80| A
    A -->|listen 192.168.1.100:80| B[192.168.1.100]
    A -->|listen 192.168.1.101:80| C[192.168.1.101]
    B --> D[網站 A<br/>/var/www/site1]
    C --> E[網站 B<br/>/var/www/site2]
```

**設定範例**：

```nginx
# 監聽第一個 IP
server {
    listen 192.168.1.100:80;
    server_name _; 
    root /var/www/site1;
    index index.html index.htm;
}

# 監聽第二個 IP
server {
    listen 192.168.1.101:80;
    server_name _;
    root /var/www/site2;
    index index.html index.htm;
}
```

**優點**：
- 完全獨立的 IP
- 不依賴 Domain Name

**缺點**：
- 消耗 IP 位址資源
- IPv4 位址日益稀缺
- 成本較高

**適用場景**：
- 需要獨立 IP 的企業網站
- 舊版不支援 SNI 的 HTTPS 網站(例如 Windows XP 上的 IE、Android 2.3 以下)
- 特殊安全需求
    -  法規遵循要求(Compliance Requirements)
        -  金融業 PCI DSS
        -  醫療業 HIPAA


#### 3. 基於 Port 的虛擬主機 (Port-Based Virtual Host)

利用 Port 來區別不同的網站。

**情境**：在不使用多個 Domain Name 或 IP 的情況下，運行多個內部應用或 API，或節省 Domain Name 註冊費用。

```mermaid
flowchart LR
    A[Client] -->|連接 :80| B[Nginx 伺服器]
    A -->|連接 :8080| B
    A -->|連接 :8081| B
    B -->|listen 80| E[網站 A<br/>/var/www/site1]
    B -->|listen 8080| F[網站 B<br/>/var/www/site2]
    B -->|listen 8081| G[網站 C<br/>/var/www/site3]
```


**設定範例**：

```nginx
# Port 80
server {
    listen 80;
    server_name localhost;
    root /var/www/site1;
}

# Port 8080
server {
    listen 8080;
    server_name localhost;
    root /var/www/site2;
}

# Port 8081
server {
    listen 8081;
    server_name localhost;
    root /var/www/site3;
}
```

**優點**：
- 不需要額外的 IP 或 Domain Name
- 節省成本
- 配置簡單
- 適合內部測試或開發環境

**缺點**：
- 使用者需要在瀏覽器中輸入 Port 號(例如 http://example.com:8080),這可能會讓非技術用戶感到困惑
- 非標準 Port 可能被防火牆封鎖,每個開放的 Port 都會增加攻擊面
- 對外服務的使用者體驗較差

**適用場景**：
- 開發和測試環境
    - 開發者可以在 localhost:8080 執行測試網站,在 localhost:80 執行正式網站,全部使用同一個 Nginx 伺服器
- 內部應用系統
- API 服務
- 預算有限的小型專案

### Name-Based Virtual Host 實作範例

這個實驗演示如何讓一個 Nginx 伺服器同時為多個 Domain Name 提供服務。

#### 步驟 1：停止 Nginx 服務

```bash
sudo systemctl stop nginx
```

#### 步驟 2：建立新的網站根目錄

```bash
sudo mkdir -p /var/www/example.com
sudo chown -R $USER:$USER /var/www/example.com
sudo chmod -R 755 /var/www
```

`index.html` 內容範例：

```html
<!DOCTYPE html>
<html>
<head>
    <title>Example.com</title>
</head>
<body>
    <h1>歡迎來到 example.com</h1>
    <p>這是基於域名的虛擬主機範例</p>
</body>
</html>
```

#### 步驟 3：新增虛擬主機設定檔

建議複製一份預設設定檔作為基礎，然後進行修改。

```bash
sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/example.com
sudo vim /etc/nginx/sites-available/example.com
```

修改內容：

```nginx
server {
    listen 80;                    # 監聽 IPv4 的 80 Port
    listen [::]:80;               # 監聽 IPv6 的 80 Port
    
    server_name example.com www.example.com;  # 設定 Domain Name
    root /var/www/example.com;    # 網站根目錄
    index index.html;             # 預設首頁檔案
    
    location / {
        try_files $uri $uri/ =404;  # 嘗試尋找檔案,找不到回傳 404
    }
}
```

:::info
完整的 example.com
```nginx
##
# You should look at the following URL's in order to grasp a solid understanding
# of Nginx configuration files in order to fully unleash the power of Nginx.
# https://www.nginx.com/resources/wiki/start/
# https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/
# https://wiki.debian.org/Nginx/DirectoryStructure
#
# In most cases, administrators will remove this file from sites-enabled/ and
# leave it as reference inside of sites-available where it will continue to be
# updated by the nginx packaging team.
#
# This file will automatically load configuration files provided by other
# applications, such as Drupal or Wordpress. These applications will be made
# available underneath a path with that package name, such as /drupal8.
#
# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples.
##

# Default server configuration
#
server {
	listen 80 ;
	listen [::]:80 ;

	# SSL configuration
	#
	# listen 443 ssl default_server;
	# listen [::]:443 ssl default_server;
	#
	# Note: You should disable gzip for SSL traffic.
	# See: https://bugs.debian.org/773332
	#
	# Read up on ssl_ciphers to ensure a secure configuration.
	# See: https://bugs.debian.org/765782
	#
	# Self signed certs generated by the ssl-cert package
	# Don't use them in a production server!
	#
	# include snippets/snakeoil.conf;

	root /var/www/example.com www.example.com;

	# Add index.php to the list if you are using PHP
	index index.html index.htm index.nginx-debian.html;

	server_name example.com;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	# pass PHP scripts to FastCGI server
	#
	#location ~ \.php$ {
	#	include snippets/fastcgi-php.conf;
	#
	#	# With php-fpm (or other unix sockets):
	#	fastcgi_pass unix:/run/php/php7.4-fpm.sock;
	#	# With php-cgi (or other tcp sockets):
	#	fastcgi_pass 127.0.0.1:9000;
	#}

	# deny access to .htaccess files, if Apache's document root
	# concurs with nginx's one
	#
	#location ~ /\.ht {
	#	deny all;
	#}
}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#	listen 80;
#	listen [::]:80;
#
#	server_name example.com;
#
#	root /var/www/example.com;
#	index index.html;
#
#	location / {
#		try_files $uri $uri/ =404;
#	}
#}
```
:::

#### 步驟 4：建立軟連結啟用設定檔

```bash
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
```

#### 步驟 5：新增主機紀錄到 /etc/hosts

為了讓本機電腦能夠解析 `example.com` 到 `127.0.0.1`：

```bash
sudo vim /etc/hosts
```

新增一行：

```
127.0.0.1 example.com www.example.com
```

#### 步驟 6：測試 Nginx 設定檔語法

```bash
sudo nginx -t
```


如果沒有問題，會顯示：

```
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

#### 步驟 7：重啟 Nginx 服務

```bash
sudo systemctl restart nginx
```

#### 步驟 8：測試

**方法 1：使用瀏覽器**

存取 `http://example.com`

**方法 2：使用 curl**

```bash
curl http://example.com
```

---

## 代理 (Proxy) 與負載平衡 (Load Balance)





### 正向代理 (Forward Proxy)

**目的**：位於客戶端和伺服器之間，客戶端透過代理伺服器向外部伺服器發送請求。

```mermaid
flowchart LR
    A[Client] --> B[Forward Proxy]
    B --> C[Internet]
    C --> D[目標伺服器]
```

**功能**：

1. **隱藏客戶端身份**：保護客戶端隱私，外部伺服器只知道代理伺服器的 IP
2. **突破網路限制**：幫助客戶端存取原本受限制的網站
3. **流量節省與快取**：代理伺服器可以快取經常存取的內容，減少對外網的頻寬使用
4. **網路存取控制**：機構可以限制內部成員對特定網站的存取

**特性**：伺服器只知道代理發出的請求，不知道實際的客戶端是誰。

### 反向代理 (Reverse Proxy)

**目的**：位於伺服器之前，代表後端伺服器接收客戶端的請求。

```mermaid
flowchart LR
    A[Client] --> B[Reverse Proxy<br/>Nginx]
    B --> C[後端伺服器 1]
    B --> D[後端伺服器 2]
    B --> E[後端伺服器 3]
```

**功能**：

1. **隱藏後端伺服器**：客戶端不知道真正處理請求的伺服器是哪一台，只與反向代理互動
2. **負載平衡**：將客戶端請求分發到多個後端伺服器，提高資源使用率和可用性
3. **安全性強化**：作為額外的防護層，隱藏內部網路結構
4. **SSL 加密**：可以在代理層處理 SSL 加密/解密，減輕後端伺服器的負擔
5. **快取**：代理伺服器本身可以快取內容，減少對後端伺服器的請求
6. **靈活性**：當後端伺服器的 IP 位址或 Port 更改時，只需向代理伺服器更改設定，無需通知客戶端

**特性**：客戶端只知道反向代理，不知道實際提供服務的後端伺服器。




### 負載平衡 (Load Balance)

負載平衡是反向代理的一個重要功能，旨在將流量合理分配到多個後端伺服器，以提升各伺服器的資源使用率及可用性。這可以有效避免流量集中在同一台伺服器造成超載，導致服務無法正常運行，同時也避免伺服器閒置造成的資源浪費。

```mermaid
flowchart TD
    A[Client 請求] --> B[Nginx<br/>負載平衡器]
    B -->|分配| C[伺服器 1]
    B -->|分配| D[伺服器 2]
    B -->|分配| E[伺服器 3]
```
:::info
#### 負載平衡演算法

Nginx 支援多種負載平衡演算法：

1. **Round Robin (輪流)**
   - 預設方式
   - 依序將請求分配給各伺服器
   - 適合後端伺服器性能相近的情況

2. **Least Connections (最少連線)**
   - 將請求分配給當前連線數最少的伺服器
   - 適合請求處理時間差異大的情況
   ```nginx
   upstream backend {
       least_conn;
       server backend1.example.com;
       server backend2.example.com;
   }
   ```

3. **IP Hash**
   - 根據客戶端 IP 進行 hash，同一 IP 會被分配到同一台伺服器
   - 適合需要會話保持 (Session Persistence) 的應用
   ```nginx
   upstream backend {
       ip_hash;
       server backend1.example.com;
       server backend2.example.com;
   }
   ```
    ##### 為什麼需要 IP Hash?

    當應用程式需要「會話保持」(Session Persistence)時，必須確保同一個使用者的請求都被分配到同一台伺服器，否則:
    - 使用者的登入狀態可能會丟失
    - 購物車內容可能會消失
    - 檔案上傳可能會失敗

4. **Weight (權重)**
   - 為伺服器分配不同的權重
   - 性能好的伺服器可以分配更多請求
   ```nginx
   upstream backend {
       server backend1.example.com weight=3;
       server backend2.example.com weight=1;
   }
   ```
:::


### Nginx 反向代理實作範例

假設我們有兩個後端服務：
- 服務 A 運行在 `127.0.0.1:3000`
- 服務 B 運行在 `127.0.0.1:3001`

我們使用 Nginx 作為反向代理，讓外部只需要存取 Port 80。

#### 步驟 1：建立反向代理設定檔

```bash
sudo vim /etc/nginx/sites-available/reverse-proxy
```

內容：

```nginx
server {
    listen 80;
    server_name proxy.lsa.moli;

    # 代理到服務 A
    location /service-a/ {
        proxy_pass http://${s110213027}.lsa.moli;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 代理到服務 B
    location /service-b/ {
        proxy_pass http://regchien.lsa.moli;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```

**重要參數說明**：

- `proxy_pass`：指定要轉發到的後端伺服器位址
- `proxy_set_header Host $host`：保留原始請求的 Host 標頭
- `proxy_set_header X-Real-IP $remote_addr`：傳遞客戶端真實 IP
- `proxy_set_header X-Forwarded-For`：記錄代理鏈中的所有 IP
- `proxy_set_header X-Forwarded-Proto`：告知後端使用的協定（http/https）

#### 步驟 2：啟用設定檔

```bash
sudo ln -s /etc/nginx/sites-available/reverse-proxy /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```

#### 步驟 3：測試

存取以下網址：
- `http://proxy.example.com/service-a/`
- `http://proxy.example.com/service-b/`


#### Nginx 負載平衡實作範例

```bash
sudo vim /etc/nginx/sites-available/load-balancer
```

內容：

```nginx
# 定義後端伺服器群組
upstream backend_servers {
    # 預設使用 Round Robin 
    server example.com;
    server example01.com;
    
    # 或使用其他演算法：
    # least_conn;  # 最少連線
    # ip_hash;     # IP Hash
}

server {
    listen 80;
    server_name lb.example.com;
    
    location / {
        proxy_pass http://backend_servers;
        #proxy_set_header Host $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
    }
}
```
:::info
**進階功能**：

Backup
```nginx
upstream backend_servers {
    # 健康檢查設定
    # max_fails=3: 連續失敗 3 次後標記為不可用
    # fail_timeout=30s: 標記為不可用後,30 秒內不會再嘗試連線
    server example.com max_fails=3 fail_timeout=30s;
    server example01.com max_fails=3 fail_timeout=30s;
    
    # 備用伺服器:只有所有主要伺服器都失敗時才使用
    server example02.com backup;
}
```
:::


---

## 實用工具與除錯技巧

:::info
### Nginx Log 存放位置 (Ubuntu 24.04 - apt 安裝)

**預設 Log 目錄**:
- 主要 Log 目錄: `/var/log/nginx/`
- Access Log (存取記錄): `/var/log/nginx/access.log`
- Error Log (錯誤記錄): `/var/log/nginx/error.log`

**查看 Log 的常用指令**:

```bash
# 即時監看 access log
sudo tail -f /var/log/nginx/access.log

# 即時監看 error log
sudo tail -f /var/log/nginx/error.log

# 查看最後 50 行 error log
sudo tail -n 50 /var/log/nginx/error.log

# 搜尋特定錯誤 (例如 502 錯誤)
sudo grep "502" /var/log/nginx/error.log

# 統計不同 HTTP 狀態碼的數量
sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# 查看最常訪問的 IP
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
```

**自訂 Log 位置** (在 Nginx 設定檔中):

```nginx
server {
    listen 80;
    server_name example.com;
    
    # 自訂 access log 位置
    access_log /var/log/nginx/example.com-access.log;
    
    # 自訂 error log 位置與記錄等級
    error_log /var/log/nginx/example.com-error.log warn;
    
    # 關閉 access log (不建議在正式環境使用)
    # access_log off;
}
```

**Log 記錄等級** (由低到高):
- `debug`: 除錯訊息 (最詳細)
- `info`: 資訊訊息
- `notice`: 一般通知
- `warn`: 警告訊息
- `error`: 錯誤訊息 (預設)
- `crit`: 嚴重錯誤
- `alert`: 需立即處理的問題
- `emerg`: 系統無法使用

**Log 輪替設定**:
- Log 輪替設定檔: `/etc/logrotate.d/nginx`
- 預設會自動壓縮與輪替舊的 log 檔案
- 避免 log 檔案過大佔用磁碟空間

```bash
# 查看 log 輪替設定
cat /etc/logrotate.d/nginx

# 手動執行 log 輪替 (測試用)
sudo logrotate -f /etc/logrotate.d/nginx
```
:::


### w3m - 文字界面瀏覽器

`w3m` 是一個基於終端機的網頁瀏覽工具，特別適合在 SSH 遠端環境中測試網頁。

#### 安裝

```bash
sudo apt install w3m
```

#### 使用方法

```bash
# 瀏覽本地網頁
w3m http://localhost

# 瀏覽遠端網頁
w3m https://www.google.com

# 查看本地 HTML 檔案
w3m /var/www/html/index.html
```

#### 完整快捷鍵列表

**基本導航**
- `q`：退出
- `Q`：不詢問直接退出
- `B`：返回上一頁
- `U`：輸入新網址
- `Tab`：跳到下一個連結
- `Shift+Tab`：跳到上一個連結
- `Enter`：開啟連結
- `ESC+Tab`：在新分頁開啟連結

**頁面操作**
- `Space` 或 `PageDown`：向下捲動一頁
- `b` 或 `PageUp`：向上捲動一頁
- `<` 或 `>`：左右捲動
- `/`：搜尋
- `n`：搜尋下一個
- `N`：搜尋上一個

**分頁管理**
- `T`：開啟新分頁
- `}`：切換到下一個分頁
- `{`：切換到上一個分頁
- `ESC+t`：顯示所有分頁列表

**檢視選項**
- `H`：顯示說明文件
- `o`：開啟選項設定面板
- `V`：顯示 HTML 原始碼
- `s`：切換搜尋模式
- `R`：重新載入頁面

**其他功能**
- `ESC+M`：開啟外部瀏覽器
- `ESC+e`：編輯目前網址
- `ESC+s`：儲存網頁
- `c`：顯示目前頁面的 URL
#### 實用場景

```bash
# 快速檢查 Nginx 是否正常運作
w3m http://localhost

# 測試虛擬主機設定
w3m http://example.com

# 檢查反向代理是否生效
w3m http://proxy.example.com/service-a/
```

#### Nginx 快取控制

在 Nginx 設定中控制快取：

```nginx
location ~* \.(jpg|jpeg|png|gif|ico)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

location ~* \.(css|js)$ {
    expires 7d;
    add_header Cache-Control "public";
}

location / {
    # 禁用快取（適合開發環境）
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
    add_header Expires "0";
}
```