Nginx正向代理与反向代理
正向代理与反向代理的区别,以及用Nginx配置实现代理服务。
一、正向代理与反向代理
1. 正向代理
正向代理其实相当于请求的中继,比如说,如果某个网站国内无法访问,也就是被墙了,我可以选择两种方式:
一个是配置代理服务器,第二种就是 VPN。
其实两种技术原理差不太多,如果说我自己访问不到这个网站,而这时可以通过一台可以访问到这个网站的服务器,也就是代理服务器,来进行访问,这台代理服务器,分析我们请求的信息,然后去对应的要去的网站上将内容取回来发给我,这样我就能读到想要访问的网站上的内容了,通过一下图片,可以很清晰的看出其原理:
2. 反向代理
反向代理比正向代理更加透明,客户端并不知道访问的是代理服务器,当客户端请求一个网址的时候,会经过反向代理服务器,而这台反向代理服务器,会根据客户端的请求,将请求转发到内网服务器中,内网服务器处理请求并返回结果到反向代理服务器上,通过反向代理服务器,将结果最终返回到客户端,详情如图:
简单来说:
正向代理代理的是客户端(如通过代理访问谷歌),而反向代理代理的是服务器(如 Nginx 代理 PHP 服务器)。
二、通过SSH反向代理实现内网穿透
1. 背景
我用学校实验室的一台服务器在跑数据,但是这台服务器没有公网 ip,只有学校内网 ip,故我只能到实验室登录。但有时候,需要在宿舍或者家里远程连接这台服务器。
于是,我就用到了反向代理。前提是我有一台公网 ip 的服务器(例如,阿里的学生机,或者 vultr 的 VPS 都可以)。
首先,准备好这两台服务器:
- 学校实验室服务器(SchoolServer)
- IP:192.168.10.50
- ssh端口:22
- 用户:student
- 密码:helloworld
- 我的外网服务器(MyServer)
- IP:111.13.100.91
- ssh端口:22
- 用户:wenyuanblog
- 密码:www.wenyuanblog.com
2. 实现原理
在学校内网服务器(以下简称 SchoolServer)中,通过 SSH 设置反向代理,指向我的公网服务器(以下简称 MyServer,该服务器作为反向代理服务器),之后用客户端连接 MyServer 时,MyServer 会把请求转交给 SchoolServer,从而间接登录学校的内网服务器。
整个过程,我们作为客户端是感知不到代理服务器的存在的。客户端是否能感知代理服务器的存在,是区别正向代理和反向代理的关键。
SSH 参数介绍
# 反向代理命令
ssh -fCNR
# 正向代理命令
ssh -fCNL
参数说明
参数 | 含义 |
---|---|
-f | 后台执行 ssh 指令 |
-C | 允许压缩数据 |
-N | 不执行远程指令 |
-R | 将远程服务器的某个端口转发到本地服务器的指定端口 |
-L | 将本地服务器的某个端口转发到远程服务器的指定端口 |
-p | 指定远程服务器的端口 |
3. 内网服务器操作
登录 SchoolServer,进行如下操作:
# ssh -N -f -R MyServer端口:127.0.0.1:本地端口 MyServer用户@MyServerIP
ssh -N -f -R 20022:127.0.0.1:22 wenyuanblog@111.13.100.91
这句命令的意思是,将 MyServer 的 20022 端口转发至 SchoolServer 22 端口,最后是 MyServer 用户名和 IP。
使用 ps aux | grep ssh
来查看是否运行。
4. 公网服务器操作
登录 MyServer,进行如下操作:
# ssh SchoolServer用户名@127.0.0.1 -p 代理端口 -L MyServerIP:代理端口:127.0.0.1:22
ssh student@127.0.0.1 -p 20022 -L 111.13.100.91:20022:127.0.0.1:22
执行这条命名,输入 student 用户的密码,现在就已经跳转登录到内网服务器了。
保持当前窗口的登录状态,这时候使用 xshell、beyondcompare,就只要在登录的配置项里 IP 填 MyServer 的 IP,端口填 20022 就好了。
三、Nginx配置实现代理服务
1. 背景
到目前为止,我们都还没有用到 Nginx 的代理服务。那什么时候会需要呢,现在有了如下需求:
在学校内网服务器上跑了一个网页(实验室代码库 GitLab),我们需要在宿舍或者家里访问这个内部网页。
该项目是部署在内网的,所以在内网直接访问不会有问题,而从外网访问当然也就访问不到。
- 学校实验室服务器(SchoolServer)
- IP:192.168.10.50
- 页面 url:192.168.10.50:8000
- 我的外网服务器(MyServer)
- IP:111.13.100.91
- 站点域名:www.wenyuanblog.com
2. 实现原理
还是通过反向代理来实现。
通过 Nginx 实现端口转发,最后可以通过公网服务器的域名+端口号访问学校内网服务器的页面。
即访问 www.wenyuanblog.com:28000 时,将得到 192.168.10.50:8000(实验室代码库)的页面。
当然了,这样配置的话,我不得不记住 28000 这个端口号,显然不方便。
所以下面的配置,我将配置成二级域名的形式,即 gitlab.wenyuanblog.com -> 192.168.10.50:8000
3. 内网服务器操作
登录 SchoolServer,进行如下操作(和二>中一样):
# ssh -N -f -R MyServer端口:127.0.0.1:本地端口 MyServer用户@MyServerIP
ssh -N -f -R 28000:127.0.0.1:8000 wenyuanblog@111.13.100.91
这句命令的意思是,将 MyServer 的 28000 端口转发至 SchoolServer 8000 端口,最后是 MyServer 用户名和 IP。
使用 ps aux | grep ssh
来查看是否运行。
4. 公网服务器操作
登录 MyServer,增加一份 Nginx 的配置文件,我习惯放于 /usr/local/nginx/conf/vhosts
目录下,考虑到是代理的配置文件,我取名为 school.proxy
。
vim school.proxy
,配置如下:
upstream school_gitlab {
server 127.0.0.1:28000;
}
server {
listen 80;
server_name gitlab.wenyuanblog.com;
location / {
proxy_pass http://school_gitlab;
proxy_set_header Host $host;
}
access_log /var/log/nginx/access/school_gitlab.log;
}
现在,我就可以通过二级域名访问学校实验室的 GitLab 了。
整个过程中,在 MyServer 的数据流向如下:
二级域名访问 -> MyServer:80 -> nginx 分发 -> MyServer:28000 -> SchoolServer:8080
四、补充:用autossh代替ssh
1. 背景
其实整个过程到上面为止已经结束了,目前已经通过反向代理实现内网穿透,平时肯定够用了。
如果想追求更进一步的配置,可以继续往下看。
什么是更进一步的配置呢?
在前面二、三两部分内容的「内网服务器操作」时,我们使用 ssh 建立的反向连接其实很不稳定,长时间不使用连接就会自动释放,这个时候就需要使用 autossh。
autossh 的参数与 ssh 的参数是一致的,但是不同的是,在隧道断开的时候,autossh 会自动重新连接而 ssh 不会。
2. 步骤修改
只需改动一个地方,那就是上面二和三里面的「3. 内网服务器操作」,其他操作不变。
现在如下操作:
Step1. 配置公钥和私钥,实现免密码登录(为后面的脚本做准备)
- 登录内网服务器(SchoolServer)
切换到普通用户 student,不建议用 root。
执行命令:ssh-keygen -t rsa -P ''
,直接 ssh-keygen 然后三次回车就可以了。-P
表示密码,-P ''
就表示空密码,也可以不用-P
参数,这样就要三车回车,用-P
就一次回车。- 它在
/home/student
下生成.ssh
目录,.ssh
下有id_rsa
和id_rsa.pub
。(这样就生成了公钥/私钥对)
- 把内网服务器(SchoolServer)下的
id_rsa.pub
复制到公网服务器(MyServer)下
执行命令:scp .ssh/id_rsa.pub wenyuanblog@111.13.100.91:/home/wenyuanblog/id_rsa.pub
由于还没有免密码登录的,所以要输入密码。 - 公网服务器(MyServer)加入内网服务器(SchoolServer)的公钥
登录公网服务器(MyServer),切换到 wenyuanblog 账户(下面的步骤不要用 root)。
如果公网服务器的 wenyuanblog 目录下没有.ssh
和authorized_keys
文件则创建这个文件夹和文件。
把从内网服务器复制的id_rsa.pub
添加到.ssh/authorzied_keys
文件里,即执行命令:
cat id_rsa.pub >> .ssh/authorized_keys
cat .ssh/authorized_keys
chmod 644 .ssh/authorized_keys
- authorized_keys 的权限要是 644 。
- 内网服务器(SchoolServer)登录公网服务器(MyServer)试试
回到内网服务器(SchoolServer),用之前的普通用户 student,执行:ssh wenyuanblog@111.13.100.91
第一次登录要 yes,现在内网机器就可以免密码登录公网机器了。
Step2. 登录内网服务器,启动 autossh,维持 ssh 连接
上面提过,使用 ssh 建立的反向连接很不稳定,长时间不使用连接就会自动释放,这个时候就需要使用 autossh。
一般新机器需要安装 autossh:
yum install autossh
(CentOS)
apt-get install autossh
(Ubuntu)
切换到 wenyuanblog 用户(非 root 用户),在其 home
目录下创建一个 autossh.sh
脚本,开辟连接到公网服务器的隧道。
autossh.sh
脚本内写入要开辟的端口:
#!/bin/bash
/usr/bin/autossh -NR 0.0.0.0:20022:127.0.0.1:22 -i ~/.ssh/id_rsa wenyuanblog@公网IP -p 22 >> ~/log/ssh_nat.log 2>&1 &
/usr/bin/autossh -NR 0.0.0.0:28000:127.0.0.1:8000 -i ~/.ssh/id_rsa wenyuanblog@公网IP -p 22 >> ~/log/ssh_nat.log 2>&1 &
这两行就分别代替了上面二和三中「3. 内网服务器操作」里的内容。
运行脚本:
chmod +x autossh.sh
sh autossh.sh
使用 ps -ef|grep autossh
和 ps -ef|grep ssh
查看当前运行中的 autossh 任务进程。
其余步骤不变,完成。