Skip to content

nginx.conf

自动匹配 CPU 核心数

worker_processes auto;

events

shell
events {
    worker_connections 1024;
    multi_accept on;
    use epoll;  # Linux epoll,windows select
}

windows select

location 匹配优先级

shell
# 优先级从高到低

# 1. 精确匹配 (=)
location = /exact {
    # 只匹配 /exact
}

# 2. 优先匹配 (^~) - 匹配后跳过正则
location ^~ /static {
    # 匹配 /static 开头,不检查正则
}

# 3. 正则匹配 (~ 大小写敏感, ~* 大小写不敏感)
location ~ \.js$ {
    # 匹配 .js 结尾
}

location ~* \.(jpg|png)$ {
    # 匹配图片文件
}

# 4. 普通匹配
location /api {
    # 匹配 /api 开头
}

# 5. 默认匹配
location / {
    # 匹配所有
}

匹配规则:

  1. 如果匹配到 ^~ 前缀
  2. 立即停止匹配
  3. 不再检查任何正则

所有 /demo 开头的请求都由这个 location 处理

shell
location ^~ /demo {
    root html;
    # Vue Router history 模式
    try_files $uri $uri/ /demo/index.html;
}

shell
location /demo {
    root html;
    try_files $uri $uri/ /demo/index.html;
}

location /api 普通字符串匹配

日志

shell
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" '
                '$request_time $upstream_response_time';

access_log logs/access.log main;
error_log logs/error.log warn;

SSL/TLS 配置

shell
listen 443 ssl http2;
server_name xxxx;

# SSL 证书
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;

浏览器缓存

shell
# 静态资源长期缓存
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Vary "Accept-Encoding";
    access_log off;
    log_not_found off;
}

# HTML 短期缓存
location ~* \.(html|htm)$ {
    expires 5m;
    add_header Cache-Control "public, must-revalidate";
}

# API 不缓存
location /api/ {
    expires -1;
    add_header Cache-Control "no-cache, no-store, must-revalidate";
    add_header Pragma "no-cache";
}

vue服务

shell
server {
    listen 80;
    server_name xxxx;
    root html;
    index index.html;

    # 使用 ^~ 确保所有子路径都由此处理
    location ^~ /demo {
        root html;
        index index.html;
        
        # Vue Router history 模式支持
        try_files $uri $uri/ /demo/index.html;
        
        # 静态资源缓存
        location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
            access_log off;
        }
    }
}

SSE/流式响应配置

shell
location /aiapi/cs/chat {
    proxy_pass http://xxx:8100/aiapi/cs/chat;
    include proxy_settings.conf;
    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Content-Type "text/event-stream";
    proxy_set_header Cache-Control "no-cache";
    add_header X-Accel-Buffering "no";
}

性能优化

慢请求判断:

  • 如果 $upstream_response_time 大 → 后端问题
  • 如果 $request_time - $upstream_response_time 大 → 网络/文件大小问题
  • 如果两者都大 → 全链路都有问题
shell
curl -w "\n
DNS: %{time_namelookup}s
TCP: %{time_connect}s
TLS: %{time_appconnect}s
TTFB: %{time_starttransfer}s
Total: %{time_total}s\n" \
-o /dev/null -s https://xxxx/app.f5826951.js
DNS: 0.030905s
TCP: 0.032735s
TLS: 0.078743s
TTFB: 0.098947s
Total: 0.105596s


DNS: 0.030905s (30.9ms)  ←  DNS 查询
TCP: 0.032735s (32.7ms)   ← TCP 三次握手
TLS: 0.078743s (78.7ms)   ← TLS/SSL 加密握手
TTFB: 0.098947s (98.9ms)  ← 从发送请求到收到第一个字节
Total: 0.105596s (105.6ms) ← 完整请求总耗时

阶段	耗时	说明
DNS: 30.9ms   DNS 查询
TCP	32.7ms	建立 TCP 连接(三次握手) 32.7 - 30.9 = 1.8ms
TLS	46.0ms	TLS 握手(加密协商) 78.7 - 32.7 = 46.0ms
TTFB	20.2ms	服务器处理时间 98.9 - 78.7 = 20.2ms
Content	6.6ms	下载内容时间 105.6 - 98.9 = 6.7ms
总耗时	105.6ms	完整请求时间

0ms        32.7ms      78.7ms      98.9ms      105.6ms
│           │            │           │            │
├─ TCP ────┤── TLS ────┤─ TTFB ────┤─ Content ──┤
│  32.7ms   │  46.0ms   │  20.2ms   │   6.7ms    │
│           │            │           │            │
└───────────┴────────────┴───────────┴────────────┘

直接nginx负载静态文件

后续文件直接

shell
location ^~ /mglibs {
    root html;
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}
accept-ranges: bytes
cache-control: max-age=31536000
cache-control: public, immutable
content-length: 143643
content-type: text/plain
date: Wed, 12 Aug 2026 02:57:04 GMT
etag: "6a7bdde3-2311b"
expires: Thu, 12 Aug 2027 02:57:04 GMT
last-modified: Wed, 12 Aug 2026 02:43:47 GMT
server: nginx
shell
$ curl -I https://xxxx/mglibs/axios/1.11.0/axios.min.js
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 12 Aug 2026 05:58:47 GMT
Content-Type: application/javascript
Content-Length: 54487
Last-Modified: Wed, 12 Aug 2026 02:43:47 GMT
Connection: keep-alive
ETag: "6a7bdde3-d4d7"
Expires: Thu, 12 Aug 2027 05:58:47 GMT
Cache-Control: max-age=31536000
Cache-Control: public, immutable
Accept-Ranges: bytes

开启gzip

响应头中没有content-encoding字段(如gzip或br),说明Nginx没有对该JS文件启用压缩。 149KB的未压缩JS文件在移动网络下传输,加上可能存在的网络波动,耗时57秒是可以解释的。

未启用gzip压缩 152kB

shell
accept-ranges: bytes
content-length: 152856
content-type: application/javascript
date: Thu, 13 Aug 2026 04:36:07 GMT
etag: "6a79a75c-25518"
last-modified: Mon, 10 Aug 2026 10:26:36 GMT
server: nginx

启用gzip压缩

http {
  gzip on;
  gzip_vary on;
  gzip_comp_level 9;
  gzip_min_length 1024;
  gzip_types text/plain text/css text/xml text/javascript 
              application/json application/javascript application/xml+rss;
}

响应头:

content-encoding: gzip
content-type: application/javascript
date: Thu, 13 Aug 2026 06:33:28 GMT
etag: W/"6a79a75c-25518"
last-modified: Mon, 10 Aug 2026 10:26:36 GMT
server: nginx
vary: Accept-Encoding

获取资源文件压缩后的大小

shell
 curl -s -H "Accept-Encoding: gzip" xxxxx/js/chunk-vendors.bb3caf12.js -o /dev/null -w "压缩后大小: %{size_download} bytes\n"
: 51067 bytes

配置生效依据

shell
Content-Encoding: gzip
Vary: Accept-Encoding
ETag: W/"..."	弱校验,符合Gzip规范

[13/Aug/2026:10:07:07 +0800] "GET /xxx/css/chunk-vendors.d82739c0.css HTTP/2.0" 200 66583 [13/Aug/2026:14:51:33 +0800] "GET /xxx/css/chunk-vendors.d82739c0.css HTTP/2.0" 200 32756

sendfile 零拷贝

开启后:硬盘 → 内核缓冲区 → 网卡

未开启:硬盘 → 内核缓冲区 → 用户缓冲区(Nginx) → 内核Socket缓冲区 → 网卡

当 sendfile 和 gzip 同时启用时,Nginx 会自动判断文件大小,对小文件使用 sendfile,对大文件使用传统方式配合压缩。

server {
    sendfile on;
}


### 强制请求头
```shell
location ^~ /xxx {
    root html;
    
    if ($request_uri ~ \.js$) {
        add_header Content-Type "application/javascript" always;
    }
    if ($request_uri ~ \.css$) {
        add_header Content-Type "text/css" always;
    }
    if ($request_uri ~ \.html$) {
        add_header Content-Type "text/html" always;
    }
    
    try_files $uri $uri/ /xxx/index.html;
}

安全

封禁IP - 对整站所有请求生效

shell
server {
    deny xxx.xxx.xxx.xxx;
    ...

}