Abstract
我在实验室部署开发环境的时候,为了图省事选择了TeamViewer作为远程控制的解决方案。随着我一通操作(前后添加了4台并且频繁使用),我成功被TV标记为了商业用户,每个session限时5min并且严重限制连接频率。唉,TV吃相越来越难看了,我只能去官网提交了申诉,不知道何时才能解封。但是作为一个穷的哭出声的(伪)geek,咋能不自己想想解决办法呢?
查了一堆资料和结合自己现有的资源,打算利用FRP+SS+XRDP/VNC来解决这个问题:在任意一个拥有公网访问的地方,通过RDP/VNC协议来访问内网里的一台机器。
Update 2020/04/05 新增了bbr优化相关
Update 2019/12/12 新增了关于ss加密算法的建议。todo: bbr优化
Update 2019/12/11 新增了关于shadowsocks-libev的描述
Update 2019/12/08 修正了关于proxifier代理配置的描述
Update 2019/08/20 经过了半个月的申诉,teamviewer终于解封了我的账户,现在我可以正常使用了。
Part 0 准备工作
内网穿透的基本思路
内网电脑装上ss-server(sss)和frp-client(frpc),自己的电脑装ss-client(ssc),服务器端装frp-server(frps)。
ssc会在本地(localhost/127.0.0.1)启动一个Socks5 Listener,监听本地的1088端口,即127.0.0.1:1088,并且将监听到的数据转发到服务器的1919端口,即a.b.c.d:1919。运行在服务器上的frps会将接受到的指定端口的数据通过7000端口转发回内网机器,内网机器上的frpc也通过7000端口接收到frps发来的数据之后,再转发给sss的8888端口。sss会监听8888端口,再转发数据到达目的地。这样就完成了整个内网穿透的过程,以VNC为例,即:
VNC viewer发起访问114.5.1.4的请求 -> 127.0.0.1:1088 (自己电脑,ssc监听) -> a.b.c.d:1919 (服务器,frps监听) -> a.b.c.d:7000 (服务器,frps) -> a.b.c.d:7000 (内网电脑,frpc) -> 127.0.0.1:8888 (内网电脑,sss监听) -> 127.0.0.1:5091 (内网电脑,VNC server)
硬件要求
- 一台运行在内网中,可以连接到公网的电脑。这是你需要在外网远程控制的电脑。
- 一台你自己的电脑。这是用来控制内网电脑的电脑。
你需要额外拥有:
- 一台有公网ip的服务器,并且保证内网电脑和你的电脑都可以访问这台服务器。我的服务器正好在村里,延迟比较低。
操作系统/软件要求
实际上对以上三台电脑的操作系统并没有什么硬性的要求,不同的操作系统和桌面环境下都会有对应的解决方案,请自行搜索,思路是不变的。本文中,我使用了:
- 内网电脑:Xubuntu 18.04 LTS,内网ip:114.5.1.4
- 自己的电脑:macOS Majove 10.14.6
- 服务器:Ubuntu 18.04 LTS,公网ip:a.b.c.d
Xubuntu和Ubuntu的区别是,前者的桌面环环境是xfce4,后者是gnome 3。这两者之间的区别有坑,mac系统在一些情况下也有坑,后面会说。
自己电脑
需要ss客户端,这里直接安装SSX-NG。你也可以使用homebrew安装(并且两个ss可以共存),但是需要使用配置文件配置,请自行搜索。
此外,你还需要proxifier来配置代理。谷歌可得可用序列号,如有能力请支持正版。
服务器
更新
1 | $ sudo apt update && sudo apt upgrade |
此外,下载最新版本的frp,并解压到~/frp。
内网机器
更新,安装软件
如果你在使用树莓派等嵌入式设备作为内网电脑(这样你使用这个梯子的时候就可以访问内网中的别的机器的了),请不要安装
shadowsocks
,而安装shadowsocks-libev
作为替代。将下面的命令中的shadowsocks
改为shadowsocks-libev
即可。前者使用pytyhon实现,效率较低,后者使用c实现,专为嵌入式设备设计,效率较高。
1 | $ sudo apt update && sudo apt upgrade |
- openssh-server: SSH服务器,ubuntu桌面版只带SSH客户端,不带服务器端,无法远程使用SSH连接。
- tightvncserver: VNC服务器
- shadowsocks: 代理。它的作用可比爬梯子大多了2333333
下载最新版本的frp,并解压到~/frp。
Part 1 内网穿透
本章节介绍了如何利用上面安装的一堆软件来实现内网穿透。
内网机器
SSH server配置
SSH这里用来确保vnc服务的可用性,或者在一些不需要图形界面的情况下,ssh就可以完成对应的任务。
使用如下命令查看ssh服务是否启动:
1 | $ ps -ax | grep ssh |
你应该可以看到ssh-agent(客户端)和ssh-server(服务端),如果没有,使用如下命令启动:
1 | $ sudo service ssh start |
sss配置
设置sss的端口、密码和加密方式等
新建/etc/shadowsocks.json,配置sss。输入以下内容,设置代理监听的端口,密码和加密方法。
1 | { |
如果你使用的是树莓派或别的不支持aes加速的设备,推荐将加密算法替换为chacha20-ietf-poly1305。树莓派的cpu内并没有aes加速指令集,这是由于aes加速是armv8的一个可选指令集,得加钱从arm那买license。更扯的是树莓派用了一个arm64的cpu,却还用的是32位的系统。
如果你使用shadowsocks-libev,请使用如下命令编辑sss的配置文件:
sudo vim /etc/shadowsocks-libev/config.json
配置sss系统服务
新建sss服务的配置文件
1 | $ sudo vim /etc/systemd/system/shadowsocks-server.service |
复制粘贴(ExecStart后面的-c之前的路径是sss的地址,可能会有细微不同,可以通过whereis ssserver命令来确定;-c之后的路径是上面的sss自己的配置文件地址)
1 | [Unit] |
如果你使用shadowsocks-libev,你可以忽略新建配置文件这步
保存之后,启动并开机启动sss
1 | $ sudo systemctl start shadowsocks-server |
如果你使用shadowsocks-libev,请将
shadowsocks-server
替换为shadowsocks-libev
.
frpc配置
编辑~/frp/frpc.ini,配置frpc通过7000端口与frps通信,并且将服务器端1919端口转发来的包转发到本地8888端口。
1 | [common] |
编辑frpc服务配置文件
1 | $ sudo vim ~/frp/systemd/frpc.service |
修改ExecStart和ExecReload后的路径
1 | [Unit] |
设置frpc开机自启动并启动frpc
1 | $ sudo mv ~/frp/systemd/frpc.service /etc/systemd/system/frpc.service |
BBR优化
Google的BBR算法可以用来优化TCP连接,并且4.9+的Linux内核已经合并了该功能。最新版的Raspbian内核版本已经是4.9+,所以我们直接讨论该种情况。如果你的内核版本低于4.9,请自行查阅相关资料。
先切换到root,然后写入系统配置并保存
1 | $ su root |
测试内核是否已经开启bbr
1 | $ sysctl net.ipv4.tcp_available_congestion_control |
输出类似于
1 | output: net.ipv4.tcp_available_congestion_control = bbr cubic reno |
查看bbr是否已经启动
1 | $ lsmod | grep bbr |
如果看到一下信息,说明已经成功启动
1 | tcp_bbr 20480 14 |
Credit to: https://www.moerats.com/archives/297/
服务器设置
编辑~/frp/frps.ini,配置frps通过7000端口与frpc通信。
1 | [common] |
编辑frps服务配置文件
1 | $ sudo vim ~/frp/systemd/frps.service |
修改ExecStart后的路径
1 | [Unit] |
设置frpc开机自启动并启动frps
1 | $ sudo mv ~/frp/systemd/frps.service /etc/systemd/system/frps.service |
自己电脑设置
首先打开SS,添加代理信息。
Address: a.b.c.d, port: 1919 (为frpc[ss]中的remote port)
Encryption: sss中的method,即aes-256-cfb
Password: sss中的password,即wdnmd_team_viewer
接着将ss切换到手动模式(Manual Mode)。然后点Prefences - Advanced - Local Socks5 Listen Port,记下该端口号(本文中使用1088,你可以自己设置)。这样,ss就配置好了,我们只需要使用proxifier配置指定的APP/网站的流量走socks5代理即可。
首先在proxifier中添加这个代理。打开Proxifier - Proxies - Add,Address为127.0.0.1,port为1088,Protocol为SOCKS VERSION 5,然后点OK。
接着设置我们访问该内网ip时,使用这个代理。Proxifier - Rules - Add,Target Hosts填写内网ip 114.5.1.4,Action为Proxy SOCKS5 127.0.0.1:1088,点ok。
现在,打开terminal,你应该可以使用ssh登录你的内网电脑了。
Part 2 VNC/XRDP配置
坑
我觉得需要先讲一下这里的坑。
VNC对gnome 3存在兼容性问题,而现在的ubuntu默认安装的就是gnome 3,这使得我花费了大量时间来试图解决这个问题。虽然网上有些教程讲的是可以的,但是我并没有成功,反而发现了一些文章在说VNC和gnome 3不兼容,这也是为什么我换了Xubuntu。如果你正在使用ubuntu,don’t panic,因为你可以再新装一个xfce4桌面环境,可以参考这篇文章。
XRDP的坑在于,你使用apt install安装的版本是0.9.5,而对于mac客户端来说,XRDP存在一个字库丢失的问题,这个问题在0.9.8版本中才被修复。所以如果你在使用mac作为客户端,可以考虑参考官方教程在内网电脑上自行编译安装XRDP。
VNC
VNC这玩意搞过树莓派的应该都知道,Raspbian自带vnc支持的,早期连个显示器太费劲,大家都用vnc远程控制它。
在终端输入
1 | $ vncserver |
来配置VNC服务器。密码长度必须介于6-8个字符,超过8个字符会被截断。
1 | You will require a password to access your desktops. |
vncserver会询问你是否要创建一个view-only password,选择n,不然只能view,不能控制。然后会启动一个编号为1的vnc session(your_hostname:1)。有的情况下会出现报错(和桌面有关),1启动不了,会启动一个编号为2的vnc session,这里需要注意。
1 | Would you like to enter a view-only password (y/n)? n |
然后杀死现在的VNC session,备份,修改配置文件。
1 | $ vncserver -kill :1 |
在vim中输入以下内容(请谷歌vim用法,不然会变成随机字符生成器233333)
1 | #!/bin/sh |
保存文件,重新启动vncserver
1 | $ sudo chmod +x ~/.vnc/xstartup |
会看到如下输出
1 | New 'X' desktop is your_hostname:1 |
和上面提到的一样,如果启动:1失败,可以改成:2,启动一个编号为2的session。
XRDP
RDP协议走的就是大chou名ming鼎zhao鼎zhu的3389端口,它在windows上是自带支持的,但是在ubuntu上,你需要安装XRDP。你可以直接参考这篇教程。此外,如果你在使用mac,请参阅上面的#坑#章节。
直接使用如下命令安装:
1 | $ sudo apt install xrdp |
创建~/.xsession 和 ~/.xsessionrc
1 | $ echo "xfce4-session" > ~/.xsession |
需要禁用light-locker,不然会有如下报错:
1 | ** (light-locker:2769): ERROR **: 08:09:59.625: Environment variable |
使用如下命令来解决这个问题:
1 | $ sudo cp /usr/bin/light-locker /usr/bin/light-locker.orig |
最后,搜索安装微软官方的RDP客户端Microsoft Remote Desktop,输入你的内网ip就可以访问。
Part 3 性能测试
实际使用中,VNC和XRDP高画质下并不会卡顿。
Part 4 讨论
本方案 vs TeamViewer
有一个显而易见的缺点是,本方案并不是同步和直接控制现有的屏幕,而是新建了一个桌面进行操作。这可能会给一些复杂任务带来困难。不过这也可能也会成为本方案的优点,因为你log out退出到登录界面之后,依然可以通过VNC连接到内网计算机,并且因为是新建了一个桌面,你的真实电脑桌面依然是锁屏状态,这样就保证了你电脑的安全性。
另一个显而易见的缺点是,opengl没办法起来,可能需要virtual opengl之类的库。这对一些需要用到显卡的东西非常不友好。最简单的例子就是,没办法开安卓虚拟机。不过可以通过配置远程ADB解决或者用Scrcpy来进行手机投屏。这实在不行,还能把apk传回来本地再自己装嘛。
好处大概就是不需要再受teamviewer的气了吧233333,没花啥钱搭出来的玩意,要什么自行车。
VPN vs SS
和VPN相比,ss轻量级了很多,并且配置起来也更方便。VPN的主要问题在于握手次数过多,使得大量的时间浪费在了这个上面。不过VPN可以走UDP,但是运营商会有QoS的限制,可能会丢包。
其他玩法
如果内网机器在家中,那稍微配置一下就可以连回家里的局域网了。如果内网机器是一个国内节点,并且国内节点在你家,那你就有了有真实地址的国内ip了(非机房ip),诶嘿嘿嘿。
你也可以把你的网站布置在内网服务器中,通过frp转发出去,这样可以很好的隐藏自己的服务,具体玩法可以参考frp的手册。