多年未更新 blog,今天偶然打开,看到副标题 thoughs worth sharing 深感惭愧,最近繁忙的工作也告一段落,我想是时候该重新拿起博客了,毕竟分享是我改不掉的坏习惯。
背景
中国区 AWS 无论是在光环新网(北京)还是西云数据(宁夏)到海外的链路都十分糟糕,当我们需要在中国区 AWS 上搭建服务,尤其是需要使用到 Google/Github 的依赖时会十分的痛苦,此时就需要一个透明网关,当满足条件时走代理,否则走 AWS 的默认出口。
其中海外机器的条件比较苛刻,如非向电信申请专门的白名单线路,我们在海外的代理服务器很有可能随时被墙,所以本文选择的方案有几个关键需求:
- 给定一组域名,比如 proxy1.mydomain.com / proxy2.mydomain.com / … 通过 DDNS 或者人肉的方式使得可以自动更新代理服务器。
- 透明翻墙网关的软件需要有 failover 的特性,即代理失效时可以自动进行转移,或者有负载均衡使得所有的 endpoints 均为有效代理。
- 为了可以使用廉价的代理订阅服务(假设不是强安全需求),软件需要支持 Shadowsocks/V2Ray 等多种协议。
- UDP 也要能完美代理,最愉悦的方式自然是走 tun。
本文意在提供一个开箱即用的解决方案,即复制粘贴即可使用,对其中细节不会深入解释,具体可自行了解。
网络拓扑
配置步骤
根据需求描述,我们这里使用 Clash,注意原作者的版本和我们这里使用的版本并不一样,原作者的 tun 部分实现并未开源,我们暂不考虑非开源方案,这里选用 comzyh 的修改版 [2], 神奇的是,有一个非常漂亮的 one-click 的脚本可以协助我们完成整个过程。
首先我们使用 Ubuntu Server 20.04 LTS (HVM) 这个 AMI (ami-04effa29f4d91541f),笔者尝试过 Amazon Linux 2 AMI,Ubuntu Server 18.04 LTS (HVM),均出现一些莫名其妙的问题,应该是 AWS 对这俩镜像在网络部分有过魔改导致的,并且 Amazon Linux 2 的 systemd 的版本很神奇,没法直接使用下面这个脚本,系统的关系并不是很大,这里直接选择一个能用的,即 Ubuntu 20.04 这个镜像。
准备配置文件
启好 EC2 以后,连接,新建 /srv/clash 文件夹,新建配置文件 /srv/clash/config.yaml,这里给出一个参考配置,有细力度需求可参考 Clash 的相关文档。
mode: Rule
log-level: info
dns:
enable: true
ipv6: false
enhanced-mode: redir-host
listen: 0.0.0.0:53
nameserver:
- 1.2.4.8
- 114.114.114.114
- 223.5.5.5
# - 内网服务 DNS
fallback:
- tls://1.0.0.1:853
- tls://dns.google:853
proxies:
- name: "ss1"
type: ss
server: "server1.yourproxyserver.com"
port: "1080"
cipher: aes-256-gcm
password: "yourpassword"
udp: true
- name: "ss2"
type: ss
server: "server2.yourproxyserver.com"
port: "1080"
cipher: aes-256-gcm
password: "yourpassword"
udp: true
proxy-groups:
- name: "Proxy"
type: select
proxies: ["ss1", "ss2"]
tun:
enable: true
device-url: dev://clash0
stack: system
rules:
- DOMAIN-SUFFIX,local,DIRECT
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,17.0.0.0/8,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT
# Final
- GEOIP,CN,DIRECT
- FINAL,Proxy
并且下载 IP 地理位置数据库[4] 到 /srv/clash 下
部署 Clash
注意由于我们的目的是将 Clash 作为透明网关的服务使用, 由于 Clash 自带有 DNS 服务, 所以我们可能要关闭掉系统原有的占用 53 端口的 DNS 服务, 具体系统具体分析, 这里不再赘述.
找个地方如 /tmp 下,依次执行
git clone https://github.com/Kr328/clash-tun-for-linux
cd clash-tun-for-linux && chmod +x *
./install.sh build # 由于墙的原因,建议本地编译好上传到服务器或者直接下作者 prebuilt 的版本[3],改名为 clash 放在该目录下
sudo ./install install
sudo systemctl daemon-reload && sudo systemctl enable clash-tun && sudo systemctl start clash-tun
systemd 会在启动 clash 之前自动执行路由表的配置,默认内网流量不过 tun,大致上长这样 (我这里执行 ip rule list
的结果)
0: from all lookup local
32758: from all uidrange 65534-65535 goto 32766
32759: from all to 172.31.255.253/30 goto 32767
32760: from all to 127.0.0.0/8 goto 32766
32761: from all to 10.0.0.0/8 goto 32766
32762: from all to 192.168.0.0/16 goto 32766
32763: from all to 224.0.0.0/4 goto 32766
32764: from all to 172.16.0.0/12 goto 32766
32765: from all lookup 354
32766: from all lookup main
32767: from all lookup default
此时,Clash 的部署就完成了。接下来我们要考虑按照设计好的网络拓扑在 AWS 进行配置,将其作为一个 NAT 网关。
AWS 配置
本文考虑到受众用户不同,所以采用在 AWS 的 WebUI 下进行操作,读者可使用 aws-cli 进行配置或将整套结构使用 Cloudformation 进行部署。
创建子网
配置网络接口
路由表及防火墙配置
首先我们打开 NAT 实例上的转发
sudo iptables -t nat -A POSTROUTING -j MASQUERADE
保存防火墙配置并且每次重启时应用,首先创建 /etc/network/if-pre-up.d/iptables,并记得给可执行权限
#!/bin/bash
iptables-restore < /etc/iptables.rules
为了能让其在网络 Ready 以后运行,创建 systemd 的 daemon 配置, 新建文件 /etc/systemd/system/iptables-rules.service 写入以下内容
[Unit]
Description = Apply iptables rules
[Service]
Type=oneshot
ExecStart=/etc/network/if-pre-up.d/iptables
[Install]
WantedBy=network-pre.target
然后让 systemd 的配置生效
sudo systemctl daemon-reload
sudo systemctl enable iptables-rules
sudo systemctl start iptables-rules
然后便是网卡配置
首先要抱怨一下 Ubuntu 的 netplan 真是个大坑, 新加接口以后如果配置从 DHCP 来,则会默认添加 default 路由,而且 Ubuntu 20.04 的 netplan 版本过老不支持 use-routes: false 选项来屏蔽这个行为,所以只能 workaround 这个事情了
首先我们添加一个接口配置, 新建文件 /etc/netplan/60-nat.yaml
network:
ethernets:
ens6:
dhcp4: true
dhcp4-overrides:
use-routes: false
dhcp6: false
match:
macaddress: 02:45:b0:69:f4:8c
set-name: ens6
version: 2
其中 ens6 是之前创建的网络接口 (eni-XXXXX) 对应在 NAT Instance 上的网卡名称,如果你是第一次附加网络接口,一般为 ens6,如果有多个附加则具体情况具体分析。
为了解决会自动增加 default 路由的问题,笔者这里采用了一个非常 dirty 的方案,即将下列内内容写到 /etc/networkd-dispatcher/routable.d/ 里[6],并给予可执行权限
#!/bin/sh
# Only remove the default route on the second interface, e.g. eth1
[ "$IFACE" != ens6 ] && exit 0
# delete the default route for this interface
ip route del default dev ens6
至此所有的配置均以结束。
参考
- https://docs.aws.amazon.com/zh_cn/vpc/latest/userguide/VPC_NAT_Instance.html
- https://github.com/comzyh/clash
- https://github.com/comzyh/clash/releases/download/20200510/clash-linux-amd64
- https://github.com/Dreamacro/maxmind-geoip/releases/latest/download/Country.mmdb
- https://github.com/Kr328/clash-tun-for-linux
- https://unix.stackexchange.com/questions/517995/prevent-netplan-from-creating-default-routes-to-0-0-0-0-0
丑陋
LikeLike
宕总!
LikeLike
👏👏👏
LikeLike
大神好久不见啊
LikeLike
好欸
LikeLiked by 1 person