nginx反代理

反代理

首先,反代理是相对于正向代理的功能。反向代理是服务器端使用的代理,可以让客户端的流量经过反向代理后访问服务器,其作用可以是多样的,可以用于负载均衡,ip端口复用,流量审查等。

为什么用nginx

这是一个非常轻量和高效的服务器,可以用于处理高并发,所以适合静态网页和反代理。(生来就是做这个的,毕竟是毛子做的)

使用反向代理

配置文件结构

各个发行版的默认配置文件不同,例如debian的http块下默认include了sites-enabled下的配置文件,只要搞懂编辑的配置文件在整个文件下的位置即可。

http代理

注意,以下的配置都在http块下

基于目录

属于ngx_http_proxy_module的功能,示例样式如下

1
2
3
4
5
6
location ^~ /location { # 可以选定子目录进行代理,目录前面可以加通配符
proxy_pass http://localhost:8000; # 指定代理的ip和地址
proxy_set_header Host $host; # 传递host给服务器
proxy_set_header X-Real-IP $remote_addr; # 传递客户端ip给服务器
}

也可以设置一些代理缓冲区大小之类的东西,但是我是用不上的哪天用上了再写吧

proxy_redirect可以用于反代理的重定向

值得注意的是,可以通过代理来使用https,只需要添加proxy_ssl_certificateproxy_ssl_certificate_key选项到合适的密钥文件即可。

基于域名

形如

1
2
3
4
5
6
7
8
9
10
11
server{
listen 80;
server_name a.com;

}

server{
listen 80;
server_name b.com;

}

当然如果需要负载均衡的一些操作的话也可以用upstream 当然这个我也用不到

代理https站点

http代理模式下的https代理是服务器和代理服务器间https连接,代理服务器和客户端之间再https连接。某些情况下我们可能需要代理已经被https加密过的站点,但是众所周知,https是不会允许有中间人攻击的,sni会要求服务器给出ip并和域名的注册ip对比,如果不符合会告诉浏览器当前的访问是不安全的。所以,只能通过更底层的代理模式来解决这个问题。

tcp层代理

属于ngx_stream_proxy_module的功能。
注意,这个配置的stream块是和http块同级的。实例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 127.0.0.1:12345;
proxy_pass 127.0.0.1:8080;
}

server {
listen 12345;
proxy_connect_timeout 1s;
proxy_timeout 1m;
proxy_pass example.com:12345;
}

server {
listen 53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns.example.com:53;
}

server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}

这种代理都是tcp层的代理,nginx服务器并不会解析上游内容,而是只做转发,从而可以实现更多服务的代理。

https代理支持

除了指定443端口外,还有一个这个模块的功能是需要的ngx_stream_ssl_preread_module。因为https流量走了代理,所以sni仍然是不通过的,所以需要不终止SSL/TLS的情况下允许ClientHello通过~~~好吧我看不懂这些是啥回头再说~~。 总而言之,你需要将ssl_preread设置成on,然后你才能代理https流量。示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
map $ssl_preread_server_name $name {
backend.example.com backend;
default backend2;
}

upstream backend {
server 192.168.0.1:12345;
server 192.168.0.2:12345;
}

upstream backend2 {
server 192.168.0.3:12345;
server 192.168.0.4:12345;
}

server {
listen 12346;
proxy_pass $name;
ssl_preread on;
}