LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

5 年工程师最推荐的一份 Nginx 配置清单,反向代理、限流、SSL、负载均衡全都有

admin
2025年7月21日 23:28 本文热度 101

Nginx 的强大,不在于它装得多快,而在于它配得有多灵活。前面我们已经完成了多种环境下的安装,接下来真正的重点来了:配置。几乎所有核心功能,都是通过精心编写的 .conf 文件实现的。学会配置,才算真正学会了用 Nginx。

Nginx 能反向代理、限流、负载均衡,全靠它的 .conf 文件来实现。我在多年的工作中总结了 Nginx 最常用的功能,接下来,本文将带入生产环境常用的实际场景,去解决如何配置 conf ,干货文章建议收藏。

一、负载均衡

单节点的反向代理配置,将 HTTP 请求转发的 Tomcat 服务器,但是只能代理到单节点,无法在集群中使用

 1server {
 2    location /testapi/ {
 3            proxy_pass     http://178.168.1.10:9120/;
 4            index   /;      # index.html index.htm;
 5            proxy_set_header Host $host;
 6            # 表示与这个nginx 直接通信的IP, 如果这个是第一层代理,这将是最真实的客户端IP
 7            proxy_set_header X-Real-IP $remote_addr;
 8            # 表示与这个nginx 直接通信的Port, 如果这个是第一层代理,这将是最真实的客户Port
 9            proxy_set_header X-Real-Port $remote_port;
10            # NGINX 在转发请求时会将客户端的 IP 地址添加到 X-Forwarded-For 头部
11            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
12            client_max_body_size 8M;
13            client_body_buffer_size 128k;
14            proxy_connect_timeout       10s; 
15            proxy_send_timeout          60s;
16            proxy_read_timeout          60s;
17    }
18}

负载均衡配置 用于将 HTTP 请求分布到多个节点的 Tomcat 服务器;负载均衡功能支持自动下线,当某一台节点服务端返回 500,则会自动下线该节点不再访问。负载均衡的配置可以单独写成 conf 文件。

 1upstream openserver-api {
 2      # ip_hash; 根据访问ip的hash结果分配 
 3      # least_conn;请求分配到连接数最少的服务
 4      # fair; 请求分配到后端响应的时间最短
 5      server 127.0.0.1:8900 weight=100 max_fails=10 fail_timeout=15s;
 6      server 127.0.0.1:8901 weight=100 max_fails=10 fail_timeout=15s;
 7}
 8
 9server {
10  location /test-api/{
11      proxy_pass     http://openserver-api/;
12      index   /;      # index.html index.htm;
13      proxy_set_header Host $host;
14      proxy_set_header X-Real-IP $remote_addr;
15      proxy_set_header X-Real-Port $remote_port;
16      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
17      client_max_body_size 8M;
18      client_body_buffer_size 128k;
19  }
20}

上面是按权重轮询服务,在15秒(fail_timeout)内该服务器出现了10次(max_fails)失败,负载均衡器就会停止向它发送请求。生产环境就是使用这样平均分配的策略;

除了轮询策略,还有其他负载均衡策略。在注释上标注了,去掉注释就可以直接使用,但是这些策略都不是平均分配的,需要自己去控制流量的大小,如果没有特殊的情况,还是建议轮询服务。

二、静态资源访问

2.1 配置网页

现在前端开发项目已经不是简单的 html 页面了,多是使用 Vue 等框架开发的,这里给出 Vue 前端项目的页面配置。

1server {
2  location /page/ {
3    alias  /home/user/web/page/dist/;
4    try_files $uri $uri/ /page/index.html;
5  }
6}

当浏览器访问 https://example.com/page 时,nginx 会代理到 /home/user/web/page/dist/目录,此时,$uri 就表示 /page

try_files 会先检查 alias 目录下 page文件是否存在,存在则返回该文件;

然后会检查 page/目录是否存在,存在则返回 page/ 目录下的 index.xml(page 不带斜杠表示文件,page/ 带斜杠表示目录);

最后如果都找不到,则返回 /page/index.html ,此时 /page/表示相对目录,和上面的 location /page/表示一个意思,即 alias 表示的路径,所以 /page/index.html 完整的路径表示 /home/user/web/page/dist/index.html

alias 和 root 的区别?

alias 是一个目录别名的定义,可以直接替换,比如 /page/ 就表示 /home/user/web/page/dist/

root 是最上层目录的定义,访问 /page/ 则表示 访问 root 后面的目录 + /page/,即 /home/user/web/page/dist/page/

2.2 配置验证文件

在很多第三方页面嵌入到主应用,或者跳转第三方域名的时候,往往需要先提前校验域名是否合法。

一般做法是将一个文本校验文件放到域名根目录,例如要访问 https://example.com, 必须要求 https://example.com/mK49l7IJfF.txt 能访问,这里的 mK49l7IJfF.txt 就需要放到域名根目录,怎么做呢?

 1# 根路径,在 localtion 内部嵌套
 2location / {
 3    alias  /home/user/web/page/dist/;
 4    try_files $uri $uri/ /index.html;
 5
 6    location = /mK49l7IJfF.txt {
 7        alias /home/user/web/index/dist/mK49l7IJfF.txt;
 8    }    
 9}
10
11#
 普通路径, 在 localtion 内部嵌套
12location /page/ {
13    alias  /home/user/web/page/dist/;
14    try_files $uri $uri/ /page/index.html;
15
16    location = /page/mK49l7IJfF.txt {
17        alias /home/user/web/index/dist/mK49l7IJfF.txt;
18    }    
19}

如果文件一直访问不通 返回404,考虑 mK49l7IJfF.txt 文件是否 Nginx 存在权限不够,无法访问。

2.3 页面禁止缓存

为了提供响应速度,浏览器访问页面会有缓存,页面无法及时更新。如何彻底浏览器禁止缓存?需要在响应的请求头中加入禁止缓存头。

1location / {
2    add_header Cache-Control "no-cache, no-store, must-revalidate";
3    add_header Pragma "no-cache";
4    add_header Expires 0;
5}

2.4 配置404页面

可以通过指定error_page 404 触发显示 404页面,location 一定要配置在 server{} 目录下,否则不生效。

另外页面中如果存在图片等资源,请注意路径参数等问题。

 1http{
 2    ...
 3    # 设置全局的 404 错误页面
 4    error_page 404 /404.html;
 5    ...
 6}
 7
 8server{
 9    ...
10   location = /404.html {
11       root /home/user/web/404/;
12       # 限制外部访问
13       internal;  
14   }
15   ...
16}
 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <title>404 - Page Not Found</title>
 7    <style>
 8        body { font-family: Arial, sans-serif; }
 9        h1 { color: red; }
10    
</style>
11</head>
12<body>
13    <h1>404 - Page Not Found 当前页面不存在</h1>
14</body>
15</html>

三、隐藏版本号

在浏览器响应头里有 Server 项,这里返回的是当前服务 web 服务器的名称,如 Nginx、Kong 等。

但是这里不应该把服务器的版本号返回出来,万一版本有漏洞,会被针对攻击。所以如何隐藏版本号呢?

1# 1、关闭 http{} 的 server_tokens
2server_tokens off;
3
4
5#2、修改 ../nginx/conf/fastcgi_params 
6fastcgi_params SERVER_SOFTWARE 
7nginx/$nginx_version
8# 改为 
9fastcgi_params SERVER_SOFTWARE nginx

fastcgi_params 这个文件里的存放的都是 Nginx 环境变量。

四、日志管理

4.1 日志定时分片

请直接参考这篇文章:别让日志撑爆磁盘!Nginx日志优化实战:自动分片、定时归档、轻松管理亿级日志

4.2 日志 JSON 格式化

将 Nginx 的日志格式化为 JSON,可以修改 log_format 指令,将日志字段转化为 JSON 格式。

JSON 格式的日志,更适合日志聚合和后续处理,比如 ELK, Flume 等工具。

JSON 格式化配置:

1log_format json '{"remote_addr": "$remote_addr", "connection": "$connection", "connection_requests": "$connection_requests", "remote_user": "$remote_user", "time_local": "$time_local", "request_length": "$request_length", "request": "$request", "status": "$status", "request_time": "$request_time", "upstream_response_time": "$upstream_response_time", "body_bytes_sent": "$body_bytes_sent", "content_length": "$content_length", "http_x_forwarded_for": "$http_x_forwarded_for", "upstream_addr": "$upstream_addr", "http_referer": "$http_referer", "http_user_agent": "$http_user_agent"}';

确保将此配置添加到 http 块中,并设置 access_log 指令以使用这个 JSON 格式:

1http {
2    log_format json '{"remote_addr": "$remote_addr", "connection": "$connection", "connection_requests": "$connection_requests", "remote_user": "$remote_user", "time_local": "$time_local", "request_length": "$request_length", "request": "$request", "status": "$status", "request_time": "$request_time", "upstream_response_time": "$upstream_response_time", "body_bytes_sent": "$body_bytes_sent", "content_length": "$content_length", "http_x_forwarded_for": "$http_x_forwarded_for", "upstream_addr": "$upstream_addr", "http_referer": "$http_referer", "http_user_agent": "$http_user_agent"}';
3
4  # 日志格式可以引用main ,也可以引用 json
5    access_log /var/log/nginx/access.log json;
6}

日志将记录为 JSON 格式,示例如下:

 1{
 2    "remote_addr""180.101.49.58",
 3    "connection""3",
 4    "connection_requests""1",
 5    "remote_user""-",
 6    "time_local""18/Jan/2025:08:02:38 +0000",
 7    "request_length""1237",
 8    "request""POST /api/queryList HTTP/1.1",
 9    "status""200",
10    "request_time""0.112",
11    "upstream_response_time""0.111",
12    "body_bytes_sent""1574",
13    "content_length""2",
14    "http_x_forwarded_for""-",
15    "upstream_addr""180.101.49.58:18105",
16    "http_referer""http://example.com:18105/query/?token=erwerwer&activityId=werwer&level=100",
17    "http_user_agent""Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0"
18}

五、灰度发布

如何基于 Nginx 设计灰度发布呢?请看这篇文章。主要运用的配置是负载均衡和权重策略。轻松搞定服务灰度发布!基于Nginx的流量分发与版本控制实战指南

六、拓展模块

6.1、限流功能

参考下面这篇文章: 高并发场景下接口防刷!3 分钟配置 Nginx 基于 IP 限流实战指南

6.2、禁止区域流量

简单的使用 deny 和 allow 配合使用。放在 http 、server、location 中都可以。

 1server {
 2    listen80;
 3    server_name example.com;
 4
 5    # 允许特定 IP 地址
 6    allow192.168.1.1;
 7    allow203.0.113.2;
 8
 9    # 拒绝所有其他 IP 地址
10    deny all;
11
12    location / {
13        # 其他配置...
14    }
15}
16
17server {
18    listen80;
19    server_name example.com;
20
21    # 禁止多个 IP 地址访问
22    deny192.168.1.100;
23    deny203.0.113.50;
24
25    location / {
26        # 其他配置...
27    }
28}

也可以使用文件批量实现 IP 限制,然后把语法文件写入到 limitip.conf 文件中

1server {
2    listen 80;
3    server_name example.com;
4    include /nginx/conf/limitip.conf;
5    ...
6}
1deny 192.168.1.100;
2deny 203.0.113.50;

那只允许中国的 IP 访问怎么做呢?

 1http {
 2    # 定义中国 IP 范围,默认所有 IP 都拒绝
 3    geo$allowed_country {
 4        default0;  # 默认拒绝所有 IP
 5        # 以下为中国的 IP 地址段示例,请根据实际情况更新
 6        101.0.0.0/8 1;
 7        103.0.0.0/8 1;
 8        106.0.0.0/8 1;
 9        # 其他中国 IP 地址段...
10    }
11
12    server {
13        listen80;
14        server_name example.com;
15
16        location / {
17            # 如果不是中国 IP,返回 403 Forbidden
18            if ($allowed_country = 0) {
19                return403;  # 非中国 IP 返回 403 Forbidden
20            }
21
22            root /usr/share/nginx/html;
23            index index.html;
24        }
25    }
26}

6.3、配置各种响应头

配置响应头是为了告诉浏览器某些操作,比如禁止缓存、禁止iframe嵌套等,Nginx 作为 Web 服务器,支持设置响应头。加在 server 里可以全局统一

 1location / {
 2    # 禁止浏览器缓存
 3    add_header Cache-Control "no-cache, no-store, must-revalidate";
 4    add_header Pragma "no-cache";
 5    add_header Expires 0;
 6
 7    #该页面不允许在frame中展示,另外还有 SAMEORIGIN(表示该页面可以在相同域名页面的frame中展示),
 8    # ALLOW-FROM url(页面可以在指定来源的frame中展示)
 9    # 这个头加之前需要和前端同步
10    add_header X-Frame-Options:DENY
11
12    #启用XSS保护;
13    add_header X-Xss-Protection: 1;
14    add_header X-Xss-Protection: mod=block;
15
16    # 严格按照 Content-Type指定的类型加载,直接猜测
17    add_header X-Content-Type-Options "nosniff";
18
19    #指定哪些域名可以访问当前资源
20    add_header Access-Control-Allow-Origin "*";
21
22    #防止浏览器在下载文件时自动执行内容(如 JS 文件)
23    add_header X-Download-Options "noopen";
24
25    # 默认只允许加载与页面相同源的资源,帮助防止跨站脚本攻击(XSS)
26    add_header Content-Security-Policy "default-src 'self';" always;
27
28    # 启用 HSTS,强制所有连接使用 HTTPS,禁止304 跳转
29    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
30
31}

6.4、防止DNS欺骗恶意域名解析

DNS 欺骗可以将非法域名解析到服务器上,导致服务器被恶意访问,在原有配置的上面可以添加一个默认 server ,当其他域名或通过 IP 访问的时候,由于匹配不到 server,就会走默认的 server, 返回444。

444 是 Nginx 服务器扩展的 HTTP错误状态码,服务器不向客户端返回任何信息,并关闭连接, 断开客户端和服务器的连接,防止恶意软件攻击威胁。通过此方式直接通过IP 将无法访问。

1server {
2    listen 80 default;
3    server_name _;  # 匹配所有没有匹配到其他虚拟主机的请求
4    return 444;     # 直接返回 444,关闭连接
5}

Q&A

Q1:remote_addr 和 http_x_forwarded_for的 区别是什么?

A: remote_addr 表示上游真实IP。假设用户和服务器间有多级代理,那么 remote_addr 就表示最接近服务器的那个代理。

remote_addr 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求。

如果上游是 nginx,那么 remote_addr 只能表示 nginx IP,而不是客户 IP;

http_x_forwarded_for 格式为 X-Forwarded-For: client, proxy1,它是一个请求头,表示多级代理的IP,可以完整的展示客户端到服务器间的代理链,每级代理需要将上级客户端IP(remote_addr)加到 X-Forwarded-For 后面。

所以 X-Forwarded-For 不包含最后一级代理,最后一级代理直接通过 remote_addr 获取。

计算方式:X-Forwarded-For = 最近代理获取到的 X-Forwarded-For + 最近代理获取到的 remote_addr。

所以服务如果通过 Nginx 代理访问,就要禁止直接访问服务,这是为了保证上级代理不会被伪造,否则客户端直连会伪造 IP 数据。必须使用从 TCP 连接中得到的 Remote Address 才是真实的,其他均不可信!

请一定记住:

1、使用 Nginx 就要禁掉直连服务,保证上级代理不会被伪造请求头;

2、单 Nginx 转发,X-Real-IP 和 X-Forwarded-For 最后一节为真实客端 IP;

3、多 Nginx 转发,X-Real-IP 和 X-Forwarded-For 最后一节为倒数第二级代理IP,建议直接将第一级转发;

Q2: Nginx 访问异常,有时能访问到 有时候访问不到?

排查发现:

1、域名本身过期;

2、域名证书过期;

3、域名没有备案;

只要服务器在国内,所有的域名,包括 hosts 自定义的的域名在国内都需要备案。

Q3: 走 Nginx 压测后端服务出现问题?

Nginx 负载到两个节点上,流量直接走Nginx ,使用 Jmter 压测服务,接口一直响应超时返回502,QPS 上不去。 

查询 Nginx 日志发现异常,从日志可以看出,Nginx 获取上游响应超时,但是直接压测服务不走 Nginx 的话,就没有这个问题,这说明服务端没有问题,而是 Nginx->api 这个路径出现问题,Nginx 负载出现问题,请求还没到 Tomcat ?

报错日志如下:

11、upstream server temporarily disabled while connecting to upstream
22、(upstream timedout(110: Connection timedout)whilereading response header from upstream)
33no live upstreams while connecting to upstream,

解决方案如下:

1、填加超时配置:max_fails 重试次数,fail_timeout = 超时重试时间,keepalive 保持长连接时间,(Http1.1,默认支持长连接,可以减少 TCP 创建)

1# 10秒内连续出现超过2次 
2server  127.0.0.1:9501 max_fails=2 fail_timeout=10s weight=1;
3server  127.0.0.1:9502 max_fails=2 fail_timeout=10s weight=1;
4keepalive 10;

2、nginx->API 链路大量 TCP 被断开,检查 TCP 连接是否存在异常。

1# 统计TCP状态数量
2netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'
3
4# 返回如下结果
5FIN_WAIT_1       1
6CLOSE_WAIT       8
7TIME_WAIT        44
8ESTABLISHED      42
1location ^~ /xxxxxx/ {
2    ...
3    # 强制走http 1.1,默认会采用 Keep-Alive
4    proxy_http_version 1.1;
5    ...
6}
7参考 https://xiezefan.me/2017/09/27/nginx-502-bug-trace/

3、排除nginx 所在的服务器内核参数设置太小导致丢包的可能性

以上就是本文的全部内容。


阅读原文:原文链接


该文章在 2025/7/22 17:23:23 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved