Nginx 部分 (二) - 基础概念-基本结构、反向代理配置
2018-02-09 16:31
1156 查看
基础概念
上一章单纯是为了跑起来,其中的配置是生产环境的配置,如果简单也是可以的,现在结构概念部分;指令和上下文:
nginx的配置文件参照上文,/opt/nginx/conf/nginx.conf①指令 – 可选项,包含名称和参数,以分号结尾
gzip on; //对响应数据进行Gzip压缩
②上下文 –
分块,你可以声明指令 – 类似于编程语言中的作用域
worker_processes 2; # 全局上下文指令 http { # http 上下文 gzip on; # http 上下文中的指令 server { # server 上下文 listen 80; # server 上下文中的指令 } }
指令类型
普通指令:在每个上下文仅有唯一值。而且,它只能在当前上下文中定义一次。子级上下文可以覆盖父级中的值,并且这个覆盖值只在当前的子级上下文中有效。
gzip on; gzip off; # 非法,不能在同一个上下文中指定同一普通指令2次 server { location /downloads { gzip off; } location /assets { # gzip is on here } }
数组指令
在同一上下文中添加多条指令,将添加多个值,而不是完全覆盖。在子级上下文中定义指令将覆盖给父级上下文中的值。
error_log /var/log/nginx/error.log; error_log /var/log/nginx/error_notive.log notice; error_log /var/log/nginx/error_debug.log debug; server { location /downloads { # 下面的配置会覆盖父级上下文中的指令 error_log /var/log/nginx/error_downloads.log; } }
行动指令
行动是改变事情的指令。根据模块的需要,它继承的行为可能会有所不同。
例如rewrite指令,只要是匹配的都会执行
server { rewrite ^ /foobar; location /foobar { rewrite ^ /foo; rewrite ^ /bar; } }
如果用户想尝试获取
/sample
server的rewrite将会执行,从 /sample rewrite 到 /foobar location /foobar 会被匹配 location的第一个rewrite执行,从/foobar rewrite到/foo location的第二个rewrite执行,从/foo rewrite到/bar
return指令提供的是不同的行为:
server { location / { return 200; return 404; } }
上面操作返回200
处理请求
在 Nginx 内部,你可以指定多个虚拟服务器,每个虚拟服务器用
server{} 上下文描述,但http只能有一个。
server 14f6e { listen *:80 default_server; server_name netguru.co; return 200 "Hello from netguru.co"; } server { listen *:80; server_name foo.co; return 200 "Hello from foo.co"; } server { listen *:81; server_name bar.co; return 200 "Hello from bar.co"; }
这将告诉
Nginx 如何处理到来的请求。Nginx 将会首先通过检查 listen 指令来测试哪一个虚拟主机在监听给定的 IP 端口组合。然后,server_name指令的值将检测 Host 头(存储着主机域名)。
Nginx 将会按照下列顺序选择虚拟主机:
匹配sever_name指令的IP-端口主机
拥有default_server标记的IP-端口主机
首先定义的IP-端口主机
如果没有匹配,拒绝连接。
例如:
Request to foo.co:80 => "Hello from foo.co" Request to www.foo.co:80 => "Hello from netguru.co" Request to bar.co:80 => "Hello from netguru.co" Request to bar.co:81 => "Hello from bar.co" Request to foo.co:81 => "Hello from bar.co"
server_name
指令
server_name指令接受多个值。它还处理通配符匹配和正则表达式。
server_name netguru.co www.netguru.co; # exact match server_name *.netguru.co; # wildcard matching server_name netguru.*; # wildcard matching server_name ~^[0-9]*\.netguru\.co$; # regexp matching
当有歧义时,nginx 将使用下面的命令:
确切的名字
最长的通配符名称以星号开始,例如“* .example.org”。
最长的通配符名称以星号结尾,例如“mail.**”
首先匹配正则表达式(按照配置文件中的顺序)
Nginx
会存储 3 个哈希表:①确切的名字,②以星号开始的通配符,和③以星号结尾的通配符。如果结果不在任何表中,则将按顺序进行正则表达式测试。
值得谨记的是
server_name .netguru.co;
是一个来自下面的缩写
server_name netguru.co www.netguru.co *.netguru.co;
有一点不同,.netguru.co
存储在第二张表,这意味着它比显式声明的慢一点
listen
指令
在很多情况下,能够找到
listen 指令,接受IP:端口值
listen 127.0.0.1:80; listen 127.0.0.1; # by default port :80 is used listen *:81; listen 81; # by default all ips are used listen [::]:80; # IPv6 addresses listen [::1]; # IPv6 addresses
然而,还可以指定
UNIX-domain 套接字。
listen unix:/var/run/nginx.sock;
最小化配置:
# /opt/nginx/nginx.conf events {} # events context needs to be defined to consider config valid http { server { listen 80; server_name netguru.co www.netguru.co *.netguru.co; return 200 "Hello"; } }
页面访问后显示: Hello
root,
location, 和 try_files 指令
root
指令
root
指令设置请求的根目录,允许 nginx 将传入请求映射到文件系统。
server { listen 80; server_name netguru.co; root /var/www/netguru.co; }
根据给定的请求,指定
nginx 服务器允许的内容
netguru.co:80/index.html # returns /var/www/netguru.co/index.html netguru.co:80/foo/index.html # returns /var/www/netguru.co/foo/index.html
location
指令
location指令根据请求的 URI 来设置配置。
location [modifier] path location /foo/ { # ... }
如果没有指定修饰符,则路径被视为前缀,其后可以跟随任何东西。
以上例子将匹配 /foo /fooo /foo123 /foo/bar/index.html ...
此外,在给定的上下文中可以使用多个 location 指令
server { listen 80; server_name netguru.co; root /var/www/netguru.co; location / { return 200 "root"; } location /foo/ { return 200 "foo"; } } netguru.co:80 / # => "root" netguru.co:80 /foo # => "foo" netguru.co:80 /foo123 # => "foo" netguru.co:80 /bar # => "root"
Nginx 也提供了一些修饰符,可用于连接
location。这些修饰符将影响 location 模块使用的地方,因为每个修饰符都分配了优先级(上至下)。
= - Exact match 准确匹配 ① ^~ - Preferential match 优先匹配 ② ~ && ~* - Regex match 正则匹配 ③ no modifier - Prefix match 前缀匹配 ④
(Nginx 会先检查精确匹配。如果找不到,我们会找优先级最高的。如果这个匹配依然失败,正则表达式匹配将按照出现的顺序进行测试。至少,最后一个前缀匹配将被使用.)
location /match { return 200 'Prefix match: matches everything that starting with /match'; } location ~* /match[0-9] { return 200 'Case insensitive regex match'; } location ~ /MATCH[0-9] { return 200 'Case sensitive regex match'; } location ^~ /match0 { return 200 'Preferential match'; } location = /match { return 200 'Exact match'; } /match/ # => 'Exact match' /match0 # => 'Preferential match' /match1 # => 'Case insensitive regex match' /MATCH1 # => 'Case sensitive regex match' /match-abc # => 'Prefix match: matches everything that starting with /match'
try_files
指令
尝试不同的路径,找到一个路径就返回。
try_files $uri index.html =404;
所以对于 /foo.html 请求,它将尝试按以下顺序返回文件:
$uri ( /foo.html ) index.html 如果什么都没找到则返回 404
有趣的是,如果我们在服务器上下文中定义 try_files,然后定义匹配的所有请求的 location —— try_files 将不会执行
这是因为在服务器上下文中定义的 try_files 是它的 pseudo-location(假地址),这是最不可能的位置。因此,定义 location/ 将比 pseudo-location 更具体。
server { try_files $uri /index.html =404; location / { } }
因此,应该避免在server 上下文中出现 try_files:
server { location / { try_files $uri /index.html =404; } }
tcp_nodelay, tcp_nopush 和 sendfile
tcp_nodelay (为了尽可能快地推送数据包)起初用于针对Tcp流量冲突和堵塞的问题,Nagle 的算法为了防止通讯被大量的小包淹没,然后采取了限制,只针对比MSS(最大报文长度)小的包,只有当接收方成功将ACK返回,才能进行下次发送,等待期间,发送方可以在此期间缓冲更多的数据之后再进行发送。
在 TCP 通讯中,在发送数据后,需要接收回应包(ACK)来确认数据被成功传达(延时 ACK),延时 ACK 旨在解决线路被大量的 ACK 包拥堵的状况。为了减少
ACK 包的
数量,接收者等待需要回传的数据加上 ACK 包回传给发送方,如果没有数据需要回传,必须在至少每 2 个 MSS,或每 200 至 500 毫秒内发送 ACK(以防我们不再收到包)。
(在这个数据交换过程中,由于 Nagel 和延迟 ACK 之间的死锁,因此引入了 200ms 的延迟)
在大多数情况下,我们不会在我们的网站上使用它,因此可以通过添加 TCP_NODELAY 标志来安全地关闭它。(TCP中就会获得200ms的提速) tcp_nodely on
tcp_nopush(一次性优化数据的发送量)
在发送给客户端之前,它将强制等待包达到最大长度(MSS)。而且这个指令只有在 sendfile 开启时才起作用。sendfile on; tcp_nopush on;
看起来 tcp_nopush 和 tcp_nodelay 是互斥的。但是,如果所有 3 个指令都开启了,nginx 会:
1、确保数据包在发送给客户之前是已满的 2、对于最后一个数据包,tcp_nopush 将被删除 —— 允许 TCP 立即发送,没有 200ms 的延迟
sendfile
正常来说,当要发送一个文件时需要下面的步骤:
malloc(3) – 分配一个本地缓冲区,储存对象数据。 read(2) – 检索和复制对象到本地缓冲区。 write(2) – 从本地缓冲区复制对象到 socket 缓冲区。
这涉及到两个上下文切换(读,写),并使相同对象的第二个副本成为不必要的。正如所看到的,这不是最佳的方式。值得庆幸的是还有另一个系统调用,提升了发送文件(的效率),它被称为:sendfile(2)(想不到吧!居然是这名字)。这个调用在文件 cache 中检索一个对象,并传递指针(不需要复制整个对象),直接传递到 socket 描述符
sendfile(2) 有一些注意事项:
1、不可用于 UNIX sockets(例如:当通过你的上游服务器发送静态文件时) 2、能否执行不同的操作,取决于操作系统
#打开方式: sendfile on;
sendfile_max_chunk 512k;# 较大的文件不要一次全读取了,浪费内存,意思是超过512k的文件不用缓存[/code]
反向代理配置:
server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location /{ root html; index index.html index.htm; proxy_pass http://baidu.com; //指定请求转发到 proxy_connect_timeout 600;//设置连接超时 proxy_read_timeout 600;//设置读响应超时 }
1、proxy_set_header Host $host;
$host 时它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名:
Host参阅地址
2、proxy_set_header X-real-ip $remote_addr;
当你使用了nginx反向服务器后,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,即$remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的,但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:
proxy_set_header X-real-ip $remote_addr;
其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:
request.getAttribute("X-real-ip")
3、proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
我们先看看这里有个X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是client1, proxy1, proxy2,以逗号隔开各个地址,由于他是非rfc标准,所以默认是没有的,需要强制添加,在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip
。也就是说在默认情况下我们使用request.getAttribute("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加如下配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的X-Forwarded-For值是空的,所以我们总感觉X-Forwarded-For的值就等于$proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。
那么$proxy_add_x_forwarded_for又是什么?
$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。
举个例子,有一个web应用,在它之前通过了两个nginx转发,www.linuxidc.com 即用户访问该web通过两台nginx。
在第一台nginx中,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量的"X-Forwarded-For"部分是空的,所以只有$remote_addr,而$remote_addr的值是用户的ip,于是赋值以赋值以后,
X-Forwarded-For变量的值就是用户的真实的ip地址了。
到了第二台nginx,使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
现在的$proxy_add_x_forwarded_for变量,X-Forwarded-For部分包含的是用户的真实ip,$remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值
以后,现在的X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。
$http_x_forwarded_for变量
这个变量就是X-Forwarded-For,由于之前我们说了,默认的这个X-Forwarded-For是为空的,所以当我们直接使用proxy_set_header X-Forwarded-For $http_x_forwarded_for
时会发现,web服务器端使用request.getAttribute("X-Forwarded-For")获得的值是null。如果想要通过request.getAttribute("X-Forwarded-For")获得用户ip,就必须先使用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ;这样就可以获得用户真实ip。
相关文章推荐
- 在Nginx服务器上配置Google反向代理的基本方法
- Nginx 反向代理服务器的基本配置(八)
- Nginx反向代理匹配部分二级域名或二级目录配置
- nginx反向代理基本配置
- nginx反向代理基本配置
- nginx反向代理跨域基本配置与常见误区
- Nginx 反向代理的基本配置及命令解析(以HLS为例子 )
- nginx安装与http反向代理基本配置
- nginx反向代理服务器安装、基本配置
- nginx学习笔记(3):TCP反向代理基本配置
- Nginx 反向代理基本配置
- nginx配置(负载均衡 反向代理 缓存 还有一些基础配置)
- 反向代理概念以及apache,nginx配置反向代理实现负载均衡方法
- Nginx配置文件详细说明,包括基本配置,反向代理配置,expire缓存过期,适合接入CDN的配置
- osworkflow基础入门部分汇总(基本概念,包用途分析及代码片断,表结构分析,主要优势,核心概念)
- 反向代理概念以及apache,nginx配置反向代理实现负载均衡方法
- Tomcat系列之服务器的基本配置及Nginx反向代理tomcat服务
- 反向代理基本概念和配置服务器的三种方法
- nginx 反向代理的基本配置(以Ubuntu 16.04LTS为例)
- 详解Nginx反向代理跨域基本配置与常见误区