Nginx正向代理与反向代理

正向代理与反向代理的区别,以及用Nginx配置实现代理服务。

一、正向代理与反向代理

1. 正向代理

正向代理其实相当于请求的中继,比如说,如果某个网站国内无法访问,也就是被墙了,我可以选择两种方式:
一个是配置代理服务器,第二种就是 VPN。

其实两种技术原理差不太多,如果说我自己访问不到这个网站,而这时可以通过一台可以访问到这个网站的服务器,也就是代理服务器,来进行访问,这台代理服务器,分析我们请求的信息,然后去对应的要去的网站上将内容取回来发给我,这样我就能读到想要访问的网站上的内容了,通过一下图片,可以很清晰的看出其原理:
forward_proxy.png

2. 反向代理

反向代理比正向代理更加透明,客户端并不知道访问的是代理服务器,当客户端请求一个网址的时候,会经过反向代理服务器,而这台反向代理服务器,会根据客户端的请求,将请求转发到内网服务器中,内网服务器处理请求并返回结果到反向代理服务器上,通过反向代理服务器,将结果最终返回到客户端,详情如图:
reverse_proxy.png

简单来说:
正向代理代理的是客户端(如通过代理访问谷歌),而反向代理代理的是服务器(如 Nginx 代理 PHP 服务器)。

二、通过SSH反向代理实现内网穿透

1. 背景

我用学校实验室的一台服务器在跑数据,但是这台服务器没有公网 ip,只有学校内网 ip,故我只能到实验室登录。但有时候,需要在宿舍或者家里远程连接这台服务器。

于是,我就用到了反向代理。前提是我有一台公网 ip 的服务器(例如,阿里的学生机,或者 vultr 的 VPS 都可以)。

首先,准备好这两台服务器:

  • 学校实验室服务器(SchoolServer)
    • IP:192.168.10.50
    • ssh端口:22
    • 用户:student
    • 密码:helloworld
  • 我的外网服务器(MyServer)

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)

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_rsaid_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 目录下没有 .sshauthorized_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 autosshps -ef|grep ssh 查看当前运行中的 autossh 任务进程。

其余步骤不变,完成。


博文对你有帮助吗?如果有的话,想不想送我一本书呢?
  目录