最近心血来潮在家里的小服务器上装了个宝塔打算存放博客的静态资源来建个伪CDN(根据自己的猜想来做的,毕竟宽带的上传带宽比现在用的云服务器的带宽大很多),但是遇到了一个蛋疼的问题,现在的宽带供应商均不提供免费的公网IPV4了,不仅价格高还没有80和443端口。于是就突发奇想打算通过手头别的带宽大些的有公网ip的云服务器和本机组建局域网然后再做个端口映射实现公网访问的效果。
主要思路(方便区分后续用localhost代替家里的服务器,remote代表有公网ip的服务器):
- 通过wireguard将两台服务器置于同一虚拟局域网
- 规则转发
安装Wireguard
WireGuard不区分服务端和客户端,安装比较便捷,我自己用到的均为ubuntu系统,因此也只演示ubuntu的安装过程,其余平台的可以参见官网安装方法:WireGuard官网
apt update
apt install wireguard
#生成私钥
wg genkey > priv_key
#使用私钥生成公钥
wg pubkey < priv_key > pub_key
#查看私钥
cat priv_key
#查看公钥
cat pub_key
上述步骤是安装wireguard以及生成公钥私钥的命令,在remote和localhost都是用上述相同的命令,仅仅只是公钥和私钥的不同,你可以理解为ssh的秘钥链接,在连接服务是秘钥保留,公钥填入对方的配置文件中。
remote端配置
- 开启转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
执行sysctl -p
查看返回值。出现net.ipv4.ip_forward = 1
则说明转发开启成功。
- 生成配置文件
进入配置文件目录并创建虚拟接口配置文件。
cd /etc/wireguard
touch wg0.conf
其中wg0是虚拟网卡的名称。
配置文件内容如下:
#remote信息
[Interface]
# 让localhost连接的端口
ListenPort = 51820
# 虚拟局域网中的子网ip段
Address = 10.7.0.1/24
# 填上之前生成remote的私钥
PrivateKey = $PRIVATEKEY
# 下面两条是放行的iptables和MASQUERADE
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# localhost对接信息
[Peer]
# localhost的服务器公钥
PublicKey = $PUBLICKEY
#路由表
AllowedIPs = 10.7.0.2/32
上面的peer相当于允许连接的客户端的信息。自行将上面的eth0改成对应的拥有公网ip的网卡名。
localhost端设置
和remote端不同的是我仅仅是实现本机的端口转发,因此不需要设置开启转发。
- 生成配置文件
cd /etc/wireguard
touch wg0.conf
和remote端的步骤一样,主要区别在于配置文件的内容不同。
配置文件内容:
[Interface]
# 虚拟局域网中localhost的ip
Address = 10.7.0.2/24
# localhost端私钥
PrivateKey = CLIENTA_PRIVATE_KEY
[Peer]
# remote公钥
PublicKey = SERVER_PUBLICKEY
# remote IP:Port
Endpoint = 1.2.3.4:51820
# 通过 wireguard传输的 IP 列表
AllowedIPs = 10.7.0.0/24
# 强烈建议开启定期握手,不然远程服务器可能没办法主动连接上本地机器
PersistentKeepalive = 20
到此处为止,两端的基础安装和配置就已经完成。
接下来是启动服务。
wg-quick up wg0
# 或者
systemctl start wg-quick@wg0
#设置开机自启
systemctl enable wg-quick@wg0
#停止
wg-quick down wg0
两端启动服务后是可以通过局域网ip直接互通的。
因为我使用的云服务器是来自台湾的,因此延迟相对较高。
但是目前仅仅是实现了两台服务器的内网互通,并没有将外部流量通过wireguard转向localhost,因此还需要设置iptables规则以及路由规则。
规则设置
remote端
对于remote端来说,需要将公网端的流量转发到localhost端,并且将来自localhost的流量从公网网卡口流出。因此只需要设置DNAT和SNAT即可,DNAT中设置想要转发的端口,也可转发所有端口,但是得排除remote的服务端口。
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to 10.7.0.2:443
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 10.7.0.2:80
#将其中的$ip替换成自己的公网ip
iptables -t nat -A POSTROUTING -s 10.7.0.0/24 ! -d 10.7.0.0/24 -j SNAT --to $ip
此时已经是将80和443端口的流量转向了localhost的80和443端口。
localhost设置
由于之前设置的配置文件中限制了通过wireguard的ip段AllowedIPs = 10.7.0.0/24
因此无法将流量从wireguard返回remote端,因此将0.0.0.0/0
加入允许的段内。
这样虽然实现了所需效果,但是这里有一个新的问题,就是所有流量都走了remote的公网,相当于整机挂了proxy,这并不是我想要的。因此通过修改localhost的配置文件,修改route表。
加入以下字段:
Table = 1
PostUp = ip rule add from 10.7.0.2 table 1; ip rule add to 10.7.0.0/24 table 1
PostDown = ip rule del from 10.7.0.2 table 1; ip rule add to 10.7.0.0/24 table 1
这样就可以实现最初的目的。
到此为止全部结束。
为了方便最后将整合的最终版配置文件贴在这里
remote端:
#remote信息
[Interface]
# 让localhost连接的端口
ListenPort = 51820
# 虚拟局域网中的子网ip段
Address = 10.7.0.1/24
# 填上之前生成remote的私钥
PrivateKey = $PRIVATEKEY
# 下面两条是放行的iptables和MASQUERADE
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to 10.7.0.2:443
PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 10.7.0.2:80
#将其中的$ip替换成自己的公网ip
PostUp = iptables -t nat -A POSTROUTING -s 10.7.0.0/24 ! -d 10.7.0.0/24 -j SNAT --to $ip
PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to 10.7.0.2:443
PostDown= iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to 10.7.0.2:80
#将其中的$ip替换成自己的公网ip
PostDown= iptables -t nat -D POSTROUTING -s 10.7.0.0/24 ! -d 10.7.0.0/24 -j SNAT --to $ip
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# localhost对接信息
[Peer]
# localhost的服务器公钥
PublicKey = $PUBLICKEY
#路由表
AllowedIPs = 10.7.0.2/32
localhost端:
[Interface]
# 虚拟局域网中localhost的ip
Address = 10.7.0.2/24
# localhost端私钥
PrivateKey = CLIENTA_PRIVATE_KEY
Table = 1
PostUp = ip rule add from 10.7.0.2 table 1; ip rule add to 10.7.0.0/24 table 1
PostDown = ip rule del from 10.7.0.2 table 1; ip rule add to 10.7.0.0/24 table 1
[Peer]
# remote公钥
PublicKey = SERVER_PUBLICKEY
# remote IP:Port
Endpoint = 1.2.3.4:51820
# 通过 wireguard传输的 IP 列表
AllowedIPs = 10.7.0.0/24, 0.0.0.0/0
# 强烈建议开启定期握手,不然远程服务器可能没办法主动连接上本地机器
PersistentKeepalive = 20