Featured image of post 简单易用的Linux研发网络全面加速方案

简单易用的Linux研发网络全面加速方案

你是否遇到过下载个代码要半天,更新个软件要半天,拉取个国外镜像要半天,且有时还失败的情景。这真是悲伤的故事,国内开发者经常要面临各种网络困境,严重影响开发的效率和热情,本文教你一个简易易用、一劳永逸的加速办法。快跟我来吧~

主要问题

  • 我曾经不止一次去学习如何配置docker镜像代理,并且搜集各种镜像源。
  • 我曾经不止一次去反复设置HTTP_PROXY/HTTPS_PROXY等,并且有时又忘记改回去。
  • 我曾经不止一次去找如何让wget等可以走代理,并且发现其它软件还得继续找。

现在我知道了,我即使学会了docker镜像代理如何配置,等换到containerd时,又要各种搜索和测试。更别说有一些镜像仓库国内就没有代理,你怎么办?我即使知道了wget怎么走代理,知道了git怎么走代理,我也不可能知道所有网络程序如何设置。那么,怎么办呢?

注:本文主要面向基于Linux开发的程序员们,其它平台开发者,或也能从中寻找到灵感。

新式透明代理Dae

首先,它居然叫Dae(大鹅!!)为什么叫大鹅呢,我也不知道,挺有趣,中西结合。话说你可能已经接触过一些支持透明代理的软件,本文介绍Dae是一款2023年才发布的算比较新的软件,它的实现也比较特别,基于当前很火的技术eBPF,理论性能也是相当强悍的。我对它的简介当然不是去抄几句README,而是我对它的粗浅理解和评价。

  • 不逊于其它代透明代理的性能,官方说得很厉害。
  • 基于劫持所有DNS请求,可以嗅探/代理任何软件的流量,这个确实厉害。
  • 支持旁路由模式,你可以暂时忘记OpenWRT,这个嘛,只能说你厉害。

它的工作原理你可以在这里找到。我们也可以通过后面如何配置一节,大体了解它的工作方式。

PS:因为基于eBPF的技术实现的,有一些上下文信息等,可以借助eBPF工具如bpftool查看到其程序以及map中的信息,这也是挺有意思的事情。

安装

我是在Ubuntu这个大众发行版上测试的,安装它只需要一行命令(参考这里)。

1
sudo sh -c "$(wget -qO- https://github.com/daeuniverse/dae-installer/raw/main/installer.sh)" @ install

但如你所见。执行这一步需要github下载,往往我们就出问题了,如果你本地凑巧有一个proxy。可以这样:

1
2
export ALL_PROXY=http://<proxy-ip>:<proxy-port>  
sudo -E sh -c "$(wget -qO- https://github.com/daeuniverse/dae-installer/raw/main/installer.sh)" @ install`

我从GPT学到了sudo -E参数,我似乎离不开AI了:) 当然你也可以用上面链接中的备用方案。 特别要注意的是,因为其采用eBPF方案,你的Linux内核版本不能过低(>=5.8)。安装完后,我们可以以系统服务来启动它:

1
2
3
4
5
# 启动 dae
sudo systemctl start dae

# 开机自动启动 dae
sudo systemctl enable dae

但不要着急,你要先搞定配置。

配置

默认情况下其配置是/usr/local/etc/dae目录下的config.dae文件。配置你搞不清的话使用上将会遇到各种奇怪的问题,你可以见我的配置,我尽力给出了比较详细的注释。

  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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
global {
    tproxy_port: 12345
    tproxy_port_protect: true
    so_mark_from_dae: 1

    # 程序的日志等级: error, warn, info, debug, trace.
    log_level: trace

    disable_waiting_network: false

    # 代理局域网流量(旁路由时开启), 我们这里为本地加速,先不开启
    #lan_interface: eth0

    # 代理本地,开启。可指定网络设备或者写auto
    wan_interface: auto

    auto_config_kernel_parameter: true
    auto_config_firewall_rule: false

    ##### Node connectivity check.

    # Host of URL should have both IPv4 and IPv6 if you have double stack in local.
    # First is URL, others are IP addresses if given.
    # Considering traffic consumption, it is recommended to choose a site with anycast IP and less response.
    tcp_check_url: 'http://cp.cloudflare.com,1.1.1.1,2606:4700:4700::1111'
    tcp_check_http_method: HEAD

    udp_check_dns: 'dns.google.com:53,8.8.8.8,2001:4860:4860::8888'

    # 网络连通性(节点)检查的间隔
    check_interval: 60s
    # 当有超过这个数值的延迟变化时(更低),触发主动切换节点
    check_tolerance: 100ms

    # 这个模式比较重要,但描述文字过长,一般也不需要修改
    dial_mode: domain

    allow_insecure: false
    sniffing_timeout: 200ms
    tls_implementation: tls
    utls_imitate: chrome_auto
}

# 订阅
subscription {
    # 写上你的订阅地址,格式为==> 订阅名: '订阅地址'。官方示例不写个模版格式,害得我去查源码:P
    plane: 'https://xxxxxx?sub=1'
}

# See https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/dns.md for full examples.
dns {
    ipversion_prefer: 4
    upstream {
        # 用于解析的地址,国内一个国外一个,官方给的是域名,我这里直接换成IP了
        alidns: 'udp://223.5.5.5:53'
        googledns: 'tcp+udp://8.8.8.8:53'
    }
    routing {
        request {
            # 属于广告的一些解析,全拒绝解析
            qname(geosite:category-ads) -> reject
            qname(geosite:category-ads-all) -> reject
            # ipv6也拒绝
            qtype(aaaa) -> reject

            # 默认使用alidns DNS解析(有可能会解出被污染的DNS,需要下面response来处理)
            fallback: alidns
        }

        # 对于解析到的DNS地址,再额外处理一下再返回 
        response {
            # 如果是googledns返回的,直接接收
            upstream(googledns) -> accept

            # 私有IP(表示被污染了),并且不属于cn范围的,再给googledns解读一下
            ip(geoip:private) && !qname(geosite:cn) -> googledns

            fallback: accept
        }
    }
}

# 出口的节点(组)定义
group {
    # 定义了一个叫proxy的组,可随便取名
    proxy {
        # 香港有时在某些会被禁用,人工加些延迟一般情况下掉过它
        filter: name(keyword: '香港')[add_latency: 300ms]

        # 新加坡有时是个好选择
        filter: name(keyword: '新加坡')[add_latency: -100ms]

        filter: name(keyword: '美国') 
        filter: name(keyword: '英国')
        filter: name(keyword: '日本')

        # 选择节点的策略。见下面注释
        policy: min_avg10
        # Other policies:
        #   random         - Randomly select a node from the group for every connection.
        #   fixed(0)       - Select the first node from the group for every connection.
        #   min            - Select the node with min last latency from the group for every connection.
        #   min_moving_avg - Select the node with min moving average of latencies from the group for every connection.
    }

    media {
        filter: name(keyword: '香港')
        policy: min_avg10
    }
    sg {
        filter: name(keyword: '新加坡')
        policy: min_avg10
    }
    usa {
        filter: name(keyword: '美国')
        policy: min_avg10
    }
}


# 完整示例见 https://github.com/daeuniverse/dae/blob/main/docs/en/configuration/routing.md
# 这下面定义了一些如何代理的规则
routing {
    // 一些进程的请求,直接转发(注意direct还是会经过dae程序,如果不想经过dae则使用must_direct)
    pname(NetworkManager) -> direct
    pname(systemd-networkd) -> direct
    pname(chronyd) -> direct

    # 目的地址是某些IP/IP段的,直接转发
    dip(224.0.0.0/3, 'ff00::/8') -> direct

    # 私有IP,直接转发
    dip(geoip:private) -> direct

    # udp在443端口,一般是HTTP3(QUIC)协议,这里禁用
    l4proto(udp) && dport(443) -> block

    # 国内IP,直接转发
    dip(geoip:cn) -> direct
    domain(geosite:cn) -> direct

    # 对广告说byebye
    domain(geosite:category-ads) -> block
    domain(geosite:category-ads-all) -> block

    # DNS地址,要不要走proxy你自己决定
    dip(8.8.8.8, 8.8.4.4) -> proxy
    dip(223.5.5.5, 223.6.6.6) -> direct

    ### OpenAI, 我们让它走SG组,即新加坡出口
    domain(geosite:openai) -> sg
    domain(suffix: openai.com) -> sg

    ### 流媒体等,走media组,香港挺适合
    domain(geosite:netflix) -> media

    ### Proxy一些开发网站。你可以后缀名匹配,也可以用正则匹配。
    domain(suffix: linkedin.com) -> proxy
    domain(regex:'.+\.quay\.io$') -> proxy
    domain(regex:'.+\.docker\.com$') -> proxy
    domain(regex:'.+\.kubernetes\.io$') -> proxy

    # proxy一些geosite定义的网站
    #domain(geosite:google) -> proxy
    domain(geosite:github) -> proxy
    domain(geosite:category-container) -> proxy
    domain(geosite:category-dev) -> proxy

    # 代理域名地址非cn的网站
    domain(geosite:geolocation-!cn) -> proxy

    # 代理IP非CN的请求
    !dip(geoip:cn) -> proxy

    # 默认直连
    fallback: direct
}

看起来蛮复杂的,其实都比较容易懂啦,相信你看注释就能明白。这里的规则,我设置为默认直连(见最后一行fallback: direct),毕竟你可能不希望不知觉中把某些信息都发给代理。

现在配置Ready,启动你的dae来试一下吧!看看下载github是否快多了呢?拉个外部docker镜像试试?如果你想进一步修改和理解上面的规则配置,我贴心地给你准备了一个关于geoip/geosite的详情。这是否值得你点赞/收藏/关注一波呢:)

  • 规则geoip:private的内容是在代码中定义并被导出为dat文件的,请点击这里geoip:private。可见我们常见的私有网段都赫然在列。
  • 规则geosite的内容是以文件夹和文件来组织的,可在这里找到更多信息。
  • 规则geoip:cn是在这里有个流水线每周打包刷新的。

遇到个问题

我在腾讯云上试过这个方案,能正常加速那些原本很慢的网站了,但在sudo apt update时遇到个报错:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ubuntu@kevin:/usr/local/etc/dae$ sudo apt update
Ign:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
Ign:2 http://mirrors.tencentyun.com/ubuntu jammy-updates InRelease
Ign:3 http://mirrors.tencentyun.com/ubuntu jammy-security InRelease
Ign:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
Ign:2 http://mirrors.tencentyun.com/ubuntu jammy-updates InRelease
Ign:3 http://mirrors.tencentyun.com/ubuntu jammy-security InRelease
Ign:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
Ign:2 http://mirrors.tencentyun.com/ubuntu jammy-updates InRelease
Ign:3 http://mirrors.tencentyun.com/ubuntu jammy-security InRelease
Err:1 http://mirrors.tencentyun.com/ubuntu jammy InRelease
  Something wicked happened resolving 'mirrors.tencentyun.com:http' (-5 - No address associated with hostname)
Err:2 http://mirrors.tencentyun.com/ubuntu jammy-updates InRelease
  Something wicked happened resolving 'mirrors.tencentyun.com:http' (-5 - No address associated with hostname)
Err:3 http://mirrors.tencentyun.com/ubuntu jammy-security InRelease
  Something wicked happened resolving 'mirrors.tencentyun.com:http' (-5 - No address associated with hostname)

原本不是好好的吗?然后我们打开dae日志开到trace级别,研究DNS解析后会发现,默认的alidns无法解析mirrors.tencentyun.com这个域名,是直接报错无任何返回。这就神奇了,好奇宝宝再试了一下,用腾讯云的DNS来解析阿里云的软件源mirrors.aliyun.com,哇,居然可以解析正确。阿里的同学要反思一下格局了啊! 知道这个原因后,要解决它我们可借助主机DNS解析,在前面的DNS解析中漏掉了一种做法,或许是比较重要的(特别在云厂商下)fallback模式asis

 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
dns {
    ipversion_prefer: 4
    upstream {
        # 在下面request/fallback设置为asis后,也不需要alidns了
        # alidns: 'udp://223.5.5.5:53'
        googledns: 'tcp+udp://8.8.8.8:53'
    }
    routing {
        request {
            # 属于广告的一些解析,全拒绝解析
            qname(geosite:category-ads) -> reject
            qname(geosite:category-ads-all) -> reject
            # ipv6也拒绝
            qtype(aaaa) -> reject

            # 使用asis来利用主机的域名解析能力
            fallback: asis
        }

        # 对于解析到的DNS地址,再额外处理一下再返回 
        response {
            # 如果是googledns返回的,直接接收
            upstream(googledns) -> accept

            # 私有IP(表示被污染了),并且不属于cn范围的,再给googledns解读一下
            ip(geoip:private) && !qname(geosite:cn) -> googledns

            fallback: accept
        }
    }
}

同样的,如果你发现你的某些域名不能被国内正确的解析,可以在上述DNS解析中再指定它的专门DNS服务器。

效果

现在我们看看效果吧,以往特别难拉取的一个镜像,你来挑战一下?

1
2
3
$ sudo docker pull gcr.io/google-containers/kube-proxy:v1.18.0

Error response from daemon: Get "https://gcr.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)

我们会发拉,根本拉不下来,连接似乎都建不起来,现在呢?

1
2
3
4
5
6
7
8
$ sudo ctr i  pull gcr.io/google-containers/kube-proxy:v1.18.0
gcr.io/google-containers/kube-proxy:v1.18.0:                                      resolved       |++++++++++++++++++++++++++++++++++++++|
index-sha256:9e858386d52d0abaf936c1d10a763648ab7d85c8eb0af08a50a64238146e5571:    done           |++++++++++++++++++++++++++++++++++++++|
manifest-sha256:b832454a96a848ad5c51ad8a499ef2173b627ded2c225e3a6be5aad9446cb211: done           |++++++++++++++++++++++++++++++++++++++|
...
elapsed: 11.9s                                                                    total:  45.6 M (3.8 MiB/s)
unpacking linux/amd64 sha256:9e858386d52d0abaf936c1d10a763648ab7d85c8eb0af08a50a64238146e5571...
done: 997.30325ms

还不错吧。同样的,若要去wget/curl资源、要git clone代码,那速度完全取决于你的节点。

后续

既然还不错,光本地还有点不太够,比如有时还想跟openai去交流一下技术让它修改点代码啥的,我们在浏览器使用Proxy SwitchyOmega来把一些网站代理一下。因为它不支持sock5代理,我们只有选择HTTP代理。很可能你想随时随地多端访问,故部署在公网更合适。为了安全,我们需要支持认证的HTTP代理。这几点诉求,都可借助v2ray实现。给个v2ray配置吧,其它就不多说啦,使用体验还挺棒的。

 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
{
    "log": {
        "loglevel": "debug"
    },
    // List of inbound proxy configurations.
    "inbounds": [
        {
            "port": 7892,
            "listen": "0.0.0.0",
            "tag": "http-proxy-auth",
            "protocol": "http",
            "settings": {
                "accounts": [
                    {
                        "user": "kevin",
                        "pass": "<你的密码,设置复杂点吧>"
                    }
                ]
            }
        }
    ],
    // List of outbound proxy configurations.
    "outbounds": [
        {
            // Protocol name of the outbound proxy.
            "protocol": "freedom",
            // Settings of the protocol. Varies based on protocol.
            "settings": {},
            // Tag of the outbound. May be used for routing.
            "tag": "direct"
        },
        {
            "protocol": "blackhole",
            "settings": {},
            "tag": "blocked"
        }
    ],
    "other": {}
}

如果是在公网,为了安全起见,你可以设置一些防火墙规则。比如我在腾讯云CVM上开启安全组,设置访问这个端口的来源IP,避免被异常访问或扫描。

后记

本文首先要感谢折腾群的群友提及dae并且诱惑我去尝试,于是一发不可收拾,其间把这些小小的经验和趟坑记录了一下,遂有此文。我们想寻找一种更适合Linux的加速网络的方案,经测试一周效果还不错。相比于之前我的解决方案是ss+privoxy方案,这个一体化更高,而且配置其实是更简单,功能更强大。稍有些遗憾的是,在我开启LAN proxy后,它表现得没那么稳定。但我没有实际测速,也不想太深究啦。

如果你有疑问或见解,欢迎留言&交流,我们只聊技术!

-EOF

我是个爱折腾技术的工程师,也乐于分享。欢迎点赞、关注、分享,更欢迎一起探讨技术问题,共同学习,共同进步。为了获得更及时的文章推送,欢迎关注我的公众号。

扫码关注公众号