nginx配置
本文主要是记录下nginx各种需求的配置,会持续更新。
nginx 配置优先级
- 匹配到全等匹配时,终止后续所有匹配,直接返回;
- 步骤一未匹配上时,然后遍历所有的普通匹配,按照最长匹配原则找到最满足的匹配项,如果匹配项前面有^~符号,则终止后续正则匹配,采用该匹配项;反之则继续后续的正则匹配
- 步骤一二都未匹配上时,此时进行正则匹配,找到第一个满足的正则匹配项,直接返回,若都不满足,则返回步骤二中的最长匹配项
两个项目通过同一nginx的相同端口访问
nginx nginx.com.cn 10.100.3.10
server 10.100.3.12
访问url:
https://aaa.test.com
https://bbb.test.com
将以上两个域名解析到nginx所在server的ip
使用同一个端口时,就按server_name走
server {
listen 443 ssl;
server_name aaa.test.com;
ssl_certificate /xx/xxx/server.crt;
ssl_certificate_key /xx/xxx/server.key;
location / {
proxy_pass http://10.100.3.12:8888;
}
}
server {
listen 443 ssl;
server_name bbb.test.com;
ssl_certificate /xx/xxx/server.crt;
ssl_certificate_key /xx/xxx/server.key;
location / {
proxy_pass http://10.100.3.12:6666;
}
}
让http访问跳转到https
访问http://aaa.test.com跳转到https://aaa.test.com,即同时支持http与https访问
server {
listen 80;
server_name aaa.test.com;
if ($scheme = http ) {
return 301 https://$host$request_uri;
}
}
使用同一个域名端口代理两个不同的服务
通过nginx.com.cn:80可以访问到aaa.test.com与bbb.test.com
server {
listen 80;
server_name nginx.com.cn;
index index.html index.htm index.php;
location /aaa {
proxy_pass https://aaa.test.com/;
}
location /bbb {
proxy_pass https://bbb.test.com/;
}
}
以上效果是:
当访问 http://nginx.com.cn/aaa 转到https://aaa.test.com/
当访问 http://nginx.com.cn/bbb 转到https://bbb.test.com/
注: proxy_pass那行的最后一个/的作用是:转发到 https://aaa.test.com/不带旧的路径,当没有这个/,就是http://nginx.com.cn/aaa 转发到https://aaa.test.com/aaa
多个路由跳转同一地址
server {
listen 80;
listen 443 ssl;
server_name m.aaa.com x.aaa.com;
ssl_certificate aaa.com-chain.pem;
ssl_certificate_key aaa.com-key.pem;
location ^~ /dir1 {
rewrite ^/(.*) https://e.bbb.com$1 redirect;
}
location ~^/(dir2/ttt|dir3|dir4|dir5) {
if ($scheme = http) {
rewrite ^(.*)$ https://$host$1 permanent;
}
proxy_pass https://f.bbb.com;
}
location /{
client_body_buffer_size 20M;
client_max_body_size 20M;
if ($scheme = http) {
rewrite ^(.*)$ https://$host$1 permanent;
}
proxy_pass https://houduanserverzu;
}
}
rewrite与proxy_pass
rewrite 与 proxy_pass虽然最后访问的页面相同,但是他们访问的方式却是不一样的。
rewrite:用户 http://old.com --> nginx (rewrite http://new.com ) -->返回new url到用户 --> 用户请求http://new.com (现象为用户搜索栏的http://old.com变为http://new.com)此为跳转;
proxy_pass:用户 http://old.com --> nginx (proxy_pass http://new.com ) --> nginx访问http://new.com 返回给用户 (现象为用户搜索栏的http://old.com不变)此为代理。
域名跳转
将域名写在upstream中,会降域名解析成ip,跳转到对应的ip,而不是域名
eg:
www.aaa.com 10.2.1.1
upstream testdomain {
server www.aaa.com;
}
server {
listen 443 ssl;
server_name bbb.test.com;
ssl_certificate /xx/xxx/server.crt;
ssl_certificate_key /xx/xxx/server.key;
location / {
proxy_pass http://testdomain;
}
}
此时效果是 http://10.2.1.1
server {
listen 443 ssl;
server_name bbb.test.com;
ssl_certificate /xx/xxx/server.crt;
ssl_certificate_key /xx/xxx/server.key;
location / {
proxy_pass http://www.aaa.com;
}
}
此时效果是 http://www.aaa.com
location =/ 与 location / 优先级不同,引发的访问错误问题
我域名www.aaa.com 走代理,在代理服务器上配置
server {
listen 80;
listen 443 ssl;
server_name www.aaa.com;
ssl_certificate aaa-chain.pem;
ssl_certificate_key aaa-key.pem;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location = / {
if ($scheme = http) {
rewrite ^(.*)$ https://$host$1 permanent;
}
client_body_buffer_size 20M;
client_max_body_size 20M;
proxy_pass http://aaa-backend;
}
}
后端服务器接受不到请求,请求访问到代理服务器的nginx/html下,并未转到后端代理.
将location =/替换为 location /,访问恢复正常。
请求头与响应头
今天的需求是:将某个文件的 location /test/aaa 的Content-Type配置为json格式"application/json",我做了如下配置一直报错 502
location /test/aaa {
proxy_set_header Content-Type "application/json";
}
原因:
请求头:客户端/上游代理 通到服务器有关于客户端请求的信息头
响应头:服务器返回到浏览器的信息头
proxy_set_header:是Nginx设置请求头信息给上游服务器
add_header:是Nginx设置响应头信息给浏览器
这里的Content-Type为响应头,需要这样配置:
location /test/aaa {
add_header 'Content-Type' 'application/json';
}
但是这样配置会添加一个新的响应头,不会覆盖之前的nginx.conf里的 default_type application/octet-stream,那么如何覆盖呢?
headers-more-nginx-module(ngx_headers_more)模块:用于添加、设置和清除输入和输出的头信息
nginx -V查看你的nginx是否安装此模块,若没有,请自行安装。
覆盖之前的响应头
location /test/aaa {
more_set_headers "Content-Type:application/json";
}
注:可能是版本的原因,写成 more_set_headers "Content-Type" "application/json"; 不生效。
删除之前的响应头
location /test/aaa {
more_clear_headers "Content-Type:application/json";
}
还有其他一些用法,大家可自行查阅其他资料
HSTS 强制跳转请求头
加上HSTS请求头,可以实现http强制跳转https
语法:Strict-Transport-Security: max-age=expireTime [; includeSubDomains] [; preload]
max-age 是必须的参数,它是一个以秒为单位的数值,它代表着HSTS Header的过期时间,一般设置为1年,即 31536000秒。
includeSubDomains 是可选参数,如果设置该参数的话,那么意味着当前域名及其子域名均开启HSTS的保护。
preload是可选参数,只有当你申请将自己的域名加入到浏览器内置列表的时候才需要使用到它。
eg: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains"
指定请求头域名作为SNI
当我的架构是:
client --https--> nginx代理(nginx1) --https--> 业务机(业务机上一个nginx2负责根据location分发请求到各个服务)
这里 nginx代理到业务机走的还是https,所以业务机上需要配域名,nginx代理上也要配域名,那我们是要申请两个域名吗?当然可以。
一个域名行不行?有点问题,当我们把域名解析到nginx1的地址上,nginx1到nginx2的转发必然要配ip "proxy_pass https://172.31.0.111:8082/", 此时校验的是172.31.0.111的证书,那肯定有问题。
server {
listen 443 ssl;
server_name cemdbtest.mytest.com;
ssl_certificate ssl/xxx.pem;
ssl_certificate_key ssl/xxx.key;
location / {
proxy_pass https://172.31.0.111:8082/;
proxy_set_header Host cemdbtest.mytest.com;
}
}
代理配置需要加上 proxy_ssl_server_name on; 作用是确保在TLS握手过程中会将SSL连接的服务器名称(即请求头中的域名)发送给后端服务器,作为SNI,类似于这样
server {
listen 443 ssl;
server_name cemdbtest.mytest.com;
add_header Strict-Transport-Security "max-age=63072000" always;
access_log /var/log/nginx/access.log json;
ssl_certificate ssl/xxx.pem;
ssl_certificate_key ssl/xxx.key;
location / {
proxy_pass https://172.31.0.111:8082/;
proxy_ssl_server_name on;
proxy_set_header Host cemdbtest.mytest.com;
}
}