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)
      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. 配置公钥和私钥,实现免密码登录(为后面的脚本做准备)
    (1)登录内网服务器(SchoolServer)
      切换到普通用户student,不建议用root
      执行命令:
      ssh-keygen -t rsa -P ''
      直接ssh-keygen然后三次回车就可以了。
      -P表示密码,-P ‘’ 就表示空密码,也可以不用-P参数,这样就要三车回车,用-P就一次回车。
      它在/home/student下生成.ssh目录,.ssh下有id_rsa和id_rsa.pub。(这样就生成了公钥/私钥对)
    (2)把内网服务器(SchoolServer)下的id_rsa.pub复制到公网服务器(MyServer)下
      执行命令:
      scp .ssh/id_rsa.pub wenyuanblog@111.13.100.91:/home/wenyuanblog/id_rsa.pub
      由于还没有免密码登录的,所以要输入密码。
    (3)公网服务器(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。
    (4)内网服务器(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任务进程。

  其余步骤不变,完成。


  目录