两台 server 没有公网 ip ( server 连接的路由器倒是有教育网的 ip ),boss 想在公网访问,想利用手上一台 vps 做内网穿透,比如把 server 的 1:10000 端口映射到 vps 的 10001:20000 上。vps和server的系统均为ubuntu。
尝试的做法是 vps 上搭个 o server,两台 server 连接之后用 iptables
的 DNAT 映射把 vps 指定端口转发给 10.8.0.x,但是遇到了两个问题:
iptables
没法非对称映射端口段
(要么 8000→20000 单个端口映射
要么 1000:2000→1000:2000 对称映射
没法 1:10000→10001:20000 非对称的端口段映射)
server 连接 o 之后,server 的全部流量都走那个 o 的虚拟网卡了…
又因为从 vps 传到 server 的请求是从公网来的,源 ip 都是公网 ip,没法单独区分返回的数据包只让它走虚拟网卡…
如果o配置上 no-route
,那么除了来自虚拟子网、源 ip 是 10.8.0.x 的请求能通过虚拟网卡回去,
一般来自公网的请求都会尝试走物理网卡回去,也就是实际上收不到返回值…
经过v友们的推荐,尝试使用FRP解决:
frps
,使用systemd实现自启动;frpc
,将vps的10001:20000转发到server1的1:10000端口,将vps的20001:30000转发到server2的1:10000端口。如果有想要自建的朋友,建议阅读完全文再动手安装。
下载FRP0.29.0 Release 并解压
wget https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz
tar -zxf frp_0.29.0_linux_amd64.tar.gz
mv frp_0.29.0_linux_amd64 frp
进入frp文件夹,编辑frps.ini
cd frp
vim frps.ini
配置文件为:
[common]
bind_port = 2221
max_pool_count = 5
log_level = error
绑定的端口2221需要在vps防火墙设置中放行UDP和TCP流量。
然后运行frps,进行测试:
./frps -c frps.ini
和frpc测试连通(见下文)后,可以设置为service,实现自启动:
先修改service文件:
vim frp/systemd/frps.service
修改ExecStart
的路径为实际frp解压路径,并且注意如果是以root用户执行,默认的User=nobody
会出现错误,需要改为User=root
。并注意以service执行的程序受到IO限制,无法打开太多端口,添加LimitNOFILE=65535
以放宽限制。
[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=/root/frp/frps -c /root/frp/frps.ini
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
之后添加服务并设置为自启动
cp systemd/frps.service /lib/systemd/system/
systemctl daemon-reload
systemctl enable frps
systemctl start frps
这时可以使用systemctl status frps
查看进程的PID,之后使用cat /proc/1238/limits
确认Max open files
项是否放宽为65535。
下载FRP0.29.0 Release 并解压
wget https://github.com/fatedier/frp/releases/download/v0.29.0/frp_0.29.0_linux_amd64.tar.gz
tar -zxf frp_0.29.0_linux_amd64.tar.gz
mv frp_0.29.0_linux_amd64 frp
进入frp文件夹,编辑frpc.ini
cd frp
vim frpc.ini
配置文件为:
[common]
server_addr = vps的ip
server_port = 2221
pool_count=2
[range:server1_tcp]
type = tcp
local_ip = 内网server1的ip,可以是本机127.0.0.1,也可以是内网里其他server的ip如192.168.1.101
local_port = 1-10000
remote_port = 10001-20000
[range:server1_udp]
type = udp
local_ip = 内网server1的ip,可以是本机127.0.0.1,也可以是内网里其他server的ip如192.168.1.101
local_port = 1-10000
remote_port = 10001-20000
[range:server2_tcp]
type = tcp
local_ip = 内网server2的ip,可以是本机127.0.0.1,也可以是内网里其他server的ip如192.168.1.101
local_port = 1-10000
remote_port = 20001-30000
[range:server2_udp]
type = udp
local_ip = 内网server2的ip,可以是本机127.0.0.1,也可以是内网里其他server的ip如192.168.1.101
local_port = 1-10000
remote_port = 20001-30000
先启动vps上的frps
,再启动server上的frpc
:
./frpc -c frpc.ini
这时就可以通过vps ip:port+10000访问server1的ip:port,vps ip:port+20000访问server2的ip:port了。
因为实际使用frpc
是在server的docker容器内,systemd自启动有些问题,所以目前frpc
使用screen
工具来后台运行:
screen -S frpcScreen
./frpc -c frpc.ini
然后按Ctrl+A Ctrl+D退出当前screen。
终止正在前台运行的frpc
以及frps
需要使用Ctrl+C组合键关闭,如果使用Ctrl+Z或者Break或者关闭ssh客户端的方式终止,则已经打开的端口无法解除占用,只能重启系统。
测试tcp连通性可以在内网server上运行python3 -m http.server 8888
来启动一个http服务,然后访问http://vps ip:18888/测试是否能够打开网页。
测试udp连通性可以使用netcat
这个工具包。
安装netcat
:
apt install netcat-openbsd
内网server运行udp监听:
nc -ul 8883
vps上连接netcat,注意这里是连接vps本机的18883端口,frp给转发到内网server的8883端口上:
nc -u 127.0.0.1 18883
之后类似于聊天工具,在任意一方输入字符并回车,另一方可以看到对方的输入,证明udp连接成功。
作者声称没有对于大范围的ip段映射进行优化,但实际测试映射20000个端口是可实现的。目前还需要继续观察是否存在性能和稳定性问题。