# nginx ## References + 🎬 [**程序員魚皮 - 光速入門 Nginx**](https://youtu.be/VjJmEf8muow) + 🎬 [**程序員魚皮 - 負載均衡**](https://youtu.be/XRvR_3fIqFU) + 🎬 [**技術蛋老師 - Nginx 入門必須懂 3 大配置**](https://youtu.be/wnO7xlm-yIo) + 🔗 [**nginx - Beginner’s Guide**](https://nginx.org/en/docs/beginners_guide.html) ## Setup > 創建一個目錄,其路徑設定為環境變數 `NGINX_HOME`,之後網站內容都會在這個目錄 ``` nginx ├─ conf │ └─ nginx.conf ├─ html │ └─ index.html ├─ logs └─ temp └─ client_body_temp ``` ## Commands | 參數 | 功能 | | - | - | | `-h` | 說明 | | `-v` | 版本號 | | `-t` | 測試 config 語法正確性 | | `-T` | 顯示 config 內容並測試語法 | | `-q` | 安靜模式 | | `-g "<directives>"` | 全域指令<br><span style="color:grey;">(比如 `"daemon off;"` 是在背景執行)</span> | | `-s <signal>` | 傳送控制訊號給主進程<br><span style="color:grey;">(🚨 `stop`、`quit`、`reload`、`reopen`)</span> | | `-p <prefix>` | 指定 nginx 工作目錄<br><span style="color:grey;">(🚨 config 中所有路徑皆相對於此)</span> | | `-c <file>` | 指定設定檔路徑<br><span style="color:grey;">(🚨 預設 `conf/nginx.conf`)</span> | ## Phase ``` 1. 解析 config 2. 接收 request 3. 匹配 server / location 4. rewrite 5. access 6. try_files / content 7. log ``` ## Config ```nginx events {} http { ... } stream { ... } ``` ### `$1` + 說明 + <mark>若 location 使用 regex math 的話,可以使用 capture grioup</mark> ### `$request_uri` / `$uri` / `$args` + 說明 + `$request_uri`:<mark>請求 URI</mark> + `$uri`:<mark>請求路由</mark> + `$args`:<mark>請求 query</mark> + 範例 + `$request_uri`:`/api/user?id=10&name=Rogelio` + `$uri`:`/api/user` + `$args`:`id=10&name=Rogelio` ### `listen` + 說明 + <mark>指定監聽的 port,預設為 80</mark> ### `root` + 說明 + <mark>某個 `location` 路由所對應的 file system 目錄</mark> + 若 `location` 路由無設定 `root`,會以 `server` 區塊定義的 `root` 作為預設值 + 範例 ```nginx server { listen 80; root /data/up1; # root: /data/up1 location / { } # root: /data/static location /images/ { root /data/static; } } ``` ### `index` + 說明 + <mark>請求路由對應到的是 file system 的目錄時,要回傳哪個檔案</mark> + <mark>預設值是 `index.html`</mark>,可自己指定多個 + 範例 ```nginx server { listen 80; root /data/www; # 若請求 / ,會依序尋找 index.html → index.htm → home.html index index.html index.htm home.html; location / { } } ``` ### `location` + 說明 + <mark>匹配請求路由</mark> + 匹配模式 + prefix match + 找出所有與請求路由開頭相符的區塊,記住 <mark>longest prefix 的那個 location</mark> ```nginx # 👉 請求 /images/icons/logo.png location / { ... } location /images/ { ... } location /images/icons/ { ... } # 👉 longest prefix 為 /images/icons/ ``` + regex match + prefix match 結束後,再輪到 regex match + <mark>若 regex match 有出現匹配,優先選擇此 location</mark> + 若 regex match 無出現匹配,選擇先前 longest prefix 的那個 location + 符號 + `~`:使用 regex、case-sensitive + `~*`:使用 regex、case-insensitive ### `try_files` + 說明 + <mark>對已匹配的請求路由,進行各種拼接嘗試,看是否能找出一個檔案回傳</mark> + 範例 ```nginx server { root /data/www; index index.html; location / { try_files $uri $uri/ =404; } } # 請求路由:/data/www/admin/dashboard # 檢查 $uri:/data/www/admin/dashboard # (🤔 沒有這個檔案) # 檢查 $uri/:/data/www/admin/dashboard/ # (✅ 這是個目錄,嘗試導向它的 index.html,假設真的有這檔案) # fallbak:404 response ``` ### `proxy_pass` + 說明 + <mark>將請求轉發(反向代理)到其他 URI</mark> + 範例 ```nginx # --- 反向代理 --- server { # API:轉發給後端 location /api/ { proxy_pass http://localhost:8000/; # 只轉發 API 給 FastAPI } # 圖片:由 Nginx 提供 location /images/ { root /data; } # 前端頁面:由 Nginx 提供 location / { root /data/www; try_files $uri $uri/ /index.html; } } ``` ### `server_name` + 說明 + <mark>匹配 domain name</mark> + 範例 > 假設 server IP 為 203.0.113.10,\ > example.com 和 rogeliokg.com 的 DNS A record 即為 203.0.113.10。\ > 雖然 client 都是由同一個 IP 和 port 訪問, > 但 nginx 可以藉由 HTTP 的 host header 來自動分流。 ```nginx server { listen 80; server_name example.com; root /data/www/example; } server { listen 80; server_name rogeliokg.com; root /data/www/rogeliokg; } ``` ### `error_page` + 說明 + 自訂錯誤頁面 + 範例 ```nginx server { listen 80; server_name example.com; root /data/www; index index.html; # 自訂 404 頁面 error_page 404 /404.html; location / { try_files $uri $uri/ /index.html; } } ``` ```nginx # 可指定多種錯誤 error_page 403 404 500 502 503 /error.html; ``` ### `gzip` + 說明 + <mark>傳輸檔案時,壓縮檔案</mark> + 範例 ```nginx http { # 開啟 gzip 壓縮 gzip on; # 指定哪些 MIME 類型的回應要壓縮 gzip_types text/plain text/css application/javascript application/json application/xml; # 小於 1KB 的內容不壓縮 gzip_min_length 1024; # 壓縮等級 (1-9,越高越慢但壓縮率更好) gzip_comp_level 5; # 讓代理伺服器可根據是否支援 gzip 快取不同版本 gzip_vary on; } ``` ### `expires` + 說明 + <mark>瀏覽器快取時間</mark> + 範例 ```nginx location ~* \.(js|css)$ { expires 30d; } location ~* \.(png|jpg|jpeg|gif|svg)$ { expires 90d; } ``` ### `add-header` + 說明 + <mark>在 response 時,額外加上 header</mark> + 範例 ```nginx server { # HTTPS listen 443 ssl; # 不允許被 <iframe> 嵌入,防止點擊劫持 add_header X-Frame-Options DENY; # 防止 MIME 類型偽造攻擊 add_header X-Content-Type-Options nosniff; # 啟用瀏覽器的基本 XSS 防護 add_header X-XSS-Protection "1; mode=block"; # 使用 HTTPS 時強制瀏覽器自動轉向 HTTPS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; } ``` ### `return` + 說明 + *ngx_http_rewrite_module redirect* + <mark>回傳的 response</mark> + 範例 ```nginx location /hello { add_header Content-Type text/plain; return 200 "Hello Nginx!"; } ``` + `return <code> <text>`:回傳文字 + `return <code> <url>`:重導向 ### `last` + 說明 + *ngx_http_rewrite_module redirect* + <mark>結束 rewrite 階段</mark> (後方 *ngx_http_rewrite_module redirect* 取消執行) + <mark>回到 server / location 階段</mark> (重新匹配改寫後的請求路由) ### `break` + 說明 + *ngx_http_rewrite_module redirect* + <mark>結束 rewrite 階段</mark> (後方 *ngx_http_rewrite_module redirect* 取消執行) + <mark>不會回到 server / location 階段</mark> ### [`rewrite`](https://blog.yuyansoftware.com.tw/2024/01/nginx-rewrite-return-301/) + 說明 + *ngx_http_rewrite_module redirect* + <mark>改寫請求路由</mark> + `rewrite <regex> <replacement> <flag>` + 範例 > `/path1` 內容:You are in path3\ > `/path2` 內容:(`/path4/index.html` 的內容)\ > `/path3` 內容:You are in path3 ```nginx server { location /path1 { rewrite /path1 /path3 last; return 200 'Hello from path1'; add_header Content-Type text/plain; } location /path2 { rewrite /path2 /path4 break; try_files $uri $uri/; } location /path3 { return 200 'You are in path3'; add_header Content-Type text/plain; } } ``` ### `set` + 說明 + *ngx_http_rewrite_module redirect* + <mark>設定變數</mark> ### `if` + 說明 + *ngx_http_rewrite_module redirect* + <mark>條件控制</mark> ### `include` + 說明 + <mark>引入外部設定檔</mark> (例如:`mime.types`) ### `default_type` + 說明 + <mark>當無法判斷檔案 MIME 類型時使用的預設值</mark> (例如:`application/octet-stream`) ## Reverse Proxy > **核心目的**:統一前端請求路徑為 `/api`,解決 CORS 問題,並保持開發與生產環境架構一致。 #### 1. 開發環境 (Development) **檔案**:`vite.config.ts` **原理**:利用 Vite Dev Server 轉發請求。 ```typescript export default defineConfig({ server: { proxy: { '/api': { target: 'http://localhost:8080', // 後端真實位址 changeOrigin: true, // 欺騙後端這來自同源 rewrite: (path) => path.replace(/^\/api/, '') // (選用) 若後端路由無 /api 則移除 } } } }) ``` #### 2. 生產環境 (Production) **檔案**:`nginx.conf` **原理**:利用 Nginx 轉發請求至後端服務。 ```nginx server { listen 80; server_name www.app.com; # 處理前端 SPA 路由 (防止重新整理 404) location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; } # 處理 API 轉發 location /api/ { # 注意結尾斜線:若有 /,Nginx 會自動把 /api 去掉才轉給後端 proxy_pass http://backend-service:8080/; # 必要 Header:讓後端知道真實 Domain 與 User IP proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up