Linux Containers/使用 VPN
本文介绍如何设置 Linux Container 以运行多种 VPN 协议,并带有 "kill switch" 以实现安全/私密的互联网使用。与使用完整的虚拟化(如 VirtualBox 或 QEMU)相比,这样做有明显优势,因为资源开销极小,并且可以在低功耗设备上运行。
容器设置
需要具备基本的 Linux Containers 设置和理解。本文假设读者已拥有一个基本的 LXC 设置并已运行。
OpenVPN 服务器模式
本子节详细介绍了在容器中提供 OpenVPN 服务所需的一些额外设置。希望使用提供的 OpenVPN 配置文件的用户无需阅读本子节。
宿主机设置
- 宿主机操作系统需要进行桥接以太网设置,以便容器运行。请参考 Linux Containers#宿主机网络配置。
- 需要启用数据包转发。请参考 Internet sharing#启用数据包转发。
- 虽然不是严格要求,但强烈建议配置防火墙。
OpenVPN 客户端模式
容器的配置需要修改为如下方式使用 OpenVPN:
/var/lib/lxc/playtime/config
... ## for OpenVPN lxc.mount.entry = /dev/net dev/net none bind,create=dir lxc.cgroup2.devices.allow = c 10:200 rwm
安装 openvpn。如果使用容器连接到第三方 VPN 提供商,只需将配置文件 foo.conf 放置在 /etc/openvpn/client/foo.conf 即可使用。要验证容器内的 OpenVPN 功能,请通过 openvpn-client@foo.service 启动 OpenVPN,一旦满意,请 启用 它以在启动时运行。
关于其他用例和设置,请参考 OpenVPN。
LimitNPROC... 开头的行。WireGuard
安装 wireguard-tools。用户将拥有第三方 VPN 服务提供的 WireGuard 配置文件,或者将设置 WireGuard 以在此角色中提供服务。如果使用容器连接到 VPN 提供商,只需将配置文件 foo.conf 放置在 /etc/wireguard/ 即可使用。
要验证容器内的 WireGuard 功能,请通过 wg-quick@foo.service 启动 WireGuard,一旦满意,请 启用 它以在启动时运行。
其他用例请参考 WireGuard。
容器内的防火墙配置
强烈建议在容器内运行一个配置正确的 防火墙。容器内防火墙的作用有两方面:
- 当 VPN 连接失败时,提供一个功能齐全的 "kill switch" 以维护隐私。
- 阻止不良内容。
本指南使用 ufw,它易于配置,但也可以使用其他示例。
ufw reset。功能性 "kill switch" 的策略是简单地设置一个拒绝策略,然后仅允许 VPN 设备上的特定服务和流量。这样,如果该设备的连接中断,就不会有本地回退。
编辑 /etc/default/ufw 并将 DEFAULT_OUTPUT_POLICY 从 "ACCEPT" 更改为 "DROP"
/etc/default/ufw
DEFAULT_OUTPUT_POLICY="DROP"
ufw 的命令需要以 root 用户执行;为了方便复制/粘贴到终端,已省略了按标准 wiki 约定为命令添加的 "#" 符号。设置拒绝策略
ufw default deny outgoing ufw default deny incoming
可选地添加任何预定义或自定义规则,这些规则定义在像 /etc/ufw/applications.d/custom 这样的文件中。
ufw allow ssh ufw allow from my-custom-app1 ufw allow from my-custom-app2
可选地进一步限制来自内部 LAN IP 地址范围甚至单个 IP 地址的访问。
ufw allow from 192.168.1.0/24
WireGuard 用户将创建一个与相应配置文件同名的接口,例如 /etc/wireguard/foo.conf,而 OpenVPN 用户可能使用 tun0。在下面的行中,用 WireGuard 配置的名称(省略 .conf 后缀)替换 'foo',或者如果使用 OpenVPN,则将 'foo' 替换为 tun0 或正在使用的任何设备。
ufw allow out on foo from any to any
最后,允许访问 VPN 提供商的 IP 地址以及预期的端口,并定义预期的协议。在下面的行中有三个变量需要考虑,定义如下:
- 'xxx' 代表 WireGuard peer/OpenVPN 服务器的 IP 地址。它将在 VPN 提供商提供的相应配置文件中定义。
- 'yyy' 代表通信将要进行的端口。同样,这将在配置文件中。
- 'zzz' 代表要使用的协议,可从 udp 或 tcp 中选择。请注意,WireGuard 只支持 udp,而 OpenVPN 支持两者。
ufw allow out to xxx port yyy proto zzz
启动 ufw 并 启用 ufw.service 以便在启动时运行。
使用 VPN 的域名作为配置文件的解决方法
如果希望在 VPN 配置文件中使用域名,可以在宿主机上运行一个 shell 脚本,预先将其解析为数值 IP,然后通过将其存储在写入容器内文件的变量中,将该 IP 地址传递给容器。该文件又可以被修改后的 VPN systemd 服务读取。这可以工作,但有点 hacky。
编辑两个变量以匹配您的用例中的容器名称和服务器名称。
在主机上
安装 bind(需要 dig)并创建以下脚本:
/path/to/container-start.sh
#!/bin/bash # this script should be called as root container=foo server=www.myvpnserver.org if ! systemctl is-active lxc@"$container" &>/dev/null; then ToUse=$(dig +short "$server") [[ -d /var/lib/lxc/$container/rootfs/etc/conf.d ]] || mkdir -p /var/lib/lxc/$container/rootfs/etc/conf.d echo "SERVER=$ToUse" > /var/lib/lxc/$container/rootfs/etc/conf.d/server.hack.txt systemctl start lxc@"$container" fi
从现在开始,调用该脚本来启动容器。它将使用 dig 获取域名对应的 IP 地址,然后启动容器。
从容器内部
修改启动 VPN 的 systemd 服务,并创建一个骨架配置文件,该文件可以被我们刚刚创建的脚本在 /var/lib/lxc/$container/rootfs/etc/conf.d/server.hack.txt 中定义的 IP 地址进行修改。
要创建骨架配置文件,只需将实时配置文件重命名为另一个名称即可。
例如,使用 WireGuard
mv /etc/wireguard/foo.conf /etc/wireguard/foo.skel
现在编辑 /etc/wireguard/foo.skel 将 Endpoint = www.myvpnserver.org 替换为 @@@,例如:
Endpoint = @@@:51820
或者,如果使用 OpenVPN
mv /etc/openvpn/client/foo.conf /etc/openvpn/client/foo.skel
编辑 /etc/openvpn/client/foo.skel 将 remote www.myvpnserver.org 替换为 @@@,例如:
remote @@@
最后,创建一个 drop-in 文件,用于读取 IP 地址并将其替换为实际配置文件中的地址。
使用 WireGuard 的示例
/etc/systemd/system/wg-quick@foo.service.d/override.conf
[Service] EnvironmentFile=-/etc/conf.d/server.hack.txt ExecStartPre=/bin/bash -ac "sed s/@@@/$SERVER/ </etc/wireguard/foo.skel >/etc/wireguard/foo.conf"
使用 OpenVPN 的示例
/etc/systemd/system/openvpn-client@foo.service.d/override.conf
[Service] EnvironmentFile=-/etc/conf.d/server.hack.txt ExecStartPre=/bin/bash -ac "sed s/@@@/$SERVER/ </etc/openvpn/client/foo.skel >/etc/openvpn/client/foo.conf"
测试服务
在运行的容器内(通过 ssh 连接或通过 lxc-attach -n playtime),通过将浏览器导出到宿主机的 X 服务器来测试设置。
$ DISPLAY=:0 firefox
xhost +SI:localuser:yourusername 进行设置,然后通过 ssh 连接到容器。结果应该是在宿主机的 X 服务器上出现一个标题为 "Mozilla Firefox (playtime)" 的 Firefox 窗口。可以使用许多网站来验证 IP 地址和 DNS 条目状态。其中一个网站是 ipleak dot net。
此时,应该只显示在配置文件中定义的相应 DNS 条目。