Nginx 相关的知识汇总
Nginx 的几个常用配置和技巧
一个站点配置多个域名
server { listen 80; # server_name 后跟多个域名即可,多个域名之间用空格分隔 server_name ops-coffee.cn b.ops-coffee.cn; }
一个服务配置多个站点
server { listen 80; server_name a.ops-coffee.cn; location / { root /home/project/pa; index index.html; } } server { listen 80; server_name ops-coffee.cn b.ops-coffee.cn; location / { root /home/project/pb; index index.html; } } server { listen 80; server_name c.ops-coffee.cn; location / { root /home/project/pc; index index.html; } }
nginx 添加账号密码验证
server { location / { auth_basic "please input user&passwd"; auth_basic_user_file key/auth.key; } }
# cat pwd.pl #!/usr/bin/perl use strict; my $pw=$ARGV[0] ; print crypt($pw,$pw)."\n";
# perl pwd.pl ops-coffee.cn
opf8BImqCAXww
# echo "admin:opf8BImqCAXww" > key/auth.key
nginx 开启列目录
server { location download { # 当你想让nginx作为文件下载服务器存在时,需要开启nginx列目录 autoindex on; # autoindex_exact_size: 为on(默认)时显示文件的确切大小,单位是byte;改为off显示文件大概大小,单位KB或MB或GB autoindex_exact_size off; # autoindex_localtime: 为off(默认)时显示的文件时间为GMT时间;改为on后,显示的文件时间为服务器时间 autoindex_localtime on; } }
默认当访问列出的 txt 等文件时会在浏览器上显示文件的内容,如果你想让浏览器直接下载,加上下边的配置
if ($request_filename ~* ^.*?\.(txt|pdf|jpg|png)$) { add_header Content-Disposition 'attachment'; }
配置默认站点
server { listen 80 default; }
当一个 nginx 服务上创建了多个虚拟主机时默认会从上到下查找,如果匹配不到虚拟主机则会返回第一个虚拟主机的内容,如果你想指定一个默认站点时,可以将这个站点的虚拟主机放在配置文件中第一个虚拟主机的位置,或者在这个站点的虚拟主机上配置 listen default
不允许通过 IP 访问
server { listen 80 default; server_name _; return 404; }
上边这个方法比较粗暴,当然你也可以配置下所有未配置的地址访问时直接301重定向到你的网站去,也能为你的网站带来一定的流量
server { rewrite ^/(.*)$ https://ops-coffee.cn/$1 permanent; }
直接返回验证文件
location = /XDFyle6tNA.txt { default_type text/plain; return 200 'd6296a84657eb275c05c31b10924f6ea'; }
很多时候微信等程序都需要我们放一个txt的文件到项目里以验证项目归属,我们可以直接通过上边这种方式修改nginx即可,无需真正的把文件给放到服务器上。
nginx 配置 upstream 反向代理
http { ... upstream tomcats { server 192.168.106.176 weight=1; server 192.168.106.177 weight=1; } server { location /ops-coffee/ { proxy_pass http://tomcats; 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_pass http://tomcats 与 proxy_pass http://tomcats/ 的区别:
虽然只是一个/的区别但结果确千差万别。分为以下两种情况:
目标地址中不带 uri(proxy_pass http://tomcats)。此时新的目标url中,匹配的 uri 部分不做修改,原来是什么就是什么。
location /ops-coffee/ {
proxy_pass http://192.168.106.135:8181;
}
http://domain/ops-coffee/ --> http://192.168.106.135:8181/ops-coffee/
http://domain/ops-coffee/action/abc --> http://192.168.106.135:8181/ops-coffee/action/abc
目标地址中带 uri(proxy_pass http://tomcats/,/ 也是 uri),此时新的目标 url 中,匹配的 uri 部分将会被修改为该参数中的 uri。
location /ops-coffee/ {
proxy_pass http://192.168.106.135:8181/;
}
http://domain/ops-coffee/ --> http://192.168.106.135:8181
http://domain/ops-coffee/action/abc --> http://192.168.106.135:8181/action/abc
nginx upstream 开启 keepalive
upstream tomcat { server ops-coffee.cn:8080; keepalive 1024; } server { location / { proxy_http_version 1.1; proxy_set_header Connection ""; proxy_pass http://tomcat; } }
keepalive: 指定每个 nginxworker 可以保持的最大连接数量为1024,默认不设置,即 nginx 作为 client 时 keepalive 未生效
proxy_http_version 1.1: 开启 keepalive 要求HTTP协议版本为 HTTP 1.1
proxy_set_header Connection "": 为了兼容老的协议以及防止 http 头中有 Connection close 导致的 keepalive 失效,这里需要及时清掉 HTTP 头部的 Connection
404 自动跳转到首页
server { location / { error_page 404 = @ops-coffee; } location @ops-coffee { # 自动跳转到首页去 rewrite .* / permanent; } }
Nginx 与安全有关的几个配置
隐藏版本号
经常会有针对某个版本的 nginx 安全漏洞出现,隐藏 nginx 版本号就成了主要的安全优化手段之一,当然最重要的是及时升级修复漏洞。
http { server_tokens off; }
开启 HTTPS
server { listen 443; server_name ops-coffee.cn; ssl on; # ssl_certificate: 配置nginx ssl证书的路径 ssl_certificate /etc/nginx/server.crt; # ssl_certificate_key: 配置nginx ssl证书key的路径 ssl_certificate_key /etc/nginx/server.key; # ssl_protocols: 指定客户端建立连接时使用的ssl协议版本,如果不需要兼容TSLv1,直接去掉即可 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # ssl_ciphers: 指定客户端连接时所使用的加密算法,你可以再这里配置更高安全的算法 ssl_ciphers HIGH:!aNULL:!MD5; }
添加黑白名单
location /admin/ { allow 192.168.1.0/24; deny all; } location /ops-coffee/ { 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; }
限制请求方法
if ($request_method !~ ^(GET|POST)$ ) { return 405; }
拒绝 User-Agent
if ($http_user_agent ~* LWP::Simple|BBBike|wget|curl) { return 444; }
图片防盗链
location /images/ { # valid_referers: 验证referer,其中none允许referer为空,blocked允许不带协议的请求,除了以上两类外仅允许referer为www.ops-coffee.cn或ops-coffee.cn时访问images下的图片资源,否则返回403 valid_referers none blocked www.ops-coffee.cn ops-coffee.cn; if ($invalid_referer) { return 403; } }
location /images/ { valid_referers blocked www.ops-coffee.cn ops-coffee.cn if ($invalid_referer) { # 不符合referer规则的请求重定向到一个默认的图片 rewrite ^/images/.*\.(gif|jpg|jpeg|png)$ /static/qrcode.jpg last; } }
控制并发连接数
http { limit_conn_zone $binary_remote_addr zone=ops:10m; server { listen 80; server_name ops-coffee.cn; root /home/project/webapp; index index.html; location / { limit_conn ops 10; } access_log /tmp/nginx_access.log main; } }
limit_conn_zone
: 设定保存各个键(例如 $binary_remote_addr)状态的共享内存空间的参数,zone=空间名字:大小
大小的计算与变量有关,例如 $binary_remote_addr
变量的大小对于记录IPV4地址是固定的 4bytes,而记录IPV6地址时固定的 16bytes,存储状态在32位平台中占用32或者64 bytes,在64位平台中占用 64 bytes。1m的共享内存空间可以保存大约3.2万个32位的状态,1.6万个64位的状态
limit_conn
: 指定一块已经设定的共享内存空间(例如name为ops的空间),以及每个给定键值的最大连接数
上边的例子表示同一IP同一时间只允许10个连接
当有多个 limit_conn
指令被配置时,所有的连接数限制都会生效。下面的配置不仅会限制单一IP来源的连接数为 10,同时也会限制单一虚拟服务器的总连接数为 2000。
http { limit_conn_zone $binary_remote_addr zone=ops:10m; limit_conn_zone $server_name zone=coffee:10m; server { listen 80; server_name ops-coffee.cn; root /home/project/webapp; index index.html; location / { limit_conn ops 10; limit_conn coffee 2000; } } }
缓冲区溢出攻击
缓冲区溢出攻击 是通过将数据写入缓冲区并超出缓冲区边界和重写内存片段来实现的,限制缓冲区大小可有效防止。
client_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k;
client_body_buffer_size
: 默认8k或16k,表示客户端请求body占用缓冲区大小。如果连接请求超过缓存区指定的值,那么这些请求实体的整体或部分将尝试写入一个临时文件。
client_header_buffer_size
: 表示客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于1k,不过如果有来自于wap客户端的较大的cookie它可能会大于 1k,Nginx将分配给它一个更大的缓冲区,这个值可以在large_client_header_buffers里面设置
client_max_body_size
: 表示客户端请求的最大可接受body大小,它出现在请求头部的Content-Length字段, 如果请求大于指定的值,客户端将收到一个"Request Entity Too Large" (413)错误,通常在上传文件到服务器时会受到限制
large_client_header_buffers
表示一些比较大的请求头使用的缓冲区数量和大小,默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,请求字段不能大于一个缓冲区大小,如果客户端发送一个比较大的头,nginx将返回"Request URI too large" (414),请求的头部最长字段不能大于一个缓冲区,否则服务器将返回"Bad request" (400)
同时需要修改几个超时时间的配置:
client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10;
client_body_timeout
: 表示读取请求body的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx 将返回 Request time out (408) 错误
client_header_timeout
: 表示读取客户端请求头的超时时间,如果连接超过这个时间而客户端没有任何响应,Nginx 将返回 Request time out (408) 错误
keepalive_timeout
: 参数的第一个值表示客户端与服务器长连接的超时时间,超过这个时间,服务器将关闭连接,可选的第二个参数参数表示 Response 头中 Keep-Alive: timeout=time的time值,这个值可以使一些浏览器知道什么时候关闭连接,以便服务器不用重复关闭,如果不指定这个参数,nginx 不会在应 Response 头中发送 Keep-Alive 信息
send_timeout
: 表示发送给客户端应答后的超时时间,Timeout是指没有进入完整established状态,只完成了两次握手,如果超过这个时间客户端没有任何响应,nginx 将关闭连接
Header 头设置
通过以下设置可有效防止XSS攻击
add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff";
X-Frame-Options
: 响应头表示是否允许浏览器加载frame等属性,有三个配置DENY禁止任何网页被嵌入,SAMEORIGIN只允许本网站的嵌套,ALLOW-FROM允许指定地址的嵌套
X-XSS-Protection
: 表示启用XSS过滤(禁用过滤为 X-XSS-Protection: 0),mode=block 表示若检查到 XSS 攻击则停止渲染页面
X-Content-Type-Options
: 响应头用来指定浏览器对未指定或错误指定 Content-Type 资源真正类型的猜测行为,nosniff 表示不允许任何猜测
在通常的请求响应中,浏览器会根据 Content-Type 来分辨响应的类型,但当响应类型未指定或错误指定时,浏览会尝试启用 MIME-sniffing 来猜测资源的响应类型,这是非常危险的
例如一个.jpg的图片文件被恶意嵌入了可执行的js代码,在开启资源类型猜测的情况下,浏览器将执行嵌入的js代码,可能会有意想不到的后果
另外还有几个关于请求头的安全配置需要注意
Content-Security-Policy
: 定义页面可以加载哪些资源,
add_header Content-Security-Policy "default-src 'self'";
上边的配置会限制所有的外部资源,都只能从当前域名加载,其中default-src定义针对所有类型资源的默认加载策略,self允许来自相同来源的内容
Strict-Transport-Security
: 会告诉浏览器用HTTPS协议代替HTTP来访问目标站点
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
上边的配置表示当用户第一次访问后,会返回一个包含了 Strict-Transport-Security
响应头的字段,这个字段会告诉浏览器,在接下来的31536000秒内,当前网站的所有请求都使用https协议访问,参数includeSubDomains
是可选的,表示所有子域名也将采用同样的规则
NGINX Config,域名变了:在线生成 NGINX 配置
如果你在使用 NGINX 架设 Web 服务器的过程中为配置而感到头痛的话,那么不妨通过 NGINX Config 这个工具来在线生成。NGINX Config 支持 HTTP、HTTPS、PHP、Python、Node.js、WordPress、Drupal、缓存、逆向代理、日志等各种配置选项。
HAProxy 是一个负载均衡服务器,自带过滤 HTTP 请求的功能,可以防止应用层的 DDOS 攻击,这方面比 nginx 更强大。
Application-Layer DDoS Attack Protection with HAProxy
正向代理和反向代理的区别:
由于防火墙的原因,我们并不能直接访问谷歌,那么我们可以借助VPN来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,而且客户端是知道目标的,而目标是不知道客户端是通过 VPN 访问的。
当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。
参考:
- What Is A Reverse Proxy? | Proxy Servers Explained
- How I set up Tinyproxy as a forward proxy and reverse proxy
Nginx 的 Master-Worker 模式
Master 进程的作用:读取并验证配置文件 nginx.conf;管理 worker 进程;
Worker 进程的作用:每一个 Worker 进程都维护一个线程(避免线程切换),处理连接和请求;注意 Worker 进程的个数由配置文件决定,一般和 CPU 个数相关(有利于进程切换),配置几个就有几个 Worker 进程,上面的例子只有1个 Worker 进程。
参考:深入浅出 Nginx https://mp.weixin.qq.com/s/ye52uOBdpc_BKk3hwYDKew
Nginx 的一个小技巧,在不使用编程语言的情况下,在 JSON 对象里返回客户端的 IP 地址。
location /ip { default_type text/plain; return 200 $remote_addr; } location /json_ip { default_type application/json; return 200 "{\"ip\":\"$remote_addr\"}"; }
$ http :8801/json_ip HTTP/1.1 200 OK Connection: keep-alive Content-Length: 18 Content-Type: application/json Date: Fri, 15 Nov 2019 03:00:16 GMT Server: nginx { "ip": "127.0.0.1" } $ http :8801/ip HTTP/1.1 200 OK Connection: keep-alive Content-Length: 9 Content-Type: text/plain Date: Fri, 15 Nov 2019 03:00:20 GMT Server: nginx 127.0.0.1
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论