# 網頁伺服器 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"; } ```