Nginx服务使用指南

Nginx

  Nginx 是一款高性能的Web服务器,最初由俄罗斯工程师 Igor Sysoev 编写,目前在生产环境下大规模使用,Nginx常用于HTTP请求的反向代理和负载均衡,同样支持TCP协议层的代理和负载均衡,Nginx 的功能是模块化开发与使用,这一点与Apache 服务器一样,除此之外,Nginx还提供健康检查、限流、邮件代理等多种功能,是开发人员构建高性能和高可用后端服务架构的首选组件。

2004年10月Nginx 发布第一个公开版本 0.1.0

2011年4月,Nginx 1.0.0 稳定版本发布 ,至此之后,每隔6个月发布一次稳定版本,即到 2021年4月发布1.20.0 版本。

功能特性

轻量级,占用内存小

高并发性能好, 支持单机10万并发连接

模块化功能

Nginx 除了少量核心代码外,所有功能都是以模块化的方式提供,常见模块如下:

模块名称 描述
ngx_http_core_module HTTP 核心模块
ngx_http_rewrite_module 重定向模块
ngx_http_ssl_module SSL模块
ngx_http_gzip_module 压缩功能模块
ngx_http_log_module 日志记录模块
ngx_http_auth_basic_module 用户认证模块
ngx_http_access_module 访问控制模块
ngx_http_proxy_module 反向代理模块
……

更多功能模块请查看[官方文档](https://nginx.org/en/docs/

)。

编译安装 Nginx

​ Nginx 可以通过yum 方法一键安装,但安装后的nginx 所包含的功能都是默认自带的,有时不能满足我们的需求,所以生产环境下的nginx 一般都是源码编译进行安装的。

在安装 Nginx之前,需要确保操作系统至少安装如下几个软件:

  • gcc 编译器
  • PCRE 库
  • zlib 库
  • OpenSSL 库
# 安装gcc 编译器
yum install -y gcc
# 安装PCRE库 (支持正则表达式)
yum install -y pcre pcre-devel
# 安装zlib库 (对HTTP包做gzip压缩)
yum install -y zlib zlib-devel
# 安装openssl(支持安全的SSL协议)
yum install -y openssl openssl-devel

在 Nginx官网下载源码,将下载好的源码压缩包解压到指定目录。然后执行3个命令就可以完成Nginx的编译安装:

/.config
make
make install

注:这是标准的Linux环境下C源码软件的编译安装流程。

编译参数

如果已安装Nginx,需要查看当前安装版本的编译参数:

root@9964178a4812:/# nginx -V
nginx version: nginx/1.21.5
built by gcc 10.2.1 20210110 (Debian 10.2.1-6) 
built with OpenSSL 1.1.1k  25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-1.21.5/debian/debuild-base/nginx-1.21.5=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie'

其中configure arguments这个参数是非常重要的,我们在后面安装其他模块的时候,需要以这个为基础,增加新的参数。

Nginx 进程

​ Nginx 服务由一个主进程和N个工作进程组成,master 进程用于读取和处理配置文件,以及维护工作流程;worker 进程对请求进行实际处理。

​ Nginx 使用基于事件的模型和依赖于操作系统的机制高效的在工作进程分配请求。工作进程的数量可以在配置文件中指定。可以使用配置文件的默认值,也可以调整为CPU 的物理内核数量。

​ Nginx 是支持单进程提供服务的,但生产环境下都会使用 一个 master 进程和N个worker 进程提供服务,这样的优势有很多,第一,多个worker进程处理请求可以有效提高服务的健壮性(一个worker进程出错后,其他 worker 进程可以继续对外提供服务);第二,多个worker 进程可以充分利用多核 CPU 架构,实现真正意义上的并行处理。

常用命令

nginx 服务的常用操作命令:

start nginx			# 启动nginx
nginx -s reload  # 向主进程发送信号,重新加载配置文件,热重启
nginx -s reopen   # 重启 Nginx
nginx -s quit    # 等待工作进程处理完成后关闭
nginx -s stop    # 快速关闭
nginx -T         # 查看当前 Nginx 最终的配置
nginx -t         # 检查配置是否有问题
nginx -V	# 打印nginx版本,编译器版本和配置参数
ps -ax | grep nginx	# 查看nginx进程

注:-s 表示向主进程发送信号。

​ 安装nginx 后使用 nginx -V 查看nginx版本,编译器版本和配置参数,这个命令非常实用,可以帮助你确认nginx的版本,确认哪些功能模块被编译进去,--with 开头的参数基本上都是控制哪些功能模块参与编译,只有被编译的模块才能提供相应的功能。确认配置文件、日志文件、工作目录的位置等重要信息:

configure arguments: 
--prefix=/etc/nginx 
--sbin-path=/usr/sbin/nginx 
--modules-path=/usr/lib64/nginx/modules 
--conf-path=/etc/nginx/nginx.conf 
--error-log-path=/var/log/nginx/error.log 
--http-log-path=/var/log/nginx/access.log 
--pid-path=/var/run/nginx.pid 
--lock-path=/var/run/nginx.lock 
--http-client-body-temp-path=/var/cache/nginx/client_temp 
--http-proxy-temp-path=/var/cache/nginx/proxy_temp 
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp 
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp 
--http-scgi-temp-path=/var/cache/nginx/scgi_temp 
--user=nginx 
--group=nginx 
--with-compat --with-file-aio --with-threads --with-http_flv_module 
......

select poll 和 epoll

IO 复用模型

配置文件

Nginx 的配置文件名为 nginx.conf ,下面是Nginx 的典型配置示例::

# main段配置信息
user  nginx;                        # 运行用户,默认即是nginx,可以不进行设置
worker_processes  auto;             # Nginx 进程数,一般设置为和 CPU 核数一样
error_log  /var/log/nginx/error.log warn;   # Nginx 的错误日志存放目录
pid        /var/run/nginx.pid;      # Nginx 服务启动时的 pid 存放位置

# events段配置信息
events {
  use epoll;     # 使用epoll的I/O模型(如果你不知道Nginx该使用哪种轮询方法,会自动选择一个最适合你操作系统的)
  worker_connections 1024;   # 每个进程允许最大并发数
}

# http段配置信息: 配置使用最频繁的部分,代理、缓存、日志定义等绝大多数功能和第三方模块的配置都在这里设置
http { 
  # 设置日志模式
  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

  access_log  /var/log/nginx/access.log  main;   # Nginx访问日志存放位置

  sendfile            on;   # 开启高效传输模式
  tcp_nopush          on;   # 减少网络报文段的数量
  tcp_nodelay         on;
  keepalive_timeout   65;   # 保持连接的时间,也叫超时时间,单位秒
  types_hash_max_size 2048;

  include             /etc/nginx/mime.types;      # 文件扩展名与类型映射表
  default_type        application/octet-stream;   # 默认文件类型

  include /etc/nginx/conf.d/*.conf;   # 加载子配置项

  # server段配置信息
  server {
	listen       80;       # 配置监听的端口
	server_name  localhost;    # 配置的域名

	# location段配置信息
	location / {
		root   /usr/share/nginx/html;  # 网站根目录
		index  index.html index.htm;   # 默认首页文件
		deny 172.168.22.11;   # 禁止访问的ip地址,可以为all
		allow 172.168.33.44;# 允许访问的ip地址,可以为all
    }

    error_page 500 502 503 504 /50x.html;  # 默认50x对应的访问页面
	error_page 400 404 error.html;   # 同上
    }
}
  • main 全局配置,对全局生效;
  • events 配置影响 Nginx 服务器与用户的网络连接;
  • http 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置;
  • server 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块;
  • location 用于配置匹配的 uri ;
  • upstream 配置后端服务器具体地址,负载均衡配置不可或缺的部分;

用一张图清晰的展示它的层级结构:

nginx配置层次

nginx.conf 配置文件的语法规则:

  1. 配置文件由指令与指令块构成
  2. 每条指令以 “;” 分号结尾,指令与参数间以空格符号分隔
  3. 指令块以 {} 大括号将多条指令组织在一起
  4. include 语句允许组合多个配置文件以提升可维护性
  5. 通过 # 符号添加注释,提高可读性
  6. 通过 $ 符号使用变量
  7. 部分指令的参数支持正则表达式,例如常用的 location 指令

配置文件位置

Nginx 配置文件位置一般在 /etc/nginx/usr/local/nginx/conf 目录下,可以使用 nginx -t 命令查看配置文件所在位置。

root@9964178a4812:/# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

当然你也可以通过 ngixn -c 命令指定自定义的配置文件。

Nginx 配置文件的内容主要分为三部分:

  • 全局配置
  • events 配置
  • http 服务配置

全局配置

​ 全局块配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,设置工作进程数量等。

示例:

########### 每个指令必须有分号结束 #################
user administrator administrators;  #配置用户或者组,默认为nobody nobody。
worker_processes 2;  #允许生成的进程数,默认为1
pid /nginx/pid/nginx.pid;   #指定nginx进程运行文件存放地址
#指定日志路径、级别,这个设置可以放入全局块,http块,server块,级别:debug|info|notice|warn|error|crit|alert|emerg
error_log log/error.log debug;  

设置用户

使用 user 指令配置用户,这很关键,如果配置的用户权限不够,则服务可能异常。

设置工作进程

​ Nginx有一个主进程和多个工作进程,主进程用于读取和处理配置文件,以及维护工作流程;工作进程对请求进行实际处理。

worker_processes 用于指定Nginx 工作进程的数量,这个配置直接影响Nginx的性能,每个工作进程都是单线程的进程。一般情况下,要配置与CPU物理内核数相等的 worker 进程,并且使用 worker_cpu_affinity 配置来绑定固定的CPU 内核,每个worker 进程独享一个CPU内核,互不抢占,就可以实现真正的并发。

worker_processes  4;
worker_cpu_affinity 1000 0100 0010 0001;

注:worker_cpu_affinity 配置可能只对 Linux系统有效;

设置日志级别

​ 日志输出级别的优先级从小到大依次是:debug、info、notice、warn、error。当设定为一个级别时,大于等于该级别的日志都会输出到指定位置。

error_log /var/log/nginx/error.log info;

events 配置

​ events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。

示例:

events {
    accept_mutex on;   #设置网路连接序列化,防止惊群现象发生,默认为on
    multi_accept on;  #设置一个进程是否同时接受多个网络连接,默认为off
    #use epoll;      #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
    worker_connections  1024;    #最大连接数,默认为512
}

惊群现象:一个网路连接到来,多个睡眠的进程被同事叫醒,但只有一个进程能获得链接,这样会影响系统性能。

http 配置

​ http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。

server块:配置虚拟主机的相关参数,一个http中可以配置多个server。

location块:配置请求的路由,以及各种页面的处理情况。

示例:

http {
    include       mime.types;   #文件扩展名与文件类型映射表
    default_type  application/octet-stream; #默认文件类型,默认为text/plain
    # access_log off; #取消服务日志    
    log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
    access_log log/access.log myFormat;  #combined为日志格式的默认值
    sendfile on;   #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
    sendfile_max_chunk 100k;  #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
    keepalive_timeout 65;  #连接超时时间,默认为75s,可以在http,server,location块。

    upstream mysvr {   
      server 127.0.0.1:7878;
      server 192.168.10.121:3333 backup;  #热备
    }
    error_page 404 https://www.baidu.com; #错误页
    server {
        keepalive_requests 120; #单连接请求上限次数。
        listen       4545;   #监听端口
        server_name  127.0.0.1;   #监听地址       
        location  ~*^.+$ {       #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
           #root path;  #根目录
           #index vv.txt;  #设置默认页
           proxy_pass  http://mysvr;  #请求转向mysvr 定义的服务器列表
           deny 127.0.0.1;  #拒绝的ip
           allow 172.18.5.54; #允许的ip           
        } 
    }
} 

server 虚拟主机

在 Nginx 的配置中,server_name 指令用于指定一个虚拟主机的域名或 IP 地址。它定义了 Nginx 需要监听哪个主机名或 IP 地址来处理客户端请求。

具体来说,server_name 指令有以下几个作用和意义:

  1. 虚拟主机配置: 通过指定不同的 server_name,你可以在同一台服务器上配置多个虚拟主机(Virtual Hosts)。每个虚拟主机可以拥有自己的独立的配置,从而实现在同一台服务器上托管多个网站或应用。
  2. 请求路由: 当客户端发送请求时,Nginx 将根据请求中的 Host 头字段匹配合适的 server_name,然后将请求路由到匹配的虚拟主机配置中进行处理。
  3. SSL 证书匹配: 在 HTTPS 协议中,浏览器会向服务器发送一个 HTTPS 请求,在请求头中包含了 Host 头字段。Nginx 可以使用 server_name 指令来匹配请求的域名,然后选择相应的 SSL 证书来进行 SSL 握手。
  4. 反向代理和负载均衡: 在配置反向代理或负载均衡时,server_name 可以帮助 Nginx 将请求路由到正确的后端服务器。
  5. 日志记录: server_name 可以作为访问日志(access log)或错误日志(error log)的一部分,帮助区分不同虚拟主机的访问情况。

server_name 指定服务器名称,可以使用确切名称、通配符名称或正则表达式来定义。

server {
    listen       80;
    server_name  example.org  www.example.org; # 确切名称
    ...
}
server {
    listen       80;
    server_name  *.example.org;		# 通配符名称
    ...
}
server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;	# 正则表达式名称
    ...
}

location 匹配

语法

location [ = | ~ | ~* | ^~ ] uri { ... };

location 指令用于匹配URL :

  • ^~ 对URL做前缀匹配;(无符号时的默认选项)
  • = 对URL做精确匹配;
  • ~ 对表示区分大小写的正则匹配;
  • ~* 表示不区分大小写的正则匹配;

root 与 alias 的区别

在Nginx中,aliasroot是用来指定服务器上文件系统路径的两个不同指令,它们有一些区别:

root指令

  • root指令用于定义在请求中指定的URI的文件系统路径的根目录。
  • 当一个请求到达时,Nginx会将URI与root指令结合,以确定要提供给客户端的文件的路径。
  • 如果URI是/images/pic.jpg,并且root指令设置为/var/www,Nginx将尝试提供/var/www/images/pic.jpg文件。
location /images/ {
    root /var/www;
}

alias指令

  • alias指令用于将请求的URL路径重定向到文件系统中不同于root路径的位置。
  • 它允许将请求映射到文件系统的不同位置,而不是在root指令所定义的位置。
  • 当使用alias时,Nginx会将匹配的部分替换为指定的目录。
  • root不同,alias不会将请求中匹配的URI添加到文件系统路径中。
location /images/ {
    alias /var/www/images/;
}

​ 举例来说,对于请求 /images/pic.jpg,如果使用alias,Nginx会将其重定向到/var/www/images/pic.jpg,而不会将/images添加到文件系统路径中。相比之下,如果使用root,则文件系统路径将是/var/www/images/images/pic.jpg

​ 总的来说,alias适合在不同路径映射到文件系统的情况下使用,而root用于设置服务器根目录。

所以下面的配置是等价的:

location /images/ {
    alias /data/w3/images/;
}
location /images/ {
    root /data/w3;
}

server 和 location 中的 root

server 和 location 中都可以使用 root:

http { 
  server {
    listen 80;
    server_name www.yayujs.com;
    	root /home/www/website/;
    	location / {
      		root /home/www/ts/;
	      	index index.html;
    	}
  }
}

如果两者都出现,是怎样的优先级呢?简单的来说,就是就近原则,如果 location 中能匹配到,就是用 location 中的 root 配置,忽略 server 中的 root,当 location 中匹配不到的时候,则使用 server 中的 root 配置。

默认服务器

​ Nginx获取客户端请求的HTTP头部信息中 Host字段,来确定将请求路由到哪个服务器。如果其值与任何服务器都不匹配,或者HTTP请求的头部根本不存在Host字段,则Nginx会将请求路由到该端口的默认服务器,默认服务器是第一个服务器,可以使用 default_server 参数明确指定默认服务器。

server {
    listen      80 default_server;
    server_name example.net www.example.net;
    ...
}

日志配置

Nginx访问日志主要有两个参数控制

access_log #用来指定日至文件的路径及使用的何种日志格式记录日志
log_format #用来定义记录日志的格式(可以定义多种日志格式,取不同名字即可)

访问日志

在 Nginx 中配置访问日志(access log)非常简单,你只需要在 Nginx 配置文件中的 server 块中添加 access_log 指令即可。下面是一个简单的示例:

server {
    listen 80;
    server_name example.com;

    location / {
        root /var/www/html;
        index index.html;
    }

    access_log /var/log/nginx/access.log;
}

在这个配置中,access_log 指令定义了访问日志文件的路径。在这个例子中,日志文件将被写入到 /var/log/nginx/access.log 文件中。

你还可以在 access_log 指令后面添加一些参数,以定制日志的格式和其他属性。例如:

access_log /var/log/nginx/access.log combined;

在这个例子中,使用了 combined 参数,它指示 Nginx 使用常见的组合日志格式(Combined Log Format)。你也可以自定义日志格式,例如:

log_format custom '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent"';

access_log /var/log/nginx/access.log custom;

这个例子中,定义了一个名为 custom 的日志格式,然后在 access_log 指令中使用了这个自定义的日志格式。

错误日志

在 Nginx 中配置错误日志(error log)同样非常简单,你可以在 Nginx 配置文件中的 http 块或 server 块中添加 error_log 指令。下面是一个简单的示例:

http 块中配置全局错误日志:

http {
    ...
    error_log /var/log/nginx/error.log;
    ...
}

在这个配置中,error_log 指令定义了错误日志文件的路径为 /var/log/nginx/error.log,这将是一个全局的错误日志文件,记录了所有 Nginx 服务器中的错误。

你也可以在 server 块中为每个虚拟主机定义单独的错误日志文件。以下是一个示例:

server {
    ...
    error_log /var/log/nginx/example.com.error.log;
    ...
}

在这个示例中,错误日志文件将被写入到 /var/log/nginx/example.com.error.log 中。

你可以在 error_log 指令后面添加一些参数,以定制错误日志的格式和其他属性,类似于 access_log 指令。例如:

error_log /var/log/nginx/error.log info;

在这个例子中,使用了 info 参数,它指示 Nginx 记录 info 级别及以上的日志信息。

除了全局错误日志和每个虚拟主机的错误日志之外,你还可以在 location 块中定义特定位置的错误日志。这在需要针对某个特定请求路径进行错误日志记录时非常有用。总之,通过 error_log 指令,你可以方便地配置 Nginx 的错误日志,以便及时发现和解决服务器问题。

变量

Nginx中存在两种变量:

  • 内置预定义变量
  • 自定义变量

内置的预定义变量

​ Nginx 中有许多内置的预定义变量,可以在配置文件中使用。这些变量提供了有关客户端请求、连接、服务器和其他相关信息的访问。以下是一些常用的 Nginx 内置预定义变量:

$arg_parameter: 获取请求中的查询参数,例如 $arg_name 表示获取名为 "name" 的查询参数的值。
$host: 获取请求的 Host 头部字段的值。
$http_user_agent: 获取请求的 User-Agent 头部字段的值,即客户端的浏览器信息。
$remote_addr: 获取客户端的 IP 地址。
$remote_port: 获取客户端的端口号。
$request_method: 获取 HTTP 请求的方法,如 GET、POST 等。
$request_uri: 获取请求的 URI,示例:/proxy-test?name=wyc
$scheme: 获取请求的协议类型,如 http 或 https。
$server_addr: 获取服务器的 IP 地址。
$server_name: 获取服务器的名字或 IP 地址。
$server_port: 获取服务器的端口号。
$uri: 获取请求的 URI,包含查询参数部分。
$document_root: 获取请求的文件路径。
$is_args: 如果请求中包含查询参数,则为 "?",否则为空字符串。
$request_filename: 获取正在处理的文件路径。
$query_string: 获取请求中的查询字符串,即问号后面的部分。

注:

​ 如要要获取自定义请求头,使用 $http_ 前缀即可,比如 $http_cus_auth 获取的是 Cus-Auth 请求头的值。

​ 如果要获取请求中的查询参数,使用 $arg_ 前缀即可,比如 $arg_name 表示获取 name 的查询参数的值。

​ 需要注意的是,预定义变量的名称通常以 $ 开头,并使用特定的命名约定。在配置文件中使用这些变量时,需要将其放在双引号中,以便正确地解析和替换变量的值

有关 Nginx 预定义变量的完整列表和更详细的说明,可以参考 Nginx 官方文档的相关章节。

location /test-param {
           add_header T-host $host;
		add_header T-http_user_agent $http_user_agent;
		add_header T-remote_addr $remote_addr;
		add_header T-remote_port $remote_port;
		add_header T-request_method $request_method;
		add_header T-request_uri $request_uri;
		
		add_header T-uri $uri;
		add_header T-server_addr $server_addr;
		add_header T-server_name $server_name;
		add_header T-server_port $server_port;
		add_header T-query_string $query_string;
		add_header T-arg_name $arg_name;
		add_header T-remote_user $remote_user;
		add_header T-time_local $time_local;
		add_header T-request $request;
		add_header T-status $status;

           return 200 "Test OK!";
       }

GET 方式请求:http://10.2.112.95:8090/test-param?name=45,返回的响应头信息:

T-Http_user_agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
T-Host:10.2.112.95
T-Remote_addr:10.2.113.90
T-Remote_port:61162
T-Server_addr:10.2.112.95
T-Server_name:127.0.0.1
T-Server_port:8090

T-Request:GET /test-param?name=45 HTTP/1.1
T-Request_method:GET
T-Request_uri:/test-param?name=45
T-Uri:/test-param
T-Query_string:name=45
T-Arg_name:45
T-Time_local:21/Feb/2024:16:35:57 +0800
T-Status:200

自定义变量

location b/ {
  set $a hello
  return 200 $a
}

拒绝访问

​ 如果想拒绝头部信息不存在Host字段的HTTP请求访问,可以配置一个空字符串的服务器名与之匹配,并返回特殊代码,已关闭连接。

server {
    listen      80;
    server_name "";
    return      444;
}

开启压缩

开启 nginx gzip 后,图片、CSS、js 等静态资源会被压缩后传输,节省网络带宽,提高传输效率,但会消耗CPU资源。

gzip on;	# 开启gzip
gzip_min_length 10k;	# 启用压缩的最小文件大小,小于该值的文件不会被压缩
gzip_comp_level 2;	# 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
gzip_types text/plain application/javascript application/x-javascri	# 进行压缩的文件类型 
gzip_http_version 1.1;  #设置压缩http协议的版本,默认是1.1
gzip_vary on;  #在http头信息添加Vary: Accept-Encoding

我们可以在配置文件的http块和server 块中配置压缩

Nginx的Gzip压缩功能虽然好用,但是下面两类文件资源不太建议启用此压缩功能。
1) 图片类型资源 (还有视频文件)
原因:图片如jpg、png文件本身就会有压缩,所以就算开启gzip后,压缩前和压缩后大小没有多大区别,所以开启了反而会白白的浪费资源。(可以试试将一张jpg图片压缩为zip,观察大小并没有多大的变化。虽然zip和gzip算法不一样,但是可以看出压缩图片的价值并不大)

2) 大文件资源
原因:会消耗大量的cpu资源,且不一定有明显的效果。

拆分配置文件

​ 通过在Nginx 配置文件中配置,Nginx 可以提供很多自定义的功能,此时 nginx.conf 配置文件的体积会越来越大,不容易维护。nginx 提供 include 指令来拆分配置文件。

/etc/nginx/nginx.conf 文件内容:

user  nginx;
worker_processes  auto;

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

events {
    worker_connections  1024;
}

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"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/default.conf 文件:

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }
    
     location /education-learn/api/ {
                 proxy_set_header X-Real-IP $remote_addr;
                 proxy_set_header REMOTE-HOST $remote_addr;
                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                 proxy_pass http://112.126.64.163:8071;
    }

    location /education-manager/api/ {
    		 proxy_set_header X-Real-IP $remote_addr;
    		 proxy_set_header REMOTE-HOST $remote_addr;
    		 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    		 proxy_pass http://112.126.64.163:8091;
    } 
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

注:一般按模块或功能来拆分配置文件的内容。

mime.types文件

​ Nginx 的 mime.types 文件是一个用于定义 MIME 类型的文件,它将文件扩展名与对应的 MIME 类型关联起来。MIME 类型是一种标识文件类型的机制,用于指示浏览器如何处理和展示特定类型的文件。

mime.types 文件通常位于 Nginx 配置目录下的 /etc/nginx 目录中。它包含一系列以扩展名为基础的 MIME 类型定义,每个定义一行。以下是一个 mime.types 文件的示例:

types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/javascript                js;
    application/pdf                       pdf;
    application/octet-stream              bin exe dll;
    application/json                      json;
}

​ 在示例中,每行定义了一个 MIME 类型及其关联的文件扩展名。例如,text/html html htm shtml; 表示将 .html.htm.shtml 扩展名的文件关联到 text/html MIME 类型。

​ 当 Nginx 接收到请求时,它会根据请求的文件扩展名查找 mime.types 文件中的定义,并将适当的 MIME 类型返回给客户端。这样客户端就知道如何处理收到的文件。

mime.types 文件的作用在于确保浏览器正确解释和处理服务器返回的文件类型,以便正确渲染页面、展示图像、执行脚本等

​ 需要注意的是,可以根据实际需求自定义和修改 mime.types 文件。例如,添加新的 MIME 类型定义或修改现有的定义。修改后的配置需要重新加载或重启 Nginx 才能生效。总而言之,mime.types 文件是 Nginx 用于定义文件扩展名与 MIME 类型之间的映射关系的配置文件,它对于正确处理和展示不同类型的文件非常重要。

配置文件示例

环境:一台Linux主机,一个IP地址:112.126.64.163,拥有两个域名:yxsc.kunlun.cloud 和 patrol.iwater.plus;

要求两个域名都使用 https 访问;本机安装了docker,启动了4个容器服务:2个前端服务(nginx镜像,端口8070和8090)和2个后端服务(Java镜像,端口 8071和8091)

user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

include /etc/nginx/default.d/*.conf;
include /etc/nginx/conf.d/*.conf;

events {
    worker_connections 1024;
}

http {
    access_log  /var/log/nginx/access.log  main;
    error_log  /var/logs/nginx-error.log error;
    
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    
    client_max_body_size   200m;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   60;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    add_header Content-Security-Policy "frame-ancestors patrol.iwater.plus:8092 patrol.iwater.plus:443 patrol.iwater.plus http://110.43.70.232:7010 http://110.43.70.232:8088 http://110.43.70.232:8093";
    #proxy_redirect off;
    #proxy_set_header Host $host;
    #proxy_set_header X-Real-IP $remote_addr;
    #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    server {
        listen 30888;
        server_name localhost;
        location /{
            root /opt/swj/h5;
            index  index.html index.htm;
        }
    }
    server {
        listen 30886;
        server_name localhost;
        location /{
            root /opt/swj/h5/jingtong;
            index  index.html index.htm;
        }
    }

    server {
    	server_name  yxsc.kunlun.cloud; 
        listen 443 ssl;
        ssl on;
        ssl_session_cache    shared:SSL:1m;
        ssl_certificate /etc/nginx/cert/fullchain.crt;
        ssl_certificate_key /etc/nginx/cert/private.pem;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; 
        ssl_prefer_server_ciphers on;
		index index.html;

        location /{
            proxy_pass  http://localhost:8070;
            proxy_set_header X-Forwarded-For $remote_addr;
			add_header 'Access-Control-Allow-Origin' '*';
    	    add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT, OPTIONS';
    	    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    	    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
			if ($request_method = OPTIONS) {
				add_header Access-Control-Allow-Methods *;
				add_header Access-Control-Allow-Headers *;
				return 204;
			}
        }
        
        location /education-manager/api{
            proxy_pass  http://localhost:8091;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        
        location /education-learn/api{
            proxy_pass  http://localhost:8071;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
     
        location /manage{
            proxy_pass  http://localhost:8090/manage;
            proxy_set_header X-Forwarded-For $remote_addr;
			
			add_header 'Access-Control-Allow-Origin' '*';
    	    add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT, OPTIONS';
    	    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    	    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
			
			if ($request_method = OPTIONS) {
				add_header Access-Control-Allow-Methods *;
				add_header Access-Control-Allow-Headers *;
				return 204;
			}
        }

        location /learn{
            proxy_pass  http://localhost:8070/learn;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        

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

    server {
        listen 8088;
        server_name patrol.iwater.plus;
        rewrite ^(.*)$    https://$host$1    permanent;
        
		location /xcx-h5/jt/{
            proxy_pass  http://localhost:30886/jt/;
	 	}
		location /xcx-h5/videoApi/ {
            proxy_pass http://120.52.191.154:8080/;
            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;
        }
		location /xcx-h5/{
            proxy_pass  http://localhost:30888/;
        }
        location /api/{
            proxy_pass  http://localhost:8040/;    
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location /education-manager/api{
            proxy_pass  http://localhost:8091;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
		location /elastic/{
            proxy_pass  http://localhost:9200/;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

        location /basis/attachments/files/preview/{
            proxy_pass  http://localhost:8040/basis/attachments/files/preview/;
        }

        location /{
            proxy_pass  http://localhost:8080/;    
        }

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

    server {
        listen 443 ssl;
        ssl on;
        ssl_session_cache    shared:SSL:1m;
        server_name patrol.iwater.plus;
        ssl_certificate /etc/letsencrypt/live/patrol.iwater.plus/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/patrol.iwater.plus/privkey.pem; # managed by Certbot 
        ssl_session_timeout 5m;
        index index.html;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #表示使用的TLS协议的类型,您需要自行评估是否配置TLSv1.1协议。
        ssl_prefer_server_ciphers on;
        charset utf-8;       
        location ^~ /historyFiles/ {
            alias /opt/historyFiles/;
            autoindex on;
            sendfile on;
            autoindex_exact_size on;
            autoindex_localtime on;
            charset utf-8;
            add_header Content-Disposition: 'attachment;';
         }

         location /xcx-h5/jt/{
            proxy_pass  http://localhost:30886/;
         }
	
	 location /sxcx-h5/videoApi/ {
        proxy_pass http://120.52.191.154:8080/;
	    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;
	    access_log /var/log/nginx/proxy.log;
	    add_header backendIP $upstream_addr;
    }

        location /xcx-h5/{
            proxy_pass  http://localhost:30888/;
        }

        location /api/{
            proxy_pass  http://localhost:8040/;    
            proxy_set_header X-Forwarded-For $remote_addr;
        }

        location /education-manager/api{
            proxy_pass  http://localhost:8091;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        
        location /education-learn/api{
            proxy_pass  http://localhost:8071;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

		location /elastic/{
            proxy_pass  http://localhost:9200/;
            proxy_set_header X-Forwarded-For $remote_addr;
        }

        location /basis/attachments/files/preview/{
            proxy_pass  http://localhost:8040/basis/attachments/files/preview/;
        }

        location /{
            proxy_pass  http://localhost:8080/;    
        }
		location = /2U7ISJL5xd.txt {
        	alias /2U7ISJL5xd.txt;
        }

		location /static/WEBPlayer.msi {
            proxy_pass http://110.43.70.232;  # 代理到VM服务
       	}
       	error_page 404 /404.html;
            location = /40x.html {
       }     
    }

  server {
        listen 8092 ssl;
        ssl on;
        ssl_session_cache    shared:SSL:1m;
        server_name patrol.iwater.plus;
        ssl_certificate /etc/letsencrypt/live/patrol.iwater.plus/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/patrol.iwater.plus/privkey.pem;
        ssl_session_timeout 5m;
        index index.html;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; #表示使用的TLS协议的类型,您需要自行评估是否配置TLSv1.1协议。
        ssl_prefer_server_ciphers on;
	ssl_ciphers HIGH:!aNULL:!MD5;
        location /{
            proxy_pass  http://110.43.70.232:7010;
         }
	location /VIID{
            proxy_pass  http://110.43.70.232:8088;
         }
	location /vdapi{
            proxy_pass  http://110.43.70.232:8093;
         }
 }
  server {
        listen 8188;
        server_name localhost;
        location /{
            root /root/software-testing/swj/h5;
            index  index.html index.htm;
	    add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
   	    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
    	    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
        }
    }
}

静态资源服务

​ 许多web项目基本上都是前后端分离开发,为了加速前端页面的响应速度,可以将前端的相关资源,如html,js,css或者图片放到nginx指定目录下。访问的时候只需要IP加路径就可以实现高效快速的访问。

缓存设置

在开发调试web的时候,经常会碰到因浏览器缓存(cache)而经常要去清空缓存或者强制刷新来测试的烦恼,在常用的缓存设置里面有两种方式,都是使用add_header来设置:分别为Cache-ControlPragma

location ~ .*\.(css|js|swf|php|htm|html )$ {
  add_header Cache-Control no-store;
  add_header Pragma no-cache;
}

​ 对于站点中不经常修改的静态内容(如图片,JS,CSS),可以在服务器中设置expires 过期时间,控制浏览器缓存,达到有效减小带宽流量,降低服务器压力的目的。

以Nginx服务器为例:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
  expires 30d;	#过期时间为30天,图片文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
}

location ~ .*\.(js|css)$ {
  expires 10d;
}

注:Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

Cache-control策略
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。

​ http协议头Cache-Control 值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age,各个消息中的指令含义如下:

  • Public指示响应可被任何缓存区缓存。
  • Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
  • no-cache指示请求或响应消息不能缓存
  • no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
  • max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
  • min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
  • max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since 要配合Cache-Control使用。

  • Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。
  • If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。

反向代理

ngx_http_proxy_module 模块提供将请求转发的其他服务器的功能,即反向代理。使用 proxy_pass 指令使用代理功能。

  server {
      listen 8088;
      server_name patrol.iwater.plus;
      
location /xcx-h5/jt/{
          proxy_pass  http://localhost:30886/jt/;
	}
location /xcx-h5/videoApi/ {
          proxy_pass http://120.52.191.154:8080;
          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_pass 指令配置反向代理。

proxy_set_header指令用于设置要发送到后端服务器的HTTP请求头。这个指令通常与proxy_pass指令一起使用。

  • Host:设置后端服务器的主机头,通常设置为被请求的主机名。
  • X-Real-IP:设置客户端的真实IP地址。
  • X-Forwarded-For:设置客户端IP地址列表,经过多个代理时使用,以识别客户端的真实IP地址。
  • X-Forwarded-Proto:设置客户端使用的协议(HTTP或HTTPS)。

这些是常见的配置参数,但你也可以根据需要设置其他自定义的HTTP头字段。请注意,在设置这些头字段时,可以使用Nginx的变量来获取相关信息。

除了添加请求头,Nginx 还支持修改和删除请求头。下面是一些常用的指令:

proxy_set_header:设置请求头的值。如果已经存在同名的请求头,则会覆盖它的值。
proxy_set_header_if_empty:仅在请求头不存在或值为空时设置请求头的值。
proxy_add_header:添加请求头,不会覆盖已有的同名请求头。
proxy_hide_header:删除指定的请求头。

配置示例

配置后的效果:

  • 访问 192.168.0.105:8000/purchase 跳转到 192.168.0.106:9001

  • 访问 192.168.0.105:8000/order 跳转到 192.168.0.106:9101

http {
	server {
      listen       8000;
      server_name  192.168.0.105;
     
      location ~/purchase/ {
          root   /usr/share/nginx/html;
          proxy_pass http://192.168.0.106:9001;
          index  index.html index.htm;
      }
      location ~/order/ {
          root   /usr/share/nginx/html;
          proxy_pass http://192.168.0.106:9101;
          index  index.html index.htm;
      }
    }
}

重写URL

​ Nginx重写功能(Rewrite)由ngx_http_rewrite_module模块提供,可使用正则表达式改变请求的URI,返回重定向地址或内容,并可以根据条件选择适当的配置。

重写指令格式如下:

# 关键字 正则表达式 代替的内容 重写类型
rewrite regex replacement [flag]

rewrite只能放在server{},location{},if{}中,并且只能对域名后边的除去传递的参数外的字符串起作用,例如 http://seanlook.com/a/we/index.php?id=1&u=str 只对/a/we/index.php重写。

示例:

https://patrol.iwater.plus/api/education-manager/api/manage/user/validationUserStatus 先对URL中的path进行重写,然后重定向到其他域名,最终访问 https://yxsc.kunlun.cloud/education-manager/api/manage/user/validationUserStatus ,rewrite 和 proxy_pass 指令可以一起使用:

location /api/education-manager {  
   rewrite ^/api/(.*) /$1 break;
         proxy_pass  http://localhost:8091;
         proxy_set_header X-Forwarded-For $remote_addr;
     }

重写类型

Nginx重写类型 [flag] 有last、break、redirect和permanent四种,如下:

  • last:本条重写规则匹配完成后,终止匹配后续重写规则,并重新发起请求继续匹配新的location URI规则;浏览器地址栏URL地址不变

  • break:本条重写规则匹配完成后,终止匹配后续重写规则; 浏览器地址栏URL地址不变

  • redirect:返回302临时重定向,浏览器地址会显示重写后的URL地址

  • permanent:返回301永久重定向,浏览器地址会显示重写后的URL地址

示例:

# 如果请求URL为/minio/ui/test/abc 那么 $1 就是 test/abc
server{
   ...
   location /minio/ui/ {
      rewrite ^/minio/ui/(.*) /$1 break;
      proxy_set_header Host $http_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;
   }
}

认证

Nginx 的两种认证方式:

  • 本机认证 auth_basic
  • 第三方认证 ngx_http_auth_request_module

本机认证

这样就实现了本机认证,需要维护 pass.db 文件

server {
    listen       80;
    server_name  local.server.com;
    
    auth_basic "User Authentication";
    auth_basic_user_file /usr/local/nginx-1.10.2/conf/pass.db;
    
    location / {
        root   /data/www;
        index  index.html;
    }
}

第三方认证

ngx_http_auth_request_module 是nginx的一个验证模块,它允许您的nginx通过发送请求到后端服务器(一般是应用服务器,例如tomcat,或者php等)进行请求, 并且根据请求决定是验证通过或者不通过。后端返回200 验证通过, 后端返回401或者403验证不通过。

该模块默认可以开启,可以在configure时使用–with-http_auth_request_module选项来开启。

Syntax:	auth_request uri | off;
Default:	auth_request off;
Context:	http, server, location

示例:

server {
    listen 80;
    server_name local.server.com;

    auth_request /auth; # 启用认证

    location /auth {
        proxy_pass https://yxsc.kunlun.cloud/api/authenticationp;   # 认证服务器地址
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header Cookie $http_auth_cookie    # 后端服务识别的认证字段
        proxy_set_header X-Original-URI $request_uri;
    }
}

HTTP 负载均衡

​ Nginx 可作为高效的HTTP负载均衡器,将流量分配到多个应用服务器,从而提高Web应用程序的性能,可伸缩性和可靠性。

​ HTTP负载均衡也称为七层负载均衡,因为HTTP协议位于网络OSI七层协议的第七层。除了七层负载均衡,还有四层负载均衡,即在TCP协议层上进行负载,LVS(linux virtual server)是目前全球最流行的四层负载均衡软件。

负载均衡算法

Nginx 支持的几种负载匀衡算法:

  • 轮询(round-robin)
  • 加权轮询(weight)
  • 最少连接(least-connected)
  • IP哈希(ip-hash)

ngx_http_upstream_module 模块用于将多个服务器定义成一个虚拟服务器组,

轮询(默认)

下面是负载均衡配置的简单示例,同一个应用程序的三个实例在 srv1- srv3 上运行,如果没有指定负载均衡算法,则默认为轮询。

http {
    upstream myapp1 {
        server srv1.example.com;
        server srv2.example.com;
        server srv3.example.com;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://myapp1;
        }
    }
}

所有请求都被代理到 myapp1 服务器组,然后 Nginx使用HTTP负载均衡来分发请求。

加权轮询

配置权重

上面的示例没有配置权重,默认情况下所有的服务器具有相同的权重。

当为服务器指定权重时,权重将参与负载均衡的选择计算。

upstream myapp1 {
    server srv1.example.com weight=3;
    server srv2.example.com;
    server srv3.example.com;
}

最少连接

最少连接算法:将请求分配给活动连接数最少的服务器;

​ 在某些请求需要较长时间才能完成的场景下,使用最少连接算法可以更好的控制实例的负载。在最少连接算法控制下,最繁忙的服务器不容易因为请求过多而过载,因为nginx 将新的请求分配给不太繁忙的服务器。

​ 在服务器组中使用 least_conn 指令将负载均衡设置为最少连接算法。

upstream myapp1 {
    least_conn;
    server srv1.example.com;
    server srv2.example.com;
    server srv3.example.com;
}

IP哈希

​ 注意,前面讲到的轮询和最少连接算法,每个客户端的后续请求都有可能分配到其他服务器,无法保证将同一客户端的请求始终分配到同一个服务器。

​ 如果想让同一客户端发起的请求始终发送到同一个服务器,可以使用 IP哈希算法,该算法将客户端的请求IP进行哈希,以确定分发到哪个服务器,相同的IP一定会计算出相同的哈希值,所以IP相同的请求一定可以分发到同一个服务器上。

​ 在服务器组中使用 ip_hash 指令将负载均衡设置为IP哈希算法。

upstream myapp1 {
   	ip_hash;
   	server srv1.example.com;
   	server srv2.example.com;
   	server srv3.example.com;
}

其他负载策略(插件)

另外, Nginx 还可以通过插件支持其他负载策略.

TCP 负载均衡

ngx_stream_core_module 模块提供TCP层面的反向代理和负载均衡,该模块在 1.9.0 版本发布,默认不构建,使用 --with-stream 配置参数编译才能使用。

简单示例:

worker_processes auto;

error_log /var/log/nginx/error.log info;

events {
    worker_connections  1024;
}

stream {
    upstream backend {
        hash $remote_addr consistent;

        server backend1.example.com:12345 weight=5;
        server 127.0.0.1:12345            max_fails=3 fail_timeout=30s;
        server unix:/tmp/backend3;
    }

    upstream dns {
       server 192.168.0.1:53535;
       server dns.example.com:53;
    }

    server {
        listen 12345;
        proxy_connect_timeout 1s;
        proxy_timeout 3s;
        proxy_pass backend;
    }

    server {
        listen 127.0.0.1:53 udp reuseport;
        proxy_timeout 20s;
        proxy_pass dns;
    }

    server {
        listen [::1]:12345;
        proxy_pass unix:/tmp/stream.socket;
    }
}

健康检查

​ Nginx 的反向代理实现中默认有服务健康检查功能,如果服务器响应失败,nginx 会将其标记为失败服务器,并在一段时间内不会将用户请求转发到该服务器上。

ngx_http_upstream_hc_module 模块提供服务的健康检查功能,使用 health_check 选项开启健康检查功能。

示例:

upstream dynamic {
    zone upstream_dynamic 64k;

    server backend1.example.com      weight=5;
    server backend2.example.com:8080 fail_timeout=5s slow_start=30s;
    server 192.0.2.1                 max_fails=3;

    server backup1.example.com:8080  backup;
    server backup2.example.com:8080  backup;
}

server {
    location / {
        proxy_pass http://dynamic;
        health_check;
    }
}

​ 上面的配置,nginx将每五秒钟/backend组中的每个服务器发送 / 请求。如果发生任何通信错误或超时,或者代理的服务器以2xx或3xx以外的状态代码响应,则运行状况检查将失败,并且服务器将被视为不正常。

max_fails 参数表示允许最大连续失败的次数,默认值为1,设置为 0 表示不开启健康状态检查。fail_timeout 表示失败后多长时间再次进行健康检查,如果响应正常,则将该服务器标记为正常状态。

参数:

# 设置两次连续运行状况检查之间的间隔,默认情况下为5秒
interval=time
# 设置特定服务器连续失败的运行状况检查次数,在此之后该服务器将被视为运行状况不佳,默认情况下为1。
fails=number
# 设置连续通过特定服务器的运行状况检查的次数,此后服务器将被视为运行状况良好,默认情况下为1。
passes=number
# 定义健康检查请求中使用的URI,默认情况下为“ /”。
uri=uri
# 指定match配置响应应通过以使运行状况检查通过的测试的块。默认情况下,响应应具有状态码2xx或3xx。
match=name
# 定义连接到服务器以执行运行状况检查时使用的端口。默认情况下,等于服务器端口。
port=number

使用 health_check match 来指定具体的健康检查匹配标准,默认响应状态码为2xx或3xx 就是健康的。

http {
    server {
    ...
        location / {
            proxy_pass http://backend;
            health_check match=welcome;
        }
    }

    match welcome {
        status 200;
        header Content-Type = text/html;
        body ~ "Welcome to nginx!";
    }
}

更多详细配置请参考官方文档

参数 描述 默认值
weight 服务器的权重 1
max_conns
max_fails 服务器的最大连续失败次数 1
fail_timeout 失败后被视为不可用的时间段 10s
backup 标记为备用服务器, 当主服务不可用时才会提供服务
down 将服务器标记为不可用
slow_start 慢启动 默认值为0,即禁止慢启动

注:

​ 阿里云负载均衡 SLB 服务使用LVS实现四层负载均衡(TCP、UDP),使用Nginx实现七层负载均衡(HTTP、HTTPS)。

限速

​ 从客户端的角度来讲,网速分为网络上传速度和网络下载速度。上传速度指的是从客户端到服务器的网络数据传送速度,下载速度指的是从服务器到客户端的网络数据传送速度。

​ Nginx 的 模块提供网络限流的功能。

ngx_http_limit_conn_module 模块用于限制网络连接数量。

下面配置限制每个客户端ip与服务器的连接数,同时限制每个虚拟服务器的网络连接总数:

server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

限流算法

网络限流算法有多种,常用的有漏桶算法(leaky bucket)和令牌桶算法(token bucket)。

漏桶算法(leaky bucket)

漏桶算法强制一个常量的输出速率而不管输入流的突发性。

规则如下:

  • 将请求放入桶中;
  • 服务定速的从桶里取出请求进行处理;
  • 桶里的请求满了就拒绝请求;
image-20210215103509486

​ 无论请求量有多大,速度有多快,经过漏桶这么一过滤,流量就平滑的流出来。但漏桶算法也存在一定的缺点,那就是无法处理突击流量,尤其是在秒杀这种场景下,突击流量会在很短的时间段内请求服务器,此时需要服务器最大限度的去处理更多的请求,但是按照漏桶算法规则执行的话,服务器依旧是按照恒定的速率处理请求,所以这是缺点所在,而令牌桶算法可以很好的解决这个问题。

令牌桶算法(token bucket)

规则如下:

  • 定速的往桶里放入令牌;
  • 请求到达桶内先申请令牌,成功后才可以处理请求,否则拒绝处理;
  • 令牌数量达到上限后,丢弃令牌。
image-20210215103434023

基于令牌桶算法,在面对突击流量来临时,服务器可以短时间内一次性处理突击流量,用户体验更佳。

注:Google 的Java开源类库 Guava提供了网络限流的工具类 RateLimiter。

限制请求速度

​ 短时间内有大量客户请求访问时,如果服务器的处理能力不够,或者请求流量过大,容易使业务服务器挂掉,此时采取限制网络速度是一个行之有效的办法。

​ nginx 支持两种常用的限流方式,一是控制并发连接数,二是控制速率。

控制连接数

ngx_http_limit_conn_module 模块提供了限制连接数功能。

示例:

https://nginx.org/en/docs/

server {
    ...
    limit_conn perip 10;
    limit_conn perserver 100;
}

limit_conn perserver 100 作用的key是 $server_name,表示虚拟主机同时能处理并发连接的总数。

控制速率

ngx_http_limit_req_module 模块提供限制网络请求的处理速率,nginx使用漏桶算法实现限流。

示例:

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
    ...
    server {
        ...
        location /search/ {
            limit_req zone=one burst=5;
        }

​ 上面的示例表示平均每秒最多允许不超过1个请求,并且突发不超过5个请求。

​ 如果请求速率超过了配置的处理速率,请求会延迟处理,以达到恒定速率处理请求。过多的请求会被延迟,直到数量达到最大突发数量 burst 为止,默认 burst 值为0,即超过速率的请求都会被拒绝。

限制下载速度

限制客户端下载速度,这个话题大多数人都不陌生,某度网盘就是这么设计的(不付费,只能被恶心)。

ngx_http_core_module 提供了限制服务器数据传输到客户端的功能,即常说的限制下载速度。

location /flv/ {
	flv;
	limit_rate_after 	500m;
	limit_rate			50k;
}

针对每一个请求,客户端下载的前500M不限速,超过500M后就限速为50k/s 。

服务高可用

​ LVS + Keepalived + Nginx + 业务服务器 即可构建一个高可用的服务架构。LVS 提供四层负载均衡,Keepalived 保证负载均衡集群系统的高可用,避免单点故障的发生;Nginx 提供七层负载均衡。

Keepalived

Keepalived 是用C语言编写的网络路由软件(开源免费)。主要目的是为Linux系统和基于Linux的基础架构提供负载均衡和高可用性的强大功能。

​ Keepalived 基于VRRP协议实现,VRRP是Virtual Router Redundancy Protocol(虚拟路由冗余协议)的缩写。VRRP协议将多台路由设备虚拟成一个设备,对外提供相同的虚拟IP。

​ Keepalived 不会单独使用,一般都会配合路由转发软件(LVS、Nginx、HAProxy)一起工作。项目开源地址:https://github.com/acassen/keepalived ,Keepalived 在2000年发布第一个版本,发展历程已有二十余年,目前版本更新仍然活跃。

主要功能:

  • 负载均衡
  • 高可用性

下载

yum install -y keepalived

配置文件 keepalived.conf 位于/etc/keepalived 目录下:

global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id LVS_DEVEL
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_script chk_nginx {
	script ""
	interval 2		# 间隔
	weight 1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.200.16
        192.168.200.17
        192.168.200.18
    }
}

virtual_server 192.168.200.100 443 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.201.100 443 {
        weight 1
        SSL_GET {
            url {
              path /
              digest ff20ad2481f97b1754ef3e12ecd3a9cc
            }
            url {
              path /mrtg/
              digest 9b3a0c85a887a256d6939da88aabd8cd
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

virtual_server 10.10.10.2 1358 {
    delay_loop 6
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    sorry_server 192.168.200.200 1358

    real_server 192.168.200.2 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.200.3 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334c
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

virtual_server 10.10.10.3 1358 {
    delay_loop 3
    lb_algo rr
    lb_kind NAT
    persistence_timeout 50
    protocol TCP

    real_server 192.168.200.4 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }

    real_server 192.168.200.5 1358 {
        weight 1
        HTTP_GET {
            url {
              path /testurl/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl2/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            url {
              path /testurl3/test.jsp
              digest 640205b7b0fc66c1ea91c463fac6334d
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

LVS(linux virtual server)

LVS(linux virtual server,Linux 虚拟服务器)是在Linux真实服务器集群上构建的高可拓展和高可用的服务器;

​ 值得一提的是,LVS 是在中国国内发起的开源软件项目,创始人–章文嵩(国防科技大学博士),1998年5月创立LVS。LVS集群的代码已在Linux 2.6的官方内核中,并得到广泛的应用。LVS 通常与 Keepalived 一起使用。

高级进阶

最佳实践

下面是一个完整的Nginx配置文件,/etc/nginx/nginx.conf 文件内容:

user  nginx;
worker_processes  auto;

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

events {
    worker_connections  1024;
}

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"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/server.conf 文件内容:(拆分)

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html;
    }

    location /manager/ {
    		 proxy_set_header X-Real-IP $remote_addr;
    		 proxy_set_header REMOTE-HOST $remote_addr;
    		 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    		 proxy_pass http://112.126.64.163:8070/;
    }
    
     location /education-learn/api/ {
                 proxy_set_header X-Real-IP $remote_addr;
                 proxy_set_header REMOTE-HOST $remote_addr;
                 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                 proxy_pass http://112.126.64.163:8071;
    }

    location /education-manager/api/ {
    		 proxy_set_header X-Real-IP $remote_addr;
    		 proxy_set_header REMOTE-HOST $remote_addr;
    		 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    		 proxy_pass http://112.126.64.163:8091;
    } 
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

先看主配置文件 nginx.conf,下面是对其中各部分的解释:

  1. user nginx;:指定 Nginx 进程的运行用户。在这个示例中,Nginx 进程将以 nginx 用户的身份运行。

  2. worker_processes auto;:指定 Nginx 使用的工作进程数。auto 表示根据可用的 CPU 核心数自动确定工作进程的数量。

  3. error_log /var/log/nginx/error.log notice;:指定错误日志文件的路径和日志级别。这里的日志级别为 notice,表示只记录通知级别及以上的错误信息。

  4. pid /var/run/nginx.pid;:指定保存 Nginx 主进程的进程 ID(PID)文件的路径。

  5. events 块:定义 Nginx 的事件模型和相关参数。

    • worker_connections 1024;:指定每个工作进程所能支持的最大并发连接数。
  6. http 块:定义 HTTP 服务器配置。

    • include /etc/nginx/mime.types;:指定 MIME 类型的配置文件。
    • default_type application/octet-stream;:指定默认的 MIME 类型。
    • log_format main ...;:定义访问日志的格式,包括 IP 地址、访问时间、请求内容、状态码等信息。
    • access_log /var/log/nginx/access.log main;:指定访问日志文件的路径和日志格式。
    • sendfile on;:启用 sendfile 机制,加速文件传输。
    • keepalive_timeout 65;:设置保持活动连接的超时时间。
    • include /etc/nginx/conf.d/*.conf;:包含额外的配置文件,这里是 /etc/nginx/conf.d/ 目录下所有的 .conf 文件。

​ 该配置文件中定义了 Nginx 的基本设置,包括工作进程数、日志路径、事件模型、访问日志格式等。通过这些配置,可以定制化 Nginx 的行为和性能,同时也可以包含额外的配置文件以扩展功能。


再看拆分出的server.conf 配置文件,下面是对其中各部分的解释:

  1. listen 80;listen [::]:80;:指定 Nginx 监听的端口,分别为 IPv4 和 IPv6 的 80 端口。

  2. server_name localhost;:定义该虚拟主机的域名或 IP 地址,这里为 localhost。

  3. access_log /var/log/nginx/host.access.log main;:指定访问日志文件的路径和格式。

  4. location /:匹配请求的 URL 路径为根路径 /

    • root /usr/share/nginx/html;:指定根路径对应的本地文件系统路径。
    • index index.html;:指定默认的索引文件为 index.html

    当用户访问根路径时,Nginx 将返回 /usr/share/nginx/html/index.html 文件的内容。

  5. location /manager/:匹配请求的 URL 路径以 /manager/ 开头。

    • proxy_set_header:设置代理请求的头信息,其中包括客户端真实 IP 地址和远程主机地址。
    • proxy_pass http://112.126.64.163:8070/;:将请求转发给指定的后端服务器地址。

    当用户访问以 /manager/ 开头的路径时,Nginx 会将请求转发给 http://112.126.64.163:8070/ 这个后端服务器。

  6. location /education-learn/api/location /education-manager/api/:类似于 /manager/,匹配特定的 URL 路径,并进行相应的代理转发。

  7. error_page 500 502 503 504 /50x.html;:定义错误页面的处理方式。

    • location = /50x.html:当出现 500、502、503 或 504 错误时,返回 /usr/share/nginx/html/50x.html 文件的内容。

​ 以上就是该 Nginx 配置文件的详细解释。它定义了监听端口、虚拟主机名称、日志文件路径、请求路径的匹配规则和代理转发等配置。根据实际需求,你可以根据这个示例进行相应的修改和定制化。

配置允许跨域

同源策略是浏览器的安全策略,默认情况下不允许跨域请求,但可以通过其他方式配置允许跨域,常用的有两种方式:

  • 配置反向代理
  • 配置CORS响应头

第一种方式是将不同源的请求改为同源请求,也就不存在跨域问题,然后在nginx配置反向代理

proxy_pass http://api:3000;

第二种方式是配置CORS响应头,以允许跨域。

 server {
 	server_name  yxsc.kunlun.cloud; 
     listen 3088;

     location /{
add_header 'Access-Control-Allow-Origin' 'http://cas.example.cn';
 	    add_header 'Access-Control-Allow-Methods' 'GET, POST,PUT, OPTIONS';
 	    add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,Cache-Control,Content-Type,Range';
 	    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = OPTIONS) {
	return 204;
}
     }
 }

内容安全策略CSP

CSP 通过 Content-Security-Policy 响应头来控制:

add_header Content-Security-Policy "frame-ancestors patrol.iwater.plus ";

Content-Security-Policy(CSP)头部是一个重要的安全特性,它允许网站管理员定义哪些内容来源是可信的,从而限制和报告浏览器加载的资源。其主要作用包括:

  1. 限制资源获取:CSP可以限制网页中一系列的资源获取情况,包括从哪里获取资源以及请求发送到哪个位置。这可以通过default-src指令来限制全局的和链接相关的作用范围,也可以通过其他指令如connect-srcimg-src等来根据资源类型限制资源范围。
  2. 报告资源获取越权:当网页尝试获取不应该获取的资源时,CSP可以报告资源获取越权的情况,使网站管理员能够做出相应调整。这有助于防止潜在的安全风险,如跨站脚本攻击(XSS)。
  3. 提高灵活性并防止恶意代码:与前端的“同源策略”相比,CSP提供了一种更为灵活的方式。同源策略限制了一个页面的资源只能从与之同源的服务器获取,而CSP则允许管理员制定策略,只允许页面向允许的域名发起跨域请求,从而防止恶意攻击。

总的来说,Content-Security-Policy头部是一个强大的安全工具,它可以帮助网站管理员更好地控制和管理其网站的内容来源,提高网站的安全性。需要注意的是,随着Web技术的不断发展,CSP也需要不断更新和完善以适应新的安全威胁和挑战。

安全配置

基础防护设置

nginx 版本信息隐藏

server_tokens off; 

黑白名单

# 白名单:只允许192.168.1.0/24网段的主机访问,拒绝其他所有
location /path/ {
    allow 192.168.1.0/24;
    deny all;
}
# 黑名单:
location /path/ {
    deny 192.168.1.0/24;
    allow all;
}
# 更多的时候客户端请求会经过层层代理,我们需要通过$http_x_forwarded_for来进行限制,可以这样写
set $allow false;
if ($http_x_forwarded_for = "211.144.204.2") { set $allow true; }
if ($http_x_forwarded_for ~ "108.2.66.[89]") { set $allow true; }
if ($allow = false) { return 404; }

配置SSL证书

在Nginx中配置SSL证书涉及到一些步骤,以下是一个简单的指南:

  1. 获取SSL证书: 你需要从证书颁发机构(CA)或使用自签名证书创建SSL证书。如果你正在为生产环境获取SSL证书,通常建议从可信的CA获取。

  2. 准备SSL证书文件: 从CA获取的SSL证书通常包括两个主要部分:证书文件(.crt)和私钥文件(.key)。确保你将这两个文件准备好。

  3. 将证书和私钥文件上传到服务器: 将.crt和.key文件上传到你的服务器,最好放在一个安全的目录中,只有root或有相应权限的用户可以访问。

  4. Nginx配置文件: 打开Nginx配置文件(通常位于/etc/nginx/nginx.conf/etc/nginx/sites-available/default),并进行以下更改:

    nginxCopy codeserver {
        listen 443 ssl;
        server_name your_domain.com;
    
        ssl_certificate /path/to/your_domain.crt;
        ssl_certificate_key /path/to/your_domain.key;
    
        # 其他 SSL 配置,如优先加密算法、SSL 版本等
        # ssl_protocols TLSv1.2 TLSv1.3;
        # ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
        # ssl_prefer_server_ciphers on;
    
        # 配置 SSL 会话缓存
        # ssl_session_cache shared:SSL:10m;
        # ssl_session_timeout 10m;
    
        location / {
            # 其他网站配置
        }
    }

    确保替换your_domain.com/path/to/your_domain.crt/path/to/your_domain.key为你实际的域名和证书文件路径。

  5. 测试配置: 运行nginx -t来测试Nginx配置文件是否存在语法错误。

  6. 重启Nginx: 如果测试通过,使用以下命令重新加载Nginx配置:

    sudo service nginx reload
    或者
    sudo systemctl reload nginx
  7. 防火墙设置: 确保防火墙允许流量通过SSL端口(默认是443)。你可能需要更新防火墙规则,以便允许HTTPS流量。

完成这些步骤后,你的Nginx服务器应该已经配置了SSL证书,并能够通过HTTPS提供安全的连接。请记得定期更新证书,并注意SSL配置的最佳实践以提高安全性。

JS脚本

​ NGINX JavaScript 简称 njs,是 JavaScript 语言的子集,实现了部分 ECMAScript 5.1(strict mode)规范和 ECMAScript 6 规范,可以使用 njs 来扩展 Nginx 功能。

nodejs 和 njs

​ Node.js 使用 V8 引擎在内存中有一个持久化的 JavaScript 虚拟机 (VM) 并执行垃圾收集以进行内存管理;而 njs 是专门为 Nginx 设计,非常轻量,会为每个请求初始化一个新的 JavaScript VM 和必要的内存,并在请求完成时释放内存。

​ JavaScript 的规范是由 ECMAScript 标准定义,随着标准版本的更新迭代,会支持更多的语言功能;njs 自研的服务端运行时,更多的优先支撑服务于 Nginx,只实现了 ECMAScript 5.1 和部分 ECMAScript 6 规范,实现更多标准规范的同时,更多会考虑是否是 Nginx 所需要的。

njs安装配置

安装 nginx-module-njs 动态模块,需要 Nginx 版本为 1.9.11 之后支持动态模块的载入。

yum install nginx-module-njs

安装后,在配置文件 nginx.conf 中需要使用 load_module 指令加载 njs 动态模块。

load_module modules/ngx_http_js_module.so;

nginx.conf:

http {
    js_import http from http.js;
    # or js_import http.js;

    server {
        listen 8000;
        location / {
            js_content http.hello;
        }
    }
}

http.js

function hello(r) {
    r.return(200, "Hello world!");
}

export default {hello};

js_import : 导入一个 njs 模块,没有指定模块名称则默认为文件名称。

js_content : 使用 njs 模块里导出的方法处理这个请求。

Fetch API

HTTP Proxying

使用 njs 模块处理 HTTP 请求,并使用 subrequest 发起子请求。

访问Redis数据库

使用 redis2-nginx-module 动态模块,结合 subrequest 来访问 Redis 数据。

访问Mysql数据库

Lua脚本

​ 在Nginx中编写Lua脚本通常是通过OpenResty框架来实现的,它提供了ngx_lua 模块,允许你在Nginx配置中嵌入Lua代码。以下是一个简单的示例,展示了如何在Nginx配置中使用Lua脚本。

​ 首先,确保你已经安装了OpenResty,它包含了ngx_lua 模块和 LuaJIT。

​ 然后,在你的Nginx配置文件中(通常是nginx.conf或者某个包含在nginx.conf中的配置文件),你可以定义一个location,并使用content_by_lua_block指令来嵌入Lua代码。例如:

http {  
    # ... 其他配置 ... 
    server {  
        listen 80;  
        server_name example.com;  
        
        location /lua_example {  
            # 设置Lua代码块  
            content_by_lua_block {  
                -- 在这里编写Lua代码  
                ngx.say("Hello from Lua in Nginx!")  
            }  
        }  
    }  
}

在这个例子中,当访问/lua_example这个路径时,Nginx会执行content_by_lua_block中定义的Lua代码,并返回”Hello from Lua in Nginx!”。

如果你想在Lua脚本中执行更复杂的操作,比如访问数据库、调用其他服务API等,你可以使用OpenResty提供的Lua库,比如resty.mysqlresty.redisresty.http等。

例如,使用resty.http库发送HTTP GET请求:

location /fetch_data {  
    content_by_lua_block {  
        local http = require "resty.http"  
        local httpc = http.new()  
  
        local res, err = httpc:request_uri("http://example.com/api/data", {  
            method = "GET",  
            headers = {  
                ["Content-Type"] = "application/json",  
                ["Accept"] = "application/json",  
            },  
        })  
  
        if not res then  
            ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR  
            ngx.say("failed to request: ", err)  
            return  
        end  
  
        ngx.status = res.status  
        ngx.say(res.body)  
  
        -- 关闭连接  
        httpc:close()  
    }  
}

​ 在这个例子中,我们创建了一个HTTP客户端,并向http://example.com/api/data发送了一个GET请求。然后,我们读取响应体并将其输出到客户端。

​ 注意,使用Lua脚本扩展Nginx功能时,你需要确保Lua代码是高效且没有潜在的性能问题。在生产环境中,应该仔细测试并监控Nginx和Lua脚本的性能。最后,别忘了重新加载或重启Nginx服务以使配置更改生效。

OpenResty

OpenResty® 是一个成熟的 Web 平台,集成了我们增强版的 Nginx 核心、增强版的 LuaJIT、许多精心编写的 Lua 库、大量高质量的第 3 方 Nginx 模块及其大部分外部依赖项。 它旨在帮助开发人员轻松构建可扩展的 Web 应用程序、Web 服务和动态 Web 网关。

​ 通过利用各种精心设计的 Nginx 模块(其中大部分由 OpenResty 团队自己开发),OpenResty® 有效地将 nginx 服务器变成一个强大的 Web 应用服务器,Web 开发人员可以在其中使用 Lua 编程语言编写脚本 各种现有的 nginx C 模块和 Lua 模块,构建能够在单个盒子中处理 10K ~ 1000K+ 连接的极高性能 Web 应用程序。

​ OpenResty® 旨在完全在 Nginx 服务器中运行您的服务器端 Web 应用程序,利用 Nginx 的事件模型不仅可以与 HTTP 客户端进行非阻塞 I/O,还可以与 MySQL、PostgreSQL、Memcached 和 Redis 等远程后端进行非阻塞 I/O 。

docker pull openresty/openresty:1.25.3.1-bullseye
# 体积更大,包含的功能模块更多
docker pull openresty/openresty:1.25.3.1-bullseye-fat

docker run -d --name openresty -p 10080:80 openresty/openresty:1.25.3.1-bullseye
docker exec -it openresty /bin/bash

openresty 与Nginx 基本一致,不过配置文件的位置有所改动:

# 主配置文件位置
/usr/local/openresty/nginx/conf/nginx.conf
# 静态资源位置
/usr/local/openresty/nginx/html
# 日志位置: 
/usr/local/openresty/nginx/logs

下面是 openresty:1.25.3.1 版本的编译参数:

nginx version: openresty/1.25.3.1
built with OpenSSL 1.1.1w  11 Sep 2023
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt='-O2 -DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/zlib/include -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl111/include' --add-module=../ngx_devel_kit-0.3.3 --add-module=../echo-nginx-module-0.63 --add-module=../xss-nginx-module-0.06 --add-module=../ngx_coolkit-0.2 --add-module=../set-misc-nginx-module-0.33 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.09 --add-module=../srcache-nginx-module-0.33 --add-module=../ngx_lua-0.10.26 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.37 --add-module=../array-var-nginx-module-0.06 --add-module=../memc-nginx-module-0.20 --add-module=../redis2-nginx-module-0.15 --add-module=../redis-nginx-module-0.3.9 --add-module=../ngx_stream_lua-0.0.14 --with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib -L/usr/local/openresty/zlib/lib -L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl111/lib -Wl,-rpath,/usr/local/openresty/zlib/lib:/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl111/lib' --with-pcre-jit --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-stream --without-pcre2 --with-http_ssl_module

Linux 内核参数优化

​ 为了支持高并发连接, 还需要修改Linux 服务器的相关内核参数, 常用的配置如下:

需要修改 /etc/sysctl.conf 配置文件来修改系统内核参数

fs.file-max = 99999
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 5000

file-max

​ 一个进程可以打开的最大句柄数,这个参数直接影响最大并发连接数。

tcp_tw_reuse

​ 这个参数设置为1 表示允许将 TIME-WAIT 状态的socket 重新用于新的TCP 连接,这对于服务器来说很有意义,因为服务器上总是有大量 TIME-WAIT 状态的连接。

tcp_keepalive_time

​ 当 keepalive 启用时,TCP 发送 keepalive 消息的频率,默认为2小时。把频率设置的小一些可以更快的清理无效的连接。

tcp_fin_timeout

​ 这个参数表示当服务器主动关闭连接时,socket 保持在 FIN-WAIT2 状态的最大时间。

动态模块

​ Nginx 动态模块是一种在启动时动态加载到 Nginx 服务器的扩展功能(可以认为是插件)。它们的主要目的是允许用户在不重新编译和重新安装 Nginx的情况下,添加或删除特定功能或模块。这提供了更大的灵活性和可维护性,因为您可以根据需要启用或禁用特定功能,而无需重新编译整个 Nginx服务器。

​ 在nginx 配置文件中会自动加载 /usr/share/nginx/modules 目录下的配置文件,按照约定,每一个配置文件代表加载一个动态模块。使用 load_modules 指令加载动态模块。

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

$ ls /usr/share/nginx/modules/
mod-http-image-filter.conf  mod-http-perl.conf  mod-http-xslt-filter.conf  mod-mail.conf  mod-stream.conf
$ cat /usr/share/nginx/modules/mod-http-perl.conf 
load_module "/usr/lib64/nginx/modules/ngx_http_perl_module.so";

注:.so 是动态链接库文件。从Nginx 1.9.11 版本开始支持动态模块。

下面是常见的动态模块

动态模块 描述 提供
ngx_http_geoip_module 提供基于 IP 地址的地理位置查询。 官方
ngx_http_image_filter_module 图片处理功能,如裁剪、调整大小和旋转。 官方
ngx_http_xslt_module 提供 XML 文档的 XSLT 转换。 官方
ngx_mail_module 提供邮件代理服务器功能,支持 POP3、IMAP 和 SMTP。 官方
ngx_stream_module 为 TCP/UDP 请求提供代理。 官方
ngx_http_lua_module Nginx 中的 Lua 脚本支持。 非官方
nginx-module-perl Nginx 中的 Perl 脚本支持。 官方
nginx-module-njs Nginx 中的 JS 脚本支持。 官方

注意事项

  • 动态模块必须在Nginx启动时加载,而不是在运行时动态加载或卸载。这意味着,如果你需要添加或移除动态模块,你需要重新配置并重启Nginx服务。
  • 不是所有的Nginx模块都支持动态加载。只有那些明确标记为支持动态加载的模块才能以这种方式使用。
  • 确保动态模块的版本与你的Nginx版本兼容。

通过动态模块,你可以根据需要扩展Nginx的功能,而无需重新编译整个Nginx服务器。这提供了一种灵活的方式来定制你的Nginx安装,以适应不同的应用场景和需求。

常见模块

常用正则

  • . : 匹配除换行符以外的任意字符
  • ? : 重复0次或1次
  • + : 重复1次或更多次
  • * : 重复0次或更多次
  • \d :匹配数字
  • ^ : 匹配字符串的开始
  • $ : 匹配字符串的介绍
  • {n} : 重复n次
  • {n,} : 重复n次或更多次
  • [c] : 匹配单个字符c
  • [a-z] : 匹配a-z小写字母的任意一个

小括号()之间匹配的内容,可以在后面通过$1来引用,$2表示的是前面第二个()里的内容。正则里面容易让人困惑的是\转义特殊字符。

常见问题

解决nginx报错

nginx: [emerg] could not build server_names_hash, you should increase server_nam
es_hash_bucket_size: 32

报错原因

​ 该报错产生的原因主要是因为Nginx中的server配置中server_name的定义值过长产生的。
解决方法

​ 在Nginx的http字段内添加如下代码,放大默认bucket_size

http {
     server_names_hash_bucket_size 64;
     .....
  }

注意:如果已经存在该字段信息,需要加大后面的数值。且数值必须是32的倍数。

README

作者:银法王

版权声明:本文遵循知识共享许可协议3.0(CC 协议): 署名-非商业性使用-相同方式共享 (by-nc-sa)

参考:

  Nginx 官方文档

  ngx_http_core_module

  ngx_http_proxy_module

  ngx_http_upstream_module

  ngx_http_upstream_hc_module

  ngx_stream_core_module

  ngx_http_limit_conn_module

  ngx_http_limit_req_module

简单一招竟把nginx服务器性能提升50倍【京东零售技术】

Nginx 生产环境下的安全配置

https://www.hxstrive.com/subject/nginx/750.htm

修改记录:

 2020-09-16 第一次修订

 2021-01-10 完善

​ 2023-06-10 完善

​ 2024-02-18 完善


Nginx服务使用指南
http://jackpot-lang.online/2021/04/08/服务器/Nginx 服务使用指南/
作者
Jackpot
发布于
2021年4月8日
许可协议