家庭搭建OPENCONNECT VPN(ubuntu 22.04)

家里运行了一些服务,希望在外面也可以方便的访问它们。

旧办法是通过路由器端口映射到内网端口,但这种方式已经很难满足我的场景,因为例如hadoop服务会开放很多web页面端口,实在难以逐一映射。

于是我选择了在家里自建VPN服务器,然后只把VPN服务的端口映射到路由器,这样只要在外面连接VPN即可像在家里一样任意访问内部网络了。

搭建Openconnect

openconnect是开源VPN项目,包含了服务端和客户端(PC/MAC/Android),是商业产品思科cisco anyconnect的开源版本。

为什么选择它呢?因为它能够从服务端自定义下发路由规则到客户端,这样就可以控制客户端哪些流量需要送往VPN隧道、哪些流量不需要经过VPN隧道,实现类似于同时兼顾访问家庭内网和公司内网的目的。

搭建方式参考官方手册:https://gitlab.com/openconnect/recipes,我以debian为例进行安装配置,非常方便:

这样就安装完成openconnect服务端了。

配置Ocserv

接下来配置VPN服务端,分为2大部分:

  • 自签一下SSL证书,因为这个VPN协议需要SSL加密。(自签没关系,只要客户端登录时选择信任证书即可)
  • 配置ocserv.conf配置文件,主要是定义VPN如何认证用户、VPN网段、还有更高级的路由表下发。
SSL证书

首先搞证书,按官方教程来即可:https://gitlab.com/openconnect/recipes/-/blob/master/ocserv-configuration-basic.md#certificate-management-self-signed

第一步:

第二步(原样敲入即可,信息都不重要):

第三步(原样敲入即可,信息都不重要):

第四步(生成CA证书):

第五步(用CA签VPN证书):

把VPN证书拷到ocserv配置目录下:

Ocserv.Conf

先修改登录方式,采用用户密码进行登录:

创建密码文件

创建用户

删除用户(如果需要的话),此处只是留下删除用户的命令,不是要求必须执行,否则刚刚创建的用户就被删除了

然后VPN监听端口有需要可以改一下:

然后就是VPN网段的配置了,我家里是192.168.1.x网段,我们要让VPN使用一个不同的网段,因为VPN server要给每个连接过来的VPN client分配一个VPN网段的IP,如果这个IP和192.168.1.x网段的某个IP冲突就有问题了,所以一定是不同网段的,同样道理也不能和客户端所在的局域网段冲突。

所以我配置了192.168.50.x的一个冷门网段,足够分配254个VPN client,为什么不是255个呢?因为VPN服务端会先占1个IP。

暂时我们配置这些,现在我们启动ocserv来介绍一下VPN是如何工作的。

分析Ocserv工作原理

大家自行在路由器映射VPN端口到公网,然后下载openconnect gui客户端(https://openconnect.github.io/openconnect-gui/),然后连接这样的地址:

https://公网IP:路由器映射端口

即可连接到家里内网的VPN服务端,输入任意正确的linux账号密码即可登录。

连接成功后,在客户端打开命令行查看路由表(我是windows电脑,使用route print命令),会发现2条本就存在的路由记录:

这是因为windows电脑也在家里,所以本身就被局域网下发了默认网关路由到192.168.2.1路由器、以及192.168.2.x网段的路由记录,这台电脑的自身IP是192.168.2.103。

但是连接VPN后,则多了2条VPN网段的记录:

又来了一条优先级更高(2)的默认网关路由,指向了192.168.50.1,也就是VPN server的IP地址,同时也多了一条192.168.50.x 这个VPN网段的路由记录,此时电脑上也出现了一张虚拟的网卡,其IP就是192.168.50.250,这是VPN server给分配的,由VPN client负责虚拟出本地网卡。

此时发往192.168.50.x网段的流量会直接从VPN网卡送出,发往其他IP的流量也会命中192.168.8.1的默认网关(同样是从VPN网卡送出),而不是电脑所在局域网原本下发的192.168.2.1的默认网关。

所以VPN网卡已经劫持了所有外出流量,经过VPN虚拟网卡封包为物理IP送往VPN server,再由VPN server拆包后得到真实IP地址,继续进行转发。

此时VPN server也多了一条该客户端的路由记录:

也就是192.168.50.250这个vpn client的流量全部送给vpns0虚拟网卡,也就是说回给该vpn client的包也需要经过vpn server的虚拟网卡封包送走。

vpn基本就是这个原理。

这点原理还不够

不要以为理解上面就万事大吉了,当VPN client请求baidu.com时,baidu的IP地址会命中默认网关发往192.168.50.1默认网关,经过封包送到VPN server的监听端口。

然后VPN server会把封包拆开,linux协议栈看到真实目标IP是baidu.com,那么显然该IP地址不是本机,需要forward给百度,此时需要linux的netfilters进行流量forward才能再次送给192.168.2.1家庭物理网关到达百度,这一步需要我们在服务端开启ipv4 forward特性:

sudo vim /etc/sysctl.conf

net.ipv4.ip_forward=1
net.ipv6.ip_forward=1

然后执行sysctl -p生效。

配置防火墙的IP Masquerading

请使用以下命令检查服务器的主网卡接口

例如,可以检查到网卡接口名字是eth0,则执行

这里命令-A表示添加到nat表的POSTROUTING链。这样就可以把VPN网络连接到Internet,并且把你的网络对外隐藏起来。这样Internet只能看到你的VPN服务器IP,但是不能看到你的VPN客户端IP,类似于你家中路由器隐藏起家庭网络。

现在可以检查一下NAT表的POSTROUTING链,可以看到目标是anywhere的源为anywhere的都执行MASQUERADE。

显示输出:

为了持久化iptables规则(默认重启后就没了),所以我们需要安装一下工具:

sudo apt install iptables-persistent

然后保存一次:

sudo netfilter-persistent save

最后

更高级的特性就是配置ocserv.conf的路由下发,下发一些路由规则到VPNclient ,这样可以控制哪些网段的流量不要发给VPN隧道,可以兼顾客户端本地局域网和家庭局域网两路一起访问的需求,但是这个要求客户端本地局域网段、VPN网段、家庭局域网段三者不能冲突。

大家可以试一下ocserv.conf中的route和no-route配置项,比如我希望VPN client不要让公司网段走VPN,那么就可以加一条这样的配置(假设公司网段是172.26.201.x):

no-route = 172.26.201.0/255.255.255.0

这样VPN client侧的虚拟网卡就会判断目标IP是这个网段的就不发往VPN server了,而是走本地其他路由规则寻址。

如果你家里的网络是路由器/旁路由FQ或者绿色dns的话,那么可以令vpn server的默认网关指向fq路由器,同时让vpn client使用你家里的绿色dns,这样就可以让vpn客户端透明fq了。

比如我家里旁路由上有绿色DNS,所以我可以令ocserv.conf下发它的IP地址作为客户端使用的DNS服务器地址(家里的192.168.2.201运行着绿色DNS,然后vpn client可以通过隧道访问到它):

在ocserv.conf中指定dns服务器地址,下发给vpn client:

dns = 192.168.2.201

这样vpn client就会请求192.168.2.201进行域名解析,得到无污染IP。

理解上述原理需要对路由表、netfilters有清晰认识,否则可能比较困难,希望对你有点帮助。

智能分流

https://github.com/don-johnny/anyconnect-routes

国内IP不进行代理,参考如下开源项目:

https://github.com/CNMan/ocserv-cn-no-route

遇到的问题

1. 对于 ubuntu 22.04 系统,目前(2023.09.01) 系统自带的 ocserv 1.1.3 会在启动之后崩溃,出现如下日志:

解决此问题的方法就是安装 ocserv 1.1.6以及以后的版本,可以从源代码编译安装。这里有个简单的解决方法,就是从 ubuntu 23.04 的安装源中下载已经编译好的安装包,直接进行安装,如下:

2. 对于腾讯云购买的海外 轻量应用服务器 需要在管理控制台配置防火墙规则,放开端口访问,否则无法进行正常的通讯访问。

参考链接


ubuntu 22.04 Warning: apt-key is deprecated

在尝试安装 nvidia-docker 的时候(ubuntu 22.04系统Docker和Nvidia-docker的安装、测试,及运行GUI应用),执行如下命令增加 nvidia 源:

系统发出如下警告:

经过分析,是脚本中的如下部分导致:

解决方法为修改为使用如下脚本:

完整修改后的脚本如下:

参考链接


Warning: apt-key is deprecated (SOLVED)

Ubuntu 22.04 搭建 Timemachine

  • 创建一个目录,作为 TimeMachine 保存数据的目录。

  • 安装 netatalk 服务和 avahi-daemon 服务。

  • 编辑 netatalk 的配置文件:

  • 在该文件原来的基础上,或新增以下配置:

  • 重启服务。

现在,你在 TimeMachine 上应该可以看到这个备份服务了,选择该备份服务就可以开始你的第一次备份了。

参考链接


ubuntu 22.04升级到cpp-12后flutter编译报错"找不到 -lstdc++"

在今天晚上 ubuntu 22.04 执行如下升级命令之后

再次执行 flutter 的构建命令,报错。

操作过程如下:

解决方法是手工安装依赖:

之后再执行构建命令。

参考链接


Build failed on linux #115909

联想T440在ubuntu 22.04系统上安装配置指纹

家里有一台旧的联想T440笔记本,某天来了兴致安装了ubuntu 22.04,默认情况下指纹识别是无法使用的。

查看硬件属于 Elan 指纹识别设备,Ubuntu 自带的 Libfprint 已经提供了支持。

安装前端工具

执行

将第一项,用空格勾选上,然后点“确定”。这样就授权指纹识别登录设备。

录入指纹

打开“设置---用户---指纹登录”,此时就可以打开了。点击“+”,录入第一个指纹吧

参考链接


联想小新Air2020锐龙版在Ubuntu下添加指纹识别

Flutter The Linux toolchain CMake build dependency (CMake 3.14 or higher is required. You are running version 3.10.2)

ubuntu 22.04 通过 snap 安装了 Flutter SDK(当前是Flutter 3.3.4),如果第三方的依赖了 CMake 3.10.2 更高的版本,会在编译的时候报错:

这个报错的原因是由于 snap 安装的 Flutter SDK 构建了一个沙箱环境,在这个环境中的 CMake3.10.2 版本,不管系统安装的是哪个版本的 CMake ,都是无效的。

要解决这个问题,或者等待 snapFlutter SDK 更新版本,或者参照 Linux install Flutter 的说明,手工安装并配置 Flutter SDK

可以参考如下代码:

参考链接


ubuntu 20.04升级到ubuntu 22.04报错“update-alternatives: 错误: /var/lib/dpkg/alternatives/mpi 损坏:次要链接与主链接 /usr/bin/mpicc 相同”

ubuntu 20.04 升级到 ubuntu 22.04 报错,报错内容如下:

解决方法:

ubuntu 20.04.4系统升级后全部应用图标都无法显示

ubuntu 20.04.4系统执行升级命令后全部应用图标都无法显示,系统变成如下图:

很多应用也无法打开了,点击之后无任何反应。

查看系统日志可以看到如下错误信息:

这个原因是由于 gdk-pixbuf 的改动导致的系统 BUG,只需要重新生成一下应用图标缓存即可。

执行如下命令:

参考链接

 

Flutter构建Linux应用

从3.0之后的版本,flutter已经正式支持构建Linux应用

条件

  • ubuntu 22.04
  • Android Studio Chipmunk |  2021.2.1
  • flutter sdk 3.x

方法

1. 打开Linux的平台支持

输入如下指令(如下命令可以使用flutter config查看,2.10以上的版本默认开启

可以使用flutter doctor查看情况。

安装编译依赖

2. 在旧项目中添加Linux平台支持

在项目地址输入如下指令

注意: 项目的名称必须是全小写,如果出现大小写则会报错

3. 构建Linux项目

4. 报错

出现这个问题

参考链接


Visual Studio Code调试Flutter报错“[CHROME]:need to run as root or suid”

在最新的Ubuntu 22.04系统上使用Visual Studio Code调试Flutter应用,Chrome使用Snap安装,通过指定 CHROME_EXECUTABLE=/snap/bin/chromium,在调试的时候,报错如下:

解决方法就是指定真实的Chrome安装路径,直接调用,而不是通过Snap的沙箱,解决沙箱无法调试的问题,如下:

参考链接


How to get the snap-based chromium to access a separately mounted filesystem?