Nginx-反向代理、动静分离、负载均衡、Rewrite、防盗链
反向代理
server {
listen 8081;
server_name www.fan.cn;
location / {
proxy_pass http://127.0.0.1:5001;
}
}
实际使用中,可以将请求转发到本机另一个服务器上,也可以根据访问的路径跳转到不同端口的服务中。
比如我们监听 9001
端口,然后把访问不同路径的请求进行反向代理:
把访问 http://127.0.0.1:9001/edu
的请求转发到 http://127.0.0.1:8080
把访问 http://127.0.0.1:9001/vod
的请求转发到 http://127.0.0.1:8081
这种要怎么配置呢,首先同样打开主配置文件,然后在 http 模块下增加一个 server 块:
server {
listen 9001;
server_name *.fan.cn;
location ~ /edu/ {
proxy_pass http://127.0.0.1:8080;
}
location ~ /vod/ {
proxy_pass http://127.0.0.1:8081;
}
}
动静分离
动静分离可通过location对请求url进行匹配,将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问。通常将静态资源放到nginx中,动态资源转发到tomcat服务器中。
server {
listen 8083;
server_name *.fan.cn;
# 当url中有/static时,会和root目录路径拼接,也就时html/static目录下找文件
location /static {
root html;
index index.html index.htm;
}
location / {
proxy_pass http://127.0.0.1:5001;
}
}
当访问http://order.fan.cn:8083/static/1.jpg
时,会去nginx中的html/staic目录找文件,当访问http://order.fan.cn:8083
,去将请求转发到http://127.0.0.1:5001
负载均衡
#定义一组服务器
upstream myServers1
{
server 127.0.0.1:5000;
server 127.0.0.1:5001;
}
server {
listen 8084;
server_name *.fan.cn;
location / {
proxy_pass http://myServers1;
}
}
以上配置使用轮询模式,5000、5001会交替被访问
其他负载均衡模式
- 权重模式
upstream myServers1
{
server 127.0.0.1:5000 weight=1;
server 127.0.0.1:5001 weight=3;
}
- ip_hash
根据客户端的ip地址转发同一台服务器,可以保持会话,但是很少用这种方式去保持会话,例如我们当前正在使用wifi访问,当切换成手机信号访问时,会话就不保持了。 - least_conn
最少连接访问,优先访问连接最少的那一台服务器,这种方式也很少使用,因为连接少,可能是由于该服务器配置较低,刚开始赋予的权重较低。 - url_hash(需要第三方插件)
根据用户访问的url定向转发请求,不同的url转发到不同的服务器进行处理(定向流量转发)。 - fair(需要第三方插件)
根据后端服务器响应时间转发请求,这种方式也很少使用,因为容易造成流量倾斜,给某一台服务器压垮。
upstream参数
server
反向服务地址加端口weight
权重,默认是1,越大权重就越大max_fails
失败多少次认为主机已挂掉则,踢出 (默认配置10s,即服务器宕掉,会自动剔除)fail_timeout
踢出后重新探测时间backup
备用服务,当其他非backup的机器全部宕机或者繁忙的时候,才会启动这台机器。down
表示当前Server不参与负载
upstream myApiTest {
server localhost:9001 backup;
server localhost:9002 down;
server localhost:9003;
}
max_conns
允许最大连接数slow_start
当节点恢复,不立即加入,而是等待 slow_start 后加入服务对列。
Rewrite
掩藏真实的url以及url中可能暴露的参数,以及隐藏web使用的编程语言,提高安全性便于搜索引擎收录
server {
listen 8085;
server_name *.fan.cn;
location / {
rewrite ^/product.html$ /product/index break;
proxy_pass http://127.0.0.1:5001;
}
}
flag标记说明:
last:本条规则匹配完后,继续向下匹配新的location URI规则;
break:本条规则匹配完即终止,不再匹配后面的规则;
redirect:返回302临时重定向,浏览器会显示跳转后的URL;
permanent:返回301永久重定向,浏览器会显示跳转后的URL;
防盗链
location ^~/images/ {
valid_referers 192.168.8.102; #valid_referers 指令,配置是否允许 referer 头部以及允许哪些 referer 访问。192.168.8.102不是ip而是域名(去掉http:// 前缀)
if ($invalid_referer) { # 注意这里if后要加空格
return 403; ## 返回错误码
}
root /www/resources;
}
HTTP 请求转发到 HTTPS
server {
listen 80;
server_name www.fan.cn;
location / {
rewrite ^(.*) https://$server_name$1 permanent;
}
}
配置 HTTPS
server {
listen 443 ssl http2 default_server; # SSL 访问端口号为 443
server_name sherlocked93.club; # 填写绑定证书的域名
ssl_certificate /etc/nginx/https/1_sherlocked93.club_bundle.crt; # 证书文件地址
ssl_certificate_key /etc/nginx/https/2_sherlocked93.club.key; # 私钥文件地址
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #请按照以下协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
适配 PC 或移动设备
根据用户设备不同返回不同样式的站点,以前经常使用的是纯前端的自适应布局,但无论是复杂性和易用性上面还是不如分开编写的好,比如我们常见的淘宝、京东......这些大型网站就都没有采用自适应,而是用分开制作的方式,根据用户请求的 user-agent 来判断是返回 PC 还是 H5 站点。
server {
listen 80;
server_name fe.sherlocked93.club;
location / {
root /usr/share/nginx/html/pc;
if ($http_user_agent ~* '(Android|webOS|iPhone|iPod|BlackBerry)') {
root /usr/share/nginx/html/mobile;
}
index index.html;
}
}
静态服务
server {
listen 80;
server_name static.sherlocked93.club;
charset utf-8; # 防止中文文件名乱码
location /download {
alias /usr/share/nginx/html/static; # 静态资源目录
autoindex on; # 开启静态资源列目录
autoindex_exact_size off; # on(默认)显示文件的确切大小,单位是byte;off显示文件大概大小,单位KB、MB、GB
autoindex_localtime off; # off(默认)时显示的文件时间为GMT时间;on显示的文件时间为服务器时间
}
}
请求过滤
# 非指定请求全返回 403
if ( $request_method !~ ^(GET|POST|HEAD)$ ) {
return 403;
}
location / {
# IP访问限制(只允许IP是 192.168.0.2 机器访问)
allow 192.168.0.2;
deny all;
root html;
index index.html index.htm;
}
静态文件缓存
由于图片、字体、音频、视频等静态文件在打包的时候通常会增加了 hash,所以缓存可以设置的长一点,先设置强制缓存,再设置协商缓存;如果存在没有 hash 值的静态文件,建议不设置强制缓存,仅通过协商缓存判断是否需要使用缓存。
# 图片缓存时间设置
location ~ .*\.(css|js|jpg|png|gif|swf|woff|woff2|eot|svg|ttf|otf|mp3|m4a|aac|txt)$ {
expires 10d;
}
# 如果不希望缓存
expires -1;
解决跨域
1、如果前后端域名不一致
# 请求跨域,约定代理后端服务请求path以/apis/开头
location ^~/apis/ {
# 这里重写了请求,将正则匹配中的第一个分组的path拼接到真正的请求后面,并用break停止后续匹配
rewrite ^/apis/(.*)$ /$1 break;
proxy_pass api.fan.cn;
# 两个域名之间cookie的传递与回写
proxy_cookie_domain admin.fan.cn api.fan.cn;
}
这样,静态资源我们使用 admin.fan.cn/xx.html,动态资源我们使用 admin.fan.cn/apis/getAwo,浏览器页面看起来仍然访问的前端服务器,绕过了浏览器的同源策略,毕竟我们看起来并没有跨域。
也可以统一一点,直接把前后端服务器地址直接都转发到另一个 server.fan.cn,只通过在后面添加的 path 来区分请求的是静态资源还是后端服务,看需求了。
2、配置 header 解决跨域
# /etc/nginx/conf.d/be.sherlocked93.club.conf
server {
listen 80;
server_name be.sherlocked93.club;
add_header 'Access-Control-Allow-Origin' $http_origin; # 全局变量获得当前请求origin,带cookie的请求不支持*
add_header 'Access-Control-Allow-Credentials' 'true'; # 为 true 可带上 cookie
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 允许请求方法
add_header 'Access-Control-Allow-Headers' $http_access_control_request_headers; # 允许请求的 header,可以为 *
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000; # OPTIONS 请求的有效期,在有效期内不用发出另一条预检请求
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204; # 200 也可以
}
location / {
root /usr/share/nginx/html/be;
index index.html;
}
}
开启gzip
gzip 是一种常用的网页压缩技术,传输的网页经过 gzip 压缩之后大小通常可以变为原来的一半甚至更小(官网原话),更小的网页体积也就意味着带宽的节约和传输速度的提升,特别是对于访问量巨大大型网站来说,每一个静态资源体积的减小,都会带来可观的流量与带宽的节省。
# /etc/nginx/conf.d/gzip.conf
gzip on; # 默认off,是否开启gzip
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# 上面两个开启基本就能跑起了,下面的愿意折腾就了解一下
gzip_static on;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_min_length 1k;
gzip_http_version 1.1;
泛域名路径分离
经常有时候我们可能需要配置一些二级或者三级域名,希望通过 Nginx 自动指向对应目录,比如:
test1.doc.sherlocked93.club
自动指向 /usr/share/nginx/html/doc/test1
服务器地址;
test2.doc.sherlocked93.club
自动指向 /usr/share/nginx/html/doc/test2
服务器地址;
server {
listen 80;
server_name ~^([\w-]+)\.doc\.sherlocked93\.club$;
root /usr/share/nginx/html/doc/$1;
}
泛域名转发
和之前的功能类似,有时候我们希望把二级或者三级域名链接重写到我们希望的路径,让后端就可以根据路由解析不同的规则:
test1.serv.sherlocked93.club/api?name=a
自动转发到 127.0.0.1:8080/test1/api?name=a
;
test2.serv.sherlocked93.club/api?name=a
自动转发到 127.0.0.1:8080/test2/api?name=a
;
server {
listen 80;
server_name ~^([\w-]+)\.serv\.sherlocked93\.club$;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://127.0.0.1:8080/$1$request_uri;
}
}
最佳实践
- 为了使 Nginx 配置更易于维护,建议为每个服务创建一个单独的配置文件,存储在 /etc/nginx/conf.d 目录,根据需求可以创建任意多个独立的配置文件。
- 独立的配置文件,建议遵循以下命名约定 <服务>.conf,比如域名是 sherlocked93.club,那么你的配置文件的应该是这样的 /etc/nginx/conf.d/sherlocked93.club.conf,如果部署多个服务,也可以在文件名中加上 Nginx 转发的端口号,比如 sherlocked93.club.8080.conf,如果是二级域名,建议也都加上 fe.sherlocked93.club.conf。
- 常用的、复用频率比较高的配置可以放到 /etc/nginx/snippets 文件夹,在 Nginx 的配置文件中需要用到的位置 include 进去,以功能来命名,并在每个 snippet 配置文件的开头注释标明主要功能和引入位置,方便管理。比如之前的 gzip、cors 等常用配置,我都设置了 snippet。
- Nginx 日志相关目录,内以 域名.type.log 命名(比如 be.sherlocked93.club.access.log 和 be.sherlocked93.club.error.log )位于 /var/log/nginx/ 目录中,为每个独立的服务配置不同的访问权限和错误日志文件,这样查找错误时,会更加方便快捷。