旁路由搭建与容器环境整理

此文仅作技术探讨记录之用,特此声明。

更变日志

  1. 2025-06-13 新增:补全文章

前言

从RouterOS换到FortiGate已有一段时间,闲了手就痒,一方面觉得单点(设备)连接总是不尽如人意,另一方面,大家都有的功能,总不能没有,于是想把这块拼图补全,然后就有了这篇文章。

个人不是很喜欢用应用域名分流、核心处理域名解析、FakeIP、旁路网关、手动指定网关、单点嵌套虚拟专用网等途径来解决其他地区网络连通方面的问题。

故使用早已部署完成的PVE里的Alpine LXC + Docker Compose来分开部署实现网关转发、域名解析等任务,刚刚好合适。

将现网中其他地区的流量通过这个网关直接将流量转发到其他地区的落地,并使域名解析通过专门的容器独立处理。

以此实现仿真实三层策略转发结构,即使临时禁用策略路由、取消转发网关,也不会使得FakeIP、域名解析等核心特性影响到现网的流量收发。

得益于FortiGate/LXC/Docker技术的强大,使得配置过程过于简单,这里仅作简单介绍。

正文

关于其他地区流量如何转发

太长不看版:绕过LAN及CN的IP

我使用思维导图、FortiGate配置页、Docker和关键应用的配置来完成这个段落,不作过多赘述。

思维导图

FortiGate 策略路由配置 标黄为关键配置项

FortiGate 策略路由配置 CN流量直连 不经海外网关

FortiGate 策略路由配置 其他流量 转发海外网关

Docker Daemon Config 节选

此处固定Docker容器地址,防止误伤其他容器网络。

1
2
3
4
5
6
7
8
9
{
"default-address-pools": [
{
"base": "172.18.0.0/16",
"size": 24
}
]
}

Docker Compose 节选

标星字段自行按需替换所需内容。

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
29
30
31
32
33
34
#...
adghome:
container_name: adghome
restart: always
image: adguard/adguardhome:latest
volumes:
- ./adghome/:/opt/adguardhome/work
- ./adghome/:/opt/adguardhome/conf
- ./adghome/:/opt/adguardhome/load
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
environment:
- TZ=Asia/Shanghai
ports:
- 53:53/udp
- 8080:8080/tcp


*****:
image: *********/******:Alpha
container_name: *****
restart: always
volumes:
- ./*****/:/root/.config/******/
environment:
- TZ=Asia/Shanghai
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
network_mode: "host"
depends_on:
- adghome
#...

关键应用配置节选

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
29
30
31
32
33
34
35
36
37
38
39
40
ipv6: false
find-process-mode: off
unified-delay: true
tcp-concurrent: true
global-client-fingerprint: random
interface-name: "eth0"


dns:
enable: false


tun:
enable: true
stack: system
strict-route: true
gso: true
auto-route: true
auto-redirect: true
auto-detect-interface: true
route-exclude-address:
- 172.16.0.0/12


sniffer:
enable: true
parse-pure-ip: true
override-destination: true
sniff:
HTTP:
ports: [80, 8080-8880]
TLS:
ports: [443, 8443]
QUIC:
ports: [443, 8443]
skip-domain:
- Mijia Cloud


# 剩余部分未在此列出,根据需要及自身情况补全

关于DNS分流如何处理的问题

太长不看版:绕过CN域名

解决完其他地区三层连通性的问题了,那么就引申出(或者说剩下)DNS的问题,需要对其他地区的DNS解析作处理。

以下过程亦为Alpine LXC处理,仍然实现了一个LXC完成所有服务的理念:

上文Docker Compose配置提到,有使用一个叫做AdGuardHome的容器作为我的整个网络的DNS服务。

我将其他地区的域名使用全局配置走其他地区DNS解析,这部分流量一样走其他地区转发网关。

除其他地区外的域名解析剔除,使用某位大大持续更新的CN域名白名单配置(见文末引用部分),经过自制的定时脚本使用cron每天自动更新解析配置,(自认为)完美解决DNS分流问题。

DNS配置文件节选示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Updated at 2025-06-14 02:00:02
# 此为全局配置,上文提到,用于解析除CN外其他地区的域名
https://1.1.1.1/dns-query
#https://1.0.0.1/dns-query
https://8.8.8.8/dns-query
https://8.8.4.4/dns-query
# 此部分为本人自定义域名走其他地区的DNS解析
#[/engage.cloudflareclient.com/]https://1.0.0.1/dns-query
#[/docker.io/]https://1.0.0.1/dns-query
# End

# 此部分为本人自定义域名走CN的DNS解析
[/paypal.com/paypalobjects.com/]https://223.5.5.5/dns-query https://120.53.53.53/dns-query https://223.6.6.6/dns-q...
[/time.apple.com/ntp.aliyun.com/time1.cloud.tencent.com/ntp.ntsc.ac.cn/]https://223.5.5.5/dns-query https://223.6...
# End
# 后续为那位大大提供的CN域名白名单内容格式化后的白名单解析配置
[/0.zone/]https://223.5.5.5/dns-query https://120.53.53.53/dns-query https://223.6.6.6/dns-query https://1.12.12.1...

自制配置更新脚本

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
~ # crontab -l
# do daily/weekly/monthly maintenance
# min hour day month weekday command
*/15 * * * * run-parts /etc/periodic/15min
0 * * * * run-parts /etc/periodic/hourly
0 2 * * * run-parts /etc/periodic/daily
0 3 * * 6 run-parts /etc/periodic/weekly
0 5 1 * * run-parts /etc/periodic/monthly

~ # cat /etc/periodic/daily/update-dns-config
#!/bin/sh

# 定义工作目录和文件
WORK_DIR="/root/adghome"
CONFIG_FILE="$WORK_DIR/dns_config.txt"
TEMP_FILE="$WORK_DIR/dns_config.tmp"
HEADER_FILE="$WORK_DIR/dns_config.header"
#BACKUP_FILE="$WORK_DIR/dns_config.backup.$(date '+%Y%m%d%H%M%S')"
BACKUP_FILE="$WORK_DIR/dns_config.backup"
LOG_FILE="/var/log/adghome-update.log"

# 记录操作日志的函数
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"
echo "$1"
}

# 创建备份
if [ -f "$CONFIG_FILE" ]; then
cp "$CONFIG_FILE" "$BACKUP_FILE"
log_message "已创建原始配置文件备份: $BACKUP_FILE"
fi

# 创建临时文件来保存头部配置
cat > "$HEADER_FILE" << 'EOF'
https://1.1.1.1/dns-query
#https://1.0.0.1/dns-query
https://8.8.8.8/dns-query
https://8.8.4.4/dns-query
#[/engage.cloudflareclient.com/]https://1.0.0.1/dns-query
#[/docker.io/]https://1.0.0.1/dns-query

[/paypal.com/paypalobjects.com/]https://223.5.5.5/dns-query https://120.53.53.53/dns-query https://223.6.6.6/dns-query https://1.12.12.12/dns-query
[/time.apple.com/ntp.aliyun.com/time1.cloud.tencent.com/ntp.ntsc.ac.cn/]https://223.5.5.5/dns-query https://223.6.6.6/dns-query https://120.53.53.53/dns-query https://1.12.12.12/dns-query
EOF

# 获取并处理CN域名列表
log_message "开始获取CN域名列表..."
if curl -s --fail https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf > "$TEMP_FILE.raw"; then
# 下载成功,继续处理
cat "$TEMP_FILE.raw" | \
sed -n 's/server=\/\(.*\)\/114.114.114.114/[\/\1\/]https:\/\/223.5.5.5\/dns-query https:\/\/120.53.53.53\/dns-query https:\/\/223.6.6.6\/dns-query https:\/\/1.12.12.12\/dns-query/p' > "$TEMP_FILE"

# 检查处理后的文件是否为空或过小(可能表示处理失败)
MIN_SIZE=1000 # 最小文件大小(字节)
ACTUAL_SIZE=$(wc -c < "$TEMP_FILE")

if [ "$ACTUAL_SIZE" -lt "$MIN_SIZE" ]; then
log_message "警告: 处理后的域名列表过小 ($ACTUAL_SIZE 字节),可能表示处理失败。取消操作..."

# 如果有备份则还原
if [ -f "$BACKUP_FILE" ]; then
log_message "正在还原原始配置文件..."
cp "$BACKUP_FILE" "$CONFIG_FILE"
fi

# 清理临时文件
rm -f "$TEMP_FILE" "$TEMP_FILE.raw" "$HEADER_FILE"
exit 1
fi

# 组装最终配置文件
{
# 添加更新时间戳
echo "# Updated at $(date '+%Y-%m-%d %H:%M:%S')"
# 添加头部配置
cat "$HEADER_FILE"
# 添加处理后的域名列表
cat "$TEMP_FILE"
} > "$CONFIG_FILE"

log_message "DNS 配置文件已成功更新"

# 重启 AdGuard Home 容器
cd /root && docker-compose restart adghome

RESTART_STATUS=$?
if [ $RESTART_STATUS -eq 0 ]; then
log_message "AdGuard Home 已成功重启"
else
log_message "错误: AdGuard Home 重启失败,状态码 $RESTART_STATUS"
fi

else
# 下载失败
log_message "错误: 无法获取CN域名列表,取消操作..."

# 如果有备份则还原
if [ -f "$BACKUP_FILE" ]; then
log_message "正在还原原始配置文件..."
cp "$BACKUP_FILE" "$CONFIG_FILE"
fi
fi

# 清理临时文件
rm -f "$TEMP_FILE" "$TEMP_FILE.raw" "$HEADER_FILE"

# 保留备份供参考
log_message "操作完成。备份文件保留在: $BACKUP_FILE"

后记

时隔一年,又想换/加OPNsense了,初步计划是把FortiGate放在外层作连接ISP、拨号、上网、NAT、IPSec,OPNsense放在内层作内网路由流量处理。

再议再议……鸽鸽鸽鸽鸽

Ref


旁路由搭建与容器环境整理
https://blog.geolee.xyz/2024/08/28/make-global-traffic-turn-sub-gateway/
作者
丈育
发布于
2024年8月28日
许可协议