站内链接:

介绍

说明

  1. 优势和使用场景
  • 快速响应,高扩展性,高可靠性,低内存消耗(10 000 非活跃连接仅有 2.5MB 消耗),单机 10 万并发连接,热部署(重点),自由的 BSD

  • 优秀的事件驱动框架;

  • 适用于传输层上 TCP 对外服务;

  1. 同类 web 前端服务器:

a. Apache HTTP Server:

  • 优点:

    • 成熟稳定:Apache 是最早的 Web 服务器之一,经过多年发展和广泛使用,已经被广泛验证和测试。
    • 强大的模块化支持:Apache 具有丰富的模块化架构,可以通过模块添加特定功能和扩展。
    • 良好的操作系统兼容性:Apache 可在多个操作系统上运行,包括 Linux、Windows、macOS 等。
  • 缺点:

    • 高资源消耗:相对于其他服务器,Apache 的资源消耗较高,特别是在高并发情况下。
    • 配置复杂:Apache 的配置文件相对复杂,需要一定的学习和理解成本。

b. Microsoft IIS (Internet Information Services):

  • 优点:

    • Windows 集成:IIS 是 Windows 操作系统的一部分,可以无缝集成到 Windows 服务器环境中。
    • 易用性:IIS 提供了可视化的管理界面和易于使用的工具,使得配置和管理变得简单。
    • 良好的.NET 集成:IIS 对于.NET 应用程序提供了良好的支持,可以直接托管和运行 ASP.NET 应用程序。
  • 缺点:

    • 仅适用于 Windows:IIS 只能运行在 Windows 操作系统上,不适用于其他操作系统。
    • 可伸缩性限制:相对于一些开源的服务器,IIS 的可伸缩性可能受限,特别是在高负载环境下。

c. Lighttpd (Lightweight HTTP Server):

  • 优点:

    • 轻量级高性能:Lighttpd 是一个轻量级的 Web 服务器,具有较低的资源消耗和快速的性能。
    • 高并发处理:Lighttpd 采用了异步非阻塞的事件驱动架构,能够高效处理大量并发连接。
    • 内存占用低:相对于一些其他服务器,Lighttpd 在内存使用方面较为节省。
  • 缺点:

    • 功能较少:与一些其他服务器相比,Lighttpd 的功能相对较少,可能不适用于某些复杂的应用场景。
    • 社区支持相对较小:相对于像 Nginx 和 Apache 这样的服务器,Lighttpd 的社区支持相对较小。

d. Caddy Server:

  • 优点:

    • 自动 HTTPS 支持:Caddy Server 内置了自动申请和管理 SSL 证书的功能,使得配置 HTTPS 变得简单。

    • 配置简单:Caddy Server 使用 Caddyfile 作为配置文件,具有易读易写的语法,配置相对简单。 - 插件生态系统:Caddy Server 拥有丰富的插件生态系统,可以通过插件扩展功能。

    • 缺点:

      • 商业许可证:Caddy Server 采用 Apache 2.0 许可证,但对于某些商业用途可能需要购买许可证。
      • 社区相对较小:相对于像 Nginx 和 Apache 这样的服务器,Caddy Server 的社区相对较小,可能不具备一些特定功能和支持。

e. Nginx:

  • 优点:

    • 高性能:Nginx 以其卓越的性能而闻名,能够处理大量并发连接和高负载环境。
    • 内存消耗低:相对于一些传统的服务器,Nginx 在内存使用方面较为节省。
    • 可扩展性:Nginx 支持高度的并发性和可扩展性,能够轻松应对高负载情况。
    • 强大的反向代理和负载均衡功能:Nginx 具有强大的反向代理和负载均衡功能,可用于构建高可用性和高性能的应用架构。
  • 缺点:

    • 动态内容处理限制:相对于一些其他服务器,Nginx 在处理动态内容(如 PHP)方面可能有一些限制。
    • 学习曲线:Nginx 的配置相对复杂,需要一定的学习和理解成本。

注意, web 静态服务器一般都是支持如下功能: 基于 REST 架构风格,以统一资源描述符(URI)或者统一资源定位符(URL)作为沟通依据,通过 HTTP/HTTPS 来提供网络服务

后端服务器

  1. java web 框架

以下是 Java 语言下常见的后端应用服务器和 Web 框架,按照使用量进行逆序排列,并以 Markdown 表格的形式呈现。请注意,由于 Java 生态系统的广泛性和不断变化,这里列出的是一部分常见的选择,可能并不包括所有的后端应用服务器和 Web 框架。

框架名 使用场景 优点 缺点
Spring Boot 大型/中型 Web 应用 强大的生态系统,广泛应用于企业级开发 学习曲线较陡峭,相对较重的配置和开发流程
Apache Tomcat 中型/小型 Web 应用 轻量级,易于部署和使用,广泛应用于 Java Web 开发 不适用于高并发场景,相对较少的扩展性和性能
Eclipse Jetty 中型/小型 Web 应用 轻量级,嵌入式容器,适用于嵌入式和独立应用 不适用于高并发场景,相对较少的扩展性和性能
WildFly 大型/中型 Web 应用 全面的 Java EE 支持,适用于企业级应用 相对较重的内存占用,较慢的启动时间
Apache Geronimo 大型/中型 Web 应用 Java EE 支持广泛,可扩展性强,适用于企业级应用 学习曲线较陡峭,相对较少的开发人员和资源
Resin 中型/小型 Web 应用 快速启动时间,低内存占用,适用于小型项目 功能相对较少,生态系统相对较小
Undertow 中型/小型 Web 应用 轻量级,高性能,适用于嵌入式和独立应用 生态系统相对较小,较少的开发人员和资源
Play Framework 大型/中型 Web 应用 响应式、高性能,适用于构建可伸缩的 Web 应用 学习曲线较陡峭,相对较少的开发人员和资源
Micronaut 中型/小型 Web 应用 轻量级、快速启动,适用于构建低延迟的微服务 生态系统相对较小,较新的框架,可能缺少某些功能
Spring MVC 中型/小型 Web 应用 基于 Spring 框架,广泛应用于 Java Web 开发 相对较重的配置和开发流程,较慢的启动时间
Grizzly 中型/小型 Web 应用 轻量级,高性能,适用于嵌入式和独立应用 较少的开发人员和资源,相对较少的扩展性和功能
  1. python web 框架

以下是 Python 语言下常见的后端应用服务器和 Web 框架,按照使用量进行逆序排列,并以 Markdown 表格的形式呈现:

框架名 使用场景 优点 缺点
Django 大型/中型 Web 应用 强大的功能集和完整的开发生态系统 学习曲线较陡峭,相对较重的配置和开发流程
Flask 中型/小型 Web 应用 简单、轻量级、易于学习和使用 功能相对较少,适用于小型项目
FastAPI 中型/小型 Web 应用 高性能、现代化的异步支持和 API 快速开发 生态系统相对较小,较新的框架,可能缺少某些功能
Tornado 异步 Web 应用 高性能、轻量级,非常适合处理大量并发连接 学习曲线较陡峭,不适用于传统的请求-响应模式
Pyramid 大型/中型 Web 应用 灵活、可扩展,支持多种开发模式和数据库 学习曲线较陡峭,相对较少的开发人员和资源
Bottle 小型 Web 应用 极简主义,轻量级,适用于小型项目 生态系统相对较小,功能相对较少
CherryPy 中型/小型 Web 应用 简单、快速启动,自包含的 Web 服务器 功能相对较少,生态系统相对较小
web2py 大型/中型 Web 应用 完整的开发框架,易于学习和使用 学习曲线较陡峭,相对较重的配置和开发流程
Falcon RESTful API 应用 极简主义,高性能,适用于构建轻量级 API 功能相对较少,不适用于复杂的 Web 应用
Bottle 小型 Web 应用 极简主义,轻量级,适用于小型项目 生态系统相对较小,功能相对较少
Quart 异步 Web 应用 基于 Flask,支持异步编程模型 生态系统相对较小,较新的框架,可能缺少某些功能
Sanic 异步 Web 应用 高性能、轻量级,适用于处理大量并发请求 较新的框架,生态系统相对较小
TurboGears 大型/中型 Web 应用 全栈框架,集成多个组件和工具 生态系统相对较小,较少的开发人员和资源
Hug RESTful API 应用 极简主义,易于使用,高性能 生态系统相对较小,功能相对较少

请注意,以上列出的是一些常见的 Python 后端应用服务器和 Web 框架,具体选择应根据项目需求、团队经验和个人偏好来决定。

插件

基于底层的系统开发商或者服务器开发者,为了提升整个 web 服务器的并发 TCP 连接,在现有的 nginx 模块不能满足业务需求时,采用以下两种方式来提供站点负载:

  • 将所有流量反向代理到后方服务器处理,但是必须后端服务器解决阻塞和并发问题,保证和 nginx 同样的高效;
  • 开发 nginx 第三方插件,以适应并发需求;

但实际上第三方插件也仅仅起到分流的功能, 实际的流量处理还是会下发到后发的应用服务器进行处理.

命令和目录

命令

  1. nginx 命令选项说明
1
2
3
4
5
6
7
-c <path_to_config>     指定一个nginx配置文件,而非缺省的
-t 仅仅测试配置文件
-g 全局配置项(不建议,直接实用配置文件)
-s stop(TERM/INT),quit(QUIT),reload(SIGHUP),reopen(USR1)

-v 版本
-V 版本,编译器版本,配置参数
  1. 启动和停止

启动: sudo which nginx

从容关闭:

1
2
ps -ef|grep nginx
kill -QUIT <pid>

快速关闭:

1
2
3
4
ps -ef|grep nginx
kill -TERM <pid-master>
kill -9 <pid-master>
kill -QUIT `cat /usr/local/nginx/nginx.pid`

平滑升级配置:

1
2
3
nginx -t -c /etc/nginx/nginx.conf
ps aux|egrep '(PID|nginx)'
kill -HUP <pid>

平滑升级二进制文件:

1
2
3
4
# 此时会有两个主进程实例,然后旧实例会在处理完旧连接之后关闭
kill -USR2 <pid>
# 帮助
/etc/init.d/nginx help
  1. 进程结构
  • master:管理 worker 进程,提供命令行服务
  • worker:一般数量和 CPU 数量相同,参照 DPDK 开发(SMP),最大化的利用 CPU,其中 worker 之间通过内存共享,原子操作来实现负载均衡

目录和信号

  1. 目录或配置说明
  • conf.d: 扩展配置文件,设置基础目录
  • sites-available: 配置虚拟主机的文件,每一個文件代表一個虚拟主机
  • sites-enable: 软连接到 sites-available
  1. 信号: 主进程可接受的信号:
  • TERM, INT 快速关闭
  • QUIT 从容关闭
  • HUP 从容关闭旧进程,重载
  • USR1 重新打开日志文件(这个在日志文件操作时有用)
  • USR2 平滑升级可执行程序(有用)
  • WINCH 从容关闭 worker

worker 进程支持 TERM,INT, QUIT, USER1 信号来进行处理

配置语法

每一个配置项的语法格式: (configure name) (configure value1) (configure value2) ....; 其中各项说明如下:

1
2
3
configure name			必须在相应的模块中支持(回忆下当初的第三方模块开发);
configure value 可以是数字,字符串,正则表达式,也可以有多个, 语法符号要使用引号包含;
variables: 特定的变量适用于特定的模块,录入$remote_addr

例如基本的配置: access_log /var/log/nginx/access.log main info;, 其中access_log就表示配置命令, 后面的三个字段表示配置值, 其中 info 为日志的 LEVEL, main 表示标签段位置信息.

常见配置项

块配置项

例如下面章节中所述的http配置就是块配置项

1
2
3
4
5
6
7
8
9
10
11
12
# 1. nginx运行相关的全局配置
global;
# 2. 用户网络连接相关的全局配置
events;
# 3. 例如: HTTP, server, upstream, location等
block name 1 {
...
sub block name A {
# A块内的配置同时生效;
# A块继承1中的配置;
}
}

调试和日志

  1. 日志配置

log_format用于定义一个命名日志格式, 该命令日志会在access_log, error_log中被引用, 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http {
# 定义一个main命名日志格式
# [$time_local]: 访问时间
# $request: 请求方法、URI 和协议
# $status: HTTP 响应状态码
# $http_referer: 客户端浏览器中的 Referer 字段
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

# 设置访问日志, 并引用main来设置日志格式
access_log /var/log/nginx/access.log main info;
error_log /var/log/nginx/error.log main error;
}
1
2
3
4
5
6
7
daemon on/off:                               # 守护进程
master_process on/off: # 是否启用master

debug_point stop/abort: # 调试点,用于模块开发
debug_connection IP/CIDR: # 事件类配置,仅在events块配置中生效. 对指定的IP地址输出DEBUG级别的日志信息
worker_rlimit_core size: # dump core大小
worker_directory path: # dump core位置

环境变量和用户

1
2
3
4
5
6
7
8
9
10
11
12
13
# 定义环境变量
env VAR| VAR=value
# 嵌入其他配置文件
include /path/file
# pid文件路径
pid /path/file

# worker进程运行的用户和用户组, 启动master之后,fork出的新的worker运行在哪些user:group下,一般master为root,worker为www-data
user username[groupname]
# worker最大描述符个数
worker_rlimit_nofile limit
# worker最大信号队列
worker_rlimit_sigpending limit

优化性能配置项

1
2
3
4
5
6
7
8
9
10
# worker进程数, 对于阻塞式调用,应该多配置一些worker,此时单CPU单worker明显不适用,但是cpu切换代价过大
worker_process number;
# 绑定worker, 绑定CPU
worker_cpu_affinity cpumask,cpumask;
# SSL硬件加速
ssl_engine device;
# gettimeofday系统调用频率
time_resolution t;
# worker进程优先级, 优先让nginx占用资源,但不介意低于内核进程nick值(-5)
worker_priority nice;

事件类配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
# 是否开启accept负载均衡锁, 某个worker连接数过多(7/8比例),会降低连接,默认打开
accept_mutex on;
# lock文件,搭配accept锁, 有些系统上无需使用该文件即可做到均衡锁机制
lock_file path/file
# 开启accept后的真正连接延迟时间, worker等待获取锁的最大延时
accept_mutex_delay Nms;
# 批量建立客户端发起的所有连接
multi_accept on/off;

# 选择事件模型, 默认自动选择最合适的事件
use [kqueue|poll|epoll];
# 单worker最大连接数
worker_connections number;

if 语法

通过使用 nginx 中支持的变量来进行 if 逻辑判断,例如:

1
2
3
if ($host = 'www.unusebamboo.com') {
return 302 https://unusebamboo.com$request_uri;
}

http 配置

基本格式

所有的 HTTP 配置项都必须直属于 http 块,server 块,location 块,upstream 块,if 块,即在 HTTP 大括号里面只能有上面的几个内嵌块

1
2
3
4
5
6
7
http {
server {
listen 80 default_server;
}
access_log /var/log/nginx/access.log main info;
include /etc/nginx/conf.d/*.conf;
}

注意, /etc/nginx/conf.d/目录下的配置就仅仅需要配置 server 即可, 因为他们在 http 中被 include, 这是一个非常重要的点.

主机配置

  1. 虚拟主机配置, 设置监听端口
1
2
# 例如IPV6配置:listen [:]: 8000;  SSL配置:listen 443 default_server ssl;
listen address: port[default_server|...];

参数:

1
2
3
4
5
6
7
8
9
default            将所在的server作为整个WEB服务的默认server块,否则会将第一个server块作为默认的server块.即默认虚拟主机
default_server 同default
backlog=num TCP连接中backlog的队列大小,如果满,新连接丢失
rcvbuf=size 监听句柄SO_RCVBUF参数
sndbuf=size 监听句柄SO_SNDBUF参数
accept_filter accept过滤器,适用于FreeBsd
deferred 客户建立连接,完成TCP三次握手,内核不会调度worker处理,除非真正的发送数据
bind 绑定address:port,仅仅在一个端口监听多个地址时,该配置才生效
ssl 基于SSL连接,否则无效
  1. 虚拟服务配置, 其通用配置如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
# HOST字段和server_name对比, 优先选择完全匹配项,如果匹配不到,使用默认虚拟主机
server_name name[...]

# server_name散列表内存大小, 配置块:http,server,location
server_names_hash_bucket_size size;

# server_name散列表最大内存大小, 配置块:http,server,location
# 减少hash过程中的冲突率,尽可能的加大内存
server_names_hash_max_size size;

# 重定向主机名称, 配置块:http,server,location
# 在转发请求时,会默认用server_name配置项中的值替换请求中的HOST字段
server_name_in_redirect on/off;

url 匹配

nginx 中 URL 正则匹配规则有点类似命令行正则匹配逻辑, 下面是 chatgpt 关于 nginx url 正则匹配的回答, 由此可以得出其匹配逻辑类似命令行的简单匹配规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
^ 和 $:表示匹配 URL 开头和结尾。例如,^/hello$ 匹配 URL 为 /hello 的请求。

.:匹配任意字符。例如,/ab.c 匹配 URL 为 /abc、/ab1c 等。

*:表示匹配前面的字符零次或多次。例如,/abc 匹配 URL 为 /ac、/abc、/abbc 等。

+:表示匹配前面的字符至少一次。例如,/ab+c 匹配 URL 为 /abc、/abbc、/abbbc 等。

?:表示匹配前面的字符零次或一次。例如,/ab?c 匹配 URL 为 /ac、/abc 等。

[]:表示匹配方括号内的任意一个字符。例如,/[abc]d 匹配 URL 为 /ad、/bd、/cd 等。

[^]:表示匹配方括号内的任意一个字符以外的字符。例如,/[^abc]d 匹配 URL 为 /dd、/ed、/fd 等。

():表示将括号内的表达式作为一个整体。例如,/(abc)+ 匹配 URL 为 /abc、/abcabc 等。

\:用于转义正则表达式中的特殊字符,例如,/? 表示匹配 URL 中的 ? 字符。

下面就尽可能穷举所有碰到的实例

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 所有路径开头都是/, 这个表示匹配所有
location / {
}

# 2. 匹配.php或.php5结尾的url, 注意: :, +, ?的区别
location .*\.(php|php5)+$ {
proxy_pass http://127.0.0.1:8090;
include proxy.conf;
}

# 3. 纯字符串匹配
location /images/ {
}

location

location 块通过指定特定的模式来与客户端请求的 URL 进行匹配, 其基本语法有如下两种

1
2
3
4
5
6
7
# 格式: location [指令模式] url匹配模式 {}, 其中指令模式指用于匹配的方式(精确, 前缀, 正则), url匹配模式则类似路由匹配

# 1. 通过指令模式 + URI正则来匹配, 其中URI正则见6.3节内容
location [=|~|~*|^~|@] uri正则 {...}

# 2. 命令location匹配, 例如6.3节中的try_files例子
location @/name/ { … }

其中 URL 的匹配规则如下:

1
2
3
4
5
6
=             完全或精确匹配
~ 大小写敏感匹配
~* 大小写不敏感匹配
^~ 只要URI的前半部分匹配即可,location ^~ /images/ {...}, 所有/images/的请求都匹配
@ nginx内部的重定向,不直接处理用户请求

例如, 有两个前端项目, 他们各自打包结束之后有自己的css, js, index.html等目录和文件, 使用场景例如某一个前端项目的帮助文档等. 那么, 对于此类项目如何配置 nginx 确保多个项目共用一个域名呢?

1
2
3
4
5
6
7
8
9
10
# a. 正式项目地址: ~: 大小写敏感, ^(
location ~ ^(/main) {
try_files $uri $uri /index.html;
}

# b. 这是帮助文档项目地址, 其中alias设置"资源路径"
location ^~ /helpCenter/ {
alias /data/project/help/;
index index.html index.html;
}

匹配优先级(见 gpt: nginx 配置中 url 匹配优先级?):

  • a. URL 匹配的优先级是从上到下依次匹配的, 一旦请求的 URL 地址匹配到某个 location 则会停止匹配
  • b. 另外, 若匹配规则过于复杂或过多则可能影响 nginx 的性能, 需要合理规划

但是对于指令模式, 其有优先级, 类似 css 样式的权重一样:

  • 权重 1: =精确匹配
  • 权重 2: ^~前缀匹配
  • 权重 3: ~~*

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 1. curl -I website.com:8080/document 返回 返回 HTTP/1.1 702
server {
server_name website.com;
location /doc {
return 701; # 用这样的方式,可以方便的知道请求到了哪里
}
location ~* ^/document$ {
return 702;

}
}

# 2. curl -I website.com:8080/document 返回 HTTP/1.1 702
server {
server_name website.com;
location /document {
return 701;
}
location ~* ^/document$ {
return 702;
}
}

# 3. curl http://website.com/document 返回 HTTP/1.1 701
server {
server_name website.com;
location ^~ /doc {
return 701;
}
location ~* ^/document$ {
return 702;
}
}

路径定位

  1. root 和 alias

root 方式设置资源路径, 用来指定请求静态资源时的根目录, 可以用来指定 Nginx 服务器的根目录, 配置块:http,server,location,if:

1
2
3
4
5
# 查找/opt/web/html/download/路径下文件, 例如url: http://127.0.0.1/download/show.html, 则会找文件
# /opt/web/html/download/show.html
location /download/ {
root /opt/web/html/;
}

alias 方式设置资源路径, 用来指定 URL 路径和文件系统路径的对应关系, 用于指定某个目录作为请求的静态资源所在的根目录, 配置块:location

1
2
3
4
5
# 查找/opt/web/html/路径下文件, 例如url: http://127.0.0.1/download/show.html, 则会找文件
# /opt/web/html/show.html
location /download/ {
alias /opt/web/html/;;
}

其中 root 和 alias 的区别, 以请求的 URI/conf/nginx.conf为例:

1
2
3
4
5
6
7
8
9
# 1. 返回/usr/local/nginx/conf2/目录下的nginx.conf资源
location /conf/ {
alias /usr/local/nginx/conf2/;
}

# 2. 返回/usr/local/nginx/conf2/conf/nginx.conf
location /conf/ {
root /user/local/nginx/conf2/;
}

其中 alias 直接丢弃 location 中的匹配部分, root 则仅仅是拼接路径, alias 仅仅用在 location 配置块中, 关于 location 见 6.4 节描述.

  1. index 访问首页配置, 配置块:http, server,location

index 配置项用于设置 Web 服务器默认的索引文件(默认值为 index.html), 若存在该文件则返回, 否则返回文件目录或者 404.

1
2
index file1, file2, ...;
# 说明: 对于请求/,alias和root在这里一般不生效,由index来返回首页信息,其中优先级:file1>file2>...
  1. try_files指令用于在请求的文件不存在时尝试其他文件或路径

它的作用是根据指定的顺序查找指定的文件或路径, 如果找到了其中一个, 则直接返回该文件或路径的内容.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 配置块:server,location, 其中file 可以是本地文件路径或 URL, uri 是 Nginx 内部的 URL
try_files path1[path2] uri;

# 1. 说明: 尝试按照顺序访问,如果成功读取就返回,如果所有path都读取不到,直接重定向到URI上
try_files /system/1.html $uri/index.html $uri.html @other;
location @other {
proxy_pass http://backend;
}

# 2.
location / {
try_files $uri $uri/ /index.php?$args;
# 如果找到请求的文件,直接返回该文件
# 如果找不到请求的文件,则将请求转发给 index.php 处理
}

try_files 指令只会查找本地文件或内部 URL, 而不会向后端服务器发送请求, 有效的降低了 web 后端服务器负担, 当然, 若是再通过proxy_pass(7.1 节)反向代理来转发就不一样了.

资源分配

TCP 连接预分配内存池大小

1
2
语法:connection_pool_size size
配置块:http, server

HTTP 连接预分配内存池带下:

1
2
3
4
语法:request_pool_size size;
配置块:http, server
说明:
TCP连接池和HTTP连接池的分配销毁是不同步的,一个TCP连接可复用于多个HTTP请求

请求和响应

  1. 超时时间配置
1
2
3
4
5
6
7
8
9
10
11
12
# 1. 读取HTTP header超时时间
client_header_timeout time;
# 配置块:http, server, location

# 2. 读取HTTP body超时时间
client_body_timeout time;
# 配置块:http, server, location

# 3. 连接超时时发送RST包
reset_timeout_connection off|on;
# 配置块:http, server, location
# 说明: 连接超时,不使用四次握手,直接发送RST包给客户端,释放所有缓存, 避免大规模的FIN_WAIT_1, FIN_WAIT_2, TIME_WAIT状态
  1. keepalive 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# keepalive超时时间
keepalive_timeout time;
# 配置块:http, server, location
# 说明: keepalive可以使用多个请求复用一个HTTP长连接,超时规范不是硬性规定,nginx发送给各个浏览器,浏览器本身有不同的策略

# 单个keepalive允许承载的请求最大数
keepalive_requests n;
# 配置块:http, server, location;

# 对keepalive使用TCP_NODELARY选项
tcp_nodelay on|off;
# 配置块:http, server, location

# 对keepalive使用TCP_nopush选项
tcp_nopush on|off
# 配置块:http, server, location
# 说明: 开启TCP_NOPUSH后,会将整个响应包头放到一个TCP包中发送

HTTP 返回码重定向:

1
2
3
4
5
6
7
8
9
10
11
12
13
配置块:http, server, location, if
语法:error_page code[code2, ...] [=|=answer-code] uri|@named_location
功能:根据请求的返回码来重定向URL
例子:
error_page 404 /404.html; 重定向到404页面
error_page 502 503 504 /50x.html;
error_page 403 http://web1.com/forbidden.html;

error_page 404=403 /forbidden.gif 使用=来更改返回码,并且重定向页面
error_page 404= /empty.gif 不立刻修改返回码,又重定向后的URL来决定返回码

error_page 404 @facebock; 重定向到另外一个location来进行处理
error_page 404= @facebock; 重定向到location=facebock,并由后者决定返回码

递归使用 error_page:

1
2
配置块:http, server, location
命令:recursive_error_pages off;

MIME 设置

定义 type 到文件扩展名的映射:

1
2
3
4
5
6
7
8
语法:types { ... };
配置块:http, server, location
例子:
types {
text/html html;
text/html conf;
image/gif gif;
}

默认 MIME 类型

1
2
3
4
语法:default_type MIME-type;
配置块:http, server, location
例子:
default_type text/plain;

请求限制

按照 HTTP 方法名限制用户请求

1
2
3
4
5
6
7
8
语法:limit_except method1,... {...};
配置块:location
例子:
limit_except GET {
allow 192.168.1.0/32;
deny all;
}
对所有的除192.168.1.0/32的GET方法阻止,其中allow和deny类似iptables,优先级从上到下;

Request Body 的最大值

1
2
3
4
语法:client_max_body_size size;
配置块:http, server, location
说明:
即限制content-length的大小

Request 的限速,每秒传输的字节数

1
2
3
4
5
6
7
8
9
语法:limit_rate speed;
配置块:http, server, location, if
例子:
针对不同的客户端,进行不同的限速
server {
if ($slow) {
set $limit_rate 4K;
}
}

页面压缩

说明:GUN-zip 压缩技术,减少页面大小,是的用户浏览页面时更快,需要 Browser 和 Server 共同支持,即 Server 压缩,Browser 解压;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 开启或者关闭
语法:gzip on|off;
配置块:http
# 最小压缩页面字节数
语法:gzip_min_length size;
配置块:http
说明: 页面字节数从header头Content-Length中获取,其中小于1K的页面效率不高

# gzip缓存内存池
语法:gzip_buffer 4 16k;
配置块:http
说明: 系统获取几个单位的缓存用于存储gzip压缩结果,16K为单位,4表示个数

# gizp压缩比
语法:gzip_comp_level 2;
配置块:http
说明: 压缩比,1~9,其中1压缩比最小,但是处理速度快

# gzip操作MIME对象
语法:gzip_types type1, type2, [...]
配置块:http
说明:
text/html始终存在,其他需要设置
例子:
注意,可以换行哦
gzip_types application/javascript
text/plain
text/css
image/svg+xml
...

# 设置vary头部,判断是否需要zip
语法:gzip_vary on|off;
配置块:http

反向代理

upstream, proxy_pass, proxy_set_header, proxy_cache, proxy_connect_timeout 等

proxy_pass

proxy_pass 指令用于将客户端的请求转发给另一个服务器进行处理,并将该服务器的响应返回给客户端, 配置块:location, if. 其整个流程如下:

  • 代理服务器接口 Request 请求,并将 Request 转发给内部网络中的上游服务器
  • 上游服务器将 Response 返回给客户端

其中 reverse prxoy 对外表现为一个代理, 通过这种反向代理实现负载均衡, 提高 Web 服务器的性能和可靠性. proxy_pass作为反向代理的一部分, 其作用如下:

  1. 负载均衡:通过反向代理,将客户端的请求分发到多个后端服务器上,以均衡服务器负载,提高应用程序的性能和可靠性。
  2. 安全防护:通过反向代理,将后端服务器隐藏在防火墙后面,保护后端服务器的安全。
  3. URL 重写:通过反向代理,将客户端的请求 URL 转换为后端服务器能够处理的 URL 格式,以实现 URL 重写和反向映射等功能。
  4. 静态文件缓存:通过反向代理,将静态文件缓存在代理服务器上,以提高文件访问速度和服务器性能。

其配置示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location / {
proxy_pass http://localhost:8000/uri/;
}
# UNIX句柄
location / {
proxy_pass http://unix:/path/to/backend.socket:/uri/;
}
# 负载均衡upstream
location / {
proxy_pass http://backend;
}
# 转为https
location / {
proxy_pass https://192.168.0.1;
}

其他配置

  1. 常用配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 功能: 指定反向代理服务器使用的 HTTP 请求方法, 默认请求下使用同原始请求相同的HTTP请求方法
语法:proxy_method METHOD
配置块:http, server, location

# 功能: 隐藏或忽略指定头部字段, 隐藏反向代理服务器的一些敏感信息, 提高系统的安全性
语法:proxy_hide_header the_header;
配置块:http, server, location

# 白名单头部字段,在转发时
语法:proxy_pass_header the_header;
配置块:http, server, location

# 向上游服务器转发HTTP body
语法:proxy_pass_request_body on|off
配置块:http, server, location

# 向上游服务器转发HTTP header
语法:proxy_pass_request_header on|off
配置块:http, server, location

上面基本配置的实例如下:

1
2
3
4
5
6
7
8
9
10
location / {
proxy_pass http://backend;

# 1. 更改METHOD
proxy_method POST;

# 2. 隐藏几个关键header
proxy_hide_header Server;
proxy_hide_header X-Powered-By;
}
  1. proxy_redirect重定向配置, 上游服务器返回重定向或者刷新请求的响应时, 重新修改 URL 和 HTTP 头信息

格式: proxy_redirect [default|off|redirect replacement], 其实例如下

1
2
3
4
location / {
proxy_pass http://backend-server;
proxy_redirect http://backend-server/ http://proxy-server/;
}

这样配置之后, 就能确保backend-server完全对客户透明.

upstream

  1. upstream 定义后端服务器的地址, 以便反向代理服务器可以将客户端的请求转发给后端服务器处理

格式: upstream name { ... }, 注意 upstream 仅仅是反向代理的一个组成部分, 其实例如下:

1
2
3
4
5
6
7
8
9
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}

location / {
proxy_pass http://backend;
}
  1. proxy_next_upstream指令用于在发生代理错误时,切换到下一个后端服务器。

语法格式: proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]

  • error: 当后端服务器返回 500 或 502 错误时切换
  • timeout: 表示当与后端服务器的连接超时时切换
  • invalid: 不合法响应
  • 5xx: 表示当后端服务器返回 5xx 错误时切换

其实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 实现功能: proxy_pass将/请求转发到后端服务器backend(负载均衡), proxy_next_upstream则在发生错误或超时时自动切换到下一个upstream中指定的服务器.
upstream backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
server 192.168.1.12:8080;
}

server {
listen 80;
server_name example.com;

location / {
proxy_pass http://backend;
proxy_next_upstream error timeout;
}
}
  1. 上游服务器指的是一组相同功能的服务器, 用于处理反向代理服务器接收到的请求, 注意将其同server {}块语法区分开来.

语法格式: server name1 [parameters], 其中name1可以是域名,IP 地址端口,UNIX 句柄, paramters 有如下的选项:

  • weigth=number:上游服务器的权重
  • max_fails=number: 转发失败次数上限,超过则剔除
  • fail_timeout=time: 转发超时时间
  • down: 表示上游服务器永久下线,搭配 ip_hash 使用
  • backup: 表示上游服务器仅仅作为备份服务器,所有正常服务器失效时会启动备份,在 ip_hash 存在时,该选项失效
  1. upstream_addr获取当前请求所要代理的上游服务器的地址, 并通过add_header返回给客户端
1
2
3
4
5
6
7
8
9
10
11
12
upstream myapp {}
server {
listen 80;
server_name example.com;

location / {
proxy_pass http://myapp;
add_header X-Upstream-Addr $upstream_addr;
# upstream_staus也是类似原理
add_header X-Upstream-Status $upstream_status;
}
}

负载均衡

nginx 负载均衡有两种方式实现:

  • ip hash 算法: 对客户端 IP 地址进行哈希计算, 将其映射到不同的服务器上
  • 轮询算法(默认): Nginx 会将请求依次发送到每个服务器上, 直到所有服务器都被轮询过一遍, 然后再次开始轮询

其实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# IP hash算法, 此时不能使用weight权重
upstream myapp {
ip_hash;
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}

# 轮询算法, 这是默认值, 可以通过weight来为轮询添加权重
upstream myapp {
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
upstream myapp {
server 192.168.1.101:8080 weight=3;
server 192.168.1.102:8080 weight=1;
server 192.168.1.103:8080 weight=2;
}

其他配置

内部变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$server_name    # 虚拟主机名称
$remote_addr # 记录客户端IP地址,一般为代理IP地址
$http_x_forwarded_for # 正规的代理服务器会将用户的IP真实IP地址存入该字段
$remote_user # 记录客户端用户名称
$request # 记录请求的URL和HTTP协议
$status # 记录请求状态
$body_bytes_sent # 发送给客户端的字节数,不包括响应头的大小
$bytes_sent # 发送给客户端的总字节数.
$connection # 连接的序列号.
$connection_requests # 当前通过一个连接获得的请求数量.
$msec # 日志写入时间.单位为秒,精度是毫秒.
$pipe # 如果请求是通过HTTP流水线(pipelined)发送,pipe值为"p”,否则为".”.
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$request_length # 请求的长度(包括请求行,请求头和请求正文).
$request_time # 请求处理时间,单位为秒,精度毫秒; 从读入客户端开始,直到把最后一个字符发送给客户端后进行日志写入为止.
$time_iso8601 # ISO8601标准格式下的本地时间.
$time_local # 通用日志格式下的本地时间

其命令格式: 关键字 格式名称 格式, 例如:

1
log_format lagoulog 'v1{|]$remote_addr:$remote_port{|]....'

White list

设置多个白名单, 以便跨域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
set $cors_origin "";
if ($http_origin ~* "^http://127.0.0.1$") {
set $cors_origin $http_origin;
}

if ($http_origin ~* "^http://localhost$") {
set $cors_origin $http_origin;
}

add_header Access-Control-Allow-Origin $cors_origin;


location / {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $cors_origin;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
return 204;
}
}

Example

文件下载

需求: 访问特定目录, 返回的静态网页直接显示服务器上指定目录的文件列表, 并可以进入特定的目录

配置:

1
2
3
4
5
6
7
8
9
10
11
server{
location ^~ /downloadFile/ {
# 需要下载的文件存放的目录, 注意alias会替换掉目录
alias /home/downloadFile/;
sendfile on;
autoindex on; # 开启目录文件列表
autoindex_exact_size on; # 显示出文件的确切大小,单位是bytes
autoindex_localtime on; # 显示的文件时间为文件的服务器时间
charset utf-8,gbk; # 避免中文乱码
}
}

另外, 如果服务器不是 https, 可以设置 chrome 确保不自动进行 http 跳转: http 不跳转

多域名

以本博客以前的架构为准,在 2024 年以前我的博客结构如下:

old-nginx

其中 unusebamboo.top 和 blog.unusebamboo.top 都是静态服务(以前不知道为何这样部署),他们的代码都在此 nginx 服务器上,所以不需要做反向代理设置,此时的 nginx 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
server {
listen 443 ssl http2 default_server;
server_name unusebamboo.top;
root /data/bamboo;

ssl_certificate "/path/unusebamboo.top.pem";
ssl_certificate_key "/path/unusebamboo.top.key";
...

server_tokens off;
large_client_header_buffers 4 16k;
add_header Cache-Control no-cache;
add_header Cache-Control private;
if ($request_method !~ ^(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS)$ ) {
return 404;
}
}


# Settings for a TLS enabled server.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_name blog.unusebamboo.top;
root /path/http/bamboo;
index index.html;

...

# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;

location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
{
expires 7d;
}

location ~ .*\.(?:js|css)$
{
expires 7d;
}
location ~ .*\.(?:htm|html)$
{
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
}

error_page 404 /404.html;
location = /40x.html {
}

error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}

引用