Skip to content

03 · 配置文件结构 · 五层洋葱

生活类比:Nginx 配置文件就像一座写字楼

  • 整栋楼(main 块) → 物业管的事:用电、监控、保洁
  • 进出门禁(events 块) → 门卫怎么登记访客
  • 办公区域(http 块) → 公司租了哪一片
  • 每家公司(server 块) → 一个虚拟主机(一个网站)
  • 公司里的部门(location 块) → 不同 URL 路径的处理规则

1. 一张图把整体结构刻进脑子

┌─────────────────────────────────────────────────────┐
│  main(全局)                                       │
│   ├─ user / worker_processes / pid / error_log     │
│   │                                                 │
│   ├─ events { ... }                                 │
│   │     └─ worker_connections                      │
│   │                                                 │
│   └─ http {                                         │
│        ├─ include mime.types                       │
│        ├─ log_format / access_log                  │
│        ├─ sendfile / keepalive_timeout / gzip      │
│        │                                            │
│        ├─ upstream backend { ... }                 │
│        │                                            │
│        ├─ server {                                  │
│        │    listen 80;                             │
│        │    server_name foo.com;                   │
│        │    location / { ... }                      │
│        │    location /api/ { ... }                 │
│        │ }                                          │
│        │                                            │
│        └─ server { ... 第二个网站 ... }             │
│      }                                              │
└─────────────────────────────────────────────────────┘

记住这 5 层就够了:main → events → http → server → location


2. 第 1 层 · main(全局)

直接写在文件顶部,不在任何 {}

nginx
user  nginx;                    # 用什么用户跑 worker(安全建议非 root)
worker_processes  auto;         # 几个工作进程,auto = CPU 核数
worker_rlimit_nofile 65535;     # 每个进程最大可打开文件数(含 socket)

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

生活类比:物业告诉门卫"今天上班几个保安、每人最多记多少个访客"。

关键指令意义推荐值
userworker 进程跑在哪个 OS 用户下nginx / www-data
worker_processes工作进程数量auto(= CPU 核心数)
worker_rlimit_nofile单进程最大文件描述符至少 65535
error_log错误日志路径 + 级别(debug/info/warn/error)warnerror
pid主进程 PID 文件/run/nginx.pid

3. 第 2 层 · events

nginx
events {
    use epoll;                  # Linux 上最高性能的 I/O 多路复用
    worker_connections 10240;   # 每个 worker 同时能处理多少连接
    multi_accept on;            # 一次循环尽量多 accept 新连接
}

生活类比:门卫用什么"对讲机型号"(epoll/kqueue)、一次能放几个人进来。

⚠️ 重要公式max_clients = worker_processes × worker_connections 例子:4 核机器 + 默认配置 → 4 × 10240 ≈ 4 万并发连接


4. 第 3 层 · http(全站通用配置)

nginx
http {
    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;

    # 性能相关
    sendfile        on;          # 零拷贝传输文件
    tcp_nopush      on;          # 攒包再发
    keepalive_timeout 65;        # 长连接保活时间

    # 压缩
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;

    # 引入子配置(推荐拆分到 conf.d/*.conf)
    include /etc/nginx/conf.d/*.conf;
}

生活类比:写字楼物业贴在大堂的"全楼通用规定"——日志怎么记、是否要节能开关(gzip)、所有公司都得遵守。


5. 第 4 层 · server(一个网站)

nginx
server {
    listen       80;
    server_name  example.com www.example.com;

    root   /var/www/example;
    index  index.html;

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

每个 server 块 = 一个虚拟主机 = 一个网站。

生活类比:写字楼里有十几家公司,每家都有自己的"门牌号"(server_name)和"前台"(location)。

5.1 listen 的几种写法

nginx
listen 80;                    # 监听 IPv4 80 端口
listen 443 ssl http2;         # 监听 443 + 启用 SSL + HTTP/2
listen [::]:80;               # 监听 IPv6
listen 8080 default_server;   # 该端口的"默认网站",没匹配上其他 server_name 时来这

5.2 server_name 匹配优先级(重要⚠️)

nginx
server_name  example.com           # ① 精确匹配
             *.example.com         # ② 前缀通配
             example.*             # ③ 后缀通配
             ~^(www|api)\.example  # ④ 正则匹配

优先级:① > ② > ③ > ④ > default_server


6. 第 5 层 · location(最常用)

location 决定这个 URL 路径怎么处理——location 是 Nginx 配置的"灵魂",第 7 章会专门讲匹配规则,这里先看个皮毛:

nginx
server {
    location / {
        # 兜底规则:所有路径
        root /var/www/html;
        index index.html;
    }

    location /static/ {
        # 静态资源
        alias /var/www/cdn/;
        expires 7d;
    }

    location /api/ {
        # 反向代理到后端
        proxy_pass http://localhost:3000/;
    }

    location ~* \.(jpg|png|gif)$ {
        # 图片:1 年强缓存
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

生活类比:公司前台贴的"业务办理指引"——

  • "前台办的(/)" → 自己处理
  • "图片复印(*.jpg)" → 给个长期通行证
  • "技术维修(/api/)" → 转给二楼工程部

7. 配置文件加载机制 · 一句话

nginx.conf
  ├─ include conf.d/*.conf    ← 主流大厂这么拆
  └─ include sites-enabled/*  ← Debian 系默认拆法

最佳实践

  • 公共配置写在 nginx.conf(main + events + http 头部)
  • 每个网站单独建一个 conf.d/<site>.conf(一个 server 块)
  • 改 conf 后必跑 nginx -tnginx -s reload

8. 配置继承规则 · 父子关系

外层定义的,内层默认继承;内层重新定义的,覆盖外层。

nginx
http {
    gzip on;                    # ← 父层

    server {
        # 这里没写 gzip → 继承 http 的 on

        location /api/ {
            gzip off;           # ← 子层覆盖:API 不压缩
        }
    }
}

生活类比:物业全楼禁烟(gzip on),但 22 楼老板特批办公室能抽烟(局部 gzip off)。


9. 变量系统 · 写灵活配置的关键

Nginx 内置一堆变量(以 $ 开头),方便你在 if / proxy_set_header / log_format 里用:

变量含义
$host请求的 Host 头
$remote_addr客户端 IP
$request_uri完整 URI(带 query,如 /foo?x=1
$uri规范化的 URI(不含 query,可被改写)
$args / $query_stringURL 后面的查询字符串
$request_methodGET / POST / ...
$http_user_agent浏览器 UA
$cookie_<name>取某个 cookie
$arg_<name>取某个 query 参数
$schemehttp 或 https

应用举例 —— 接口防盗链

nginx
location /api/ {
    if ($http_referer !~* ^https?://(www\.)?example\.com) {
        return 403;
    }
    proxy_pass http://backend/;
}

10. 一份新手能直接抄的最小 nginx.conf

下方"💻 示例代码"里有 nginx.conf(带详细中文注释)和 example.com.conf(一个 server 块的标准模板)。


11. ⚠️ 配置常见错误

  1. {} 没配对nginx -t 直接告诉你"unexpected }"
  2. 指令末尾忘了 ; → 同上
  3. include 路径错了 → 仔细看 nginx -t 输出
  4. server_name 写错没生效 → 先看是不是命中了 default_server
  5. 改配置忘了 reloaddocker exec nginx-xx nginx -s reload
  6. 复制网上配置粘贴中文引号 → "不可见字符"鬼地狱(巨坑),永远用英文 "

12. 章末面试题速览

详见 qa.md 第 6-8 题。

  1. Nginx 配置的层级结构是怎样的? → main / events / http / server / location(五层洋葱)。
  2. worker_processes 应该设几个?auto,等于 CPU 核数;I/O 密集型可适当 ×2。
  3. 同一个端口能配多个 server 吗? → 能,靠 server_name 区分(虚拟主机);都没匹配上走 default_server

13. 一句话总结

看到 nginx.conf 不要怕:从外往里就是 main → events → http → server → location,外层管全局、内层管细节、内层覆盖外层。

下一章 → 04 · 静态文件服务:让 Nginx 当个合格的"网页保姆"。

💻 示例代码

💻 示例代码

txt
###############################################################################
# /etc/nginx/conf.d/example.com.conf
# 一个标准 server 块的入门模板:静态站 + /api 反向代理
###############################################################################

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

    # 网站根目录
    root  /var/www/example;
    index index.html;

    # ---- 路由 1:根路径(页面) ----
    location / {
        try_files $uri $uri/ /index.html;     # SPA 兜底(详见 04 章)
    }

    # ---- 路由 2:静态资源 → 强缓存 1 年 ----
    location ~* \.(?:css|js|jpg|jpeg|png|gif|webp|svg|ico|woff2?)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;     # 静态资源不写 access log,省磁盘
    }

    # ---- 路由 3:API → 反向代理后端(详见 05 章) ----
    location /api/ {
        proxy_pass http://127.0.0.1:3000/;
        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;
    }

    # ---- 路由 4:健康检查 ----
    location = /healthz {
        access_log off;
        return 200 "ok\n";
        add_header Content-Type text/plain;
    }

    # ---- 错误页 ----
    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
        root  /usr/share/nginx/html;
    }
}
txt
###############################################################################
#  nginx.conf · 学习版 · 带详细中文注释
#  目标:让你看完这一份配置,对"五层洋葱"有完整认知
###############################################################################

# ===== 第 1 层 · main(全局,写在文件顶部) =====================================

user  nginx;                    # worker 进程跑在哪个 OS 用户下(推荐非 root)
worker_processes  auto;         # auto = CPU 核数;要排查问题可临时设 1 调试
worker_rlimit_nofile 65535;     # 单进程最大文件描述符(含 socket)

# 错误日志:路径 + 级别。生产用 warn,调试时改 info / debug
error_log  /var/log/nginx/error.log  warn;
pid        /var/run/nginx.pid;

# ===== 第 2 层 · events(连接处理模型) ========================================
events {
    use epoll;                  # Linux 上首选 epoll;FreeBSD 用 kqueue
    worker_connections 10240;   # 每个 worker 同时能 hold 多少连接(含上游)
    multi_accept on;            # 一个事件循环尽量多接收新连接
    accept_mutex off;           # 现代多核机器关掉它,让所有 worker 都有机会 accept
}

# ===== 第 3 层 · http(全 HTTP 通用配置) ======================================
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" '
                      'rt=$request_time uct="$upstream_connect_time" '
                      'urt="$upstream_response_time"';
    access_log  /var/log/nginx/access.log  main;

    # ---- 性能 ----
    sendfile        on;         # 零拷贝传输文件(kernel 直接把文件丢给 socket)
    tcp_nopush      on;         # 配合 sendfile:等满 1 个 MSS 再发,省小包
    tcp_nodelay     on;         # 长连接里小包立刻发(Nagle 算法关闭)
    keepalive_timeout  65;      # 长连接保活时间(秒)
    keepalive_requests 1000;    # 一条长连接最多复用多少次

    # 隐藏 Nginx 版本号(防止扫描器盯上)
    server_tokens off;

    # 默认请求体上限(上传文件大的可在 server / location 内单独覆盖)
    client_max_body_size 8m;

    # ---- 压缩(gzip) ----
    gzip on;
    gzip_min_length 1k;         # 小于 1KB 的不压(不划算)
    gzip_comp_level 5;          # 1 ~ 9,数字越大压缩比越高 / CPU 越累
    gzip_vary on;               # 加 Vary: Accept-Encoding 头,给 CDN 用
    gzip_types
        text/plain text/css application/json application/javascript
        application/xml application/xml+rss image/svg+xml;

    # ---- 引入子配置(推荐拆文件管理) ----
    include /etc/nginx/conf.d/*.conf;
}

example.com.conf ↗ · nginx.conf ↗