Nginx入门到实践
Nginx是一个开源且高性能、可靠的HTTP中间件、代理服务。
Nginx优势
-
IO多路复用epoll
-
轻量级
-
CPU亲和
-
sendfile
安装Nginx
- 进入官网
- 选择对应的操作系统
- 根据文档配置,将$releasever修改为对应的Centos版本。例如我是Centos7,就修改为7
示例
Nginx默认配置语法
参数 | 注释 |
---|---|
user | 设置nginx服务的系统使用用户 |
worker_processes | 工作进程数 |
error_log | nginx的错误日志 |
pid | nginx服务启动时候的pid |
参数 | 注释 | |
---|---|---|
events | worker_connections | 每个进程允许最大连接数 |
use | 使用内核模型 |
虚拟机主机配置方式
- 基于主机多IP方式
- 基于多port方式
- 基于多host名称方式 (多域名方式)
Nginx日志
error.log 错误日志
access.log 每次请求
log_format日志详解
Syntax: | log_format name [escape=default|json|none] string …; |
---|---|
Default: | log_format combined “…”; |
Context: | http |
log_format 关键字
name 自定义变量
[escape=default|json|none] string … 日志具体内容,即HTTP请求变量、nginx内置变量、自定义变量组成
log_format combined “…” 日志默认值
日志内容:
HTTP请求变量 - arg_PARAMETER http_HEADER sent_http_HEADER
内置变量 - Nginx内置的http-只能配置在http作用域下配置
自定义变量 - 自定义的
Nginx模块
-
nginx官方模块
-
第三方模块
–with-http_stub_status_module
作用:Nginx的客户端状态,连接信息
Syntax: | stub_status; |
---|---|
Default: | — |
Context: | server,location |
-
示例
在配置文件中添加
server { ... location /mystatus{ stub_status; } ... }
访问结果
- 状态参数详解
- Active connections 活跃连接数
- accepts 已接受的客户端连接总数
- handled 已处理的连接总数
- requests 客户端连接总数
- Reading 读取请求头的当前连接数
- Writing 将响应写回客户端的当前连接数
- Waiting 等待请求的当前空闲客户端连接数
–with-http_random_index_module
作用:目录中选择一个随机主页
Syntax: | random_index on|off; |
---|---|
Default: | random_index off; |
Context: | location |
-
示例
在配置文件中添加
server { ... location / { root /opt/app/code; random_index on; #index index.html index.htm; } ... }
.开始的隐藏文件不会选择
–with-http_sub_module
作用:HTTP内容替换
Syntax: | sub_filter string replacement; |
---|---|
Default: | — |
Context: | http,server,location |
- 允许在替换期间保留原始响应中的“Last-Modified”头字段,以便于响应缓存。
Syntax: | sub_filter_last_modified on|off; |
---|---|
Default: | sub_filter_last_modified off; |
Context: | http,server,location |
- 匹配第一个(on)还是所有(off)
Syntax: | sub_filter_once on|off; |
---|---|
Default: | sub_filter_once on; |
Context: | http,server,location |
-
示例
在配置文件中添加
server { ... location / { root /opt/app/code; index index.html index.htm; sub_filter '<a>aaa' '<a>AAA'; sub_filter_once off; } ... }
Nginx请求限制
连接频率限制
limit_conn_module
Syntax: | limit_conn_zone key zone=name:size; |
---|---|
Default: | — |
Context: | http |
key 表示存储在共享内存中的key
zone=name:size 表示共享内存名称和大小
Syntax: | limit_conn zone number; |
---|---|
Default: | — |
Context: | http,server,location |
zone 表示存储在共享内存中的key
number 表示限制的连接数
-
示例
在配置文件中添加
limit_conn_zone $binary_remote_addr zone=conn_zone:1m; server { ... location / { root /opt/app/code; # 服务端同一时刻只允许一个IP连接过来 limit_conn conn_zone 1; index index.html index.htm; } ... }
请求频率限制
limit_req_module
Syntax: | limit_req_zone key zone=name:size rate=rate; |
---|---|
Default: | — |
Context: | http |
key 表示存储在共享内存中的key
zone=name:size 表示共享内存名称和大小
rate=rate 表示请求数率,例如:10r/s每秒请求10次
Syntax: | limit_req zone=name [burst=number] [nodelay]; |
---|---|
Default: | — |
Context: | http,server,location |
zone 表示存储在共享内存中的key
[burst=number] 表示突发请求数(最大请求数),遗留的请求放到下一秒执行(延迟响应)
[nodelay | delay=number] 其中nodelay表示请求没有延迟,超出的请求丢失;delay=number表示可以延迟处理请求的数量
-
示例
在配置文件中添加
# 通过$binary_remote_addr(ip)限制,每秒1个 limit_req_zone $binary_remote_addr zone=req_zone:1m rate=1r/s; server { ... location / { root /opt/app/code; #limit_req zone=req_zone burst=3 nodelay; #limit_req zone=req_zone burst=3; #limit_req zone=req_zone; index index.html index.htm; } ... }
Nginx的访问控制
基于IP的访问控制
http_access_module
- 允许访问
Syntax: | allow address|CIDR|unix:|all; |
---|---|
Default: | — |
Context: | http,server,location,limit_except |
address:IP地址
CIDR:网段
unix:unix或linux上socket方式的访问
all:允许所有
- 拒绝访问
Syntax: | deny address|CIDR|unix:|all; |
---|---|
Default: | — |
Context: | http,server,location,limit_except |
- 局限性解决
- 采用别的HTTP头信息控制访问,如:HTTP_X_FORWARD_FOR
- 结合geo模块
- 通过HTTP自定义变量传递
基于用户的信任认证
http_auth_basic_module
Syntax: | auth_basic string|off; |
---|---|
Default: | auth_basic off; |
Context: | http,server,location,limit_except |
- 存储用户名和密码信息
Syntax: | auth_basic_user_file file; |
---|---|
Default: | — |
Context: | http,server,location,limit_except |
- 局限性
- 用户信息依赖文件方式
- 操作管理机械,效率低下
- 局限性解决
- Nginx结合LUA实现高效验证
- Nginx和LDAP打通,利用nginx-auth-ldap模块
静态资源web服务
- 静态资源类型:非服务器动态运行生成的文件
- 静态资源服务场景—CDN
- 配置语法-文件读取
Syntax: | sendfile on |off; |
---|---|
Default: | sendfile off; |
Context: | http,server,location,if in location |
引读:–with-file-aio 异步文件读取 (很少用)
-
配置语法-tcp_nopush (多个文件打包一起发送)
作用:sendfile开启的情况下,提高网络包的传输效率
sendfile开启才能使用
Syntax: | tcp_nopush on | off; |
---|---|
Default: | tcp_nopush off; |
Context: | http,server,location |
-
配置语法-tcp_nodelay 文件不等待,实时发送(实时性高)
作用:keepalive连接下,提高网络包的传输实时性
Syntax: | tcp_nodelay on | off |
---|---|
Default: | tcp_nodelay on; |
Context: | http,server,location |
-
配置语法-压缩
作用:压缩传输
Syntax: | gzip on | off; |
---|---|
Default: | gzip off; |
Context: | http,server,location,if in location |
- 配置语法-压缩比
Syntax: | gzip_comp_level level; |
---|---|
Default: | gzip_comp_level 1; |
Context: | http,server,location |
- gzip_http版本
Syntax: | gzip_http_version 1.0|1.1; |
---|---|
Default: | gzip_http_version 1.1; |
Context: | http,server,location |
扩展nginx压缩模块
http_gzip_static_module 预读gzip功能,需要事先压缩好
http_gunzip_module 应用支持gunzip的压缩方式(不支持gzip压缩时使用,较少)
-
示例
在配置文件中添加
server { ... # 开启文件读取 sendfile on; location ~ .*\.(jpg|gif|png)$ { gzip on; gzip_http_version 1.1; gzip_comp_level 2; # gzip压缩类型 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; root /opt/app/code/images; } location ~ .*\.(txt|xml)$ { gzip on; gzip_http_version 1.1; gzip_comp_level 1; gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png; root /opt/app/code/doc; } location ~ ^/download { # 预读功能 gzip_static on; tcp_nopush on; root /opt/app/code; } ... }
浏览器缓存
HTTP协议定义的缓存机制(如:Expires;Cache-control等)
- 浏览器无缓存
- 客户端有缓存
- 校验过期机制
校验是否过期 | Expires、Cache-Control(max-age) | 协议版本不同 |
---|---|---|
协议中Etag头信息校验 | Etag | 一串字符串 |
Last-Modified头信息校验 | Last-Modified | 具体的时间到秒 |
-
配置语法 - expires
作用:添加Cache-Control、Expires头
Syntax: | expires [modified] time; expires epoch | max | off; |
---|---|
Default: | expires off; |
Context: | http,server,location,if in location |
-
示例
在配置文件中添加
server { ... location ~ .*\.(htm|html)$ { expires 24h; root /opt/app/code } .... }
跨域访问
为什么浏览器禁止跨域访问?(不安全,容易出现CSRF攻击)
- 配置语法-打开跨域访问
Syntax: | add_header name value [always]; |
---|---|
Default: | — |
Context: | http,server,location,if in location |
读取这个Access-Control-Allow-Origin头信息,查看是否允许跨站;默认阻止
-
示例
在配置文件中添加
server { ... location ~ .*\.(htm|html)$ { # 允许的域名 *代表所有 可以只打开指定的域名 add_header Access-Control-Allow-Origin *; # 允许的方法 add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; root /opt/app/code; } .... }
防盗链
目的:防止资源被盗用
-
设置思路
首要方式:区别哪些请求是非正常的用户请求
基于http_refer防盗链配置模块
Syntax: | valid_referers none|blocked|server_names|string…; |
---|---|
Default: | — |
Context: | server,location |
-
示例
在配置文件中添加
server { ... location /app{ ... # none代表没有refer信息的 blocked代表refer信息不是http://这种标准形式的 # 支持域名正则匹配的方式 valid_referers none blocked 192.168.247.130 ~/google\./; if($invalid_referer){ return 403; } .... } .... }
http_refer的方式有一定的局限性
代理服务
-
正向代理:代理的对象是客户端
-
反向代理:代理的对象是服务端
http的方式:http://localhost:8000/uri/
https的方式:https://192.168.1.1:8000/uri/
socket的方式:http://unix:/tmp/backend.socket:/uri/;
- 配置语法
Syntax: | proxy_pass URL; |
---|---|
Default: | — |
Context: | location,if in location,limit_except |
-
示例
在配置文件中添加
server { ... # 代理到8080端口 location ~ /test_proxy.html$ { proxy_pass http://127.0.0.1:8080; } .... }
其他配置语法
- 缓冲区
Syntax: | proxy_buffering on|off; |
---|---|
Default: | proxy_buffering on; |
Context: | http,server,location |
扩展 proxy_buffer_size 、proxy_buffers 、proxy_busy_buffers_size
- 跳转重定向
Syntax: | proxy_redirect default; proxy_redirect off; proxy_redirect redirect replacement; |
---|---|
Default: | proxy_redirect default; |
Context: | http,server,location |
- 头信息
Syntax: | proxy_set_header field value; |
---|---|
Default: | proxy_set_header Host $proxy_host; proxy_set_header Connection close; |
Context: | http,server,location |
扩展:proxy_hide_header 、proxy_set_body
- 超时
Syntax: | proxy_connect_timeout time; |
---|---|
Default: | proxy_connect_timeout 60s; |
Context: | http,server,location |
扩展:proxy_read_timeout 、proxy_send_timeout
-
示例
在配置文件中添加
server { ... # 代理到8080端口 location ~ /test_proxy.html$ { proxy_pass http://127.0.0.1:8080; proxy_redirect default; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_connect_timeout 30; proxy_send_timeout 60; proxy_read_timeout 60; proxy_buffer_size 32k; proxy_buffering on; proxy_buffers 4 128k; proxy_busy_buffers_size 256k; proxy_max_temp_file_size 256k; } .... }
负载均衡服务
nginx属于七层负载均衡
- Nginx负载均衡
nginx通过代理,将请求代理到upstream server,upstream server里面存放了一些相似的服务
- 配置语法
Syntax: | upstream name {…} |
---|---|
Default: | — |
Context: | http |
-
示例
在配置文件中添加
http { ... # 负载均衡 默认轮询 ip/域名/socket方式 upstream test { server 192.168.247.130:8001; server 192.168.247.130:8002; server 192.168.247.130:8003; } ... server { ... location / { proxy_pass http://test; #500/502/503/504/invalid_header/timeout/error 这些情况时用下一个代理 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; ... } ... } ... }
后端服务器在负载均衡调度中的状态
down | 当前的server暂时不参与负载均衡 |
---|---|
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后,服务暂停的时间 |
max_conns | 限制最大的接收的连接数 |
-
示例
在配置文件中添加
http { ... upstream test { server 192.168.247.130:8001 down; server 192.168.247.130:8002 backup; server 192.168.247.130:8003 max_fails=1 fail_timeout=10s; } ... server { ... location / { proxy_pass http://test; ... } ... } ... }
调度算法
轮询 | 按时间顺序逐一分配到不同的后端服务器 |
---|---|
加权轮询 | weight值越大,分配到的访问几率越高 |
ip_hash | 每个请求按访问IP的hash结果分配,这样来自同一个IP的固定访问一个后端服务器 |
url_hash | 按照访问的URL的hash结果来分配请求,是每个URL定向到同一个后端服务器 |
least_conn | 最少连接数,哪个机器连接数少就分发 |
hash关键数值 | hash自定义的key |
加权轮询示例
在配置文件中添加
http {
...
upstream test {
server 192.168.247.130:8001;
server 192.168.247.130:8002 weight=5;
server 192.168.247.130:8003;
}
...
server {
...
location / {
proxy_pass http://test;
...
}
...
}
...
}
ip_hash示例
在配置文件中添加
http {
...
upstream test {
ip_hash;
server 192.168.247.130:8001;
server 192.168.247.130:8002;
server 192.168.247.130:8003;
}
...
server {
...
location / {
proxy_pass http://test;
...
}
...
}
...
}
自定义hash关键数值
- 配置语法
Syntax: | hash key [consistent] |
---|---|
Default: | — |
Context: | upstream |
-
示例
在配置文件中添加
http { ... upstream test { hash $request_uri; server 192.168.247.130:8001; server 192.168.247.130:8002; server 192.168.247.130:8003; } ... server { ... location / { proxy_pass http://test; ... } ... } ... }
缓存服务
- 配置语法
Syntax: | proxy_cache_path path [levels=levels] [user_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time]; |
---|---|
Default: | — |
Context: | http |
Syntax: | proxy_cache zone|off |
---|---|
Default: | proxy_cache off; |
Context: | http,server,location |
- 配置语法-缓存过期周期
Syntax: | proxy_cache_valid [code …] time; |
---|---|
Default: | — |
Context: | http,server,location |
- 配置语法-缓存的维度
Syntax: | proxy_cache_key string; |
---|---|
Default: | proxy_cache_key $scheme$proxy_host$request_uri; |
Context: | http,server,location |
-
示例
在配置文件中添加
http{ #配置3台服务 upstream test { server 192.168.247.130:8001; server 192.168.247.130:8002; server 192.168.247.130:8003; } #配置proxy_cache_path 存放缓存临时文件的目录 缓存的目录分级(2层) keys_zone开辟的空间 max_size最大大小(超过启动淘汰规则) 不活跃时间60分钟 proxy_cache_path /opt/app/cache levels=1:2 keys_zone=test_cache:10m max_size=10g inactive=60m use_temp_path=off; server { ... location / { proxy_cache test_cache; proxy_pass http://test; # 200或304的code 在12小时过期 proxy_cache_valid 200 304 12h; # 其他code 在10分钟过期 proxy_cache_valid any 10m; # 缓存的key定义 proxy_cache_key $host$uri$is_args$args; #add_header Nginx-Cache "$upstream_cache_status"; #500/502/503/504/invalid_header/timeout/error 这些情况时用下一个服务 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; ... } ... } }
如何清理指定缓存
- rm -rf 缓存目录内容
- 第三方扩展模块ngx_cache_purge
如何让部分页面不缓存
Syntax: | proxy_no_cache string …; |
---|---|
Default: | — |
Context: | http,server,location |
-
示例
在配置文件中添加
http{ ... server { ... if($request_uri ~ ^/(url3|login|register|password\/reset)){ set $cookie_nocache 1; } location / { proxy_cache test_cache; proxy_pass http://test; # 200或304的code 在12小时过期 proxy_cache_valid 200 304 12h; # 其他code 在10分钟过期 proxy_cache_valid any 10m; # 缓存的key定义 proxy_cache_key $host$uri$is_args$args; proxy_no_cache $cookie_nocache $arg_nocache $arg_comment; proxy_no_cache $http_pragma $http_authorization; #add_header Nginx-Cache "$upstream_cache_status"; #500/502/503/504/invalid_header/timeout/error 这些情况时用下一个服务 proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; ... } ... } }
分片请求
大文件分片请求
Syntax: | slice size; |
---|---|
Default: | slice 0; |
Context: | http,server,location |
优势:每个子请求收到的数据会形成一个独立文件,一个请求断了,其他请求不受影响。
缺点:当文件很大或者slice很小的时候,可能会导致文件描述符耗尽等情况。
动静分离
通过中间件将动态请求和静态请求分离。
upstream java_api {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name localhost;
root /opt/app/code;
# 动态请求 请求tomcat页面 代理方式
location ~ \.jsp$ {
proxy_pass http://java_api;
proxy_set_header Host $host;
}
# 静态请求
location ~ \.(jpg|png|gif)$ {
expires 1h;
gzip on;
}
...
}
Rewrite规则
-
作用:实现url重写以及重定向
-
场景
- URL访问跳转,支持开发设计(页面跳转、兼容性支持、展示效果等)
- SEO优化
- 维护(后台维护、流量转发等)
- 安全
-
配置语法
Syntax: | rewrite regex replacement[flag]; |
---|---|
Default: | — |
Context: | server,location,if |
- flag
last | 停止rewrite检测 |
---|---|
break | 停止rewrite检测 |
redirect | 返回302临时重定向,地址栏会显示跳转后的地址 |
permanent | 返回301永久重定向,地址栏会显示跳转后的地址 |
-
示例
在配置文件中添加
server{ ... root /opt/app/code; # break会去/opt/app/code/test/下面寻找 location ~ ^/break { rewrite ^/break /test/ break; } # last重新建了一个请求到test location ~ ^/last { rewrite ^/last /test/ last; } location /test/ { default_type application/json; return 200 '{"status":"success"}'; } ... }
规则场景
server {
listen 80;
server_name localhost;
root /opt/app/code;
location / {
# 场景一 重写请求路径
rewrite ^/course-(\d+)-(\d+)-(\d+)\.html$ /course/$1/$2/course_$3.html break;
# 场景二 Chrome浏览器访问的指定地址重定向百度
if ($http_user_agent ~* Chrome) {
rewrite ^/nginx http://www.baidu.com redirect;
}
# 场景三 请求的资源不存在就重定向百度
if (!-f $request_filename) {
rewrite ^/(.*)$ http://www.baidu.com/$1 redirect;
}
index index.html index.htm;
}
...
}
-
Rewrite规则优先级
执行server块的rewrite指令
执行location匹配
执行选定的location中的rewrite
Nginx高级模块
secure_link_module模块
- 制定并允许检查请求的链接的真实性以及保护资源免遭未经授权的访问
- 限制链接生效周期
- 配置语法
Syntax: | secure_link expression; |
---|---|
Default: | — |
Context: | http,server,location |
Syntax: | secure_link_md5 expression; |
---|---|
Default: | — |
Context: | http,server,location |
-
示例
在配置文件中添加
server { listen 80; server_name localhost; root /opt/app/code; location / { # 两个参数md5和expires secure_link $arg_md5,$arg_expires; # secure_link_md5加密方式 test自定义加密串 secure_link_md5 "$secure_link_expires$uri test"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } } ... }
geoip_module模块
基于IP地址匹配MaxMind GeoIP二进制文件,读取IP所在地域信息。
安装模块 yum install nginx-module-geoip
-
使用场景
- 区别国内外作HTTP访问规则
- 区别国内城市地域作HTTP访问规则
-
查看module安装
$ cd /etc/nginx/modules/ $ ls
-
示例
-
在nginx.conf中引入模块
load_module "modules/ngx_http_geoip_module.so"; load_module "modules/ngx_stream_geoip_module.so";
-
下载文件
# 现在要登陆后下载 $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz $ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
-
修改配置文件
# 引入文件 geoip_country /etc/nginx/geoip/GeoIP.dat; geoip_city /etc/nginx/geoip/GeoLiteCity.dat; server { listen 80; server_name localhost; location / { if ($geoip_country_code != CN) { return 403; } root /usr/share/nginx/html; index index.html index.htm; } location /myip { default_type text/plain; return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city"; } ... }
-
基于Nginx的HTTPS服务
- 生成密钥和CA证书
- 确认openssl(openssl version)
- 查看ssl模块(nginx -V 查看–with-http_ssl_module)
- 步骤
- 生成key密钥
- 生成证书签名请求文件(csr文件)
- 生成证书签名文件(CA文件)
# 1. 生成key密钥 设置一个密码
$ openssl genrsa -idea -out test.key 1024
# 2. 生成证书签名请求文件(csr文件)使用设置的密码
$ openssl req -new -key test.key -out test.csr
# 3. 生成证书签名文件(CA文件) 使用设置的密码
# 注意一定要加-days,否则默认一个月左右过期
$ openssl x509 -req -days 3650 -in test.csr -signkey test.key -out test.crt
# 查看当前加密证书算法类型
$ openssl x509 -noout -text -in ./test.crt
# 去除key密钥文件的保护密码
$ openssl rsa -in ./test.key -out ./test_nopass.key
- HTTPS语法配置
ssl的开启与关闭
Syntax: | ssl on|off; |
---|---|
Default: | ssl off; |
Context: | http,server; |
ssl证书文件
Syntax: | ssl_certificate file; |
---|---|
Default: | — |
Context: | http,server |
ssl密码文件
Syntax: | ssl_certificate_key file; |
---|---|
Default: | — |
Context: | http,server |
-
示例
在配置文件中添加
server { listen 443; server_name 192.168.247.130; ssl on; ssl_certificate /etc/nginx/ssl_key/test.crt; ssl_certificate_key /etc/nginx/ssl_key/test.key; index index.html index.htm; location / { root /opt/app/code; } }
场景 - 配置苹果要求的证书
- 服务器所有的连接使用TSL1.2以上版本(openssl 1.0.2)
- HTTPS证书必须使用SHA256以上哈希算法签名
- HTTPS证书必须使用RSA 2048位或ECC 256位以上公钥算法
- 使用前向加密技术
# 直接通过key密钥文件生成CA证书文件,不生成中间csr文件
$ openssl req -days 3650 -x509 -sha256 -nodes -newkey rsa:2048 -keyout test.key -out test_apple.crt
server
{
listen 443;
server_name 192.168.247.130;
ssl on;
ssl_certificate /etc/nginx/ssl_key/test_apple.crt;
ssl_certificate_key /etc/nginx/ssl_key/test.key;
index index.html index.htm;
location / {
root /opt/app/code;
}
}
HTTPS服务优化
- 激活keepalive长连接
- 设置ssl session缓存
server
{
listen 443;
server_name 192.168.247.130;
# 激活长连接
keepalive_timeout 100;
ssl on;
# 设置ssl session缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_certificate /etc/nginx/ssl_key/test.crt;
ssl_certificate_key /etc/nginx/ssl_key/test.key;
index index.html index.htm;
location / {
root /opt/app/code;
}
}
Nginx与Lua开发
Lua是一个简洁、轻量、可扩展的脚本语言。
优势:充分得结合Nginx的并发处理epoll优势和Lua的轻量,实现简单的功能和高并发的场景。
Lua基础语法
安装Lua yum install lua
-- 行注释
--[[
块注释
--]]
-- while循环
sum=0
num=1
while num <= 100 do
sum = sum + num
num = num + 1
end
print("sum = ",sum)
-- for循环
sum = 0
for i = 1,100 do
sum = sum + i
end
-- if-else判断语句
if age == 40 and sex == "Male" then
print("大于40男人")
elseif age > 60 and sex ~= "Female" then
print("非女人而且大于60")
else
local age = io.read()
print("Your age is "..age)
end
--[[
布尔类型只有nil和false是false,其他都是true
lua没有++或是+=这样的操作
变量默认都是全局变量,local修饰表示局部变量
"~=" 是不等于
字符串的拼接操作符 ".."
io库的分别从stdin和stdout读写的read和write函数
--]]
Nginx+Lua环境安装
-
下载相关文件
# 下载nginx 1.18.0 $ wget http://nginx.org/download/nginx-1.18.0.tar.gz # 下载LuaJIT 2.1 $ wget https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz # 下载ngx_devel_kit模块 $ wget https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.1.tar.gz # 下载lua-nginx-module模块 $ wget https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.13.tar.gz
-
安装LuaJIT
# 解压缩 $ tar -zxvf LuaJIT-2.1.0-beta3.tar.gz # 进入相关目录 $ cd LuaJIT-2.1.0-beta3/ # 编译安装 $ make install PREFIX=/usr/local/LuaJIT # 添加环境变量 $ echo 'export LUAJIT_LIB=/usr/local/LuaJIT/lib' >> /etc/profile $ echo 'export LUAJIT_INC=/usr/local/LuaJIT/include/luajit-2.1' >> /etc/profile # 加载lua库,加入到ld.so.conf文件 $ echo '/usr/local/lib' >> /etc/ld.so.conf $ echo '/usr/local/LuaJIT/lib' >> /etc/ld.so.conf # 重新加载环境变量 $ source /etc/profile $ ldconfig
-
解压ngx_devel_kitj和lua-nginx-module
$ tar -zxvf v0.3.1.tar.gz $ tar -zxvf v0.10.13.tar.gz
-
安装配置nginx1.18
# 安装必要依赖 $ yum install -y gcc pcre-devel openssl-devel zlib-devel # 解压缩 $ tar -zxvf nginx-1.18.0.tar.gz # 进入相关目录 $ cd nginx-1.18.0 # 编译安装nginx $./configure --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_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='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' \ --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' \ --add-module=/home/anglesang/work/app/ngx_devel_kit-0.3.1 \ --add-module=/home/anglesang/work/app/lua-nginx-module-0.10.13 # 同目录下,编译安装 $ make -j 4 && make install # 验证 查看最后几行 $ nginx -V
避坑
-
lua-nginx-module-0.10.19
模板使用了新版导致,使用lua-nginx-module-0.10.13
解决adding module in /home/anglesang/work/app/lua-nginx-module-0.10.19 checking for LuaJIT 2.x ... not found ./configure: error: unsupported LuaJIT version; ngx_http_lua_module requires LuaJIT 2.x.
-
安装lua开发包解决
yum install -y lua-devel
checking for Lua library ... not found checking for Lua library in /usr/local/ ... not found checking for Lua library in /usr/local/ ... not found checking for Lua library in /usr/pkg/ ... not found checking for Lua library in /opt/local/ ... not found checking for Lua library in /usr/local/*/lua51/ ... not found checking for Lua library in /usr/ ... not found checking for LuaJIT library in /usr/local/ ... not found checking for LuaJIT library in /usr/ ... not found checking for LuaJIT library in /usr/ ... not found ./configure: error: ngx_http_lua_module requires the Lua library.
Nginx调用Lua模块指令
Nginx的可插拔模块化加载执行,共11个处理阶段
set_by_lua set_by_lua_file | 设置nginx变量,可以实现复杂的赋值逻辑 |
---|---|
access_by_lua access_by_lua_file | 请求访问阶段处理,用于访问控制 |
content_by_lua content_by_lua_file | 内容处理器,接受请求处理并输出响应 |
… | … |
Nginx Lua API
ngx.var | nginx变量 |
---|---|
ngx.req.get_headers | 获取请求头 |
ngx.req.get_uri_args | 获取url请求参数 |
ngx.redirect | 重定向 |
ngx.print | 输出响应内容体 |
ngx.say | 同ngx.print,但是会最后输出一个换行符 |
ngx.header | 输出响应头 |
… | … |
实战场景 - 灰度发布
按照一定的关系区别,分部分的代码进行上线,使代码的发布能平滑过渡上线。
-
memcached 配置
# 安装memcached $ sudo yum install -y memcached # 启动memcached $ memcached -p 11211 -u nobody -d -m 128 # 连接memcached $ telnet 127.0.0.1 11211 # 设置值 $ set 192.168.247.133 0 0 1 > 1 # 获取值 验证 $ get 192.168.247.133
-
启动并配置两个tomcat 8080和9090
复制tomcat8080为tomcat9090,将tomcat9090中的server.xml文件中的所有8改为9
-
修改nginx配置
server { listen 80; server_name localhost; access_log /var/log/nginx/log/host.access.log main; location /hello { default_type 'text/plain'; content_by_lua 'ngx.say("hello, lua")'; } location /myip { default_type 'text/plain'; content_by_lua ' clientIP = ngx.req.get_headers()["Host"] ngx.say("IP:",clientIP) '; } location / { default_type "text/html"; content_by_lua_file /opt/app/lua/dep.lua; } location @server{ proxy_pass http://127.0.0.1:9090; } location @server_test{ proxy_pass http://127.0.0.1:8080; } error_page 500 502 503 504 404 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
-
测试lua
访问
http://192.168.247.130/hello
地址 -
添加lua文件
clientIP = ngx.req.get_headers()["X-Real-IP"] if clientIP == nil then clientIP = ngx.req.get_headers()["x_forwarded_for"] end if clientIP == nil then clientIP = ngx.var.remote_addr end local memcached = require "resty.memcached" local memc, err = memcached:new() if not memc then ngx.say("failed to instantiate memc: ", err) return end local ok, err = memc:connect("127.0.0.1", 11211) if not ok then ngx.say("failed to connect: ", err) return end local res, flags, err = memc:get(clientIP) if err then ngx.say("failed to get clientIP ", err) return end if res == "1" then ngx.exec("@server_test") return end ngx.exec("@server")
-
添加lua调用memcached的模块
# 下载lua中memcached的模块 $ wget https://github.com/openresty/lua-resty-memcached/archive/refs/tags/v0.15.tar.gz # 解压 $ tar -zxvf v0.15.tar.gz # 移动 $ cp -r lua-resty-memcached-0.15/lib/resty /usr/lib64/lua/5.1 # 重新加载环境变量 $ ldconfig
Nginx常见问题
-
相同server_name多个虚拟主机优先级访问
server{ listen 80; server_name testserver1 aaa.aaa.com; location / { ... } } server{ listen 80; server_name testserver2 aaa.aaa.com; location / { ... } }
优先级根据配置加载顺序
-
location匹配优先级
匹配方式 含义 = 全等匹配 普通匹配 ^~ 普通匹配,使用前缀匹配 ~ 正则匹配,区分大小写 ~* 正则匹配,不区分大小写
- 匹配到全等匹配时,终止后续所有匹配,直接返回
- 步骤一未匹配上时,遍历所有的普通匹配,按照最长匹配原则找到最满足的匹配项,如果匹配项前面有^~符号,则终止后续正则匹配,采用该匹配项;反之则继续后续的正则匹配
- 步骤一二都未匹配上时,此时进行正则匹配,找到第一个满足的正则匹配项,直接返回,若都不满足,则返回步骤二中的最长匹配项(正则匹配和loaction的顺序有关系)
-
try_files使用
按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有的文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。
location / { try_files $uri $uri/ /index.php; }
-
Nginx的alias和root区别
-
root
location /test/img/ { root /home/anglesang/img/; }
请求
http://www.test.com/test/img/cat.png
实际访问资源
/home/anglesang/img/test/img/cat.png
root地址+uri
-
alias
location /test/img/ { alias /home/anglesang/img/; }
请求
http://www.test.com/test/img/cat.png
实际访问资源
/home/anglesang/img/cat.png
-
-
用什么方法传递用户的真实IP
set x_real_ip = $remote_addr
-
nginx中常见错误码
-
413 Request Entity Too Large
用户上传文件限制
client_max_body_size
-
503 bad gateway
后端服务无响应
-
504 Gateway Time-out
后端服务执行超时
…
-
Nginx性能优化
ab压测工具
-
几个关于压力测试的概念
-
吞吐率(Requests per second)
概念:服务器并发处理能力的量化描述,单位是reqs/s,指的是某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。
计算公式:总请求数 / 处理完成这些请求数所花费的时间,即
Request per second = Complete requests / Time taken for tests -
并发连接数(The number of concurrent connections)
概念:某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。 -
并发用户数(The number of concurrent users,Concurrency Level)
概念:要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。 -
用户平均请求等待时间(Time per request)
计算公式:处理完成所有请求数所花费的时间/ (总请求数 / 并发用户数),即
Time per request = Time taken for tests /( Complete requests / Concurrency Level) -
服务器平均请求等待时间(Time per request: across all concurrent requests)
计算公式:处理完成所有请求数所花费的时间 / 总请求数,即
Time taken for / testsComplete requests
可以看到,它是吞吐率的倒数。
同时,它也=用户平均请求等待时间/并发用户数,即
Time per request / Concurrency Level
-
-
安装
yum install -y httpd-tools
-
ab -n 2000 -c 2 http://127.0.0.1/
-n 总的请求数
-c 并发数
-k 是否开启长连接
系统与Nginx性能优化
-
文件句柄设置
linux\Unix 一切皆文件,文件句柄就是一个索引
-
设置方式
-
系统全局性修改
-
用户局部性修改
-
进程局部性修改
-
-
-
CPU亲和配置
# 物理CPU个数 $ cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l # 每个物理CPU中core的个数 $ cat /proc/cpuinfo | grep "cpu cores" | uniq # 逻辑CPU的个数 $ cat /proc/cpuinfo | grep "processor" | wc -l
-
nginx通用配置优化
# 每个work连接数 work_connections 1024; # 字符集统一 charset utf-8; # 日志格式 log_format .... # 日志情况设置 access_log off; # sendfile设置 sendfile on; # 静态资源推荐 tcp_nopush on; # 动态资源推荐 tcp_nodeny on; keepalive_timeout 65; # gzip压缩可配置
Nginx安全
-
常见恶意行为
爬虫行为和恶意抓取、资源盗用
基础防盗链功能 - 目的不让恶意用户能轻易的爬取网站对外数据
secure_link_module - 对数据安全性提高加密验证和失效性,适合如核心重要重要数据
access_module - 对后台、部分用户服务的数据提供IP防控 -
常见的攻击手段
-
后台密码撞库 - 通过猜测密码字典不断对后台系统登录性尝试,获取后台登录密码
方法一、后台登录密码复杂度
方法二、access_module - 对后台提供IP防控
方法三、预警机制 -
文件上传漏洞 - 利用这些可以上传的接口将恶意代码植入到服务器中,再通过url去访问以执行代码
对上传文件判断
location ^~ /upload { root /opt/app/images; if($request_filename ~* (.*)\.php){ return 403; } }
-
SQL注入 - 利用未过滤/未审核用户输入的攻击方法,让应用运行本不应该运行的SQL代码
…
-
其他
# 检查配置文件语法
$ nginx -t -c /etc/nginx/nginx.conf
# centos系,查看nginx文件
$ rpm -ql nginx
$ systemctl start nginx
$ systemctl restart nginx
$ systemctl stop nginx
$ systemctl reload nginx
$ systemctl status nginx