Chuyển đến nội dung chính

第2課:Nginx 基本設定

學習 Nginx 設定,包含 nginx.conf 語法、context(http/server/location)、基本 directive。 指導建立虛擬主機、提供靜態檔案、index 檔案、autoindex 和自訂錯誤頁面。 包含實際範例和正式環境最佳實踐。

🔒 DevSecOps — 第2課 第2課:Nginx 基本設定

Nginx 從入門到進階

第1部:基礎

xdev.asia

1. nginx.conf 設定檔語法

nginx.conf 是 Nginx 的核心,定義了整個 Web 伺服器的運作方式。理解設定語法是掌握 Nginx 的第一步。

1.1. 基本結構

# 簡單 directive (simple directive)
worker_processes 4;

區塊 directive (block directive)

events { worker_connections 1024; }

巢狀區塊 (nested blocks)

http { server { location / { root /var/www/html; } } }

1.2. 語法規則

1. Directive:

  • 每個 directive 以分號 ; 結尾
  • Directive 可以是 simple(單行)或 block(含 {})
  • 大小寫敏感:Root 與 root 不同
# 正確
worker_processes 2;

錯誤 - 缺少分號

worker_processes 2

錯誤 - 大小寫錯誤

Worker_Processes 2;

2. 註解:

# 這是單行註解
worker_processes 4;  # 行尾註解

Nginx 沒有多行註解

每行都必須使用

3. 引入檔案:

# 引入其他檔案
include /etc/nginx/mime.types;

使用萬用字元引入多個檔案

include /etc/nginx/conf.d/.conf; include /etc/nginx/sites-enabled/;

4. 變數:

# Nginx 有許多內建變數

以 $ 開頭

$remote_addr # 用戶端 IP $request_uri # 請求的 URI $host # 主機名稱

使用範例

location / { return 200 "Your IP: $remote_addr\n"; }

5. 字串值:

# 簡單值不需要引號
root /var/www/html;

含有空格或特殊字元時需要引號

error_log "/var/log/nginx/error.log" warn; add_header X-Custom-Header "Hello World";

可使用單引號或雙引號

root '/var/www/html'; root "/var/www/html";

1.3. 單位與大小

# 時間單位
client_body_timeout 60s;      # 秒(預設)
client_body_timeout 60;       # 也是秒
client_body_timeout 60m;      # 分鐘
client_body_timeout 1h;       # 小時
client_body_timeout 1d;       # 天

大小單位

client_max_body_size 10m; # 百萬位元組(megabytes) client_max_body_size 10M; # 也是 megabytes client_max_body_size 1g; # gigabytes client_max_body_size 1024k; # kilobytes client_max_body_size 1048576; # bytes(無單位)

1.4. 測量單位

# 無單位 = bytes
client_max_body_size 1048576;  # 1MB

k/K = kilobytes

client_max_body_size 1024k;

m/M = megabytes

client_max_body_size 1m;

g/G = gigabytes (Nginx 0.7.0+)

client_max_body_size 1g;


2. Context 與 Directive

Nginx 使用 context 系統按層級整理設定。每個 context 定義了 directive 的適用範圍。

2.1. 主要 Context

# MAIN CONTEXT(全域)
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

EVENTS CONTEXT

events { worker_connections 1024; use epoll; }

HTTP CONTEXT

http { # 適用於所有 HTTP 流量

# SERVER CONTEXT
server {
    # 適用於特定虛擬主機
    
    # LOCATION CONTEXT
    location / {
        # 適用於特定 URL 模式
    }
}

}

STREAM CONTEXT(TCP/UDP 用)

stream { server { listen 3306; } }

MAIL CONTEXT(郵件代理用)

mail { server { listen 25; } }

2.2. HTTP Context — 全域設定

http {
# MIME 類型
include /etc/nginx/mime.types;
default_type application/octet-stream;

# 記錄
log_format main '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent"';

access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;

# 效能
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

# Gzip 壓縮
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript;

# 安全性標頭
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

# 引入 server block
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;

}

2.3. Server Context — 虛擬主機

http {
# Server block 1
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com;

    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;
}

# Server block 2
server {
    listen 80;
    server_name blog.example.com;
    root /var/www/blog;
}

# 預設伺服器(catch-all)
server {
    listen 80 default_server;
    server_name _;
    return 444;  # 關閉連線
}

}

2.4. Location Context — URL 比對

server {
listen 80;
server_name example.com;
root /var/www/html;

# 完全比對
location = /about {
    # 僅比對 /about
}

# 前綴比對
location /images/ {
    # 比對 /images/*、/images/photo.jpg 等
}

# 正規表示式比對(大小寫敏感)
location ~ \.(jpg|png|gif)$ {
    # 比對以 .jpg、.png、.gif 結尾的檔案
}

# 正規表示式比對(大小寫不敏感)
location ~* \.(jpg|png|gif)$ {
    # 比對 JPG、jpg、JpG 等
}

# 前綴比對(停止正規表示式檢查)
location ^~ /api/ {
    # 比對 /api/* 並停止正規表示式檢查
}

# 預設 location
location / {
    # 其他都不符合時比對所有請求
}

}

2.5. Location 比對優先順序

Nginx 依優先順序處理 location:

  1. = - 完全比對(最高)
  2. ^ - 前綴比對(停止正規表示式)
  3. 或 ~* - 正規表示式比對(依檔案中出現順序)
  4. 無修飾符 - 前綴比對(最低)

說明範例:

server {
listen 80;
server_name example.com;

# 優先度1 - 完全比對
location = /test {
    return 200 "Exact match: /test\n";
}

# 優先度2 - 前綴(停止正規表示式)
location ^~ /test {
    return 200 "Prefix match (^~): /test*\n";
}

# 優先度3 - 正規表示式(大小寫不敏感)
location ~* ^/test {
    return 200 "Regex match (~*): /test*\n";
}

# 優先度4 - 前綴比對
location /test {
    return 200 "Prefix match: /test*\n";
}

# 預設
location / {
    return 200 "Default location\n";
}

}

測試結果:

curl http://example.com/test

→ "Exact match: /test"

curl http://example.com/test123

→ "Prefix match (^): /test*"(因為 ^ 停止了正規表示式)

若移除 ^~ location:

curl http://example.com/test123

→ "Regex match (~): /test"


3. 設定虛擬主機(Server Blocks)

虛擬主機讓單一 Nginx 伺服器能服務多個網站和網域。

3.1. 建立第一個虛擬主機

步驟1:建立網站目錄

# 建立文件根目錄
sudo mkdir -p /var/www/mysite.com/html

建立日誌目錄

sudo mkdir -p /var/www/mysite.com/logs

設定擁有者

sudo chown -R $USER:$USER /var/www/mysite.com sudo chmod -R 755 /var/www/mysite.com

步驟2:建立範例 HTML 檔案

cat > /var/www/mysite.com/html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Welcome to mysite.com</title>
<style>
body { font-family: Arial, sans-serif; margin: 50px; }
h1 { color: #00539C; }
</style>
</head>
<body>
<h1>Welcome to mysite.com!</h1>
<p>This is my first Nginx virtual host.</p>
</body>
</html>
EOF

步驟3:建立虛擬主機設定檔

# Ubuntu/Debian
sudo nano /etc/nginx/sites-available/mysite.com

CentOS/RHEL

sudo nano /etc/nginx/conf.d/mysite.com.conf

設定檔內容:

server {
# 埠號與伺服器名稱
listen 80;
listen [::]:80;
server_name mysite.com www.mysite.com;

# 文件根目錄
root /var/www/mysite.com/html;
index index.html index.htm;

# 日誌
access_log /var/www/mysite.com/logs/access.log;
error_log /var/www/mysite.com/logs/error.log;

# 主要 location
location / {
    try_files $uri $uri/ =404;
}

# 錯誤頁面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

location = /404.html {
    internal;
}

location = /50x.html {
    internal;
}

# 拒絕存取隱藏檔案
location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
}

}

步驟4:啟用虛擬主機(Ubuntu/Debian)

# 建立符號連結
sudo ln -s /etc/nginx/sites-available/mysite.com /etc/nginx/sites-enabled/

檢查設定

sudo nginx -t

重新載入 Nginx

sudo systemctl reload nginx

步驟5:設定 DNS 或 hosts 檔案

# 新增至 /etc/hosts(本機測試用)
sudo nano /etc/hosts

新增以下行:

127.0.0.1 mysite.com www.mysite.com

步驟6:測試

curl http://mysite.com

或開啟瀏覽器:http://mysite.com

3.2. 多網域的虛擬主機

# 設定1:同一內容對應多個網域
server {
listen 80;
server_name mysite.com www.mysite.com example.com www.example.com;
root /var/www/mysite.com/html;
index index.html;
}

設定2:子網域

server { listen 80; server_name blog.mysite.com; root /var/www/blog; index index.html; }

server { listen 80; server_name shop.mysite.com; root /var/www/shop; index index.html; }

設定3:萬用字元子網域

server { listen 80; server_name *.mysite.com; root /var/www/subdomains/$host;

# $host 將包含 subdomain.mysite.com

}

設定4:正規表示式伺服器名稱

server { listen 80; server_name ~^(www.)?(?<domain>.+)$; root /var/www/$domain; }

3.3. 預設伺服器(Catch-all)

# 預設伺服器處理不符合的請求
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;  # 底線 = 不在乎伺服器名稱

# 選項1:回傳 444(關閉連線)
return 444;

# 選項2:回傳 403 Forbidden
# return 403;

# 選項3:重新導向到主站
# return 301 https://mainsite.com$request_uri;

# 選項4:顯示維護頁面
# root /var/www/default;
# index maintenance.html;

}

3.4. 進階 Listen Directive

server {
# IPv4
listen 80;

# IPv6
listen [::]:80;

# 特定 IP
listen 192.168.1.100:80;

# 不同埠號
listen 8080;

# 預設伺服器
listen 80 default_server;

# SSL
listen 443 ssl;
listen [::]:443 ssl;

# HTTP/2
listen 443 ssl http2;

# 多個選項
listen 80 default_server reuseport;

}


4. 提供靜態檔案

Nginx 擅長提供靜態內容(HTML、CSS、JS、圖片)。

4.1. 基本設定

server {
listen 80;
server_name static.example.com;

# 文件根目錄
root /var/www/static;

# Index 檔案
index index.html index.htm;

# 主要 location
location / {
    try_files $uri $uri/ =404;
}

}

目錄結構:

/var/www/static/
├── index.html
├── css/
│   ├── style.css
│   └── bootstrap.css
├── js/
│   ├── app.js
│   └── jquery.js
└── images/
├── logo.png
└── background.jpg

處理的請求:

http://static.example.com/              → /var/www/static/index.html
http://static.example.com/css/style.css → /var/www/static/css/style.css
http://static.example.com/images/logo.png → /var/www/static/images/logo.png

4.2. Root 與 Alias

Root directive:

location /images/ {
root /var/www/static;
}

請求:/images/photo.jpg

檔案路徑:/var/www/static/images/photo.jpg

(root + location 路徑)

Alias directive:

location /images/ {
alias /var/www/photos/;
}

請求:/images/photo.jpg

檔案路徑:/var/www/photos/photo.jpg

(alias 取代 location 路徑)

詳細範例:

server {
listen 80;
server_name example.com;

# 使用 root
location /static/ {
    root /var/www;
}
# /static/style.css → /var/www/static/style.css

# 使用 alias
location /assets/ {
    alias /var/www/static/;
}
# /assets/style.css → /var/www/static/style.css

# 完整路徑的 alias
location = /favicon.ico {
    alias /var/www/icons/favicon.ico;
}

}

注意:使用 alias 時,若 alias 以 / 結尾,則 location 路徑也必須以 / 結尾。

4.3. Try_files Directive

# 語法
try_files file ... uri;
try_files file ... =code;

範例1:依序檢查檔案、資料夾,否則回傳 404

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

範例2:退回至 index.html(SPA 用)

location / { try_files $uri $uri/ /index.html; }

範例3:檢查多個檔案

location / { try_files $uri $uri/index.html $uri.html =404; }

範例4:退回至後端

location / { try_files $uri $uri/ @backend; }

location @backend { proxy_pass http://localhost:3000; }

4.4. 各類型檔案的設定

server {
listen 80;
server_name cdn.example.com;
root /var/www/cdn;

# HTML 檔案
location ~ \.html$ {
    add_header Cache-Control "public, max-age=3600";
}

# CSS 與 JavaScript
location ~ \.(css|js)$ {
    add_header Cache-Control "public, max-age=31536000";
    access_log off;
}

# 圖片
location ~ \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
    add_header Cache-Control "public, max-age=31536000";
    access_log off;
    expires 1y;
}

# 字型
location ~ \.(woff|woff2|ttf|otf|eot)$ {
    add_header Cache-Control "public, max-age=31536000";
    add_header Access-Control-Allow-Origin "*";
    access_log off;
}

# 影片
location ~ \.(mp4|webm|ogg)$ {
    add_header Cache-Control "public, max-age=31536000";
    mp4;  # 啟用 MP4 串流
    access_log off;
}

# 下載
location /downloads/ {
    add_header Content-Disposition "attachment";
}

}

4.5. 靜態檔案的安全性

server {
listen 80;
root /var/www/html;

# 拒絕存取隱藏檔案
location ~ /\. {
    deny all;
    access_log off;
    log_not_found off;
}

# 拒絕存取備份檔案
location ~ ~$ {
    deny all;
    access_log off;
    log_not_found off;
}

# 拒絕存取設定檔案
location ~ \.(conf|config|yml|yaml|ini)$ {
    deny all;
}

# 保護敏感目錄
location ~ ^/(\.git|\.svn|\.env) {
    deny all;
}

}


5. 設定 Index 檔案與 Autoindex

5.1. Index Directive

# 語法
index file ...;

範例1:預設 index

server { listen 80; root /var/www/html; index index.html index.htm; }

範例2:多個 index 檔案(依順序)

server { listen 80; root /var/www/html; index index.php index.html index.htm default.html; }

範例3:各 location 使用不同 index 檔案

server { listen 80; root /var/www/html;

location / {
    index index.html;
}

location /blog/ {
    index index.php;
}

location /docs/ {
    index readme.md index.html;
}

}

5.2. Autoindex(目錄清單)

# 啟用 autoindex
server {
listen 80;
server_name files.example.com;
root /var/www/files;

location / {
    autoindex on;
}

}

Autoindex 詳細設定

location /downloads/ { autoindex on; # 啟用目錄清單 autoindex_exact_size off; # 以 KB、MB 顯示大小而非 bytes autoindex_localtime on; # 顯示本地時間而非 GMT autoindex_format html; # 格式:html、xml、json、jsonp }

JSON 格式範例

location /api/files/ { autoindex on; autoindex_format json; }

Autoindex 輸出:

Index of /downloads/

../ file1.pdf 23-Nov-2024 10:30 2.5M file2.zip 22-Nov-2024 15:45 15M folder/ 20-Nov-2024 09:00 -

5.3. 自訂 Autoindex 樣式

server {
listen 80;
root /var/www/files;

location / {
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;
    
    # 新增自訂頁首/頁尾
    add_before_body /autoindex/header.html;
    add_after_body /autoindex/footer.html;
}

location /autoindex/ {
    internal;
    alias /var/www/autoindex/;
}

}

header.html 檔案:

<!DOCTYPE html>
<html>
<head>
<title>File Directory</title>
<style>
body { font-family: Arial; margin: 20px; }
h1 { color: #333; }
a { color: #0066cc; text-decoration: none; }
a:hover { text-decoration: underline; }
</style>
</head>
<body>
<h1>File Directory</h1>
<hr>

footer.html 檔案:

    <hr>
<p>© 2024 My Company</p>
</body>
</html>

6. 自訂錯誤頁面

6.1. 基本設定

server {
listen 80;
server_name example.com;
root /var/www/html;

# 自訂錯誤頁面
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

# 錯誤頁面的 location
location = /404.html {
    internal;  # 僅供內部存取
}

location = /50x.html {
    internal;
}

}

6.2. 詳細的錯誤頁面

建立 404.html 檔案:

cat > /var/www/html/404.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>404 - Page Not Found</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 50px;
background: #f5f5f5;
}
h1 { font-size: 72px; color: #e74c3c; }
p { font-size: 24px; color: #555; }
a { color: #3498db; text-decoration: none; }
</style>
</head>
<body>
<h1>404</h1>
<p>Oops! Page not found.</p>
<p><a href="/">← Go back home</a></p>
</body>
</html>
EOF

建立 50x.html 檔案:

cat > /var/www/html/50x.html << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>500 - Server Error</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
padding: 50px;
background: #f5f5f5;
}
h1 { font-size: 72px; color: #e67e22; }
p { font-size: 24px; color: #555; }
</style>
</head>
<body>
<h1>500</h1>
<p>Internal Server Error</p>
<p>We're working on it!</p>
</body>
</html>
EOF

6.3. 進階錯誤頁面

server {
listen 80;
server_name example.com;
root /var/www/html;

# 各 location 的錯誤頁面
location / {
    error_page 404 /errors/404.html;
}

location /api/ {
    error_page 404 /errors/api-404.json;
    error_page 500 /errors/api-500.json;
}

# 含自訂訊息的錯誤頁面
location /special/ {
    error_page 404 =200 /custom-404.html;
    # =200 覆寫狀態碼
}

# 重新導向至外部錯誤頁面
location /old-site/ {
    error_page 404 = @external_error;
}

location @external_error {
    return 302 https://example.com/error-handler;
}

# 含變數的錯誤頁面
location /dynamic/ {
    error_page 404 /404.html?page=$uri;
}

# 錯誤用的具名 location
error_page 404 = @notfound;

location @notfound {
    return 404 "Custom 404 message\n";
}

}

6.4. 含格式的錯誤記錄

http {
# 定義自訂錯誤記錄格式
log_format error_log '[$time_local] $status $request '
'Client: $remote_addr '
'Server: $server_name';

server {
    listen 80;
    server_name example.com;
    
    # 使用自訂格式
    error_log /var/log/nginx/example.error.log error_log;
    
    # 不同的日誌層級
    error_log /var/log/nginx/debug.log debug;
}

}


7. 實作練習

練習1:建立虛擬主機

  1. 為 mysite.local 建立虛擬主機
  2. 文件根目錄:/var/www/mysite
  3. 建立包含任意內容的 index.html
  4. 新增至 /etc/hosts 並測試

練習2:靜態檔案伺服器

  1. 建立目錄結構:
/var/www/static/
├── index.html
├── css/style.css
├── js/app.js
└── images/logo.png
  1. 設定 Nginx 提供這些檔案
  2. 為各類型檔案設定不同的快取標頭

練習3:目錄清單

  1. 為 files.local 建立虛擬主機
  2. 啟用 autoindex
  3. 自訂格式與樣式
  4. 用多個檔案測試

練習4:自訂錯誤頁面

  1. 建立自訂 404 和 500 頁面
  2. 套用至虛擬主機
  3. 存取不存在的 URL 進行測試
  4. 測試 500 錯誤(可用 return 500 模擬)

練習5:多個虛擬主機

  1. 建立 3 個虛擬主機:
    • site1.local → /var/www/site1
    • site2.local → /var/www/site2
    • blog.site1.local → /var/www/blog
  2. 每個網站有不同的內容
  3. 設定並測試全部

8. 常見問題排解

錯誤1:403 Forbidden

# 原因:權限
ls -la /var/www/html

修正:設定正確的擁有者

sudo chown -R www-data:www-data /var/www/html sudo chmod -R 755 /var/www/html

原因:SELinux(CentOS)

sudo setenforce 0

錯誤2:404 Not Found

# 檢查 root directive
location / {
root /var/www/html;  # 這個路徑正確嗎?
index index.html;    # 這個檔案存在嗎?
}

用 curl 檢查

curl -I http://example.com

錯誤3:設定未重新載入

# 先測試設定
sudo nginx -t

若 OK 則重新載入

sudo systemctl reload nginx

查看錯誤記錄

sudo tail -f /var/log/nginx/error.log

錯誤4:伺服器名稱無效

# 檢查 DNS/hosts
cat /etc/hosts

檢查 server_name directive

grep server_name /etc/nginx/sites-available/*

清除瀏覽器快取

或用 curl 測試

curl -H "Host: mysite.com" http://localhost


9. 最佳實踐

  1. 整理設定檔案:
/etc/nginx/
├── nginx.conf(主要設定)
├── conf.d/(全域設定)
└── sites-available/(個別網站)
  1. 明確的註解:
# 封鎖垃圾機器人
if ($http_user_agent ~* (bot|crawler|spider)) {
return 403;
}
  1. 使用 include:
http {
include /etc/nginx/mime.types;
include /etc/nginx/conf.d/*.conf;
}
  1. 重新載入前先測試:
sudo nginx -t && sudo systemctl reload nginx
  1. 備份設定:
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup

總結

在本課中,您學到了:

  • ✅ nginx.conf 語法與結構
  • ✅ Nginx 的 context 與 directive
  • ✅ 建立與管理虛擬主機
  • ✅ 高效提供靜態檔案
  • ✅ 設定 index 檔案與 autoindex
  • ✅ 自訂錯誤頁面

下一課:我們將探討記錄與監控——如何追蹤和分析 Nginx 伺服器的流量。