许多中小企业,或者家庭都有在局域网外远程访问内网服务的需求。
花生壳之类的应用可能是一个不错的解决方案,但毕竟要收费。
其实,只需要你有Linux系统的云主机和内网服务器,用ssh+nginx就可以很简单地搭建出这样的系统。
环境准备
准备以下设备:
- 一台代理服务器:可以是一台服务器/PC,或一台网关/路由器(要取得root权限),用于向云端反向代理本地服务。
- 一台业务服务器:用于搭建本地服务。
- 此服务器是非必需的:
- 如果内网已经有开放的业务(如OA,内网可访问的任何网页),可以不用此服务器
- 也可以把反向代理在与内网业务搭建在同一台服务器上。
- 此服务器是非必需的:
- 一台公网服务器:可以是云端的虚拟服务器,要有公网IP,用于向用户转发代理流量。
- 另一台PC:用于模拟用户,访问本地服务。
基础步骤
Step 1: 启动内网服务
如果内网已经有开放的业务(如OA,内网可访问的任何网页),可跳过此步骤。
在我的环境中,是用nginx搭了一个简单的http服务,开放在8011端口上。长这样:
Step 2:启动反向代理
在你要建立反向代理的内网服务器上,在浏览器中输入http://[local_ip]:[local_port],验证一下可以正常访问内网服务。
如果没问题,可通过ssh建立反向代理。命令如下:
1 | ssh -Nf -R [cloud_port]:[local_ip]:[local_port] [cloud_user]@[cloud_ip] |
各字段含义:
- cloud_port:云端服务器上,向公网提供服务的端口号
- local_ip/local_port:在企业内网提供服务的IP和端口,如果代理与内网业务部署在同一台服务器上,local_ip写为”localhost”
- cloud_user:云端服务器的用户名
- cloud_ip:云端服务器IP
配置示例:
我的环境如下:在代理服务器上,通过192.168.150.4:8011可访问内网服务,要将此服务代理到云端服务器的20081端口上。
在我的环境中,在代理服务器上输入的命令是:
1 | ssh -Nf -R 20081:192.168.150.4:8011 user_d@[cloud_ip] |
输入完成后,会需要你输入云服务器的密码,进行认证。
Step 3:在云服务器上开启代理转发
确保云端服务器的 SSH 配置文件 /etc/ssh/sshd_config 中允许反向隧道:
1 | GatewayPorts yes |
如果进行了修改,重启 SSH 服务:
1 | sudo systemctl restart sshd |
至此,代理就搭建完成了,通过公网IP就已经可以访问内网业务了。
TIPS:
- 如果还访问不了,可以检查一下服务器和云服务商的防火墙配置,看是否有阻断端口的策略
进阶步骤
内网业务就这么大咧咧地开放到公网上了,难免会有一些安全性上的顾虑。我们能不能在访问之前,对用户先进行一个认证,认证通过后,才开放访问具体的业务呢?(有点零信任ZTNA的意思了)
大致的方案是:在云服务器上,通过nginx做一个简单的认证系统,认证通过后,跳转到代理的业务端口(上例中的20081)上。
Step 4:基于nginx搭建简单的认证系统
安装 Apache 工具包(用于 htpasswd)
1 | sudo apt install apache2-utils |
创建密码文件,使用 htpasswd 创建一个密码文件。这里会要求输入user_a的密码
1 | sudo htpasswd -c /etc/nginx/.htpasswd user_a |
配置nginx
编辑 Nginx 配置文件,假设配置文件路径为 /etc/nginx/sites-enabled/auth.conf:
1 | server { |
这份配置文件中,在5000端口上开启了一个认证服务,认证通过后,请求会被转发到代理的端口上,即:http://localhost:20081/;
重启 Nginx
1 | sudo systemctl restart nginx |
通过以上配置后,浏览器通过http://[cloud_ip]:5000访问,会跳出认证对话框,输入正确的用户名密码后,才可正常访问业务。
Step 5: 限制业务只能通过本地回环口访问
经过step 4的配置,通过http://[cloud_ip]:5000访问,可以进行用户的认证。但是通过http://[cloud_ip]:20081仍然可以直接访问业务,这就存在一个很大的漏洞:访问20081端口可以绕过认证,直接访问业务。
办法当然也是有的,只要限制业务只能通过本地回环口访问,即只能通过nginx的跳转来访问。这样,用户直接访问http://[cloud_ip]:20081就会被拦截下来。
使用 iptables:允许来自回环地址的流量
1 | sudo iptables -A INPUT -p tcp -s 127.0.0.1 --dport 20081 -j ACCEPT |
拒绝其他所有访问
1 | sudo iptables -A INPUT -p tcp --dport 20081 -j DROP |
至此,系统就搭建完成了,访问http://[cloud_ip]:5000,认证通过后,跳转到代理至公网上的内网业务。
小结
基于ssh和nginx搭建了如下的系统:
- 使用ssh反向代理将内网业务代理至公网上
- 使用nginx的认证,实现对公网上开放的端口访问的安全检查。