安装

使用源码安装nginx

1
2
3
4
5
6
7
8
9
10
# 安装所需依赖
yum install -y pcre-devel
yum install -y openssl openssl-devel

wget https://nginx.org/download/nginx-1.23.3.tar.gz
mkdir /usr/local/nginx
tar -zxvf nginx-1.23.3.tar.gz
cd nginx-1.23.3
./configure --prefix=/usr/local/nginx
make && make install

安装非默认模块

启用 HTTPS 支持

1
2
./configure --prefix=/usr/local/nginx --with-http_ssl_module 
make && make install

如果没有安装openssl或版本过低则需要先安装openssl,查看openssl版本openssl version

安装:

1
2
3
4
wget https://www.openssl.org/source/openssl-1.1.1l.tar.gz
tar -zxvf openssl-x.x.x.tar.gz
make
make install

安装nginx时配置:

1
2
# 假设/root/opensslw
--prefix=/usr/local/nginx --with-openssl=/root/openssl --with-http_ssl_module

获取用户真实IP支持

1
2
./configure --prefix=/usr/local/nginx --with-http_realip_module
make && make install

配置

http块常用配置

与客户端有关的配置主要在 http 块中设置

指令 说明
client_body_buffer_size 设置读取客户端请求体的缓冲区大小。如果请求体的大小大于缓冲区的大小,则整个或一部分请求体会被写入临时文件。在默认情况下,会为 32 位系统、x86-64 系统设置8KB 的缓冲区,其他 64 位系统为 16KB 的缓冲区
client_body_temp_path 定义存储客户端请求体的临时文件目录,最多可以定义 3 个子集目录
client_body_timeout 定义读取客户端请求体的超时时间,即两个连续的读操作之间的时间间隔。如果超时HTTP 会抛出 408 错误
client_header_buffer_size 设置客户端请求头的缓冲区大小,默认为 1KB
client_max_body_size 设置客户端请求的最大主体的大小,默认为 1MB
client_header_timeout 设置客户端请求头的超时时间
etag 如果设置为 on,表示静态资源自动生成 ETag 响应头
large_client_header_buffers 设置大型客户端请求头的缓冲区大小
keepalive_timeout 设置连接超时时间。服务器将在超过超时时间后关闭 HTTP 连接
send_timeout 指定客户端的响应超时时间
server_names_hash_bucket_size 设置 server_names(Nginx 中配置的全部域名)散列表的桶的大小,默认值取决于处理器缓存行的大小
server_names_hash_max_size 设置 server_names 散列表的最大值
server_tokens 启用或禁用在错误页面和服务器响应头字段中标识的 Nginx 版本
tcp_nodelay 启用或禁用 TCP_NODELAY 选项。只有当连接保持活动时,才会被启用
tcp_nopush 仅当 sendfile 时使用,能够将响应头和正文的开始部分一起发送

location规则

分类 格式 说明
精确匹配 location = /uri 优先级最高,匹配命中即退出,需完全匹配才算命中
一般匹配 location /uri 取最长的匹配,暂存结果并搜索正则匹配
location ^~ /uri 取最长的匹配,之后不再搜索正则匹配
location / 通用匹配,即一定会被命中
正则匹配 location ~ uri 用于正则uri前,表示uri里面包含正则,并且区分大小写
location ~* uri 用于正则uri前,表示uri里面包含正则,不区分大小写
  1. 最先精确匹配,如果精确匹配到了就停止搜索。
  2. 精确匹配失败,进行一般匹配。一般匹配如有多个命中,按匹配的长度决定最终匹配,与location配置顺序无关。
  3. 如一般匹配带有前缀^~,则不再进行正则匹配,直接返回结果。
  4. 如一般匹配没有前缀^~,则继续进行正则匹配,如正则匹配未命中则返回暂存结果,否则返回正则匹配结果。
  5. 正则匹配与location配置顺序有关(从上往下),返回第一个命中的结果。

常用内置变量

变量名 说明
$arg_name 指 URL 请求中的参数,name 是参数的名字
$args 代表 URL 中所有请求的参数
$binary_remote_addr 客户端地址以二进制数据的形式出现,通常会和限速模块一起使用
$body_bytes_sent 发送给客户端的字节数,不包含响应头
$bytes_sent 发送给客户端的总字节数
$document_uri 设置$uri 的别名
$hostname 运行 Nginx 的服务器名
$http_referer 表示请求是从哪个页面链接过来的
$http_user_agent 客户端浏览器的相关信息
$remote_addr 客户端 IP 地址
$remote_port 客户端端口号
$remote_user 客户端用户名,通常在 Auth Basic 模块中使用
$request_filename 请求的文件路径,基于 root alias 指令和 URI 请求生成
$request_time 请求被 Nginx 接收后,一直到响应数据返回给客户端所用的时间
$request_uri 请求的 URI,带参数
$request 记录请求的 URL 和 HTTP
$request_length 请求的长度,包括请求行、请求头和请求正文
$server_name 虚拟主机的 server_name 的值,通常是域名
$server_port 服务器端口号
$server_addr 服务器的 IP 地址
$request_method 请求的方式,如 POST 或 GET
$scheme 请求协议,如 HTTP 或 HTTPS
$sent_http_name 任意响应头,name 为响应头的名字,注意 name 要小写
$realip_remote_addr 保留原来的客户地址,在 real_ip 模块中使用
$server_protocol 请求采用的协议名称和版本号,常为 HTTP/1.0 或 HTTP/1.1
$uri 当前请求的 URI,在请求过程中 URI 可能会被改变,例如在内部重定向或使用索引文件时
$nginx_version Nginx 的版本号
$pid worker 进程的 PID
$pipe 如果请求是 HTTP 流水线(pipelined)发送的,pipe 值为”p”,否则为”.”
$connection_requests 当前通过一个连接获得的请求数量
$cookie_name name 即 Cookie 的名字,可得到 Cookie 的信息
$status HTTP 请求状态
$msec 日志写入时间。单位为秒,精度是毫秒
$time_local 在通用日志格式下的本地时间
$upstream_addr 请求反向代理到后端服务器的 IP 地址
$upstream_port 请求反向代理到后端服务器的端口号请求反向代理到后端服务器的端口号
$upstream_response_time 请求在后端服务器消耗的时间
$upstream_status 请求在后端服务器的 HTTP 响应状态
$geoip_city 城市名称,在 geoip 模块中使用
  • 根据参数名跳转不同URL

    1
    2
    3
    4
    5
    6
    location / {   #请求默认路径是 http://a,如果 URL 中的参数是 at=5,则路径变为 http://b
    if ($arg_at= '5') {
    proxy_pass http://b;
    }
    proxy_pass http://a;
    }
  • http跳转到https

    1
    2
    3
    if ($scheme = 'http') { 
    rewrite ^/(.*)$ https://$host/$1 redirect;
    }

应用

限制ip访问

使用模块ngx_http_access_module

1
2
3
4
5
6
location / { 
deny 192.168.1.1; # 禁止 192.168.1.1 访问
allow 192.168.1.0/24; # 允许 192.168.1.0/24 访问
allow 17.1.1.2; # 允许 17.1.1.2 访问
deny all; # 除 allow 的 IP 地址外,其他的 IP 地址都禁止访问
}

auth身份验证

使用模块ngx_http_auth_basic_module

1
2
3
4
5
6
7
8
server { 
listen 80;
server_name localhost;
location / {
auth_basic "Nginx Basic"; # 浏览器访问是时的弹框显示内容
auth_basic_user_file conf.d/passwd; # 存放密码的文件地址
}
}

密码文件生成语法:

1
printf "yourusername:$(openssl passwd -crypt yourpassword)\n" >> /etc/nginx/conf.d/passwd

访问控制

使用模块ngx_http_core_module

1
2
3
4
5
6
7
location / {
satisfy any;
allow 192.168.1.0/32;
deny all;
auth_basic "closed site";
auth_basic_user_file conf/htpasswd;
}
  • satisfy all:当这个请求能够被accessauth_basicauth_request这三个模块都放行,该才能够继续往下走。若被任意一个模块拒绝,就会返回400或者500系列的状态码。
  • satisfy any:只要这个请求被任意一个access阶段的模块放行,就可以继续被执行。
Syntax Default Content
auth_basic string\ off; auth_basic off; http, server, location
satisfy all\ any; satisfy all; http, server, location

后端获取客户端真实ip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
location / {
#保留代理之前的host 包含客户端真实的域名和端口号
proxy_set_header Host $host;
#保留代理之前的真实客户端ip
proxy_set_header X-Real-IP $remote_addr;
#这个Header和X-Real-IP类似,但它在多级代理时会包含真实客户端及中间每个代理服务器的IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
#表示客户端真实的协议(http还是https)
proxy_set_header X-Forwarded-Proto $scheme;
#指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值
#如果使用"default"参数,将根据location和proxy_pass参数的设置来决定。
#proxy_redirect [ default|off|redirect replacement ];
proxy_redirect off;
proxy_pass http://IP:PORT;
}

反向代理

Nginx 使用ngx_http_proxy_module来完成对后端服务的代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# http://nginx:80/eureka/js/1.js 等于 http://10.129.20.36:8761//js/1.js
location /eureka {
proxy_pass http://10.129.20.36:8761/;
}

# http://nginx:80/eureka/js/1.js 等于 http://10.129.20.36:8761/eureka/js/1.js
location /eureka {
proxy_pass http://10.129.20.36:8761;
}

# http://nginx:80/eureka/js/1.js 等于 http://10.129.20.36:8761/eureka/js/1.js
location /eureka/ {
proxy_pass http://10.129.20.36:8761;
}

# http://nginx:80/eureka/js/1.js 等于 http://10.129.20.36:8761/js/1.js
location /eureka/ {
proxy_pass http://10.129.20.36:8761/;
}

控制请求头和请求体:

  • proxy_hide_header:禁止某个请求头被转发到后端服务器;
  • proxy_pass_header:允许已被禁止转发的请求头继续转发;
  • proxy_set_header:添加获修改请求头信息;
  • proxy_set_body:对请求体进行覆盖,如proxy_set_body 'b=123xxx'

控制请求和后端服务器的交互时间:

  • proxy_connect_timeout:设置请求和后端服务器建立连接的超时时间;
  • proxy_read_timeout:等待real server响应数据的超时时间,超时只在两次连续的读操作之间设置, 而不是用于传输整个响应。如果real server在此时间内没有传输任何内容,则连接将关闭;
  • proxy_send_timeout:向real server发送请求的超时时间,超时只在两次连续写入操作之间设置, 而不是用于传输整个请求,如果real server在此时间内没有收到任何内容,则连接将关闭;
Syntax Default Content
proxy_connect_timeout; proxy_connect_timeout 60s; http, server, location
proxy_read_timeout time; proxy_read_timeout 60s; http, server, location
proxy_send_timeout time; proxy_send_timeout 60s; http, server, location

代理多台服务器

如果需要指向多台服务器就要用到ngx_http_upstream_module模块,它为反向代理提供了负载均衡及故障转移等重要功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义一个 HTTP 服务组
upstream test_servers {
# 用 server 定义 HTTP 地址
server 127.0.0.1:81 max_fails=5 fail_timeout=10s weight=10;
server 127.0.0.1:82 max_fails=5 fail_timeout=10s weight=5;
server test.123.com backup;
server 127.0.0.1:82 down;
}
server {
listen 80;
location / {
# 通过代理将请求发送给 upstream 命名的 HTTP 服务
proxy_pass http://test_servers;
}
}

参数说明:

  • weight:设置请求分发到后端服务器的权重,即每台后端服务器能够响应的请求数量的比例;
  • max_fails:请求最大失败次数,在指定时间内请求失败的最大次数,默认是 1。如果设置为 0,代表禁用这个设置;
  • fail_timeout:在指定时间内请求失败的次数,超过这个次数则认为服务器不可用;
  • down:标记服务不可用;
  • backup:当 upstream 中所有的后端服务器都被设置为不可用时(如全都超过了请求最大失败次数),upstream 会对backup 的服务器进行分流

故障转移

  • proxy_next_upstream:定义转发条件,当请求返回Nginx时,如果HTTP状态满足proxy_next_upstream设置的条件,就会触发 Nginx 将请求重新转发到下一台后端服务器,并累加出现此状态的服务器的失败次数(当超过max_failsfail_timeout的值时就会设置此服务器为不可用)。如果设置为off,则表示关闭此功能。
  • proxy_next_upstream_tries:定义尝试请求的次数,达到次数上限后就停止转发,并将请求内容返回客户端。若设置为 0,则表示无次数限制。
  • proxy_next_upstream_timeout:限制尝试请求的超时时间,如果第一次请求失败,下一次请求就会被此参数值控制。若设置为 0,则表示无超时时间。
Syntax Default Content
proxy_next_upstream error\ timeout
\
invalid_header\ http_500\ http_502\ http_503
\
http_504\ http_403\ http_404\ http_429
\
non_idempotent\ off…; proxy_next_upstream error timeout; http, server, location
proxy_next_upstream_tries number; proxy_next_upstream_tries 0; http, server, location
proxy_next_upstream_timeout time; proxy_next_upstream_timeout 0; http, server, location

负载均衡

相同的 URL(包含参数)会进入相同的后端缓存系统:

1
2
3
4
5
upstream test_servers { 
hash $request_uri;
server 127.0.0.1:81 max_fails=5 fail_timeout=10s weight=10;
server 127.0.0.1:82 max_fails=5 fail_timeout=10s weight=5;
}
  • hash:按照指定的 key 将请求分布到后端服务器上,key 可以是变量、文本或它们的组合,key 相同的请求会被代理到同一台后端服务器上;
  • ip_hash:根据 IP 地址将请求分流到后端服务器上,同一个 IP 地址的请求会被代理到同一台后端服务器上;
  • least_conn:当将请求分流到后端服务器时,请求量最小的服务器会优先获得分流;
  • sticky:根据 Cookie 将请求分布到后端服务器上,同一个 Cookie 的请求只会进入同一台服务器。如果请求被分布到某台服务器上,但是在请求时这台服务器已经无法提供服务,那么会重新选择一台服务器进行“捆绑”,并且下次会直接进入重新“捆绑”的服务器;
Syntax Default Content
hash key - upstream
ip_hash; - upstream
least_conn; - upstream
sticky cookie name … - upstream

长连接

在Nginx 中,使用 upstream 进行后端访问默认用的是短连接,但这会增加网络资源的消耗。可以通过配置长连接,来减少因建立连接产生的开销、提升性能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream test_servers { 
server 127.0.0.1:81 max_fails=5 fail_timeout=10s weight=10;
server 127.0.0.1:82 max_fails=5 fail_timeout=10s weight=5;
keepalive 100;
keepalive_requests 1000;
keepalive_timeout 1h;
}
server {
listen 80;
proxy_set_header Host $Host;
proxy_set_header x-forwarded-for $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1; # 设置 HTTP 请求协议,要确保是 HTTP 1.1 的长连接协议
proxy_set_header Connection ""; # 清空 Connection 请求头,避免客户端传递短连接的请求头信息
location / {
proxy_pass http://test_servers;
}
}
  • keepalive:设置 worker 进程和后端服务器之间保持空闲连接的最大值,如果空闲连接数大于这个值,将会关闭使用最少的连接;
  • keepalive_requests:设置每个连接的最大请求次数,超过这个次数就会关闭该连接建立新的连接;
  • keepalive_timeout:设置 keep-alive 客户端连接在服务器端保持开启的超时时间;
Syntax Default Content
keepalive connections; - upstream
keepalive_requests number; keepalive_requests 1000; upstream
keepalive_timeout time; keepalive_timeout 1h; upstream

rewrite

使用模块ngx_http_rewrite_module

跳转规则

配置在server

  • 请求/1.html,最终返回3.html

    1
    2
    3
    4
    5
    6
    server{
    listen 80;

    rewrite /1.html /2.html ;
    rewrite /2.html /3.html ;
    }
  • 请求/1.html,最终返回2.html

    1
    2
    3
    4
    5
    6
    server{
    listen 80;

    rewrite /1.html /2.html break;
    rewrite /2.html /3.html ;
    }
  • 请求/1.html,最终返回403状态码(绕过后续rewritereturn,但会继续匹配location

    1
    2
    3
    4
    5
    6
    7
    8
    9
    server{
    listen 80;

    rewrite /1.html /2.html break;
    rewrite /2.html /3.html ;
    location /2.html {
    return 403;
    }
    }

    此时,breaklast实现效果一致。

配置在location

  • 请求/1.html,最终返回b.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    server{
    listen 80;

    location / {
    rewrite /1.html /2.html;
    rewrite /2.html /3.html;
    }
    location /2.html
    {
    rewrite /2.html /a.html;
    }
    location /3.html
    {
    rewrite /3.html /b.html;
    }
    }
  • 请求/1.html,最终返回2.html(本location内的rewrite以及其他location都不再执行)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    server{
    listen 80;

    location / {
    rewrite /1.html /2.html break;
    rewrite /2.html /3.html;
    }
    location /2.html
    {
    rewrite /2.html /a.html;
    }
    location /3.html
    {
    rewrite /3.html /b.html;
    }
    }
  • 请求/1.html,最终返回a.html(本location内的rewritereturn不再执行,但会继续匹配location,这是breaklast的区别)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    server{
    listen 80;

    location / {
    rewrite /1.html /2.html last;
    rewrite /2.html /3.html;
    }
    location /2.html
    {
    rewrite /2.html /a.html;
    }
    location /3.html
    {
    rewrite /3.html /b.html;
    }
    }

总结:

  1. rewrite配置在server块中,会一直向下执行本区块内的rewrite,直到结束或碰到breaklastbreaklast在server块中实现效果一致),但仍然会匹配location。
  2. rewrite配置在location块中,碰到breaklast都会结束当前块,但last会继续匹配location,break则不会。

应用

内部重定向:

1
2
3
4
5
# 匹配以/a/开头的请求,并将/a/后面的 URI 全部捕获,
# 然后重定向成 /b/$1 ,其中$1 就是前面捕获到的 URI。
# 匹配成功后将其修改成/b 的 URI,并停止 rewrite 阶段,执行下一个阶段,即 proxy_pass
rewrite ^/a/(.*) /b/$1 break;
proxy_pass http://test_servers;

域名跳转:

1
2
3
4
5
6
# permanent 参数表示永久重定向,将所有的请求全部跳转到指定域名上
# 通过(.*)将 URL 保留下来,跳转过程中参数不会丢失。HTTP 状态码为 301
rewrite ^/(.*)$ http://www.zhe800.com/$1 permanent;
# redirect 参数表示临时重定向,将所有的请求全部跳转到指定域名上
# 通过(.*)将 URL 保留下来,跳转过程中参数不会丢失。HTTP 状态码 302
rewrite ^/(.*)$ http://www.zhe800.com/$1 redirect;

返回任意http状态码:

1
2
return 307 http://www.test.com/$request_uri;  # 临时重定向
return 308 http://www.test.com/$request_uri; # 永久重定向

307和308为HTTP1.1支持的状态码,用于告知客户端跳转过程中请求的方法不变,并保留请求体,用于跳转POST请求。

Syntax Default Content
return code [text]
return code URL;
return URL;
- server,location,if

图片防盗链

为了阻止盗链的情况出现,可以使用ngx_http_referer_module模块。此模块是 Nginx 的内置模块,不需要重新编译。

1
2
3
4
5
6
location ~* \.(gif|jpg|png|webp)$ { 
valid_referers none blocked server_names *.testnginx.com ~\.baidu\. \.google\.;
if ($invalid_referer) {
return 403;
}
}

如果referer不是示例中的这些域名,则会返回403错误。

日志

使用模块ngx_http_log_module

自定义日志格式:

1
2
3
4
5
log_format json_log escape=json '{"ip":"$remote_addr","timestamp": 
"$time_iso8601",'
'"host":"$http_host","request":"$request",'
'"cookie":"$http_cookie","req_time":"$request_time",
"uri":"$uri","referer":"$http_referer" }';

使用escape=json则日志内容不会被转义,中文字符可以直接在日志里面显示。

Syntax Default Content
log_format name [escape=default|json|none] string …; log_format combined “…”; http

日志存储方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
# json_log 定义了日志格式
access_log /data1/access.log json_log;

# 日志压缩记录,每缓存 5MB 的数据就进行日志压缩
access_log /data1/access_1.log combined gzip flush=5m;

# 根据条件进行记录,当 if 等于 0 或为空时日志不会被记录
# 下面代码的意思是当 HTTP 状态码以 4 开头时,日志不会被记录
map $status $loggable {
~^[4] 0;
default 1;
}
access_log /path/to/access.log combined if=$loggable;

指令access_log只记录访问日志,关于错误信息的日志记录在error_log上。

Syntax Default Content
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
access_log logs/access.log combined; http, server, location, if in location, limit_except