一些约定

在后文中我会把内网中的服务器称作部署端,将中转服务器称作代理端

后文中涉及的ssh命令如果要改端口应加上 -p<端口号>

准备工作

我们需要准备一个有公网ip并开放80端口的服务器(对配置几乎没有要求,在内网搭服务器的肯定不是什么每秒几十万条访问的大项目),如果你的域名没有备案最好选国外的服务器。此时鸡肋的LinuxONE就派上用场了,LinuxONE原本应为S360X架构很难直接部署什么东西,但这个项目一共只用两个第三方项目:Nginx,autossh(选)。而我的LinuxONE因为被封号的缘故所以我选了辰讯云的1核1G香港VPS,理由只有一个8元每月的价格。

理论存在实践开始

一.开启代理端的反向隧道功能

这细分下来有2步,开启公钥访问和开启反向隧道

开启公钥访问

绝大多数的服务器都是设置密码的,想要通过密码来开启反向隧道对于自动化来说并不方便所以要开启公钥访问。

我们首先在部署端生成一份公钥:

ssh-keygen -t rsa -b 4096 -C "[email protected]"

此处邮箱换成你自己的。

然后我们尝试将公钥拷贝到代理端(注意,在部署端执行):

ssh-copy-id [email protected]

此处替换成代理端的用户名和地址,运行这条命令时会让你输入密码,输的是代理端的密码。

运行完后我们可以在部署端尝试使用ssh命令连接代理端确认是否配置成功:

ssh [email protected]

如果这时还提示你输入密码的话说明开启失败,我们到代理端进行排查。

检查~/.ssh/authorized_keys,看你的公钥是否添加到其中。如果没有可能是网络相关问题,重新拷贝试试;如果已经添加成功那就是没有开启公钥连接的功能。我们编辑/etc/ssh/sshd_config文件,将PubkeyAuthentication选项开启(改成yes)将AuthorizedKeysFile前的注释去除(如果有)。

做完以上几步回到部署端再次尝试连接应该就可以免密登录了。

开启反向隧道功能

运行命令:

sed -i "s/#GatewayPorts no/GatewayPorts yes/g" /etc/ssh/sshd_config
systemctl restart ssh

这样就打开了反向隧道功能。

二.使用ssh尝试进行隧道连接

部署端开启需要代理的http服务,接着运行:

ssh -qngfNTR <端口1>:user@localhost:<端口2> 0.0.0.0 -o ServerAliveInterval=10

端口1是部署端http服务的端口,端口2是要连接的代理端的目标端口。

如果你不需要使用https证书,那你可以直接将端口2设为80然后跳过后面的内容直接看第四部分。如果你需要配置https证书那请不要选80端口。

我们到代理端执行curl指令:

curl localhost:<端口2>

如果得到的正确的应答那就说明配置正确。

三.使用Nginx配置反向代理(代理端)

在代理端使用Nginx有很多好处:

  • 将http是证书放在代理端可以简化证书系统
  • Nginx会对静态资源做缓存
  • and so on

我们将Nginx的配置文件配置为(这里只给出配置模板,安装和配置的教程网上有很多,Nginx值得一学):

server {
    listen 80;
    server_name <你的域名>;#多个域名以空格分开

    location / {
        proxy_pass http://localhost:<端口2>;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

此时我们将DNS改到代理端的ip,尝试访问应该就能够成功访问到部署端的网站了

四.持久化(部署端)

如果我们是以ssh方式进入到部署端的话,一旦断开连接配置好的隧道就会断开。即使是直接配置的,如果部署端重启隧道也会断开。所以我们要使用autossh(第三方软件)并配置crontab开机启动。

autossh可以在ssh断开后自动尝试重连,使用方式和ssh无异属于ssh套壳。

我们使用命令:

croetab -e

添加@reboot ssh -qngfNTR <端口1>:user@localhost:<端口2> 0.0.0.0 -o ServerAliveInterval=10

这样就会在服务器每次开机后自动运行。