服务器怎么配置Nginx

结论: 配置 Nginx 的关键是理解它的层级结构——main 管进程、events 管连接、http 管全局、server 管站点、location 管路由。实操顺序为:装好后先调 /etc/nginx/nginx.conf 的性能参数,再为每个站点建独立 server 块,按 location 优先级写路由规则,最后用反向代理对接后端应用并套上 SSL。

引言:Nginx 为什么是服务器的标配

Nginx 是目前最主流的 Web 服务器与反向代理(Reverse Proxy),以事件驱动(Event-Driven)架构著称,同样的硬件能支撑数倍于传统多进程模型的并发连接。在服务器上它通常承担四件事:托管静态文件、反向代理到后端应用(Node.js、Java Spring Boot、Python Gunicorn)、做负载均衡(Load Balancing)、终止 SSL 并做缓存。

绝大多数线上故障不是 Nginx 本身的问题,而是配置层级理解错误:把只该出现在 http 的指令写进 server、把 location 匹配规则写得互相覆盖、或者改完不 nginx -t 就直接 reload。本文按"结构 → 站点 → 路由 → 代理 → 优化"的顺序讲清每个环节。示例基于 Ubuntu 24.04 LTS 与 Nginx 1.26(截至 2026 年主流稳定版为 1.26 / 1.27)。

Nginx 配置文件结构与目录

结论:Nginx 的配置是树形上下文(Context)结构,每条指令只能出现在特定的上下文中,写错位置会直接报 directive is not allowed here。

上下文作用常见指令出现次数
main全局进程级user、worker_processes、error_log、pid1
events连接处理模型worker_connections、use、multi_accept1
httpHTTP 全局include、gzip、log_format、upstream、server1
server虚拟主机listen、server_name、root、ssl_*多个
locationURL 路由proxy_pass、try_files、expires、deny多个
upstream后端服务器组server、least_conn、keepalive多个

Ubuntu/Debian 的目录约定如下,读懂它能少走很多弯路:

  • /etc/nginx/nginx.conf:主配置文件,包含全局与 http 块。
  • /etc/nginx/sites-available/:可用站点配置(写在这里)。
  • /etc/nginx/sites-enabled/:已启用站点(由 sites-available 软链过来)。
  • /etc/nginx/conf.d/*.conf:http 块末尾自动 include 的目录,CentOS 系默认用这个。
  • /var/log/nginx/access.log、error.log:访问与错误日志。

安装与基础检查命令:

bash
sudo apt update && sudo apt install -y nginx
sudo systemctl enable --now nginx
nginx -v                 # 查看版本
nginx -T                 # 打印最终生效的完整配置(排错神器)
sudo nginx -t            # 语法检查,改配置后必做
sudo systemctl reload nginx   # 平滑重载,不中断连接

第一步:调优主配置文件

结论:Nginx 开箱即用的参数偏保守,生产环境至少要调 worker_processes、worker_connections、keepalive_timeout 与 gzip 四项。下面是一份可直接套用的 /etc/nginx/nginx.conf。

nginx
user  www-data;
worker_processes  auto;              # 自动设为 CPU 核心数
worker_rlimit_nofile 65535;          # 单进程可打开的最大文件数
error_log  /var/log/nginx/error.log warn;
pid        /run/nginx.pid;

events {
    use epoll;                       # Linux 下性能最好的事件模型
    worker_connections 10240;        # 每个 worker 的最大并发连接
    multi_accept on;                 # 一次尽可能多地接受新连接
}

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" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" urt="$upstream_response_time"';
    access_log /var/log/nginx/access.log main;

    sendfile        on;              # 零拷贝发送静态文件
    tcp_nopush      on;              # 配合 sendfile,减少报文数量
    tcp_nodelay     on;              # 小包立即发送,降低延迟
    server_tokens   off;             # 隐藏版本号,降低被针对性攻击的风险

    keepalive_timeout   65;          # 长连接超时(秒)
    keepalive_requests  1000;        # 单条长连接最多处理的请求数
    client_max_body_size 64m;        # 请求体上限,影响上传大小
    client_body_timeout  30s;
    reset_timedout_connection on;

    # ---- gzip 压缩 ----
    gzip on;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_min_length 1024;            # 小于 1KB 不压缩,避免得不偿失
    gzip_proxied any;
    gzip_types text/plain text/css application/json application/javascript
               application/x-javascript text/xml application/xml application/xml+rss
               text/javascript image/svg+xml font/woff2;

    # ---- 文件描述符缓存 ----
    open_file_cache max=10000 inactive=30s;
    open_file_cache_valid 60s;
    open_file_cache_min_uses 2;

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

几个容易算错的数值:

  • 理论最大并发 ≈ worker_processes × worker_connections。4 核 × 10240 ≈ 4 万并发连接。但作为反向代理时每个客户端连接会占用一个到后端的连接,实际承载的客户端数约为该值的一半。
  • worker_rlimit_nofile 必须 ≥ worker_connections 的 1~2 倍,否则会报 too many open files;同时要确认系统 ulimit -n 已放宽。
  • gzip_comp_level 超过 6 之后压缩率提升极小但 CPU 消耗陡增,6 是性价比拐点。
  • gzip_types 里不需要写 text/html,Nginx 默认就会压缩 HTML。

第二步:server 块与虚拟主机

结论:一个 server 块就是一个虚拟主机,靠 listen + server_name 区分。一台服务器托管多个域名,只要建多个 server 块即可。

下面是一份典型的站点配置,包含 HTTP 跳转 HTTPS、静态资源缓存、PHP 转发:

nginx
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;      # 全站跳转 HTTPS
}

server {
    listen 443 ssl;
    http2 on;                                   # Nginx 1.25.1+ 写法;老版本用 listen 443 ssl http2
    server_name example.com www.example.com;

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

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

    # 静态资源强缓存 + 关闭日志,减少磁盘写
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # PHP 交给 PHP-FPM
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_read_timeout 300s;
    }

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}

要点说明:

  • server_name 支持通配符(*.example.com)和正则,精确名称优先级最高。
  • 没有匹配到任何 server_name 的请求会落到该端口的默认 server(第一个定义的,或标了 default_server 的那个)。
  • try_files 是伪静态与前端路由的标配,Vue/React 单页应用通常写成 try_files $uri $uri/ /index.html;。
  • return 301 比 rewrite 效率更高,纯跳转一律用 return。

第三步:location 匹配规则与优先级

结论:location 的匹配顺序是 Nginx 最容易被搞错的地方。规则只有一条主线:先精确,再前缀,最后正则。

写法类型含义优先级
location = /path精确匹配完全一致才命中,命中即终止1(最高)
location ^~ /path优先前缀前缀匹配且跳过正则检查2
location ~ \.php$正则(区分大小写)按出现顺序依次尝试3
location ~* \.PNG$正则(不区分大小写)同上3
location /path普通前缀取最长者,正则全落空才用4(最低)

完整判定流程:

  1. 用 = 精确匹配,命中立即使用;
  2. 对所有前缀 location 试匹配,记住最长的那个;
  3. 若最长前缀是 ^~,立即使用并停止;
  4. 否则按配置文件顺序逐个测试正则,第一个命中的即用;
  5. 正则全不命中,才使用第 2 步记住的最长前缀。

典型配置示例:

nginx
location = / {
    # 只匹配首页
}

location ^~ /static/ {
    alias /data/static/;          # alias 会替换掉 location 前缀,root 则是拼接
    expires 7d;
}

location ~* \.(gif|jpg|jpeg|png|webp)$ {
    expires 30d;
    add_header Cache-Control "public";
}

location /api/ {
    proxy_pass http://backend/;   # 注意末尾的 / 会把 /api/ 前缀去掉
}

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

特别注意 alias 与 root 的区别:root /data/static 会把 /static/a.jpg 解析为 /data/static/static/a.jpg,而 alias /data/static 解析为 /data/static/a.jpg。这是最常见的 404 来源。

第四步:反向代理配置

结论:反向代理的作用是把外部请求转发给内部应用(如 8080 端口的 Java 服务),同时隐藏后端。核心是 proxy_pass 加一组转发头,缺了 Host 与 X-Forwarded-* 后端拿不到真实信息。

nginx
upstream backend {
    least_conn;                          # 最少连接调度
    server 127.0.0.1:8080 weight=5 max_fails=3 fail_timeout=15s;
    server 127.0.0.1:8081 weight=5 max_fails=3 fail_timeout=15s;
    keepalive 64;                        # 与后端保持的长连接数
}

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

    location / {
        proxy_pass http://backend;

        proxy_http_version 1.1;
        proxy_set_header Connection "";           # 配合 keepalive,必须清空
        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_connect_timeout 5s;
        proxy_send_timeout    60s;
        proxy_read_timeout    60s;

        proxy_buffering on;
        proxy_buffer_size 8k;
        proxy_buffers 16 8k;
    }

    # WebSocket 支持
    location /ws/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
    }
}

避坑提示:

  • proxy_pass 后面带不带 / 结果完全不同。若 location 是 /api/ 且 proxy_pass http://backend/(带斜杠),转发时 /api/ 前缀会被剥掉;不带斜杠则原样透传。
  • 后端要拿到真实客户端 IP,除了转发头,还需在应用侧配置信任代理(如 Spring Boot 的 server.forward-headers-strategy=native)。
  • 上传大接口要同步调大 client_max_body_size,否则报 413。

第五步:SSL/TLS 与性能优化收尾

结论:HTTPS 已成为默认要求,现代 Nginx 只需启用 TLS 1.2/1.3、关闭不安全套件并开启会话复用,安全性与性能可以兼得。

nginx
server {
    listen 443 ssl;
    http2 on;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305;

    ssl_session_cache shared:SSL:20m;     # 约可缓存 8 万个会话
    ssl_session_timeout 1d;
    ssl_session_tickets off;              # 关闭 ticket 更安全

    ssl_stapling on;                      # OCSP Stapling,减少客户端验证耗时
    ssl_stapling_verify on;
    resolver 8.8.8.8 1.1.1.1 valid=300s;

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
}

最后压测验证,用 ab 或 wrk 观察 QPS 与错误率,再按瓶颈调整 worker_connections 或后端:

bash
sudo nginx -t && sudo systemctl reload nginx
curl -I https://example.com
ss -lntp | grep nginx
tail -f /var/log/nginx/error.log