为Ubuntu主机配置Privado VPN
如何为Ubuntu系统的电脑配置Privado VPN,支持域名白名单访问,并支持作为代理服务器
本文是和ChatGPT、Gemini对话后操作的总结,我也不一定完全懂全部配置,我也找到一篇教程,各位也可以去看
起因和基础信息
起初需要是因为N8N中把每日新闻推送到Github,进而Netlify时,国内不能稳定连接Github,于是我就索性把Privado VPN也配置上,有梯子就肯定不会有这个问题。可是配置好之后,N8N中获取国内新闻的RSS订阅就用不了了,可能是因为链接在国内,所以又去配置域名白名单。
我的需求有这些:
- 梯子能用,且可以白名单访问
- ZeroTier不影响使用
- IPV6不影响访问(我需要IPV6公网)
电脑基础信息: -No LSB modules are available.
- Distributor ID: Ubuntu
- Description: Ubuntu 24.04.3 LTS
- Release: 24.04
- Codename: noble
加装Privado VPN
这里总共有两个方法,我在1月先使用的OpenVPN方法,第一次成功连接后第二次就一定会失败,我分析是被“墙”拦截了,所以更推荐使用WireGuard方法,不容易被“墙”拦截。首先贴出官方配置教程1,我使用的是命令行环境,因为是SSH连接到电脑的。
首先需要去自己账号的管理页面获取WireGurad的配置文件(往下划就看到了),然后转移到Ubuntu主机上(下面假设转移到的路径是/wiregurad_config/<config_name> 。至于这里的<config_name>能不能改,我也不是很清楚,我怀疑它的名字是有意义的,所以我没有更改。
然后是安装WireGuard,执行下面命令
1
sudo apt update && sudo apt install wireguard
随后将前面获取的配置文件移动到WireGuard的配置文件夹下,也就是执行这个命令
1
sudo mv /wireguard_config/<config_name> /etc/wireguard/<config_name>
接下来可以试试配置文件能不能正常加载了,不过要注意,前面的<config_name>是带有.conf后缀的,而下面的这个不需要后缀名,也就是不带.conf
1
sudo wg-quick up <config_name> # 关闭把up改down
见到类似如下输出就是没问题的
1
2
3
4
5
6
7
8
9
[#] wg setconf privado.ams-034 /dev/fd/63
[#] ip -4 address add 100.65.38.223/32 dev privado.ams-034
[#] ip link set mtu 1420 up dev privado.ams-034
[#] wg set privado.ams-034 fwmark 51820
[#] ip -4 rule add not fwmark 51820 table 51820
[#] ip -4 rule add table main suppress_prefixlength 0
[#] ip -4 route add 0.0.0.0/0 dev privado.ams-034 table 51820
[#] sysctl -q net.ipv4.conf.all.src_valid_mark=1
[#] nft -f /dev/fd/63
然后我们就可以配置它开机自启动了,这个也很简单,WireGuard自带Services,直接开启对应Services就可以了,如下,注意这里<config_name>也不带.conf
1
sudo systemctl enable wg-quick@<config_name>.service
这样它就会开机自启动了,我们可以检查一下我们的外部地址,执行下面的命令
1
curl ipinfo.io
比如我连接的是阿姆斯特丹,返回就如下
1
2
3
4
5
6
7
8
9
10
11
{
"ip": "91.148.245.68",
"city": "Heerhugowaard",
"region": "North Holland",
"country": "NL",
"loc": "52.6714,4.8486",
"org": "AS34343 BIP Backbone ASN",
"postal": "1701",
"timezone": "Europe/Amsterdam",
"readme": "https://ipinfo.io/missingauth"
}
配置白名单访问
现在我们就完成了WireGuard的安装,下面就是为其添加一个白名单过滤。原理上,WireGuard支持对静态IP进行配置,但是不支持域名和动态IP,对于我们的需求来说,这很显然不够,你不可能期望Google,ChatGPT,Github这些大网站都是静态IP,所以我们采取的方法是,自建DNS服务维护这些网站的IP,WireGuard根据这些IP控制是不是经过VPN。所以这里最主要的是,我们需要搭建一个本地DNS服务来维护这些IP。
这里ChatGPT给我的建议是
🥇 smartdns + ipset + nftables + WireGuard(白名单模式)
其中smartdns是本地的DNS服务,不过最终我感觉ipset好像没有用。第一步,我们来安装它们,大家可以先不安装ipset,看看后面需不需要再说。
1
2
sudo apt update
sudo apt install smartdns nftables ipset
然后是为Privado创建一个IP表,最初ChatGPT给的命令是
1
sudo ipset create vpnset hash:ip timeout 3600
但是我用了之后后面报错,nft不识别vpnset这个组,不过没关系,我们还可以创建nft自己的组并做一下配置,不过配置前我们需要知道Privado对应的fwmark参数(这个参数就是一个标记,最好是对应上),执行这个命令查询
1
sudo wg show
我得到的输出是这样的
1
2
3
4
5
6
7
8
9
10
11
interface: privado.ams-034
public key: Ah(中间码掉)=
private key: (hidden)
listening port: 58794
fwmark: 0xca6c # 就是这个
peer: Kg(中间码掉)=
endpoint: (我码掉了)
allowed ips: 0.0.0.0/0
latest handshake: 2 minutes, 20 seconds ago
transfer: 98.25 KiB received, 133.30 KiB sent
要的就是fwmark参数,然后我们进行配置,执行下面命令2
1
2
3
4
5
6
7
8
9
10
sudo nft add table inet vpn
sudo nft add set inet vpn vpnset '{ type ipv4_addr; flags interval,timeout; timeout 1h; }'
# 给非白名单打标(走直连)
sudo nft add chain inet vpn output '{ type route hook output priority mangle; policy accept; }'
sudo nft add rule inet vpn output ip daddr != @vpnset meta mark set 0xca6c counter
# 保证转发流量(Docker/ZeroTier)也一样
sudo nft add chain inet vpn prerouting '{ type filter hook prerouting priority mangle; policy accept; }'
sudo nft add rule inet vpn prerouting ip daddr != @vpnset meta mark set 0xca6c counter
注意命令里的0xca6c各位替换为自己获取的值就可以了
不过这里我们对nft的配置还没有完成,经过我实践发现,如果就这样到后面连DNS都会直接坏掉,因为DNS解析的流量也会被打标签过VPN,所以我们还得把DNS解析的流量分出来,这部分必须直连,而且应该在全部的最前面,命令如下2
1
2
3
4
5
6
sudo nft add set inet vpn dns_upstream '{ type ipv4_addr; flags interval; }' # 创建子set存放
sudo nft add element inet vpn dns_upstream { 119.29.29.29, 223.5.5.5, 8.8.8.8, 1.1.1.1 } # 这些都是DNS解析地址,可以改成你自己的,不过要对得上机器用的DNS,不然也不对,写哪些后面smartdns就也写哪些
# 直接放行
sudo nft insert rule inet vpn output ip daddr @dns_upstream counter accept
sudo nft insert rule inet vpn prerouting ip daddr @dns_upstream counter accept
验证可以使用这个命令列出电脑全部的nftable规则2
1
sudo nft list ruleset
输出里看到这样就是正常没问题的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
table inet vpn {
set vpnset {
type ipv4_addr
flags interval,timeout
timeout 1h
}
set dns_upstream {
type ipv4_addr
flags interval
elements = { 1.1.1.1, 8.8.8.8,
119.29.29.29, 223.5.5.5 }
}
chain output {
type route hook output priority mangle; policy accept;
ip daddr @dns_upstream counter packets 0 bytes 0 accept
ip daddr != @vpnset meta mark set 0x0000ca6c counter packets 0 bytes 0
}
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ip daddr @dns_upstream counter packets 0 bytes 0 accept
ip daddr != @vpnset meta mark set 0x0000ca6c counter packets 0 bytes 0
}
}
smartdns自动写入
不过组创建完了,smartdns还没有配置,所以没有任何域名写入,接下来我们需要配置smartdns,这样就会自动写入IP地址了。配置也很简单,首先进入配置文件按照官网3指示添加设置
1
sudo vi /etc/smartdns/smartdns.conf
比如要github.com通过梯子,就在最后面加上
1
nftset /github.com/#4:inet#vpn#vpnset
其他域名也同理更改前面就可以了。
不过不要着急,为了后面取代系统DNS,我们还需要修改一个地方,找到文件前面(或者新加),不论如何保证有这一行
1
2
bind :53 # IPV4
bind [::]:53 # IPV6
这个的意思是程序启动后自动挂载到电脑的53端口(也就是DNS解析端口,不过目前这个端口还有系统的DNS解析,所以启动也是无用的。配置smartdns开机启动使用的命令是
1
sudo systemctl enable smartdns
不过现在启动smartdns无用,因为正如我前面所说,53端口还占用着的,只有系统DNS下了启动才是成功的
总的来说到现在为止,如果域名符合我们的规则,就会被打上标记,后面我们利用这些标记,无标记的通过WireGuard就好了
nftable持久化
不过现在我们先专注于nft,我们的全部配置都依赖于这样的表,而nftable有一个很麻烦的点,每一次重启你的配置就没有了,我每一次重启后,前面配置的vpn表就消失了,所以我们需要将其配置持久化,每一次都能自动读取。为此,我们需要修改nft的配置,命令如下2
1
sudo sh -c "nft list table inet vpn > /etc/nftables.conf"
这个命令的意思是把查询的结果写入/etc/nftables.conf 文件(覆盖当前内容),查询的命令就是我们前面测试添加成功没有的命令。然后我们还需要修改一点东西,因为这个配置文件默认是有信息的,文件开头通常应该有#!/usr/sbin/nft -f和flush ruleset,我也不知道它们什么意思,但是尽量少改,我还是又进入文件把这两行补在了文件的开头,结果就是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/sbin/nft -f
flush ruleset
table inet vpn {
set vpnset {
type ipv4_addr
flags interval,timeout
timeout 1h
}
set dns_upstream {
type ipv4_addr
flags interval
elements = { 1.1.1.1, 8.8.8.8, 119.29.29.29, 223.5.5.5 }
}
chain output {
type route hook output priority mangle; policy accept;
ip daddr @dns_upstream counter packets 0 bytes 0 accept
ip daddr != @vpnset meta mark set 0x0000ca6c counter packets 0 bytes 0
}
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ip daddr @dns_upstream counter packets 0 bytes 0 accept
ip daddr != @vpnset meta mark set 0x0000ca6c counter packets 0 bytes 0
}
}
然后配置一下开机自动读取这个文件就可以了,只需要这个命令
1
sudo systemctl enable --now nftables
就可以自动读取了。
smartdns取代系统DNS
现在让我们回到正题,用smartdns替换系统DNS,首先使用这个命令关闭系统DNS
1
sudo systemctl disable --now systemd-resolved
然后启动smartdns
1
sudo systemctl enable --now smartdns
这时建议先检查一下我们前面的配置有没有问题,可以先查询table,然后ping一个网站,然后再看table有没有写入。为此可以像我一样把两个测外部IP的网站配置成一个通过,一个不通过(这里贴几个网站),然后测外部IP就很容易看到有没有问题
1
2
3
4
curl 4.ipw.cn
curl ipinfo.io
curl ipin.io
curl ipconfig.me
如果有问题,可以试一下这个命令,临时解决一下,看看是不是源地址的问题,如果是,那就是网卡看返回和发送网卡不一样直接丢弃了
1
sudo iptables -t nat -A POSTROUTING -o <出口的物理网卡> -s <WireGuard地址> -j MASQUERADE
撤销用这个命令
1
sudo iptables -t nat -D POSTROUTING -o <出口的物理网卡> -s <WireGuard地址> -j MASQUERADE
两个命令里的<WireGuard地址>可以这样得到
1
ip -4 -o addr show dev privado.ams-034
得到的是
1
29: privado.ams-034 inet 100.65.38.223/32 scope global privado.ams-034\ valid_lft forever preferred_lft forever
如果能解决问题,持久化就往/etc/wireguard/<config_name>.conf 的[Interface]里添加
1
2
PostUp = iptables -t nat -A POSTROUTING -o enp4s0 -s <WG_IP>/32 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o enp4s0 -s <WG_IP>/32 -j MASQUERADE
Docker
在前面配置完成之后,我的电脑就已经能用了,最后的小问题是Docker的DNS坏了,原因未知,但是解决方案也很简单,就是去Docker的配置文件手动设置本机的DNS就可以了,就是去/etc/docker/daemon.json 修改文件,加上这段
1
"dns":["192.168.101.92"]
其中192.168.101.92是主机的LAN IP,可以使用这个命令查看
1
ip -4 -o addr show dev <出口物理网卡,我是enp4s0>
得到
1
3: enp4s0 inet 192.168.101.92/24 brd 192.168.101.255 scope global dynamic noprefixroute enp4s0\ valid_lft 84212sec preferred_lft 84212sec
输出第一个就是主机LAN IP,加上重启Docker就好了
1
sudo systemctl restart docker
长期使用维护
现在我们的配置已经完成了,最后我总结一下长期使用时的维护方法,其实主要是添加删除域名之类的
首先,更改域名直接修改/etc/smartdns/smartdns.conf 在后面添加域名
1
nftset /youtube.com/#4:inet#vpn#vpnset
然后重启smartdns就可以了
1
sudo systemctl restart smartdns
配置网络代理
在给Ubuntu配置网络代理后,我们也可以进一步把它当做代理服务器,下面我们就来配置,这里我没有使用Tinyproxy,因为我最开始配置后使用codex结果一直出问题,感觉它代理HTTPS流量有一点问题,一直连接都报错意外的EOF,AI说可能是COONECT有问题,所以最后选的是Squid
1
sudo apt install squid
然后进入/etc/squid/squid.conf 编辑配置文件(因为这个文件自动生成的例子,太多了,还很长,我直接把它重命名/etc/squid/squid.example.conf 了,后面的配置都是重新写的)。
首先,写http_port,把它设置为你希望它运行的端口,比如我就改成http_port 3128。然后加上允许访问的源IP地址,比如我的电脑的LAN IP是192.168.101.92/24,ZeroTier的IP是172.22.165.129/16,那我就这样写
1
2
3
4
5
6
acl localnet src 192.168.101.0/24 # 0表示这一位随意匹配
acl zerotier src 172.22.0.0/16
http_access allow localnet
http_access allow zerotier
http_access deny all
然后为了支持HTTPS流量,还需要放行CONNECT到443端口的流量,还是配置文件
1
2
3
acl SSL_ports port 443
acl CONNECT method CONNECT
http_access allow CONNECT SSL_ports
含义是放行HTTPS到443端口的流量
然后启动Squid
1
sudo systemctl enable --now squid
需要注意的是,尽管Codex的流量是HTTPS流量,代理配置的环境变量仍然必须写HTTP,也就是这样
1
2
HTTP_PROXY=http://192.168.101.92:3128
HTTPS_PROXY=http://192.168.101.92:3128
因为Squid是HTTP代理,不能处理HTTPS流量,做HTTPS代理是直接转发的流量包,但是对接它本身必须使用HTTP
Privado官方的配置教程:Linux Wireguard® Manual Setup - PrivadoVPN ↩︎
官网IPSet配置方法:IPSet和NFTSet - SmartDNS ↩︎