<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>技術 on 亂筆</title>
        <link>https://blog.l3zc.com/zh-hant-hk/categories/tech/</link>
        <description>Recent content in 技術 on 亂筆</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-hant-hk</language><atom:link href="https://blog.l3zc.com/zh-hant-hk/categories/tech/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>拋棄所謂「客户端」，直接使用 Mihomo 核心</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2025/07/switch-to-pure-mihomo-kernel/</link>
            <pubDate>Thu, 03 Jul 2025 10:30:00 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2025/07/switch-to-pure-mihomo-kernel/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post 拋棄所謂「客户端」，直接使用 Mihomo 核心&#34; /&gt;&lt;p&gt;自從開始使用 Clash/Mihomo，我和大多數人一樣選擇了基於其核心的圖形化客户端——圖方便。實際上，這些 Mihomo 客户端本質上都差不多：核心都是同一個，他們主要負責提供一個易用的介面、管理配置檔案、訂閲更新，以及 GUI 下的系統代理設定。基於這一點，我認為判斷一個 Mihomo 客户端優劣的關鍵，便是看它的「覆寫」功能做得如何。每一個透過客户端下載或者訂閲的配置檔案，都會經過一系列「覆寫」過程，比如更換 &lt;code&gt;mixed-port&lt;/code&gt;、新增 &lt;code&gt;sniffer&lt;/code&gt; 配置等，最後生成用於啓動 Mihomo 核心的最終配置。&lt;/p&gt;&#xA;&lt;p&gt;然而，並非所有客户端都能勝任這一核心工作。比如 ShellCrash，其覆寫功能經常莫名其妙出岔子，説到底還是實現得太粗糙。如果連覆蓋和修改配置都做不好，這種客户端實在難稱合格。&lt;/p&gt;&#xA;&lt;p&gt;與其依賴這些&lt;del&gt;屎一樣的&lt;/del&gt;不盡如人意的 Mihomo 客户端，不如自己動手，直接自己編寫、管理配置檔案交給核心啓動，而不是依賴「黑箱」一般的各種「客户端」，不僅更純淨、更穩定，而且更可控。&lt;/p&gt;&#xA;&lt;h2 id=&#34;需要的預備知識&#34;&gt;需要的預備知識&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;基本的 Linux 操作&lt;/li&gt;&#xA;&lt;li&gt;知道如何使用 CLI 編輯器，如 nano&lt;/li&gt;&#xA;&lt;li&gt;已經搭建 Substore（可選）&lt;/li&gt;&#xA;&lt;li&gt;預設使用 root 用戶操作，非 root 用戶請自行注意提權&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;安裝-mihomo-核心&#34;&gt;安裝 Mihomo 核心&#xA;&lt;/h2&gt;&lt;p&gt;對於基於 Debian 的分支，可以使用預編譯的&lt;code&gt;.deb&lt;/code&gt;包安裝，對於其他使用&lt;code&gt;systemd&lt;/code&gt;的系統，下載&lt;a class=&#34;link&#34; href=&#34;https://github.com/MetaCubeX/mihomo/releases&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;編譯好的二進位制檔案&lt;/a&gt;，重新命名為&lt;code&gt;mihomo&lt;/code&gt;，放到&lt;code&gt;/usr/local/bin&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;curl -o /usr/local/bin/mihomo &lt;下載連結&gt;&#xA;chmod +x /usr/local/bin/mihomo&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然後新建&lt;code&gt;/etc/systemd/system/mihomo.service&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-systemd&#34;&gt;[Unit]&#xA;Description=mihomo Daemon, Another Clash Kernel.&#xA;After=network.target NetworkManager.service systemd-networkd.service iwd.service&#xA;&#xA;[Service]&#xA;Type=simple&#xA;LimitNPROC=500&#xA;LimitNOFILE=1000000&#xA;CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE&#xA;AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE CAP_SYS_TIME CAP_SYS_PTRACE CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE&#xA;Restart=always&#xA;ExecStartPre=/usr/bin/sleep 1s&#xA;ExecStart=/usr/local/bin/mihomo -d /etc/mihomo&#xA;ExecReload=/bin/kill -HUP $MAINPID&#xA;&#xA;[Install]&#xA;WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用&lt;code&gt;systemctl daemon-reload&lt;/code&gt;重新載入&lt;code&gt;systemd&lt;/code&gt;，此時還沒有配置檔案，不能直接啓動核心，但可以使用&lt;code&gt;systemctl enable mihomo&lt;/code&gt;讓核心開機自啓，方便後續使用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置檔案&#34;&gt;配置檔案&#xA;&lt;/h2&gt;&lt;p&gt;核心啓動時會載入&lt;code&gt;/etc/mihomo/config.yaml&lt;/code&gt;，沒有了黑箱一樣的礙事「客户端」，配置檔案可以隨心所欲的定製。部分機場會下發完整的配置檔案，直接用&lt;code&gt;curl&lt;/code&gt;下載即可。&lt;/p&gt;&#xA;&lt;p&gt;對於訂閲的管理，我目前使用 Substore，我之前分享過&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/&#34; &gt;「最速 Substore 訂閲管理指南」&lt;/a&gt;，可以直接蔘考這篇文章來定製自己的訂閲。為了實現純核心啓動，現在我的 Substore &lt;a class=&#34;link&#34; href=&#34;https://github.com/powerfullz/override-rules/blob/main/convert.js&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;JS 格式覆寫&lt;/a&gt;已經加入了&lt;code&gt;full&lt;/code&gt;引數，可以生成完整的配置檔案，包括各種埠設定、統一延遲和外部控制器等，開箱即用。&lt;/p&gt;&#xA;&lt;p&gt;在 Substore 配置完成以後便可以下載配置檔案並啓動核心：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;sudo curl -o /etc/mihomo/config.yaml 配置檔案連結&#xA;sudo systemctl start mihomo&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;自定義覆寫&#34;&gt;自定義覆寫&#xA;&lt;/h3&gt;&lt;p&gt;我的配置檔案不能滿足你的所有需求？沒問題！你可以自己新增覆寫，想要什麼加什麼。&lt;/p&gt;&#xA;&lt;p&gt;我用過各種覆寫規則，後來也開始自己從零開始編寫覆寫規則，即使使用自己的覆寫規則能滿足 99% 的場景，但有極個別的域名還是會在規則中有遺漏，更不用説用別人寫的覆寫規則了。這些遺漏的規則大多是形如我伺服器的非標準埠 SSH 的前置代理等相對隱私的規則，直接上傳到 Github 公開顯然不太合適，那麼在自定義規則的基礎上再新增覆寫就成了唯一的選擇。&lt;/p&gt;&#xA;&lt;p&gt;好在 Substore 可以新增多個指令碼操作，只需要在生成配置檔案時額外新增一個指令碼操作就能解決我們的問題。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;function main(config) {&#xA;  config[&#34;rules&#34;].unshift(&#34;DOMAIN-SUFFIX,xxx,DIRECT&#34;)&#xA;  return config&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;需要注意的是覆寫&lt;code&gt;rules&lt;/code&gt;時必須要使用&lt;code&gt;.unshift()&lt;/code&gt;放在最前面，而不是用&lt;code&gt;.push()&lt;/code&gt;放到最後面，因為放在&lt;code&gt;MATCH&lt;/code&gt;後面的規則是永遠都匹配不到的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;自定義配置檔案&#34;&gt;自定義配置檔案&#xA;&lt;/h3&gt;&lt;p&gt;完全不喜歡我的覆寫規則？不會用/不喜歡用 Substore？沒問題！你也可以蔘考 &lt;a class=&#34;link&#34; href=&#34;https://wiki.metacubex.one/config/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Mihomo 文件&lt;/a&gt;，自己從頭開始手搓配置檔案：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;mode: rule&#xA;mixed-port: 7890&#xA;redir-port: 7892&#xA;tproxy-port: 7893&#xA;allow-lan: true&#xA;log-level: info&#xA;ipv6: true&#xA;external-controller: 127.0.0.1:8000&#xA;# secret: yoursecret&#xA;unified-delay: true&#xA;routing-mark: 7894&#xA;tcp-concurrent: true&#xA;disable-keep-alive: true # 推薦在給移動裝置代理時啓用，可以解決待機異常耗電的問題&#xA;&#xA;dns:&#xA;  # 你的 DNS 配置&#xA;&#xA;sniffer:&#xA;  # 你的域名嗅探配置&#xA;&#xA;geodata-mode: true&#xA;geox-url:&#xA;  # 自定義 Geodata 檔案 URL&#xA;&#xA;proxy-providers:&#xA;  # 你的機場訂閲&#xA;&#xA;rule-providers:&#xA;  # 外部規則&#xA;&#xA;rules:&#xA;  # 分流規則&#xA;&#xA;proxy-groups:&#xA;  # 自定義代理分組&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;管理面板&#34;&gt;管理面板&#xA;&lt;/h2&gt;&lt;p&gt;管理面板可以根據個人喜好選擇，以 Zashboard 為例，我在使用 mihomo 自帶的&lt;code&gt;external-ui&lt;/code&gt;時遇到了一些莫名其妙的問題，所以乾脆直接執行一個 Docker 容器，畢竟這東西就真的只是一個 Web 面板，只要確保核心 API 使用 HTTP 時，Web 面板也使用 HTTP 即可，如果此時 Web 面板使用 HTTPS，則會因為 CORS 策略問題無法連線。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ mkdir zashboard &amp;&amp; cd zashboard&#xA;$ nano compose.yml&#xA;$ docker compose up -d&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;compose.yml&lt;/code&gt;內容：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:&#xA;  zashboard:&#xA;    image: ghcr.io/zephyruso/zashboard:latest&#xA;    ports:&#xA;      - &#34;8899:80&#34;&#xA;    restart: &#34;unless-stopped&#34;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;自動維護&#34;&gt;自動維護&#xA;&lt;/h2&gt;&lt;p&gt;核心已經執行起來，自動更新訂閲這種功能怎麼實現？&lt;/p&gt;&#xA;&lt;p&gt;答曰：自行編寫一個 Shell 指令碼，配合 Crontab 即可實現自動更新訂閲的功能。例如我希望每天凌晨 3 點自動更新訂閲並重啓服務，遂編寫&lt;code&gt;/etc/mihomo/auto_update.sh&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;#!/bin/bash&#xA;&#xA;# === 配置資訊 ===&#xA;CONFIG_URL=&#34;&#34;&#xA;CONFIG_PATH=&#34;/etc/mihomo/config.yaml&#34;&#xA;BACKUP_DIR=&#34;/etc/mihomo&#34;&#xA;BACKUP_PREFIX=&#34;config.yaml&#34;&#xA;MAX_BACKUPS=7&#xA;TMP_PATH=&#34;/tmp/config.yaml.tmp&#34;&#xA;LOG_FILE=&#34;/var/log/mihomo_update.log&#34;&#xA;&#xA;# === 日誌 ===&#xA;log() {&#xA;    echo &#34;$(date &#39;+%F %T&#39;) $1&#34; | tee -a &#34;$LOG_FILE&#34;&#xA;}&#xA;&#xA;# === 備份現有配置，並自動清理舊備份 ===&#xA;backup_config() {&#xA;    if [ -f &#34;$CONFIG_PATH&#34; ]; then&#xA;        backup_file=&#34;$BACKUP_DIR/${BACKUP_PREFIX}.$(date &#39;+%Y%m%d_%H%M%S&#39;).bak&#34;&#xA;        cp &#34;$CONFIG_PATH&#34; &#34;$backup_file&#34;&#xA;        log &#34;配置檔案已備份到 $backup_file&#34;&#xA;        # 清理多餘的備份，只保留最新的 $MAX_BACKUPS 個&#xA;        old_backups=$(ls -1t $BACKUP_DIR/${BACKUP_PREFIX}.*.bak 2&gt;/dev/null | tail -n +$(($MAX_BACKUPS+1)))&#xA;        for f in $old_backups; do&#xA;            rm -f &#34;$f&#34; &amp;&amp; log &#34;已刪除舊備份 $f&#34;&#xA;        done&#xA;    else&#xA;        log &#34;未找到現有配置檔案，無需備份&#34;&#xA;    fi&#xA;}&#xA;&#xA;# === 下載新配置 ===&#xA;download_config() {&#xA;    log &#34;開始下載新配置...&#34;&#xA;    curl -fsSL -o &#34;$TMP_PATH&#34; &#34;$CONFIG_URL&#34;&#xA;    if [ $? -ne 0 ]; then&#xA;        log &#34;下載配置失敗，請檢查網絡或地址&#34;&#xA;        return 1&#xA;    fi&#xA;    # 基本校驗：檢測檔案體積&#xA;    if [ ! -s &#34;$TMP_PATH&#34; ]; then&#xA;        log &#34;下載檔案為空，停止更新&#34;&#xA;        return 2&#xA;    fi&#xA;    log &#34;配置下載完成&#34;&#xA;    return 0&#xA;}&#xA;&#xA;# === 更新配置檔案 ===&#xA;replace_config() {&#xA;    mv &#34;$TMP_PATH&#34; &#34;$CONFIG_PATH&#34;&#xA;    log &#34;配置檔案已更新&#34;&#xA;}&#xA;&#xA;# === 重啓 mihomo 服務 ===&#xA;restart_service() {&#xA;    systemctl restart mihomo&#xA;    if [ $? -eq 0 ]; then&#xA;        log &#34;mihomo 服務已重啓&#34;&#xA;    else&#xA;        log &#34;mihomo 服務重啓失敗，請手動檢查&#34;&#xA;    fi&#xA;}&#xA;&#xA;main() {&#xA;    backup_config&#xA;&#xA;    download_config&#xA;    DL_STATUS=$?&#xA;    if [ &#34;$DL_STATUS&#34; -ne 0 ]; then&#xA;        log &#34;操作終止：配置檔案未更新，保留原有配置&#34;&#xA;        exit 1&#xA;    fi&#xA;&#xA;    replace_config&#xA;&#xA;    restart_service&#xA;&#xA;    log &#34;=== 更新流程完成 ===&#34;&#xA;}&#xA;&#xA;main &#34;$@&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;使用&lt;code&gt;crontab -e&lt;/code&gt;編輯 Crontab，設定如下 Crontab 即可在每天凌晨三點自動更新配置：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-crontab&#34;&gt;0 3 * * * /etc/mihomo/update_config.sh&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;防火牆&#34;&gt;防火牆&#xA;&lt;/h2&gt;&lt;p&gt;手動配置防火牆把流量劫持到 Mihomo 核心其實並不是什麼難事，我之前在「&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/#%E5%9C%A8-exit-node-%E5%8A%AB%E6%8C%81%E6%B5%81%E9%87%8F&#34; &gt;從入門到進階：Tailscale + ShellCrash 異地組網和科學上網&lt;/a&gt;」（以下簡稱「Tailscale 那篇文章」中的兩個小節中提到過具體的操作方法，這裏只提操作，不做解説。&lt;/p&gt;&#xA;&lt;p&gt;根據我的情況，我需要把&lt;code&gt;tailscale0&lt;/code&gt;上的網絡卡的所有流量劫持到 Mihomo 核心，其它的情況（例如本機代理）操作也大同小異。如果只是想劫持 TCP 流量，那麼用&lt;code&gt;iptables&lt;/code&gt;的 REDIRECT 功能已經足夠，但若還想劫持 UDP、QUIC 等流量，則必須用到 Tproxy。&lt;strong&gt;最後，不要忘了 IPV6。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;以下是我的防火牆配置：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;# 建立自定義鏈&#xA;iptables -t mangle -N MIHOMO&#xA;&#xA;# 根據自己的需要忽略本地流量&#xA;iptables -t mangle -A MIHOMO -d 127.0.0.1/8 -j RETURN&#xA;iptables -t mangle -A MIHOMO -d 100.64.0.0/10 -j RETURN&#xA;iptables -t mangle -A MIHOMO -d 192.168.1.0/24 -j RETURN&#xA;iptables -t mangle -A MIHOMO -d 172.17.0.0/16 -j RETURN&#xA;&#xA;# mark UDP 和 TCP 到代理&#xA;iptables -t mangle -A MIHOMO -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;iptables -t mangle -A MIHOMO -p udp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;&#xA;# 介面跳轉&#xA;iptables -t mangle -A PREROUTING -i tailscale0 -j MIHOMO&#xA;&#xA;# 路由表配置&#xA;echo &#34;233 mihomo&#34; | tee -a /etc/iproute2/rt_tables&#xA;ip rule add fwmark 233 lookup mihomo&#xA;ip route add local 0.0.0.0/0 dev lo table mihomo&#xA;&#xA;# IPv6&#xA;# 建立鏈&#xA;ip6tables -t mangle -N MIHOMO6&#xA;&#xA;# 跳過本地地址&#xA;ip6tables -t mangle -A MIHOMO6 -d ::1/128 -j RETURN&#xA;ip6tables -t mangle -A MIHOMO6 -d fd7a:115c:a1e0::/48 -j RETURN&#xA;&#xA;# 標記 TCP/UDP&#xA;ip6tables -t mangle -A MIHOMO6 -i tailscale0 -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;ip6tables -t mangle -A MIHOMO6 -i tailscale0 -p udp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;&#xA;# 介面跳轉&#xA;ip6tables -t mangle -A PREROUTING -i tailscale0 -j MIHOMO6&#xA;&#xA;# 路由表配置&#xA;echo &#34;233 mihomo&#34; | tee -a /etc/iproute2/rt_tables&#xA;ip -6 rule add fwmark 233 lookup mihomo&#xA;ip -6 route add local ::/0 dev lo table mihomo&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;大多數系統預設不會儲存防火牆規則，關於規則持久化的內容我已經分別在 Tailscale 那篇文章的「&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/#%E8%B7%AF%E7%94%B1%E8%A7%84%E5%88%99%E6%8C%81%E4%B9%85%E5%8C%96&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;路由規則持久化&lt;/a&gt;」和「&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/#iptables-%E8%A7%84%E5%88%99%E6%8C%81%E4%B9%85%E5%8C%96&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;iptables 規則持久化&lt;/a&gt;」兩小節做了詳細説明，直接蔘考即可。&lt;/p&gt;&#xA;&lt;h3 id=&#34;本機代理怎麼配置&#34;&gt;本機代理怎麼配置？&#xA;&lt;/h3&gt;&lt;p&gt;大多數代理軟件預設的配置（其實就是 ShellCrash 的預設配置）是 REDIRECT，用它也基本能滿足大多數需求，REDIRECT 的示例如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;# IPv4 劫持 eth0&#xA;iptables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 7892&#xA;&#xA;# IPv6 劫持 eth0&#xA;ip6tables -t nat -A PREROUTING -i eth0 -p tcp -j REDIRECT --to-ports 7892&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中 7892 要和 Mihomo 配置中的&lt;code&gt;redir-port&lt;/code&gt;一致，&lt;code&gt;eth0&lt;/code&gt;就是想要劫持的 Interface，相比 Tproxy 那可真是簡單太多了。&lt;/p&gt;&#xA;&lt;p&gt;實際上我個人並不喜歡用把本機所有流量都劫持到防火牆，我更喜歡在需要時直接透過環境變數、&lt;code&gt;proxy-chains&lt;/code&gt;和各種軟件自帶的代理配置把流量指向 Mihomo 核心，例如想讓 Docker 走代理，則可以直接編輯 Docker 的&lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;來指定代理，而不是直接一股腦把網絡卡上的所有流量都劫持到代理：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &#34;proxies&#34;: {&#xA;    &#34;http-proxy&#34;: &#34;http://127.0.0.1:7890&#34;,&#xA;    &#34;https-proxy&#34;: &#34;http://127.0.0.1:7890&#34;,&#xA;    &#34;no-proxy&#34;: &#34;127.0.0.0/8&#34;&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;這麼折騰何必呢用客户端不香嗎&#34;&gt;這麼折騰，何必呢？用客户端不香嗎？&#xA;&lt;/h2&gt;&lt;p&gt;別問，問就是玩虛空終端玩的。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>從入門到進階：Tailscale &#43; ShellCrash 異地組網和科學上網</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2025/04/tailscale-setup-recap/</link>
            <pubDate>Mon, 14 Apr 2025 10:10:25 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2025/04/tailscale-setup-recap/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post 從入門到進階：Tailscale + ShellCrash 異地組網和科學上網&#34; /&gt;&lt;p&gt;在幾次旅途中，我試圖將新拍的照片上傳到長沙家中的 Immich 伺服器。過去我用 Cloudflare Tunnel 做反代，但由於國內特殊的網絡環境，連線慢速、頻繁中斷、上傳失敗幾乎成了常態。後來我開始嘗試 Tailscale —— 一個基於 WireGuard 的內網穿透工具，它終於讓我在全國各地都能穩定、高速地訪問家中的 NAS 和照片庫。&lt;/p&gt;&#xA;&lt;p&gt;但新的問題也隨之而來：Tailscale 在 Android 手機上執行時，需要作為 VPN 服務接管系統流量，而我平時使用的 Clash 同樣依賴 VPN 介面進行分流。由於 Android 系統限制（只能啓用一個 VPN 服務），兩者無法共存，導致我必須在「訪問家中服務」和「科學上網」之間二選一。&lt;/p&gt;&#xA;&lt;p&gt;這篇文章從 Tailscale 的原理講起，到自建 DERP 伺服器最佳化連線質量，再到如何用 iptables 劫持 Tailscale Exit Node 的流量並轉發給 ShellCrash，實現流量的靈活轉發與安全穿透。無論你是想訪問家庭區域網上的 NAS、照片庫，還是希望在陌生網絡中保護自己的資料安全，這篇文章都能為你提供一套實用、穩定的解決方案。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什麼是-tailscale&#34;&gt;什麼是 Tailscale&#xA;&lt;/h2&gt;&lt;p&gt;Tailscale 是一款基於 WireGuard 協議的零配置虛擬區域網工具，它能夠讓分佈在不同網絡環境中的裝置像處於同一個安全內網中一樣互聯互通。透過自動穿透 NAT、防火牆等網絡障礙，Tailscale 讓你無需公網 IP、無需埠轉發，也能輕鬆訪問家中的 NAS、個人伺服器、開發環境等內網資源。它的核心優勢在於簡單、安全、穩定，啓動即用，資料傳輸全程加密，適合個人開發者、遠端辦公者、家庭用戶等多種場景使用。&lt;/p&gt;&#xA;&lt;p&gt;Tailscale 的技術實現非常巧妙：其構建在 WireGuard 加密協議之上，卻顛覆了傳統 VPN 的 IP 分配邏輯。每個裝置透過 SSO/OAuth2 完成身份認證後，會獲得一個終身繫結的節點金鑰。這種基於身份的組網模式，讓「長沙的 NAS」和「香港的手機」在虛擬網絡中如同辦公室同事般直接對話。&lt;/p&gt;&#xA;&lt;h2 id=&#34;tailscale-的連線過程原理&#34;&gt;Tailscale 的連線過程原理&#xA;&lt;/h2&gt;&lt;h3 id=&#34;中心控制伺服器control-server&#34;&gt;中心控制伺服器（Control Server）&#xA;&lt;/h3&gt;&lt;p&gt;每個 Tailscale 客户端在啓動後，首先會連線控制伺服器（controlplane），進行身份驗證，並拉取整個網絡中其他節點的資訊，包括每台裝置的公網 IP、埠、NAT 型別等。這一步相當於是「認識朋友」。&lt;/p&gt;&#xA;&lt;p&gt;Tailscale 的控制伺服器不會轉發任何資料，只負責協調連線 —— 類似一個排程中心。&lt;/p&gt;&#xA;&lt;h3 id=&#34;derp-伺服器&#34;&gt;DERP 伺服器&#xA;&lt;/h3&gt;&lt;p&gt;説到 Tailscale 能保持高連線成功率的關鍵，就不得不提到 Tailscale 自研的中轉協議 DERP，在 Tailscale 的網絡架構裏，DERP（Designated Encrypted Relay for Packets）是一個很重要但通常只在必要時介入的元件。簡單來説，它就是一個基於 HTTP 的加密中繼伺服器，用來在兩台裝置無法直接通訊時，作為它們之間的「中轉站」。&lt;/p&gt;&#xA;&lt;p&gt;所有客户端之間的連線都是先選擇 DERP 模式（中繼模式），這意味着連線立即就能建立，用戶無需等待。然後連線雙方開始並行地進行路徑發現，通常幾秒鐘之後，Tailscale 就能發現一條更優路徑，然後將現有連線透明升級（upgrade）過去，變成點對點連線（直連）。&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;需要注意的是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;所有透過 DERP 的資料都是端到端加密的，DERP 伺服器無法檢視內容；&lt;/li&gt;&#xA;&lt;li&gt;Tailscale 會盡可能少地使用 DERP，一旦直連建立成功，就會自動切換過去；&lt;/li&gt;&#xA;&lt;li&gt;官方部署了多個分散式 DERP 節點，客户端會自動選擇延遲最低的那個；&lt;/li&gt;&#xA;&lt;li&gt;你也可以自建 DERP 節點（比如在國內），來解決延遲高或連線不穩定的問題。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;可以把 DERP 理解為一個兜底機制，雖然效能不如直連，但確保了即便不能打洞成功，裝置之間也始終能保持連線。&lt;/p&gt;&#xA;&lt;h3 id=&#34;nat-穿透nat-traversal&#34;&gt;NAT 穿透（NAT Traversal）&#xA;&lt;/h3&gt;&lt;p&gt;拿到對端的地址資訊後，Tailscale 會嘗試透過 NAT 穿透來建立點對點（P2P）連線。這個過程使用了 STUN 協議，雙方互相傳送探測包，嘗試在 NAT 路由器上打出一條直連的通道。如果雙方的網絡條件允許，就可以成功建立起一個 UDP 的直連隧道，資料走直連，速度快、延遲低。&lt;/p&gt;&#xA;&lt;p&gt;受制於篇幅，我無法完整細緻的講述 NAT 穿透的原理，若對這部分感興趣，可以閲讀 Tailscale 官方的「&lt;a class=&#34;link&#34; href=&#34;https://tailscale.com/blog/how-nat-traversal-works&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;How NAT traversal works&lt;/a&gt;」一文。&lt;/p&gt;&#xA;&lt;h3 id=&#34;完整連線流程圖示&#34;&gt;完整連線流程圖示&#xA;&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TD&#xA;    A[裝置 A 啓動 Tailscale] --&gt; B[透過 DERP 伺服器建立初始連線]&#xA;    B --&gt; C[交換網絡資訊和 WireGuard 金鑰]&#xA;    C --&gt; D[雙方並行進行 NAT 型別探測]&#xA;    D --&gt; E{能否直連？}&#xA;    E -- 是 --&gt; F[建立 P2P 直連隧道]&#xA;    F --&gt; G[定期檢測連線質量]&#xA;    G --&gt; H{直連優於 DERP？}&#xA;    H -- 是 --&gt; I[切換大部分流量至直連通道]&#xA;    H -- 否 --&gt; J[繼續透過 DERP 轉發部分或全部流量]&#xA;    E -- 否 --&gt; J&#xA;&#xA;    style B fill:#e3f2fd,stroke:#2196f3,color:#000&#xA;    style F fill:#e8f5e9,stroke:#4caf50,color:#000&#xA;    style J fill:#fff3e0,stroke:#ff9800,color:#000&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;自建-derp&#34;&gt;自建 DERP&#xA;&lt;/h2&gt;&lt;p&gt;Tailscale 的安裝在各個平台上都相對簡單，官方文件已經提供了詳細的操作指南。本文將不再贅述安裝過程，以下內容預設你已經在相關裝置上成功安裝並登入了 Tailscale。&lt;/p&gt;&#xA;&lt;h3 id=&#34;為什麼要自建-derp&#34;&gt;為什麼要自建 DERP？&#xA;&lt;/h3&gt;&lt;p&gt;Tailscale 在全球部署了眾多 DERP &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;中繼伺服器，用於在打洞失敗時接管流量中轉。但由於眾所周知的原因，中國大陸並沒有官方部署的 DERP 節點。這意味着：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一旦 NAT 打洞失敗，所有流量都必須繞行海外的 DERP 節點，延遲高、速度慢，體驗極差；&lt;/li&gt;&#xA;&lt;li&gt;某些官方 DERP 節點容易被 GFW 干擾，可能出現連線中斷、握手失敗等問題；&lt;/li&gt;&#xA;&lt;li&gt;即使打洞成功，Tailscale 仍需透過 DERP 交換路由資訊和 WireGuard 金鑰，如果 DERP 不可達，連線質量也會受到影響。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;因此，在國內網絡環境下，自建一個本地 DERP 節點，不僅可以顯著提高連線穩定性和傳輸效能，還能規避部分網絡封鎖所帶來的不可預期問題，是一個非常值得做的最佳化。&lt;/p&gt;&#xA;&lt;h3 id=&#34;準備工作&#34;&gt;準備工作&#xA;&lt;/h3&gt;&lt;p&gt;前面提到，DERP 是基於 HTTP 的，所以你需要準備好一個 HTTP 反代服務，並自行解決 SSL 證書的簽發等基礎問題。本文使用 Docker 部署，在部署開始之前，你需要在你的伺服器上裝好 Docker 以及 Docker Compose 等附加元件。為了編輯配置檔案，你當然也得知道如何使用 nano 之類的編輯器。為了最好的效果，你的伺服器最好擁有靜態公網 IPv4+IPv6 雙棧地址。&lt;/p&gt;&#xA;&lt;p&gt;如果以上條件都具備，就可以開始部署了。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;mkdir tailscale-derp &amp;&amp; cd tailscale-derp&#xA;nano docker-compose.yml&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;docker-composeyml&#34;&gt;docker-compose.yml&#xA;&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:&#xA;  derper:&#xA;    name: tailscale-derp&#xA;    image: fredliang/derper&#xA;    environment:&#xA;      - DERP_DOMAIN=derp.nightcity.pub&#xA;      - DERP_VERIFY_CLIENTS=true&#xA;      - DERP_ADDR=:4433&#xA;    network_mode: host&#xA;    restart: unless-stopped&#xA;    volumes:&#xA;      - &#34;/var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;network_mode: host&lt;/code&gt;是一個關鍵配置，表示容器將共享宿主機的網絡棧。如果使用 Docker 預設的 bridge 網絡模式，容器的網絡會經過 Docker 內網轉發，會造成 DERP 的 STUN 服務識別到 Docker &lt;code&gt;172.17.0.0/16&lt;/code&gt;網段下的地址，而&#xA;無法識別到客户端正確的外網地址，導致 Tailscale 客户端無法正確連線。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;volumes:&#xA;  - &#34;/var/run/tailscale/tailscaled.sock:/var/run/tailscale/tailscaled.sock&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前面提到所有透過 DERP 的資料都是端到端加密的，DERP 並不知道是誰在使用，這意味着如果不採取措施，任何知道你 DERP 伺服器地址和埠號的人都可以使用它。這條配置的作用是掛載宿主機的 Tailscale 套接字檔案到容器內，目的是允許 derper 服務透過 Tailscale 的 tailscaled 服務進行身份驗證。配合&lt;code&gt;DERP_VERIFY_CLIENTS=true&lt;/code&gt;，可以防止你的 DERP 節點被他人白嫖。&lt;/p&gt;&#xA;&lt;p&gt;需要注意的是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;宿主機必須已經安裝並登陸 Tailscale 客户端（tailscaled），否則這個檔案不存在，容器會報錯；&lt;/li&gt;&#xA;&lt;li&gt;tailscaled 必須以 root 許可權執行，才能建立這個 sock 檔案。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;反向代理&#34;&gt;反向代理&#xA;&lt;/h3&gt;&lt;p&gt;以 Caddy 為例，需要反向代理 4433 埠，併為其部署 SSL 證書。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-caddyfile&#34;&gt;{&#xA;        email webmaster@l3zc.com&#xA;}&#xA;&#xA;*.l3zc.com {&#xA;        encode gzip&#xA;&#xA;        tls {&#xA;                dns dnspod APP_ID,APP_KEY&#xA;                resolvers 119.29.29.29 223.5.5.5&#xA;        }&#xA;&#xA;        @derp host derp.l3zc.com&#xA;        reverse_proxy @derp :4433&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;需要注意的是，如果你和我一樣使用 Caddy 配合 dnsproviders 申請泛域名證書，Tailscale 的 MagicDNS 可能會導致 Caddy 本地證書驗證失敗而報錯，需要手動指定&lt;code&gt;resolvers&lt;/code&gt;引數解決。&lt;/p&gt;&#xA;&lt;p&gt;訪問剛剛反代的節點，如果出現以下頁面，説明配置正確。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image_hu_8846b1a6f5d79837.webp&#34; alt=&#34;DERP 搭建成功&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;配置-acl-策略&#34;&gt;配置 ACL 策略&#xA;&lt;/h3&gt;&lt;p&gt;開啓 Tailscale 控制枱的「&lt;a class=&#34;link&#34; href=&#34;https://login.tailscale.com/admin/acls/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Access Controls&lt;/a&gt;」頁面配置 ACL 策略，將配置好的 DERP 加上。&lt;/p&gt;&#xA;&lt;p&gt;Tailscale 的 ACL 策略是用 HuJSON&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; 寫的，想要在 VSCode 中編輯，選擇語言為「JSON with Comments（jsonc）」即可。以下是一個配置示例：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-jsonc&#34;&gt;{&#xA;  &#34;acls&#34;: [{ &#34;action&#34;: &#34;accept&#34;, &#34;src&#34;: [&#34;*&#34;], &#34;dst&#34;: [&#34;*:*&#34;] }],&#xA;  &#34;ssh&#34;: [&#xA;    {&#xA;      &#34;action&#34;: &#34;check&#34;,&#xA;      &#34;src&#34;: [&#34;autogroup:member&#34;],&#xA;      &#34;dst&#34;: [&#34;autogroup:self&#34;],&#xA;      &#34;users&#34;: [&#34;autogroup:nonroot&#34;, &#34;root&#34;]&#xA;    }&#xA;  ],&#xA;&#xA;  // 自建 DERP 配置&#xA;  &#34;derpMap&#34;: {&#xA;    &#34;OmitDefaultRegions&#34;: false, // 改為 true 以排除官方 DERP&#xA;    &#34;Regions&#34;: {&#xA;      &#34;900&#34;: {&#xA;        &#34;RegionID&#34;: 900,&#xA;        &#34;RegionCode&#34;: &#34;sha&#34;,&#xA;        &#34;RegionName&#34;: &#34;Shanghai&#34;,&#xA;        &#34;Nodes&#34;: [&#xA;          {&#xA;            &#34;Name&#34;: &#34;myderp&#34;,&#xA;            &#34;RegionID&#34;: 900,&#xA;            &#34;HostName&#34;: &#34;derp.l3zc.com&#34;&#xA;          }&#xA;        ]&#xA;      }&#xA;    }&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Tailscale 保留&lt;code&gt;RegionID&lt;/code&gt;中的 1-899 作為官方節點，自建節點的 RegionID 必須大於等於 900。&lt;/p&gt;&#xA;&lt;h3 id=&#34;測試連線&#34;&gt;測試連線&#xA;&lt;/h3&gt;&lt;p&gt;配置好 ACL 並儲存，Tailscale 會自動為所有客户端同步配置，稍等片刻在客户端用&lt;code&gt;tailscale netcheck&lt;/code&gt;測試連線。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image-1_hu_25ccc2304c1a66fd.webp&#34; alt=&#34;用 tailscale netcheck 測試連線&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;需要注意返回的 IP 是否是自己真實的公網 IP，若返回了&lt;code&gt;172.17.0.0/16&lt;/code&gt;網段的地址，説明你 Docker 部分配置錯了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;與科學上網並存在-exit-node-劫持流量到-clash-核心&#34;&gt;與科學上網並存：在 Exit Node 劫持流量到 Clash 核心&#xA;&lt;/h2&gt;&lt;h3 id=&#34;宣告-exit-node&#34;&gt;宣告 Exit Node&#xA;&lt;/h3&gt;&lt;p&gt;在家中準備一個 24 小時開機的裝置，可以是樹莓派，可以是 MacMini。在上面安裝 Tailscale 並將其宣告為 Exit Node，並根據需要在 Tailscale 內網宣告家庭內網網段，隨後在控制枱啓用這個裝置作為 Exit Node，你就獲得了一個免費的 VPN，可以讓你在陌生的網絡環境中保持安全。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo tailscale up --advertise-exit-node --advertise-routes 192.168.1.0/24&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image-2_hu_bac8de7f1a5258d0.webp&#34; alt=&#34;找到 Route Settings&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/Snipaste_2025-04-13_21-20-09_hu_d8313f59e1940d09.webp&#34; alt=&#34;啓用相關設定&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;廣播完成後，無論身處何地，只要能連上 Tailscale 網絡，就能訪問家中所有的內網裝置。&lt;/p&gt;&#xA;&lt;h3 id=&#34;啓用-ip-轉發和禁用-udp-gro&#34;&gt;啓用 IP 轉發和禁用 UDP GRO&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&#xA;&lt;/h3&gt;&lt;p&gt;啓用 IP 轉發是樹莓派等裝置作為 Exit Node 所必須的配置，這裏以樹莓派為例，如果你使用其他裝置，請自行查閲 Tailscale 官網教程。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;echo &#39;net.ipv4.ip_forward = 1&#39; | sudo tee -a /etc/sysctl.d/99-tailscale.conf&#xA;echo &#39;net.ipv6.conf.all.forwarding = 1&#39; | sudo tee -a /etc/sysctl.d/99-tailscale.conf&#xA;sudo sysctl -p /etc/sysctl.d/99-tailscale.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根據 Tailscale 官方的説法&lt;sup id=&#34;fnref:5&#34;&gt;&lt;a href=&#34;#fn:5&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;5&lt;/a&gt;&lt;/sup&gt;，禁用 UDP GRO&lt;sup id=&#34;fnref:6&#34;&gt;&lt;a href=&#34;#fn:6&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;6&lt;/a&gt;&lt;/sup&gt; 可以提升轉發效能，但官方的持久化教程似乎在樹莓派上無效，好在我們可以手動配置。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# 安裝 ethtool&#xA;sudo apt update &amp;&amp; sudo apt install ethtool -y&#xA;&#xA;# 關閉 UDP GRO&#xA;sudo ethtool -K eth0 gro off&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;針對持久化的問題手動編寫 systemd 配置檔案：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 建立服務檔案&#xA;sudo nano /etc/systemd/system/ethtool.service&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;檔案內容如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-systemd&#34;&gt;[Unit]&#xA;Description=Configure eth0 GRO&#xA;After=network.target&#xA;&#xA;[Service]&#xA;Type=oneshot&#xA;ExecStart=/sbin/ethtool -K eth0 gro off&#xA;&#xA;[Install]&#xA;WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;隨後啓動服務：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo systemctl daemon-reload&#xA;sudo systemctl enable ethtool&#xA;sudo systemctl start ethtool&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;在-exit-node-劫持流量&#34;&gt;在 Exit Node 劫持流量&#xA;&lt;/h3&gt;&lt;p&gt;我的 Exit Node 是一台樹莓派，在樹莓派上配置好 Exit Node 之後就來到了最後一步，也就是劫持手機傳送到 Exit Node 上的流量，實現科學上網。出於穩定性原因，我不希望在家庭主路由上直接執行代理軟件，為了實現這一點，直接在樹莓派上劫持流量是唯一的選擇。&lt;/p&gt;&#xA;&lt;p&gt;首先安裝 ShellCrash，請自行根據你的需要匯入配置檔案、配置自動任務等：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;export url=&#39;https://fastly.jsdelivr.net/gh/juewuy/ShellCrash@master&#39; &amp;&amp; wget -q --no-check-certificate -O /tmp/install.sh $url/install.sh  &amp;&amp; bash /tmp/install.sh &amp;&amp; source /etc/profile &amp;&gt; /dev/null&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;隨後啓動服務，修改修改防火牆執行模式為純淨模式，我個人建議將 SNI 嗅探開啓，並將 DNS 模式從&lt;code&gt;fake-ip&lt;/code&gt;切換為&lt;code&gt;redir-host&lt;/code&gt;&lt;sup id=&#34;fnref:7&#34;&gt;&lt;a href=&#34;#fn:7&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;7&lt;/a&gt;&lt;/sup&gt;，同時啓用 IPv6 透明代理。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image-5_hu_9e9d06f0578b4304.webp&#34; alt=&#34;修改防火牆劫持範圍&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image-3_hu_efcbb45f4cd30701.webp&#34; alt=&#34;啓用域名嗅探&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/image-6_hu_d681ee087b8dd14a.webp&#34; alt=&#34;修改埠設定&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;設定純淨模式的目的是手動配置 iptables 以實現更精準的流量劫持。我們直接用 iptables 劫持所有 tailscale 網絡卡作為 Exit Node 轉發的流量，首先用&lt;code&gt;ifconfig&lt;/code&gt;檢視 tailscale 網絡卡的名稱，預設情況下一般為 Tailscale 0：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;root@raspberrypi:~# ifconfig&#xA;eth0: ......&#xA;&#xA;tailscale0: flags=4305&lt;UP,POINTOPOINT,RUNNING,NOARP,MULTICAST&gt;  mtu 1280&#xA;        inet 100.111.19.50  netmask 255.255.255.255  destination 100.111.19.50&#xA;        inet6 fd7a:115c:a1e0::3d01:1332  prefixlen 128  scopeid 0x0&lt;global&gt;&#xA;        inet6 fe80::c0d5:1a1b:2005:48eb  prefixlen 64  scopeid 0x20&lt;link&gt;&#xA;        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)&#xA;        RX packets 6780155  bytes 958732442 (914.3 MiB)&#xA;        RX errors 0  dropped 0  overruns 0  frame 0&#xA;        TX packets 4811113  bytes 10858316472 (10.1 GiB)&#xA;        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;劫持&lt;code&gt;tailscale0&lt;/code&gt;網絡卡的所有流量到本地 Clash 核心監聽埠&lt;code&gt;7892&lt;/code&gt;，這個設定在 ShellCrash 中叫做「靜態路由埠」。以及，如果你不想和我一樣遇到莫名其妙的網絡問題，就一定不要忘記劫持 IPv6。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# IPv4 劫持 tailscale0&#xA;iptables -t nat -A PREROUTING -i tailscale0 -p tcp -j REDIRECT --to-ports 7892&#xA;&#xA;# IPv6 劫持 tailscale0&#xA;ip6tables -t nat -A PREROUTING -i tailscale0 -p tcp -j REDIRECT --to-ports 7892&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;進階用-tproxy-劫持-udp-流量&#34;&gt;進階：用 TProxy 劫持 UDP 流量&#xA;&lt;/h3&gt;&lt;p&gt;iptables 的 REDIRECT 只能重定向 TCP 流量，UDP 沒有連線狀態（無連線協議），所以 REDIRECT 無法保留目標地址，導致透明代理無法知道原始目標地址。&lt;/p&gt;&#xA;&lt;p&gt;所以，如果你用如下方式劫持 UDP 流量：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;iptables -t nat -A PREROUTING -i tailscale0 -p udp -j REDIRECT --to-ports 7892&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;則這個規則不會生效或代理行為不正常。&lt;/p&gt;&#xA;&lt;p&gt;那麼，有辦法代理 UDP 流量嗎？有的兄弟，有的。但前提是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;核心支援 UDP 透明代理（Clash Premium 和 Mihomo 都支援）；&lt;/li&gt;&#xA;&lt;li&gt;使用 TProxy 模式，而不是 REDIRECT；&lt;/li&gt;&#xA;&lt;li&gt;正確配置了 iptables mangle 表和 policy routing；&lt;/li&gt;&#xA;&lt;li&gt;代理配置檔案中啓用了 UDP 代理（如 mode: rule + udp: true）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;假設你已經滿足第一條、第二條和最後一條，則以下是一個示例&lt;sup id=&#34;fnref:8&#34;&gt;&lt;a href=&#34;#fn:8&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;8&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 建立自定義鏈&#xA;sudo iptables -t mangle -N SHELLCRASH&#xA;&#xA;# 根據自己的需要忽略本地流量&#xA;sudo iptables -t mangle -A SHELLCRASH -d 127.0.0.1/8 -j RETURN&#xA;sudo iptables -t mangle -A SHELLCRASH -d 100.64.0.0/10 -j RETURN&#xA;sudo iptables -t mangle -A SHELLCRASH -d 192.168.1.0/24 -j RETURN&#xA;sudo iptables -t mangle -A SHELLCRASH -d 172.17.0.0/16 -j RETURN&#xA;&#xA;# mark UDP 和 TCP 到代理&#xA;sudo iptables -t mangle -A SHELLCRASH -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;sudo iptables -t mangle -A SHELLCRASH -p udp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;&#xA;# 介面跳轉&#xA;sudo iptables -t mangle -A PREROUTING -i tailscale0 -j SHELLCRASH&#xA;&#xA;# 路由表配置&#xA;echo &#34;233 shellcrash&#34; | sudo tee -a /etc/iproute2/rt_tables&#xA;sudo ip rule add fwmark 233 lookup shellcrash&#xA;sudo ip route add local 0.0.0.0/0 dev lo table shellcrash&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;當然，不要忘記 IPv6：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 建立鏈&#xA;sudo ip6tables -t mangle -N SHELLCRASH6&#xA;&#xA;# 跳過本地地址&#xA;sudo ip6tables -t mangle -A SHELLCRASH6 -d ::1/128 -j RETURN&#xA;sudo ip6tables -t mangle -A SHELLCRASH6 -d fd7a:115c:a1e0::/48 -j RETURN&#xA;&#xA;# 標記 TCP/UDP&#xA;ip6tables -t mangle -A SHELLCRASH6 -i tailscale0 -p tcp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;ip6tables -t mangle -A SHELLCRASH6 -i tailscale0 -p udp -j TPROXY --on-port 7893 --tproxy-mark 233&#xA;&#xA;# 介面跳轉&#xA;sudo ip6tables -t mangle -A PREROUTING -i tailscale0 -j SHELLCRASH6&#xA;&#xA;# 路由表配置&#xA;echo &#34;233 shellcrash&#34; | sudo tee -a /etc/iproute2/rt_tables&#xA;sudo ip -6 rule add fwmark 233 lookup shellcrash&#xA;sudo ip -6 route add local ::/0 dev lo table shellcrash&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;路由規則持久化&#34;&gt;路由規則持久化&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;ip rule&lt;/code&gt;和&lt;code&gt;ip route&lt;/code&gt;建立的規則在重啓後會丟失，所以需要我們手動持久化，最簡單直接的方法就是建立一個指令碼，並將其新增至 crontab。&lt;/p&gt;&#xA;&lt;p&gt;建立一個指令碼：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo nano /usr/local/bin/policy-route.sh&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;編輯為如下內容：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash&#xA;&#xA;# IPv4 策略路由&#xA;ip rule add fwmark 233 lookup 233&#xA;ip route add local 0.0.0.0/0 dev lo table 233&#xA;&#xA;# IPv6 策略路由&#xA;ip -6 rule add fwmark 233 lookup 233&#xA;ip -6 route add local ::/0 dev lo table 233&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;授予執行許可權後編輯 Crontab：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo chmod +x /usr/local/bin/policy-route.sh&#xA;sudo crontab -e&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 crontab 檔案底部加上如下內容：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-crontab&#34;&gt;@reboot /usr/local/bin/policy-route.sh&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;原理解釋tproxy-到底是怎麼轉發-udp-流量的&#34;&gt;原理解釋：TProxy 到底是怎麼轉發 UDP 流量的？&#xA;&lt;/h3&gt;&lt;p&gt;如果你看到這裏，也許會產生疑惑：為什麼整個流程中，我們沒有在 iptables 裏寫&lt;code&gt;--to-ports&lt;/code&gt;，也沒看到目標地址被改寫，UDP 流量就莫名其妙地被代理了？這是怎麼做到的？&lt;/p&gt;&#xA;&lt;p&gt;要解釋這個問題，我們先來看 TProxy 和 REDIRECT 的根本區別：&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;REDIRECT 模式：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用 iptables nat 表；&lt;/li&gt;&#xA;&lt;li&gt;將目標地址改寫為本地地址（比如 127.0.0.1:7892）；&lt;/li&gt;&#xA;&lt;li&gt;通常用於 TCP 流量；&lt;/li&gt;&#xA;&lt;li&gt;不能保留真實目標地址；&lt;/li&gt;&#xA;&lt;li&gt;需要指定&lt;code&gt;--to-ports&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TB&#xA;    A[客户端裝置&lt;br&gt;透過 Tailscale 發起 TCP 請求]&#xA;    B[tailscale0 介面接收流量]&#xA;    C[iptables NAT PREROUTING&lt;br&gt;REDIRECT --to-ports 7892]&#xA;    D[ShellCrash 本地監聽&lt;br&gt;127.0.0.1:7892]&#xA;    E[ShellCrash 發起新 TCP 請求&lt;br&gt;→ 目標伺服器]&#xA;    F[響應從網絡返回&lt;br&gt;ShellCrash 轉發響應]&#xA;    G[響應回到客户端裝置]&#xA;&#xA;    A --&gt; B --&gt; C --&gt; D --&gt; E --&gt; F --&gt; G&#xA;&#xA;    style C fill:#f9f,stroke:#aaa,stroke-width:1px,color:#000&#xA;    style D fill:#bbf,stroke:#aaa,stroke-width:1px,color:#000&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;TPROXY 模式：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用 iptables mangle 表；&lt;/li&gt;&#xA;&lt;li&gt;不修改目標 IP，而是保留原始目標地址；&lt;/li&gt;&#xA;&lt;li&gt;透過 fwmark 和 policy routing 將報文路由到 &lt;code&gt;lo&lt;/code&gt;；&lt;/li&gt;&#xA;&lt;li&gt;代理程式監聽一個特殊埠（例如 7893），並啓用 &lt;code&gt;IP_TRANSPARENT&lt;/code&gt;；&lt;/li&gt;&#xA;&lt;li&gt;支援 UDP 和 TCP；&lt;/li&gt;&#xA;&lt;li&gt;不需要 iptables 內指定 &lt;code&gt;--to-ports&lt;/code&gt;，因為不是 NAT，而是標記 + 路由。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TB&#xA;    A[客户端裝置&lt;br&gt;透過 Tailscale 發起 TCP/UDP 請求]&#xA;    B[tailscale0 介面接收流量]&#xA;    C[iptables MANGLE PREROUTING&lt;br&gt;打上 fwmark 233]&#xA;    D[ip rule: fwmark 233&lt;br&gt;使用 routing table shellcrash]&#xA;    E[ip route: local 0.0.0.0/0&lt;br&gt;dev lo table shellcrash]&#xA;    F[ShellCrash 在 lo:7893 監聽&lt;br&gt;IP_TRANSPARENT 模式]&#xA;    G[ShellCrash 獲取原始目標地址&lt;br&gt;發起代理連線]&#xA;    H[響應從網絡返回&lt;br&gt;ShellCrash 轉發響應]&#xA;    I[響應回到客户端裝置]&#xA;&#xA;    A --&gt; B --&gt; C --&gt; D --&gt; E --&gt; F --&gt; G --&gt; H --&gt; I&#xA;&#xA;    style C fill:#f9f,stroke:#aaa,stroke-width:1px,color:#000&#xA;    style F fill:#bbf,stroke:#aaa,stroke-width:1px,color:#000&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;TProxy 不使用 DNAT/REDIRECT，而是透過 mangle 表給資料包打上 mark，然後透過 policy routing（&lt;code&gt;ip rule&lt;/code&gt; + &lt;code&gt;ip route&lt;/code&gt;）將這些資料包送到 &lt;code&gt;lo&lt;/code&gt; 介面。代理程式（如 Clash / ShellCrash）監聽在 &lt;code&gt;lo&lt;/code&gt;&lt;sup id=&#34;fnref:9&#34;&gt;&lt;a href=&#34;#fn:9&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;9&lt;/a&gt;&lt;/sup&gt; 上的埠（例如 7893），透過啓用 &lt;code&gt;IP_TRANSPARENT&lt;/code&gt; 選項，可以讀取資料包的原始目標 IP 和埠並進行代理轉發。&lt;/p&gt;&#xA;&lt;p&gt;簡而言之，TProxy 模式只需要：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;iptables&lt;/code&gt; 給資料包打上 mark；&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;ip rule&lt;/code&gt; + &lt;code&gt;ip route&lt;/code&gt; 將這些包送到 &lt;code&gt;lo&lt;/code&gt;；&lt;/li&gt;&#xA;&lt;li&gt;程式監聽 &lt;code&gt;lo&lt;/code&gt; 上的埠並開啓 &lt;code&gt;IP_TRANSPARENT&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以不需要在 iptables 中指定 &lt;code&gt;--to-ports&lt;/code&gt;，因為目標 IP 和埠保持不變，代理程式自己可以感知並處理。&lt;/p&gt;&#xA;&lt;h3 id=&#34;iptables-規則持久化&#34;&gt;iptables 規則持久化&#xA;&lt;/h3&gt;&lt;p&gt;安裝&lt;code&gt;iptables-persistent&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;sudo apt update&#xA;sudo apt install iptables-persistent&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;安裝過程中會提示你是否儲存當前的 IPv4 和 IPv6 配置，選擇「是」即可。之後如果你新增了新的規則，記得執行儲存命令：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# 儲存當前 IPv4/IPv6 規則&#xA;sudo netfilter-persistent save&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;儲存後的規則檔案路徑：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;IPv4：&lt;code&gt;/etc/iptables/rules.v4&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;IPv6：&lt;code&gt;/etc/iptables/rules.v6&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;你也可以直接編輯上面的&lt;code&gt;rules.v4&lt;/code&gt;/&lt;code&gt;rules.v6&lt;/code&gt;檔案，按需修改。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最終效果&#34;&gt;最終效果&#xA;&lt;/h2&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/Screenshot_2025-04-14-18-05-18-259_com.tailscale._hu_783d6158c36336e1.webp&#34; alt=&#34;基本都能打洞成功&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/Screenshot_2025-04-14-18-04-45-053_com.cnspeedtes_hu_a47b6440dc775101.webp&#34; alt=&#34;速度尚可接受&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;這套方案的使用體驗取決於你家的上行頻寬，我家的網絡是下行 500M 上行 60M，目前沒有遇到一次打洞失敗的情況，所以基本都能跑滿，延遲也尚可接受，並且可以在外地隨時隨地端到端加密訪問家中的 Immich 和 OpenWRT 路由器等裝置以及實現科學上網，總體來看，我還算比較滿意。&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://icloudnative.io/posts/custom-derp-servers/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://icloudnative.io/posts/custom-derp-servers/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://tailscale.com/kb/1232/derp-servers&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://tailscale.com/kb/1232/derp-servers&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;有關 HuJSON: &lt;a class=&#34;link&#34; href=&#34;https://github.com/tailscale/hujson&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://github.com/tailscale/hujson&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;蔘考： &lt;a class=&#34;link&#34; href=&#34;https://tailscale.com/kb/1408/quick-guide-exit-nodes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://tailscale.com/kb/1408/quick-guide-exit-nodes&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:5&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://tailscale.com/kb/1320/performance-best-practices#linux-optimizations-for-subnet-routers-and-exit-nodes&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://tailscale.com/kb/1320/performance-best-practices#linux-optimizations-for-subnet-routers-and-exit-nodes&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:6&#34;&gt;&#xA;&lt;p&gt;UDP GRO（Generic Receive Offload）是 Linux 核心中的一種網絡最佳化技術，主要用於合併多個小資料包以提高處理效率。但在裝置作為網絡轉發節點的使用場景下，這可能會導致轉發延遲增加和高丟包率環境下的吞吐量下降。&amp;#160;&lt;a href=&#34;#fnref:6&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:7&#34;&gt;&#xA;&lt;p&gt;相較於&lt;code&gt;fake-ip&lt;/code&gt;，&lt;code&gt;redir-host&lt;/code&gt;相容性更好，出現問題的機率更低，也不會出現開關代理之後短時間內因為&lt;code&gt;fake-ip&lt;/code&gt;殘留而斷網的情況，所以一般情況下我建議使用&lt;code&gt;redir-host&lt;/code&gt;搭配 GeoSite 分流規則使用。我這台樹莓派的 DNS 上游是&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;已經配置好的 SmartDNS&lt;/a&gt;，不存在 DNS 污染的問題，體驗良好。&amp;#160;&lt;a href=&#34;#fnref:7&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:8&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://blog.zonowry.com/posts/clash_iptables_tproxy/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://blog.zonowry.com/posts/clash_iptables_tproxy/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:8&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:9&#34;&gt;&#xA;&lt;p&gt;&lt;code&gt;lo&lt;/code&gt; 是 Linux 系統中預設的「迴環介面（Loopback Interface）」，在透明代理中，它不僅處理 localhost 流量，還被用來接收原本屬於外部世界的網絡連線，實現對外部流量的本地劫持和轉發。&amp;#160;&lt;a href=&#34;#fnref:9&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>Google Play 商店的國內 CDN：從密碼學入門到分流策略最佳化</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2025/03/chinese-cdn-used-by-playstore/</link>
            <pubDate>Sat, 15 Mar 2025 13:15:01 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2025/03/chinese-cdn-used-by-playstore/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post Google Play 商店的國內 CDN：從密碼學入門到分流策略最佳化&#34; /&gt;&lt;p&gt;改用自己的 Mihomo 覆寫規則後，手機從 Google Play 上下載應用就會一直轉圈圈，而換用機場的規則就沒問題，非常奇怪。遂調取 Mihomo 核心日誌檢視。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-log&#34;&gt;play-lh.googleusercontent.com:443 match RuleSet(cdn_domainset) using 靜態資源[🇭🇰 香港 07]&#xA;play.googleapis.com:443 match GeoSite(GFW) using 節點選擇[🇭🇰 香港 07]&#xA;play-lh.googleusercontent.com:443 match RuleSet(cdn_domainset) using 靜態資源[🇭🇰 香港 07]&#xA;play-fe.googleapis.com:443 match GeoSite(GFW) using 節點選擇[🇭🇰 香港 07]&#xA;services.googleapis.cn:443 match GeoSite(CN) using 全球直連[DIRECT]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;（以上日誌已精簡）&lt;/p&gt;&#xA;&lt;p&gt;國行手機內建的 Google Play 服務使用&lt;code&gt;services.googleapis.cn&lt;/code&gt;而非&lt;code&gt;services.googleapis.com&lt;/code&gt;域名提供服務，而這個域名在大多數分流規則中都是直連，對，問題就出在這裏，修改規則把這個域名分流到代理就萬事大吉了！&lt;/p&gt;&#xA;&lt;p&gt;……萬事大吉了，嗎？&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;rr4---sn-j5o7dn7s.xn--ngstr-lra8j.com:443 match Match using 漏網之魚[🇭🇰 香港 07]&#xA;rr2---sn-j5o7dn7s.xn--ngstr-lra8j.com:443 match Match using 漏網之魚[🇭🇰 香港 07]&#xA;rr1---sn-j5o76n7z.xn--ngstr-lra8j.com:443 match Match using 漏網之魚[🇭🇰 香港 07]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;等等，為什麼每次從 Play 商店下載應用都會出現這些奇怪的域名？在網上查詢一番資料後，新世界的大門就此開啓。&lt;/p&gt;&#xA;&lt;h2 id=&#34;與-google-截然相反卻又異曲同工的-ångströ&#34;&gt;與 Google 截然相反卻又異曲同工的 Ångströ&#xA;&lt;/h2&gt;&lt;p&gt;看到 xn&amp;ndash;ngstr-lra8j.com，熟悉域名的同學肯定知道，這是 PunyCode 編碼，這串字元解碼後就是 ångströ.com。Anders Jonas Ångström 是一位瑞典物理學家，他是光譜學的奠基人。&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;埃斯特朗（Ångström）是為紀念他而以他的名字命名的長度單位，$ 1 Å = 10^{-10} m = \frac{1}{10} nm $，通常用於描述非常短的距離，比如原子和分子尺寸或光的波長。其代表極端小的量級，尤其是在物理學和化學中用於精細測量。&lt;/p&gt;&#xA;&lt;p&gt;雖然 Google 的名字並不是直接取自「Googol」，但是它的靈感來源於該詞。「Googol」是一個數學術語，表達$10^{100}$，即1後面跟着100個零，是一個極其龐大的數字，常用來表示電腦科學中涉及的巨大數字或資訊量。&lt;/p&gt;&#xA;&lt;p&gt;在命名哲學上，Google 與Ångströ 這對看似分處光譜兩端的科技概念，卻展現出耐人尋味的對稱美學。前者源於數學概念「Googol」的創造性改寫，後者則脱胎於物理單位「Ångström」的意象重構。這兩個經過藝術化變奏的稱謂，恰似科技文明的雙螺旋：Google 之稱承載着駕馭浩如星海的數字宇宙的雄心，Ångströ 之謂則暗喻着雕琢精微的原子級技術圖景。當這兩個經過創造性變形的專業術語在矽谷相遇，恰好構成了一組完美的認知座標——既指向人類處理資訊的尺度極限，也昭示着科技文明同時向宏觀與微觀進軍的壯闊征程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;入門密碼學google-基礎設施域名的規律&#34;&gt;入門密碼學：Google 基礎設施域名的規律&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&#xA;&lt;/h2&gt;&lt;p&gt;OK，enough。現在讓我們把視角轉回 Google 的基礎設施。先來看一些完整的連線域名：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;rr4---sn-j5o7dn7s.xn--ngstr-lra8j.com&#xA;rr1---sn-j5o76n7z.xn--ngstr-lra8j.com&#xA;rr5---sn-i3b7knzs.xn--ngstr-lra8j.com&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這些看似隨機的字串，實際上是經過一些簡單的密碼學加密後的結果。讓我們拆解其中的核心部件。&lt;/p&gt;&#xA;&lt;h3 id=&#34;城市名稱的轉換規則&#34;&gt;城市名稱的轉換規則&#xA;&lt;/h3&gt;&lt;p&gt;以&lt;code&gt;rr1---sn-j5o76n7z&lt;/code&gt;為例，關鍵的資訊段在&lt;code&gt;sn-&lt;/code&gt;後面的 8 位：&lt;code&gt;r1---sn-[123][45][6][78]&lt;/code&gt;。前三位，也就是本例中的&lt;code&gt;j5o&lt;/code&gt;是城市名稱，由該城市主要機場的 IATA 碼透過一定的密碼學變換轉換而來。&lt;/p&gt;&#xA;&lt;p&gt;首先構建一張 5 * 7 的數字字母表：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;行0: 1 0 2 3 4&#xA;行1: 5 6 7 8 9&#xA;行2: a b c d e&#xA;行3: f g h i j&#xA;行4: k l m n o&#xA;行5: p q r s t&#xA;行6: u v w x y&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;逆時針旋轉這張表，即從新表格的左下角開始，依次按照原表格「從左到右，從上到下」的順序，把原表的資料在新表上按照「從下到上，從左到右」的順序謄抄。&lt;/p&gt;&#xA;&lt;p&gt;旋轉完成後，可以得到下表：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;| 6 d k r y |&#xA;| --------- |&#xA;| 5 c j q x |&#xA;| 4 b i p w |&#xA;| 3 a h o v |&#xA;| 2 9 g n u |&#xA;| 0 8 f m t |&#xA;| --------- |&#xA;| 1 7 e l s |&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;表格中間用線條框出來的 5*5 的部分就是最終的密碼錶，一共有 25 個字元，「從左到右，從上到下」依次代表字母&lt;code&gt;a&lt;/code&gt;到字母&lt;code&gt;y&lt;/code&gt;。例如，上海虹橋國際機場的 IATA 代碼為&lt;code&gt;sha&lt;/code&gt;,我們可以透過這張表得到加密後的密文：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;s&lt;/code&gt;在字母表中是第 19 個字母，「從左到右，從上到下」依次在密碼錶中數到第 19 個字元，也就是&lt;code&gt;n&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;h&lt;/code&gt;在字母表中是第 8 個字母，「從左到右，從上到下」依次在密碼錶中數到第 8 個字元，也就是&lt;code&gt;i&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;a&lt;/code&gt;在字母表中是第 1 個字母，「從左到右，從上到下」依次在密碼錶中數到第 1 個字元，也就是&lt;code&gt;5&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;加密後的密文就是&lt;code&gt;ni5&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;反之亦然，回到一開始的城市名稱&lt;code&gt;j5o&lt;/code&gt;，從我們剛剛得到的密碼錶中反推出原文：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;j&lt;/code&gt;按照「從左到右，從上到下」的順序是第 3 個字元，也就是&lt;code&gt;c&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;5&lt;/code&gt;按照「從左到右，從上到下」的順序是第 1 個字元，也就是&lt;code&gt;a&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;o&lt;/code&gt;按照「從左到右，從上到下」的順序是第 14 個字母，也就是&lt;code&gt;n&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;翻譯完成的明文是&lt;code&gt;can&lt;/code&gt;，也就是廣州白雲國際機場的 IATA 碼，顯然，我們連線到的伺服器位於廣州。&lt;/p&gt;&#xA;&lt;p&gt;要是谷歌有某個伺服器位於蘇黎世，而蘇黎世機場的 IATA 碼是&lt;code&gt;zrh&lt;/code&gt;，有一個字母&lt;code&gt;z&lt;/code&gt;，可是我們的密碼錶只有&lt;code&gt;a&lt;/code&gt;到&lt;code&gt;y&lt;/code&gt;啊？別擔心，Google 當然也考慮到了這個問題，&lt;code&gt;z&lt;/code&gt;對應密碼錶中的&lt;code&gt;1&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;將這套規則用代碼表示如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;table = &#34;5cjqx4bipw3ahov29gnu08fmt1&#34;&#xA;def iata2cipher(iata):&#xA;    global table&#xA;    iata = iata.upper()&#xA;    cipher = &#34;&#34;&#xA;    for element in iata:&#xA;        index = ord(element) - 65&#xA;        cipher += table[index]&#xA;    return cipher&#xA;&#xA;def cipher2iata(cipher):&#xA;    global table&#xA;    cipher = cipher.lower()&#xA;    iata = &#34;&#34;&#xA;    for element in cipher:&#xA;        index = table.find(element)&#xA;        iata += chr(65 + index)&#xA;    return iata&#xA;&#xA;# print(iata2cipher(input(&#34;IATA:&#34;)))&#xA;# print(cipher2iata(input(&#34;Cipher:&#34;)))&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;伺服器組編號&#34;&gt;伺服器組編號&#xA;&lt;/h3&gt;&lt;p&gt;[45]和[78]位，如&lt;code&gt;76&lt;/code&gt;和&lt;code&gt;7z&lt;/code&gt;，表示伺服器組（接入點）編號，由下表第一列（已經用分隔線隔開）包含的字元組成，&lt;code&gt;7elsz6dkry&lt;/code&gt;分別代表&lt;code&gt;0123456789&lt;/code&gt;。所以，&lt;code&gt;76&lt;/code&gt;的明文是&lt;code&gt;05&lt;/code&gt;，&lt;code&gt;7z&lt;/code&gt;的明文是&lt;code&gt;04&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;  | 1 2 3 4 5 6&#xA;7 | 8 9 a b c d&#xA;e | f g h i j k&#xA;l | m n o p q r&#xA;s | t u v w x y&#xA;z | 0 1 2 3 4 5&#xA;6 | 7 8 9 a b c&#xA;d | e f g h i j&#xA;k | l m n o p q&#xA;r | s t u v w x&#xA;y | z&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以 Python 表示如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;codeTable = &#34;7elsz6dkry&#34;&#xA;def cipher2code(cipher):&#xA;    global codeTable&#xA;    cipher = cipher.lower()&#xA;    codeString = &#34;&#34;&#xA;    for element in cipher:&#xA;        index = codeTable.find(element)&#xA;        codeString += chr(index + 48)&#xA;    return codeString&#xA;&#xA;# print(cipher2code(input(&#34;Cipher:&#34;)))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;同樣要將數字加密為密文同理，這裏不再贅述。&lt;/p&gt;&#xA;&lt;h3 id=&#34;支援協議&#34;&gt;支援協議&#xA;&lt;/h3&gt;&lt;p&gt;[6]位表示網絡協議資訊：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;n&lt;/code&gt;：IPv6（地址段 0x000-0x3FF）&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;u&lt;/code&gt;：IPv6（地址段 0x400-0x7FF）&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;m&lt;/code&gt;：僅支援 IPv4&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;a5mekn7r&lt;/code&gt;，IPv6 字首：&lt;code&gt;2607:f8b0:4007:a::/64&lt;/code&gt;，IPv4 字首：&lt;code&gt;74.125.103.0/24&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;a5m7zu7r&lt;/code&gt;，IPv6 字首：&lt;code&gt;2607:f8b0:4007:407::/64&lt;/code&gt;，IPv4 字首：&lt;code&gt;74.125.215.0/24&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;a5mekm76&lt;/code&gt;，僅支援 IPv4，字首：&lt;code&gt;208.117.242.0/24&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;正確的分流處理&#34;&gt;正確的分流處理&#xA;&lt;/h2&gt;&lt;blockquote class=&#34;alert alert-warning&#34;&gt;&#xA;        &lt;div class=&#34;alert-header&#34;&gt;&#xA;            &lt;span class=&#34;alert-icon&#34;&gt;⚠️&lt;/span&gt;&#xA;            &lt;span class=&#34;alert-title&#34;&gt;警告&lt;/span&gt;&#xA;        &lt;/div&gt;&#xA;        &lt;div class=&#34;alert-body&#34;&gt;&#xA;            &lt;p&gt;Google 顯然不會為這些位於中國大陸的，未經 ICP 備案的 CDN 的穩定性和速度背書。如果流量足夠，那還是直接將&lt;code&gt;services.googleapis.cn&lt;/code&gt;加入代理列表吧。&lt;/p&gt;&#xA;        &lt;/div&gt;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;瞭解了 Google 基礎設施域名的加密規律後，我們可以根據這些資訊實現更精準的分流策略。目前已知 Google 在中國大陸的 CDN 節點主要分佈在北京（&lt;code&gt;2x3&lt;/code&gt;）、上海（&lt;code&gt;ni5&lt;/code&gt;）和廣州（&lt;code&gt;j5o&lt;/code&gt;），對應的域名特徵可以透過正規表示式識別：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;rules:&#xA;  - DOMAIN-REGEX,^r+[0-9]+(---|\.)sn-(2x3|ni5|j5o)\w{5}\.xn--ngstr-lra8j\.com$,DIRECT&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這條規則會匹配所有形如 &lt;code&gt;rr1---sn-j5o76n7z.xn--ngstr-lra8j.com&lt;/code&gt; 的國內 CDN 域名，並將其標記為直連。而對於其他未被覆蓋的 Google 域名（如 &lt;code&gt;play.googleapis.com&lt;/code&gt; 等），仍遵循原有的代理規則。&lt;/p&gt;&#xA;&lt;p&gt;事實上，GeoSite 數據庫的上游 &lt;a class=&#34;link&#34; href=&#34;https://github.com/v2fly/domain-list-community&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;v2fly/domain-list-community&lt;/a&gt; 已針對 Google Play 的國內 CDN 節點進行了最佳化&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;。只需在 Mihomo 配置中啓用 &lt;code&gt;GEOSITE,GOOGLE-PLAY@CN&lt;/code&gt; 規則，即可自動實現國內 CDN 直連與海外域名代理的智慧分流：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;rules:&#xA;  - GEOSITE,GOOGLE-PLAY@CN,直連&#xA;  - GEOSITE,GOOGLE,代理&lt;/code&gt;&lt;/pre&gt;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Anders_Jonas_%C3%85ngstr%C3%B6m&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://en.wikipedia.org/wiki/Anders_Jonas_%C3%85ngstr%C3%B6m&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://github.com/lennylxx/ipv6-hosts/wiki/sn-domains&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://github.com/lennylxx/ipv6-hosts/wiki/sn-domains&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;具體的commit: &lt;a class=&#34;link&#34; href=&#34;https://github.com/v2fly/domain-list-community/pull/2436/commits/a86c1bf3d9bf577869180874d87c76ddf6282fc1&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://github.com/v2fly/domain-list-community/pull/2436/commits/a86c1bf3d9bf577869180874d87c76ddf6282fc1&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>最速 Substore 訂閲管理指南</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2025/03/clash-subscription-convert/</link>
            <pubDate>Fri, 07 Mar 2025 10:54:29 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2025/03/clash-subscription-convert/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post 最速 Substore 訂閲管理指南&#34; /&gt;&lt;p&gt;當我趁着春節各家機場的促銷訂閲多個機場之後，如何充分利用每個節點就變成了説難不難説簡單也不簡單的問題，我當然可以訂閲各家機場提供的配置檔案，然後在他們之間切換，但這樣未免也太麻煩了。更何況我還有自建節點，我可不想為了這一個節點專門去開一個新的配置。&lt;/p&gt;&#xA;&lt;p&gt;Sub-Store 很好的解決了這個問題，它可以從多個訂閲中抽取節點資訊，透過正規表示式或者 JS 整理它們，最後輸出一個整合了所有節點資訊的訂閲。&lt;/p&gt;&#xA;&lt;p&gt;部署它可以直接使用 xream 打包好的映象，這個映象整合了前後端，如果在公網部署，記得更改一下後端路徑，否則你的配置檔案很可能會被盜用。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:&#xA;  sub-store:&#xA;    image: xream/sub-store&#xA;    container_name: substore&#xA;    restart: always&#xA;    environment:&#xA;      - SUB_STORE_CRON=55 23 * * *&#xA;      - SUB_STORE_FRONTEND_BACKEND_PATH=/super-random-path&#xA;    ports:&#xA;      - &#34;3001:3001&#34;&#xA;    volumes:&#xA;      - ./data:/opt/app/data&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;反代 3001 埠即可訪問 Substore 的前端，這裏以 Caddy 為例：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-caddyfile&#34;&gt;sub-domain.example.com {&#xA;        reverse_proxy :3001&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;當然，初次進入前端別忘了新增後端地址，這時的後端地址取決於之前 compose file 裏的設定，在本文的例子中，後端地址為&lt;code&gt;https://sub-domain.example.com/super-random-path&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;組合訂閲的管理&#34;&gt;組合訂閲的管理&#xA;&lt;/h2&gt;&lt;p&gt;新增所有機場上游和自建節點之後，就可以開始把它們全都加進單個組合訂閲，但各個機場對節點的命名五花八門，預設情況下看起來非常雜亂，甚至不同機場之間的節點還有重名的可能。好在 Sub-Store 有透過指令碼對節點進行批次重新命名操作的功能，這裏推薦&lt;a class=&#34;link&#34; href=&#34;https://github.com/Keywos/rule/blob/main/rename.js&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;一個指令碼&lt;/a&gt;，能夠幫我們為所有的機場節點重新命名。&lt;/p&gt;&#xA;&lt;p&gt;欲使用這個指令碼，只需在編輯訂閲時將以下地址貼上到指令碼操作處即可。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;https://raw.githubusercontent.com/Keywos/rule/main/rename.js&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image_hu_8310153db045f240.webp&#34; alt=&#34;節點操作&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-1_hu_333de5a5c288737.webp&#34; alt=&#34;整理完成的節點列表&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;最後再進行一些你喜歡的節點操作，可以整理出一個統一規範的節點列表。&lt;/p&gt;&#xA;&lt;h2 id=&#34;生成-clash-配置&#34;&gt;生成 Clash 配置&#xA;&lt;/h2&gt;&lt;p&gt;現在雖然已經有了節點列表，但現在生成的配置檔案並不包含任何規則，需要自行編寫或者拉取第三方規則。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-2_hu_755a17a55a5da685.webp&#34; alt=&#34;選擇 Mihomo 配置&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-3_hu_244966c33439c095.webp&#34; alt=&#34;編輯資訊&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-4_hu_c92302b1defa984b.webp&#34; alt=&#34;生成分享連結&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-6_hu_c37bf30e1b9005a7.webp&#34; alt=&#34;指令碼操作&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;轉到 Substore 的檔案管理，建立一份新的 Mihomo 配置：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;「來源」選擇組合訂閲，並在訂閲名稱上選擇你的訂閲組&lt;/li&gt;&#xA;&lt;li&gt;在指令碼操作中填入自己的覆寫配置&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;這是我自己的覆寫規則 &lt;a class=&#34;link&#34; href=&#34;https://github.com/powerfullz/override-rules&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;powerfullz/override-rules&lt;/a&gt;，以 &lt;a class=&#34;link&#34; href=&#34;https://github.com/mihomo-party-org/override-hub&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;mihomo-party-org/override-hub&lt;/a&gt; 內的 ACL4SSR 規則為靈感，幾乎完全重新編寫，具有以下優點：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;整合 SukkaW/Surge 和 Cats-Team/AdRules 規則集，最佳化廣告攔截、隱私保護及流量分流精度&lt;/li&gt;&#xA;&lt;li&gt;新增 Truth Social、E-Hentai、TikTok、加密貨幣等實用分流規則&lt;/li&gt;&#xA;&lt;li&gt;移除冗餘規則集&lt;/li&gt;&#xA;&lt;li&gt;引入 Loyalsoldier/v2ray-rules-dat 完整版 GeoSite/GeoIP 數據庫&lt;/li&gt;&#xA;&lt;li&gt;針對 IP 規則新增 no-resolve 引數，避免本地 DNS 解析，提升上網速度，無 DNS 泄露&lt;/li&gt;&#xA;&lt;li&gt;JS 格式覆寫現已實現節點國家動態識別與分組，自動為實際存在的各國家/地區節點生成對應代理組，節點變動時分組自動變化，省心省力。例如：你的訂閲沒有韓國的節點，則最終生成的配置中「韓國節點」這個代理組就不會出現。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;javascript-格式覆寫&#34;&gt;JavaScript 格式覆寫&#xA;&lt;/h3&gt;&lt;p&gt;複製 JavaScript 格式覆寫檔案的 raw 連結&lt;code&gt;https://raw.githubusercontent.com/powerfullz/override-rules/refs/heads/main/convert.js&lt;/code&gt;，並根據需要在後面附加引數，格式如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;https://raw.githubusercontent.com/powerfullz/override-rules/refs/heads/main/convert.js#引數1=true&amp;引數2=true&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;目前支援如下引數：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;引數&lt;/th&gt;&#xA;          &lt;th&gt;功能&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;loadbalance&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;啓用國家/地區節點組的負載均衡&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;landing&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;啓用落地節點功能&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;ipv6&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;啓用 IPv6 支援&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;full&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;生成針對純核心使用場景的完整配置&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;code&gt;keepalive&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;啓用 TCP KeepAlive&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;例如，若有負載均衡和 IPv6 需求，最終的覆寫指令碼連結為：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;https://raw.githubusercontent.com/powerfullz/override-rules/refs/heads/main/convert.js#loadbalance=true&amp;ipv6=true&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;將最終的覆寫指令碼連結貼上到指令碼操作處，使用 Substore 的生成預覽功能確認沒有問題後即可儲存。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-7_hu_a9aea54492dfed6c.webp&#34; alt=&#34;新建一個指令碼操作並貼上最終的訂閲連結&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;yaml-格式覆寫&#34;&gt;YAML 格式覆寫&#xA;&lt;/h3&gt;&lt;p&gt;&lt;del&gt;YAML 格式覆寫我自己已經不用了，隨緣維護，但歡迎 PR&lt;/del&gt;&lt;/p&gt;&#xA;&lt;p&gt;寫了個 Github Actions 自動根據 JS 格式覆寫生成 YAML 格式覆寫，所以現在 YAML 格式又開始維護了。&lt;/p&gt;&#xA;&lt;p&gt;除了直接引用 convert.js 動態覆寫，你也可以使用倉庫中預先生成好的 32 份 YAML 格式覆寫——它們都放在 yamls/ 目錄裏，由 GitHub Actions 在每次推送後自動重新生成、覆蓋。適用於諸如 Clash Verge 等不支援 JS 覆寫的客户端和轉換服務。&lt;/p&gt;&#xA;&lt;p&gt;檔案命名規則：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;config_lb-{0|1}_landing-{0|1}_ipv6-{0|1}_full-{0|1}_keepalive-{0|1}.yaml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;示例（開啓 full，其餘關閉）：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;https://raw.githubusercontent.com/powerfullz/override-rules/refs/heads/main/yamls/config_lb-0_landing-0_ipv6-0_full-1_keepalive-0.yaml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CI 只是套用一份假的&lt;code&gt;fake_proxies.json&lt;/code&gt;來生成覆寫，所以不可能實現 JS 覆寫自動根據節點匹配生成對應代理組的功能，只能把所有地區節點組都放進去。如果你已經搭建 Substore，並且想要「動態識別國家 + 傳蔘」的靈活性，還是推薦使用 JS 覆寫。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-6_hu_c37bf30e1b9005a7.webp&#34; alt=&#34;填入對應的 RAW 連結&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;生成下載連結&#34;&gt;生成下載連結&#xA;&lt;/h2&gt;&lt;p&gt;儲存成功後點選分享按鈕生成分享連結，設定分享有效期後點選「建立分享」，生成的連結即最終成型的 Mihomo 配置檔案，將其作為訂閲連結在你的代理軟件內訂閲就大功告成了。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/03/clash-subscription-convert/image-5_hu_945ace35e127c9fd.webp&#34; alt=&#34;最終效果&#34; /&gt;&#xA;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>我的家庭網絡域名解析方案</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2025/02/what-i-have-done-on-my-dns/</link>
            <pubDate>Thu, 06 Feb 2025 09:01:51 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2025/02/what-i-have-done-on-my-dns/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post 我的家庭網絡域名解析方案&#34; /&gt;&lt;p&gt;人在中國，用起 DNS 會碰到兩個問題，一個是 DNS 污染，另一個是 DNS 泄露。想要上網上得痛快，就必須要先解決 DNS 的問題。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什麼是-dns-泄露&#34;&gt;什麼是 DNS 泄露&#xA;&lt;/h2&gt;&lt;p&gt;如果你現在正在開着代理看這篇文章，可以先開啓&lt;a class=&#34;link&#34; href=&#34;https://browserleaks.com/dns&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;這個網站&lt;/a&gt;檢測一下自己的 DNS 請求是否被髮送到了國內的 DNS 伺服器上。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-5_hu_76c2844c94b4a181.webp&#34; alt=&#34;典型的 DNS 泄露&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;簡單來説，當你在使用 VPN 等代理工具時，你認為你的請求不會被除了你和 VPN 提供商以外的第三方看到，然而主機的 DNS 請求卻被髮送送給了運營商的 DNS 伺服器或者是公共 DNS 伺服器(阿里、騰訊等)進行解析，而你的真實 IP 地址和請求的域名都會被記錄下來。如果 DNS 請求解析一些敏感網站的域名(比如電報、維基解密等)，就會被監管者注意到，從而被警告或者請去喝茶。&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此，正確地配置代理工具的分流策略來避免 DNS 泄露就顯得尤為重要。&lt;/p&gt;&#xA;&lt;h2 id=&#34;smartdns-的配置&#34;&gt;SmartDNS 的配置&#xA;&lt;/h2&gt;&lt;h3 id=&#34;防止-dns-泄露&#34;&gt;防止 DNS 泄露&#xA;&lt;/h3&gt;&lt;p&gt;DNS 作為上網的指路人，排在第一位的要求就是必須要快，在這樣的要求下本地部署 SmartDNS 充當家庭網絡的 DNS 伺服器真的再合適不過了。關於 SmartDNS 的作用和配置技巧，以及其如何優選 CDN 加快網絡訪問速度，Sukka 的「&lt;a class=&#34;link&#34; href=&#34;https://blog.skk.moe/post/i-have-my-unique-dns-setup/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;我有特別的 DNS 配置和使用技巧&lt;/a&gt;」已經講的很好，推薦在繼續閲讀本文之前先去看看這篇文章，其中的內容我在這裏便不再贅述，我的敍述重心將會放在如何在 Luci 介面上實現這些配置。&lt;/p&gt;&#xA;&lt;p&gt;如果你和我一樣使用 OpenWRT，SmartDNS 的 Luci App 會在每次啓動時根據面板上儲存的配置自動生成新的配置檔案，所以，不要直接修改&lt;code&gt;/etc/smartdns&lt;/code&gt;目錄下原有的配置檔案，所有的更改都應該在 Luci App 裏操作。&lt;/p&gt;&#xA;&lt;p&gt;基本上，SmartDNS 上游數量越多越好，因為較多的上游並不會影響 SmartDNS 的效能&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;，並且多個上游可以增加冗餘。為了防止 DNS 泄露，在配置上游時，應當在預設分組新增國外 DNS 上游（當然，最好是加密 DNS），並將國內的伺服器歸入一個單獨的分組（例如&lt;code&gt;domestic&lt;/code&gt;），並加上&lt;code&gt;-exclude-default-group&lt;/code&gt;的額外引數以將它們從預設分組中排除。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image_hu_bd77370d9a6d2fcd.webp&#34; alt=&#34;國內上游的分組設定&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-1_hu_1ba4737b13c17f98.webp&#34; alt=&#34;一些可供蔘考的上游&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;加速國內域名解析&#34;&gt;加速國內域名解析&#xA;&lt;/h3&gt;&lt;p&gt;設定好國外上游，DNS 泄露的問題就解決了，但因為我們在預設分組中排除了國內上游，訪問新的域名時需要等待國外上游返回結果，這顯然會拖慢國內網站的訪問速度，並且還會劣化 CDN。&lt;/p&gt;&#xA;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/felixonmars/dnsmasq-china-list&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;dnsmasq-china-list&lt;/a&gt; 是 Felix Yan 的專案，目前支援透過 Makefile 生成 SmartDNS 格式的配置檔案，目前已經有人做好了現成的 Github Action 每天自動更新，直接下載就可以了，注意這些配置檔案只會在國內 DNS 上游分組名稱為&lt;code&gt;domestic&lt;/code&gt;時生效。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;cd /etc/smartdns&#xA;wget https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/accelerated-domains.china.domain.smartdns.conf&#xA;wget https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/apple.china.domain.smartdns.conf&#xA;wget https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/chinalist.domain.smartdns.conf&#xA;wget https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/google.china.domain.smartdns.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;隨後在 SmartDNS 中引入這些配置檔案，將下面的內容貼上到「自定義設定」欄的末尾。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;conf-file /etc/smartdns/accelerated-domains.china.domain.smartdns.conf&#xA;conf-file /etc/smartdns/apple.china.domain.smartdns.conf&#xA;conf-file /etc/smartdns/chinalist.domain.smartdns.conf&#xA;conf-file /etc/smartdns/google.china.domain.smartdns.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-2_hu_92b3727e74c74e1a.webp&#34; alt=&#34;引入配置檔案&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;這樣配置之後，國內域名的訪問速度便不再會受到影響，訪問國外域名時，也不會再有 DNS 泄露的問題了。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-6_hu_d5c1130c9fef193d.webp&#34; alt=&#34;在無代理的情況下防止 DNS 泄露&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;去廣告&#34;&gt;去廣告&#xA;&lt;/h3&gt;&lt;p&gt;DNS 層面的去廣告效果有限，重點應該放在防止誤殺上，所以不要用那臭名昭著&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;的號稱自己是「致力於成為中文區命中率最高的廣告過濾列表」的 Anti AD，而是使用一些別的規則。個人使用的規則是 &lt;a class=&#34;link&#34; href=&#34;https://github.com/217heidai/adblockfilters&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;217heidai/adblockfilters&lt;/a&gt;，這是一個已經整理好的聚合規則，直接拉取即可。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;wget -O /etc/smartdns/adblock.conf https://gcore.jsdelivr.net/gh/217heidai/adblockfilters@main/rules/adblocksmartdns.conf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後引入配置檔案：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;conf-file /etc/smartdns/adblock.conf&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;自動更新規則&#34;&gt;自動更新規則&#xA;&lt;/h3&gt;&lt;p&gt;設定如下 Crontab 即可在每天凌晨三點自動更新所有規則。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-crontab&#34;&gt;0 0 3 * * ?  wget -O /etc/smartdns/adblock.conf https://gcore.jsdelivr.net/gh/217heidai/adblockfilters@main/rules/adblocksmartdns.conf&#xA;0 0 3 * * ? wget -O /etc/smartdns/accelerated-domains.china.domain.smartdns.conf https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/accelerated-domains.china.domain.smartdns.conf&#xA;0 0 3 * * ? wget -O /etc/smartdns/apple.china.domain.smartdns.conf https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/apple.china.domain.smartdns.conf&#xA;0 0 3 * * ? wget -O /etc/smartdns/chinalist.domain.smartdns.conf https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/chinalist.domain.smartdns.conf&#xA;0 0 3 * * ? wget -O /etc/smartdns/google.china.domain.smartdns.conf https://gcore.jsdelivr.net/gh/Olixn/china_list_for_smartdns@main/google.china.domain.smartdns.conf&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;旁路由可以用嗎&#34;&gt;旁路由可以用嗎&#xA;&lt;/h3&gt;&lt;p&gt;除非不使用 IPv6，否則最好還是將 OpenWRT 路由器作為主路由。在作為旁路由的情況下，某些系統（説的就是你，Windows）會不遵守旁路由廣播的 IPv4 DNS，而執意使用運營商光貓廣播的 IPv6 DNS 進行解析，我嘗試修改過一些相關的登錄檔鍵值，但毫無作用。無奈只好讓運營商上門將光貓改為橋接模式，並將 OpenWRT 用作主路由。&lt;/p&gt;&#xA;&lt;h2 id=&#34;覆寫-clash-規則&#34;&gt;覆寫 Clash 規則&#xA;&lt;/h2&gt;&lt;p&gt;這時如果你開着 Clash 去跑 DNS 泄露測試，大機率還是會看到你的 DNS 請求被髮到了中國的 DNS 伺服器上——幾乎所有機場的預設配置都會使用騰訊、阿里等國內大廠的加密 DNS，雖然不至於明文泄露到運營商 DNS 而導致你接到反詐中心的電話，但總讓人膈應 &lt;del&gt;（強迫症犯了）&lt;/del&gt;，更有甚者甚至完全沒有相關配置。&lt;/p&gt;&#xA;&lt;p&gt;好在如果使用的是 Clash Verge Rev，那麼可以很方便的覆寫機場的配置，這裏分享我的覆寫配置，將其貼上到全域性擴充套件配置中即可覆寫機場的配置。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;dns:&#xA;  enable: true&#xA;  ipv6: false&#xA;  prefer-h3: true&#xA;  use-system-hosts: true&#xA;  nameserver:&#xA;    - &#34;https://dns.cloudflare.com/dns-query&#34;&#xA;    - &#34;https://dns.sb/dns-query&#34;&#xA;    - &#34;https://dns.google/dns-query&#34;&#xA;    - &#34;https://public.dns.iij.jp/dns-query&#34;&#xA;    - &#34;https://jp.tiar.app/dns-query&#34;&#xA;    - &#34;https://jp.tiarap.org/dns-query&#34;&#xA;  nameserver-policy:&#xA;    &#34;geosite:cn&#34;:&#xA;      - system&#xA;  fallback:&#xA;    - &#34;tls://8.8.4.4&#34;&#xA;    - &#34;tls://1.1.1.1&#34;&#xA;  proxy-server-nameserver:&#xA;    - &#34;https://doh.pub/dns-query&#34;&#xA;    - &#34;https://223.5.5.5/dns-query&#34;&#xA;  direct-nameserver:&#xA;    - system&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-3_hu_92a7537b0aa409b3.webp&#34; alt=&#34;如何修改全域性擴充套件配置&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;配置解析&#34;&gt;配置解析&#xA;&lt;/h3&gt;&lt;p&gt;根據 Mihomo 文件&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;，其 DNS 請求的流程如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TD&#xA;  Start[客户端發起請求] --&gt; rule[匹配規則]&#xA;  rule --&gt;  Domain[匹配到基於域名的規則]&#xA;  rule --&gt; IP[匹配到基於 IP 的規則]&#xA;&#xA;  Domain --&gt; |域名匹配到直連規則|DNS&#xA;  IP --&gt; DNS[透過 Clash DNS 解析域名]&#xA;&#xA;&#xA;  Domain --&gt; |域名匹配到代理規則|Remote[透過代理伺服器解析域名並建立連線]&#xA;&#xA;  Cache --&gt; |Redir-host/FakeIP-Direct 未命中|NS[匹配 nameserver-policy 並查詢 ]&#xA;  Cache --&gt; |Cache 命中|Get&#xA;  Cache --&gt; |FakeIP 未命中,代理域名|Remote&#xA;&#xA;  NS --&gt; |匹配成功| Get[將查詢到的 IP 用於匹配 IP 規則]&#xA;  NS --&gt; |沒匹配到| NF[nameserver/fallback 併發查詢]&#xA;&#xA;  NF --&gt; Get[查詢得到 IP]&#xA;  Get --&gt; |快取 DNS 結果|Cache[(Cache)]&#xA;  Get --&gt; S[透過 IP 直接/透過代理建立連線]&#xA;&#xA;  DNS --&gt; Redir-host/FakeIP&#xA;  Redir-host/FakeIP --&gt; |查詢 DNS 快取|Cache&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中&lt;code&gt;nameserver-policy&lt;/code&gt;的優先順序高於&lt;code&gt;nameserver&lt;/code&gt;和&lt;code&gt;fallback&lt;/code&gt;，指定&lt;code&gt;geosite:cn&lt;/code&gt;中的網站以系統 DNS 查詢，也就是使用之前配置好的 SmartDNS 查詢，可以享受到區域網級別的響應速度和自帶測速的 CDN 選擇。而不在&lt;code&gt;geosite:cn&lt;/code&gt;中的網站則使用&lt;code&gt;nameserver/fallback&lt;/code&gt;查詢，使用國外加密上游就可以確保解析結果的可信並防止 DNS 泄露。&lt;/p&gt;&#xA;&lt;h3 id=&#34;替換-geoip-和-geosite-數據庫&#34;&gt;替換 geoip 和 geosite 數據庫&#xA;&lt;/h3&gt;&lt;p&gt;Mihomo 預設使用 V2Ray 官方的 geoip 和 geosite 數據庫，這個數據庫其實不太全，而且更新的頻率也很慢，所以我還是用 &lt;a class=&#34;link&#34; href=&#34;https://github.com/Loyalsoldier/v2ray-rules-dat&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Loyalsoldier/v2ray-rules-dat&lt;/a&gt; 這個「加強版」數據庫替換了原來的數據庫，只需下載&lt;code&gt;geoip.dat&lt;/code&gt;和&lt;code&gt;geosite.dat&lt;/code&gt;以後丟進核心目錄即可。當然，也可以新增幾行覆寫配置以實現自動/一鍵更新：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;geodata-mode: true&#xA;geox-url:&#xA;  geoip: &#34;https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat&#34;&#xA;  geosite: &#34;https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat&#34;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;clash-meta-for-android&#34;&gt;Clash Meta For Android&#xA;&lt;/h3&gt;&lt;p&gt;對於手機上的 Clash Meta For Android（以下簡稱 Clash），覆寫設定時需要更加考慮手機的實際情況。&lt;/p&gt;&#xA;&lt;p&gt;首先手機上的 Clash 覆寫設定選項就不如桌面端的 Clash Verge Rev 這麼靈活，很多鍵值都不能覆寫。另外，手機不像電腦，需要經常切換網絡環境，這就導致系統 DNS 也會換得很頻繁，經測試，在這種情況下，每次更換網絡環境都需要開關一次 Clash 才能讓其更新&lt;code&gt;system&lt;/code&gt;所代表的 DNS。於是我們只能退而求其次，固定一個國內加密 DNS 作為國內查詢。&lt;/p&gt;&#xA;&lt;p&gt;進入 Clash -&amp;gt;「設定」-&amp;gt;「覆寫」以下是所有覆寫設定：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;「DNS」-&amp;gt;「策略」：強制啓用&lt;/li&gt;&#xA;&lt;li&gt;「DNS」-&amp;gt;「Prefer h3」：已啓用&lt;/li&gt;&#xA;&lt;li&gt;「DNS」-&amp;gt;「Name Server」：新增兩個國外加密 DNS&lt;/li&gt;&#xA;&lt;li&gt;「DNS」-&amp;gt;「Name Server 策略」：在「鍵」一欄中填寫&lt;code&gt;geosite:cn&lt;/code&gt;，值一欄填寫&lt;code&gt;https://doh.pub/dns-query&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;提前從 Github 上下載&lt;code&gt;geoip.dat&lt;/code&gt;和&lt;code&gt;geosite.dat&lt;/code&gt;，最後進入 Clash -&amp;gt;「設定」-&amp;gt;「Meta Features」，分別用「匯入 GeoIP 數據庫」和「匯入 GeoSite 數據庫」功能匯入它們。&lt;/p&gt;&#xA;&lt;h2 id=&#34;完成&#34;&gt;完成&#xA;&lt;/h2&gt;&lt;p&gt;最後再開啓一個 &lt;a class=&#34;link&#34; href=&#34;https://browserleaks.com/dns&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;DNS 泄露測試&lt;/a&gt;，看一看問題是否解決，如果不再出現國內的 DNS，説明配置正確，好好享受 SmartDNS 和 Clash 帶來的網絡最佳化和防泄漏吧~&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/02/what-i-have-done-on-my-dns/image-4_hu_fb37d196f4006eaa.webp&#34; alt=&#34;DNS 不再泄露&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;蔘考自: &lt;a class=&#34;link&#34; href=&#34;https://blog.lololowe.com/posts/8f1e/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://blog.lololowe.com/posts/8f1e/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;SmartDNS 在設計時就考慮到了延遲問題，具體機制可以蔘考「&lt;a class=&#34;link&#34; href=&#34;https://blog.skk.moe/post/i-have-my-unique-dns-setup/#%E4%B8%AD%E5%9C%BA%E4%BC%91%E6%81%AF%EF%BC%9ASmartDNS-%E6%98%AF%E5%A6%82%E4%BD%95%E9%81%BF%E5%85%8D%E5%9B%A0%E6%B5%8B%E9%80%9F%E5%AF%BC%E8%87%B4-DNS-%E8%A7%A3%E6%9E%90%E8%BF%87%E6%85%A2%E7%9A%84&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;中場休息：SmartDNS 是如何避免因測速導致 DNS 解析過慢的&lt;/a&gt;」。&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;有人整理了 &lt;a class=&#34;link&#34; href=&#34;https://github.com/Mosney/anti-anti-AD&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Anti AD 的光榮事蹟&lt;/a&gt;。&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;引用自: &lt;a class=&#34;link&#34; href=&#34;https://wiki.metacubex.one/config/dns/diagram/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://wiki.metacubex.one/config/dns/diagram/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>Windows Hiccup 小日常：處理時間同步服務的問題</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2024/11/windows-ntp-hiccup/</link>
            <pubDate>Mon, 18 Nov 2024 10:03:47 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2024/11/windows-ntp-hiccup/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post Windows Hiccup 小日常：處理時間同步服務的問題&#34; /&gt;&lt;p&gt;不知出了什麼問題，我的電腦的時間從來不會自動和 NTP 伺服器同步，雖然短期內並不會對使用造成什麼影響，但倘若放任不管，時鐘的偏移量太多，則可能會造成 SSL 和 TOTP 等依賴時間戳的應用出現問題，再者，手動按同步鍵也很不方便，今天我決定必須要解決這個問題。&lt;/p&gt;&#xA;&lt;h2 id=&#34;specialpollinterval&#34;&gt;SpecialPollInterval&#xA;&lt;/h2&gt;&lt;p&gt;在網上搜尋一番之後，我發現有人提到&lt;code&gt;SpecialPollInterval&lt;/code&gt;這個鍵值，其具體位置是&lt;code&gt;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient&lt;/code&gt;，微軟官方文件對其的描述如下：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;This entry specifies the special poll interval in seconds for manual peers. When the SpecialInterval 0x1 flag is enabled, W32Time uses this poll interval instead of a poll interval determine by the operating system. The default value on domain members is 3,600. The default value on stand-alone clients and servers is 604,800.&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;對於一般客户端，這個鍵值的預設值是&lt;code&gt;604800&lt;/code&gt;，也就是一個星期同步一次，這個間隔顯然太久，於是我將其設定成了&lt;code&gt;3600&lt;/code&gt;令其一小時同步一次。&lt;/p&gt;&#xA;&lt;h2 id=&#34;w32tm&#34;&gt;w32tm&#xA;&lt;/h2&gt;&lt;p&gt;幾天後，當我再次檢查時間時，卻發現時間仍然沒有自動同步，這一次的偏移量已經達到了 15.8 秒。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/11/windows-ntp-hiccup/Screenshot20241117-1915_hu_13e6b8a28a875d07.webp&#34; alt=&#34;系統時間快了15.8秒&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;於是查詢「SpecialPollInterval」想要知道其具體的作用和未及預期目的的原因，卻發現了微軟的一篇&lt;a class=&#34;link&#34; href=&#34;https://learn.microsoft.com/zh-cn/troubleshoot/windows-server/active-directory/specialpollinterval-polling-interval-time-service-not-correct&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;疑難解答&lt;/a&gt;。這篇疑難解答指出：「每次客户端輪詢時間樣本到 NTP 伺服器時，NTP 客户端都會進入 SPIKE 狀態。 時間服務管理其內部狀態，如果客户端進入 SPIKE 狀態，則客户端不會同步其時間。」&lt;/p&gt;&#xA;&lt;p&gt;為了解決這個問題，需要將 Windows 時間配置為使用 MinPollInterval/MaxPollInterval 作為輪詢間隔。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-powershell&#34;&gt;w32tm /config /update /manualpeerlist:cn.pool.ntp.org /syncfromflags:MANUAL&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;服務尚未啓動&#34;&gt;服務尚未啓動&#xA;&lt;/h2&gt;&lt;p&gt;執行這一行配置時出現了「服務尚未啓動」的提示，這説明用於時間同步的服務根本沒有啓動。如此基礎的服務竟然不會自動開機啓動，我也不知道這是 Windows 的 Bug 還是我後期使用無意間製造的問題，不管怎樣，首先啓動這個服務：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-powershell&#34;&gt;net start w32time&#xA;w32tm /register   # 註冊一些基本的登錄檔鍵值和相關服務&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;隨後 Win + R 執行&lt;code&gt;services.msc&lt;/code&gt;開啓服務管理面板，找到「Windows Time」服務，將其啓動型別設定為「自動」，即可讓其開機自動啓動。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/11/windows-ntp-hiccup/image_hu_521a92b1a7f11576.webp&#34; alt=&#34;將 W32Time 的啓動型別設定為自動&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/11/windows-ntp-hiccup/image-1_hu_36c2133f76139721.webp&#34; alt=&#34;出現「下次同步」字樣即説明成功&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;再次重新啓動電腦，這次開啓「設定」&amp;ndash;&amp;gt;「時間和語言」&amp;ndash;&amp;gt;「日期和時間」&amp;ndash;&amp;gt;「附加時鐘」，切換到「Internet 時間」選項卡，如果出現了「下次同步」的字樣，説明這套系統終於是正常運作了。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>OBS 多路推流折騰記：那些本不必要的麻煩</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2024/09/my-multi-streaming-setup/</link>
            <pubDate>Wed, 18 Sep 2024 06:16:51 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2024/09/my-multi-streaming-setup/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post OBS 多路推流折騰記：那些本不必要的麻煩&#34; /&gt;&lt;p&gt;長話短説，最近我開始直播我的遊戲實況，我並不指望有多少人看，Just, Why not? 再者每個直播平台都會有直播回放。相當於免費儲存我每一次遊戲的錄影，何樂而不為？&lt;/p&gt;&#xA;&lt;p&gt;扯遠了，如你所見，近期我有了多平台同時直播的需求，然而 OBS 本身顯然不支援同時推流，同時也因為不支援設定代理的特點和眾所周知的原因，無法推流到 twitch.tv，於是我開始尋找解決方案。&lt;/p&gt;&#xA;&lt;h2 id=&#34;明確需求&#34;&gt;明確需求&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;多路平台同時直播&lt;/li&gt;&#xA;&lt;li&gt;最好對效能影響小&lt;/li&gt;&#xA;&lt;li&gt;其中一路需要推流需要代理&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;多路推流&#34;&gt;多路推流&#xA;&lt;/h2&gt;&lt;p&gt;多路推流有現成的外掛可用：&lt;a class=&#34;link&#34; href=&#34;https://github.com/sorayuki/obs-multi-rtmp&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Github&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 Release 頁面下載&lt;code&gt;.exe&lt;/code&gt;安裝包，安裝完成後記得在「停靠視窗」選單裏勾選「多路推流」。這時候預設會彈出一個獨立視窗，可以趁這個機會順便調整一下 OBS 的佈局。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/my-multi-streaming-setup/image_hu_b8b674a93b9f86bc.webp&#34; alt=&#34;啓用多路推流面板&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;外掛的設定也沒什麼好説的，用在原版 OBS 的填法在這個外掛裏如法炮製即可。&lt;/p&gt;&#xA;&lt;h3 id=&#34;bilibili-直播姬&#34;&gt;Bilibili 直播姬&#xA;&lt;/h3&gt;&lt;p&gt;莫名其妙，B 站小於 50 粉絲的 Up 主只能使用直播姬開播，其他國內平台做出類似規定者大概也不在少數，啓用第三方推流模式之後，直播面板會顯示推流的配置。此時的不需要按照直播姬給出的推流地址進行配置，因為直播姬莫名其妙的給了一個每次都會變的內網 IP，直接以&lt;code&gt;127.0.0.1&lt;/code&gt;或者&lt;code&gt;localhost&lt;/code&gt;替換即可。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/my-multi-streaming-setup/image-2_hu_71c45766ee560a9.webp&#34; alt=&#34;Bilibili 直播姬的第三方推流模式&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/my-multi-streaming-setup/image-1_hu_17dc4c09eb0ae0af.webp&#34; alt=&#34;外掛的設定&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;推流到-twitch&#34;&gt;推流到 Twitch&#xA;&lt;/h2&gt;&lt;p&gt;推流到 Twitch 則會因為 GFW 多出很多不必要的麻煩。&lt;/p&gt;&#xA;&lt;p&gt;OBS 本身並不支援設定代理，起初我打算用 Clash 的 TAP 模式強制代理 OBS 的流量，而 Clash 的 TAP 並不監聽 rtmp 流量，宣告失敗。我決定直接架設一個轉發伺服器，這個伺服器需要既可以與 Twitch 通訊，又可以不受 GFW 的干擾。&lt;/p&gt;&#xA;&lt;p&gt;在網上查到一些資訊，Caddy 似乎不支援 RTMP 協議，而 &lt;code&gt;nginx-rtmp&lt;/code&gt; 外掛則專門為 RTMP 協議設計。這幾乎是唯一的選擇。&lt;/p&gt;&#xA;&lt;p&gt;部署的前提：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;熟悉基本的 Linux 命令列操作。&lt;/li&gt;&#xA;&lt;li&gt;伺服器已經安裝好&lt;code&gt;docker&lt;/code&gt;和&lt;code&gt;docker compose&lt;/code&gt;外掛。&lt;/li&gt;&#xA;&lt;li&gt;有合適的命令列文字編輯器，比如&lt;code&gt;nvim&lt;/code&gt;或者絕大部分 distro 自帶的&lt;code&gt;nano&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;新建目錄：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mkdir nginx-rtmp &amp;&amp; cd nginx-rtmp&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;建立&lt;code&gt;docker-compose.yml&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;services:&#xA;  nginx-rtmp:&#xA;    image: tiangolo/nginx-rtmp:latest&#xA;    container_name: nginx_rtmp&#xA;    ports:&#xA;      - &#34;1935:1935&#34; # RTMP port&#xA;    volumes:&#xA;      - ./nginx.conf:/etc/nginx/nginx.conf&#xA;    restart: unless-stopped&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;建立&lt;code&gt;nginx.conf&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-nginx&#34;&gt;worker_processes  auto;&#xA;&#xA;events {&#xA;    worker_connections  1024;&#xA;}&#xA;&#xA;rtmp {&#xA;    server {&#xA;        listen 1935;&#xA;        chunk_size 4096;&#xA;&#xA;        application live {&#xA;            live on;&#xA;            push rtmp://live.twitch.tv/app/{Twitch 主直播金鑰};&#xA;        }&#xA;    }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;啓動編排：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;docker compose up -d&#xA;# 老版本 compose 外掛則是 docker-compose up&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;當然，別忘了開放防火牆埠。我的防火牆蔘考了 &lt;a class=&#34;link&#34; href=&#34;https://github.com/chaifeng/ufw-docker#solving-ufw-and-docker-issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;To Fix The Docker and UFW Security Flaw Without Disabling Iptables&lt;/a&gt; 一文中提到的配置，相應地，開放埠的命令如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;ufw route allow proto tcp from any to any port 1935&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;配置完成後，OBS 內的推流目標地址填入&lt;code&gt;rtmp://伺服器ip/live&lt;/code&gt;，推流碼填寫任意值均可。設定完成後即可開始推流。&lt;/p&gt;&#xA;&lt;h3 id=&#34;netch&#34;&gt;Netch&#xA;&lt;/h3&gt;&lt;p&gt;如果沒有伺服器，亦可以使用 Netch 代理 OBS 程序進行推流。&lt;/p&gt;&#xA;&lt;p&gt;首先下載 Netch 1.9.2 版本，注意一定要是 1.9.2 版本。新增一個程序模式，將 OBS 資料夾加入，隨後啓用該程序模式的代理即可。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/my-multi-streaming-setup/image-3_hu_fab77139607785da.webp&#34; alt=&#34;建立一個程序模式&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;尾聲&#34;&gt;尾聲&#xA;&lt;/h2&gt;&lt;p&gt;這次為了在同時在 Twitch 和 B 站上推流，遇到了很多原本不必要的麻煩。我可以怪 OBS 沒有內建代理功能，也可以怪 Clash Verge 等代理工具不支援 RTMP，轉來轉去，最終要怪的，還得是 GFW。雖然最後的結果還算令人滿意，僅僅為了推流而折騰這些東西的體驗實在是稱不上良好。也許我今後我應該去研究修改 Mihomo 核心，讓其支援 RTMP 協議，亦或是自己寫一套獨立的實現單獨轉發 OBS 的流量，不論如何，在這片土地上，想要暢快的直播，道阻且長。&lt;/p&gt;&#xA;&lt;p&gt;最後，歡迎關注我的 Twitch 頻道: &lt;a class=&#34;link&#34; href=&#34;https://www.twitch.tv/powerfullz233&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://www.twitch.tv/powerfullz233&lt;/a&gt;&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>docker-mailserver 郵件伺服器搭建記錄</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2024/09/docker-mailserver-deployment-recap/</link>
            <pubDate>Fri, 06 Sep 2024 03:57:18 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2024/09/docker-mailserver-deployment-recap/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post docker-mailserver 郵件伺服器搭建記錄&#34; /&gt;&lt;p&gt;某天早上醒來，發現收件箱裏多了封郵件，通知我的郵箱在韓國登入，當時認為只是偶爾的 IP 誤判，也就沒有多想。可接下來幾天，時不時又有新的郵件進來，而且每次 IP 都不一樣，這下可就有些問題了，再不採取行動，怕不是郵箱真的要被拿去羣發郵件。於是趕緊刪掉了域名的 MX、SPF、DMARC 記錄，尋找新的解決方案。&lt;/p&gt;&#xA;&lt;p&gt;我原本只是想改改密碼，結果呢，騰訊企業郵箱改密碼的入口真的巨能藏，到處都找不到。算了，遷移，何必受這氣。&lt;/p&gt;&#xA;&lt;p&gt;於是就有了這篇文章，從最開始的開放防火牆埠開始，到最後的最佳化送達率，我將分享我搭建 docker-mailserver 郵件伺服器的經驗，希望能幫你少踩些坑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;搭建-docker-mailserver-郵件伺服器前的準備&#34;&gt;搭建 docker-mailserver 郵件伺服器前的準備&#xA;&lt;/h2&gt;&lt;h3 id=&#34;防火牆的處理&#34;&gt;防火牆的處理&#xA;&lt;/h3&gt;&lt;p&gt;首先先開放防火牆的郵件服務常用埠，分別是&lt;code&gt;25&lt;/code&gt;、&lt;code&gt;143&lt;/code&gt;、&lt;code&gt;465&lt;/code&gt;、&lt;code&gt;587&lt;/code&gt;、&lt;code&gt;993&lt;/code&gt;，各分支開放埠的操作不同，請自行谷歌或詢問 AI，以 Ubuntu 使用的&lt;code&gt;ufw&lt;/code&gt;為例：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;ufw allow 25&#xA;ufw allow 143&#xA;ufw allow 465&#xA;ufw allow 587&#xA;ufw allow 993&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我的防火牆比較特殊，用到了&lt;code&gt;ufw&lt;/code&gt;和 &lt;a class=&#34;link&#34; href=&#34;https://github.com/chaifeng/ufw-docker#solving-ufw-and-docker-issues&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;To Fix The Docker and UFW Security Flaw Without Disabling Iptables&lt;/a&gt; 一文中提到的配置。所以當我想要把 Docker 容器的埠暴露在外時需要做出額外的配置。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;# 開放郵件伺服器所需的埠&#xA;ufw route allow proto tcp from any to any port 25&#xA;ufw route allow proto tcp from any to any port 143&#xA;ufw route allow proto tcp from any to any port 465&#xA;ufw route allow proto tcp from any to any port 587&#xA;ufw route allow proto tcp from any to any port 993&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;驗證你的伺服器是否具備搭建條件&#34;&gt;驗證你的伺服器是否具備搭建條件&#xA;&lt;/h3&gt;&lt;p&gt;很多伺服器，尤其是各種廉價的 VPS，並不適合搭建 docker-mailserver，各大郵件服務商為了過濾垃圾郵件，索性將所有曾經有過 Spam 行為的 IP 全部列入黑名單。如果你的 IP 被某個 Spammer 使用過，而恰好又被你的伺服器提供商分配給了你，而你折騰了幾個小時的郵件伺服器卻愣是收不到郵件，最後發現竟是 IP 被列入黑名單的原因，我不知道你會作何感想。&lt;/p&gt;&#xA;&lt;p&gt;有的伺服器提供商的 IP 乍一看確實不在郵件黑名單中，但實際上搭建好之後還是無法傳送郵件，為什麼？因為伺服器提供商擔心 IP 被濫用，索性將郵件服務的埠全都封鎖了。&lt;/p&gt;&#xA;&lt;p&gt;使用如下指令碼檢測你的伺服器是否具備搭建郵件伺服器的條件：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;bash &lt;(curl -sL IP.Check.Place)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image-3_hu_6dacc5e9abb4b1ca.webp&#34; alt=&#34;不能搭建郵件伺服器&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image-4_hu_fb1b1c9dd78cde41.webp&#34; alt=&#34;可以搭建郵件伺服器&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;如果在這一步發現你的伺服器不適合搭建甚至不能搭建&lt;code&gt;docker-mailserver&lt;/code&gt;，那就趁早打住吧，想辦法換一個更乾淨、限制更少的 IP 再説。&lt;/p&gt;&#xA;&lt;h2 id=&#34;搭建過程&#34;&gt;搭建過程&#xA;&lt;/h2&gt;&lt;h3 id=&#34;拉取配置檔案&#34;&gt;拉取配置檔案&#xA;&lt;/h3&gt;&lt;p&gt;docker-mailserver 需要配置的配置檔案有兩個，&lt;code&gt;compose.yaml&lt;/code&gt;和&lt;code&gt;mailserver.env&lt;/code&gt;，分別拉取配置檔案：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;mkdir mailserver &amp;&amp; cd mailserver&#xA;sudo apt install wget&#xA;wget -O compose.yaml &#34;https://raw.githubusercontent.com/docker-mailserver/docker-mailserver/master/compose.yaml&#34;&#xA;wget -O mailserver.env &#34;https://github.com/docker-mailserver/docker-mailserver/blob/master/mailserver.env&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;根據需求，可以修改不同的配置，下面是我修改的部分：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;POSTMASTER_ADDRESS=webmaster@l3zc.com&#xA;TZ=Asia/Shanghai&#xA;SSL_TYPE=manual&#xA;SSL_CERT_PATH=/certs/cert.crt&#xA;SSL_KEY_PATH=/certs/cert.key&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;用-caddy-準備和自動維護-tls-證書&#34;&gt;用 Caddy 準備和自動維護 TLS 證書&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&#xA;&lt;/h3&gt;&lt;p&gt;因為我已經在使用 Caddy，所以我這次就打算直接使用 Caddy 來自動維護證書。根據專案的官方文件，我只需要在 Caddyfile 裏新增一個子域名，Caddy 就可以自動幫我維護證書。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-caddyfile&#34;&gt;mail.example.com {&#xA;  tls internal {&#xA;    # ?? 這不是直接生成的內部證書麼&#xA;    key_type rsa2048&#xA;  }&#xA;&#xA;  # Optional, can be useful for troubleshooting&#xA;  # connection to Caddy with correct certificate:&#xA;  respond &#34;Hello DMS&#34;&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;當我更新完 DNS 記錄，實際操作起來發現，我的情況比較特殊：我這台伺服器上並沒有用到 Caddy 的自動申請證書功能，而是使用了15年有效期的泛域名 Cloudflare Origin Certificate。即使我不為這個子域名指定證書檔案，Caddy 也會在載入這張泛域名證書後認為無需再申請新的證書。這就很尷尬了，用 Caddy 的時候 Cloudflare Origin Certificate 和郵件伺服器只能二選一。只好安裝了&lt;code&gt;dns.providers.cloudflare&lt;/code&gt;，並放棄使用 Cloudflare Origin Certificate，轉而讓 Caddy 自動為每個子域名申請和維護 TLS/SSL 證書，反正都是自動的，眼不見心不煩。&lt;/p&gt;&#xA;&lt;p&gt;安裝&lt;code&gt;dns.providers.cloudflare&lt;/code&gt;後的全域性配置：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-caddyfile&#34;&gt;{&#xA;        acme_dns cloudflare {API_KEY}&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最後把 Caddy 的證書儲存位置對映到 docker-mailserver 容器內。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;volumes:&#xA;  - /home/user/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/yourdomain.tld/:/certs/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果 Caddy 以 root 用戶執行，則證書的位置應當為&lt;code&gt;/root/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/yourdomain.tld/&lt;/code&gt;，做出相應的修改即可。&lt;/p&gt;&#xA;&lt;p&gt;然後就是之前提到過的配置，我將證書儲存位置對映到了容器內的&lt;code&gt;/certs/&lt;/code&gt;目錄，所以配置為：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;SSL_CERT_PATH=/certs/cert.crt&#xA;SSL_KEY_PATH=/certs/cert.key&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;首次啓動容器&#34;&gt;首次啓動容器&#xA;&lt;/h3&gt;&lt;p&gt;首次啓動容器需要立即（120 秒內）建立新的 Postmaster 賬號。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose up -d&#xA;docker exec -it &lt;CONTAINER NAME&gt; setup email add &lt;postmaster@yourdomain.tld&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;最佳化送達率&#34;&gt;最佳化送達率&#xA;&lt;/h2&gt;&lt;h3 id=&#34;dns-記錄&#34;&gt;DNS 記錄&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;一條 A 記錄，名稱隨意（假設為&lt;code&gt;mail&lt;/code&gt;），指向伺服器 IP（Cloudflare 需使用「僅 DNS」）&lt;/li&gt;&#xA;&lt;li&gt;一條 MX 記錄，Apex 域（@），指向&lt;code&gt;mail.yourdomain.tld&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;一條 TXT 記錄（SPF），Apex 域（@），可以在&lt;a class=&#34;link&#34; href=&#34;https://mxtoolbox.com/SPFRecordGenerator.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;這裏&lt;/a&gt;生成(可選)。&lt;/li&gt;&#xA;&lt;li&gt;一條 TXT 記錄（DMARC），名稱&lt;code&gt;_dmarc&lt;/code&gt;，可以在&lt;a class=&#34;link&#34; href=&#34;https://mxtoolbox.com/DMARCRecordGenerator.aspx&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;這裏&lt;/a&gt;生成（可選）。&lt;/li&gt;&#xA;&lt;li&gt;一條 TXT 記錄（DKIM），名稱&lt;code&gt;mail._domainkey&lt;/code&gt;，具體配置在後文（可選）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;dkim-spf-和-dmarc&#34;&gt;DKIM, SPF 和 DMARC&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&#xA;&lt;/h3&gt;&lt;p&gt;什麼是 DKIM，SPF 和 DMARC？簡單來説，DKIM 是一個數字簽名機制；SPF 類似於「員工名單」，記錄所有合法的發件伺服器；DMARC 則用於指示收件方的伺服器如何處理未透過 DKIM 和 SPF 驗證的郵件。&lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;首先設定 DKIM，在伺服器上生成公私鑰對。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker exec -it &lt;CONTAINER NAME&gt; setup config dkim&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;生成後的公私鑰對可以在對映的容器目錄&lt;code&gt;./docker-data/dms/config/opendkim/keys/&lt;/code&gt;下找到。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image_hu_1f64fffc01f8db13.webp&#34; alt=&#34;mail.txt 便是公鑰的 DNS Zone file&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image-1_hu_d6c86630e3947c78.webp&#34; alt=&#34;Cloudflare 的匯入入口&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;下載 mail.txt（複製其內所有內容貼上到本地檔案也可以），將其匯入到 Cloudflare Dashboard 即可完成 DKIM 設定。需要注意配置完成 DKIM 後需要重啓容器才能生效。&lt;sup id=&#34;fnref:4&#34;&gt;&lt;a href=&#34;#fn:4&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose up -d --force-recreate&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;前面提到 SPF 相當於一個「員工名單」，既然我合法的發件伺服器只有一台，那麼 DNS 填寫如下設定即可。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code&gt;&#34;v=spf1 mx ~all&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;再就是 DMARC，可以使用前面提到的模板生成，這裏不再贅述。&lt;/p&gt;&#xA;&lt;p&gt;如果你的域名服務商擁有自己的設定嚮導（例如 Cloudflare），亦可以使用它們簡化設定流程。&lt;/p&gt;&#xA;&lt;h2 id=&#34;客户端設定&#34;&gt;客户端設定&#xA;&lt;/h2&gt;&lt;p&gt;客户端設定相對就很簡單了，IMAP 和 SMTP 伺服器都是&lt;code&gt;mail.yourdomain.ltd&lt;/code&gt;，開啓 SSL 後埠分別是 465 和 993，登入即可。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image-2_hu_51756253bf099359.webp&#34; alt=&#34;設定示例&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;善用-mailtester&#34;&gt;善用 MailTester&#xA;&lt;/h2&gt;&lt;p&gt;至此我們已經完成了搭建 docker-mailserver 郵件伺服器的整個過程，在開始傳送郵件之前，我們可以使用 &lt;a class=&#34;link&#34; href=&#34;https://www.mail-tester.com/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;MailTester&lt;/a&gt; 測試我們的配置是否正確。如果測試結果是 10/10，那麼我們的 docker-mailserver 郵件伺服器應該會擁有漂亮的送達率，好好享受吧。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/09/docker-mailserver-deployment-recap/image-5_hu_6de856f3e3b52ca0.webp&#34; alt=&#34;完美的評分&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;如果不是 10/10，也不要着急，認真檢視扣分的原因，對症下藥，一項一項解決即可。&lt;/p&gt;&#xA;&lt;h2 id=&#34;todo-list&#34;&gt;TODO-List&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 配套 WebUI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://docker-mailserver.github.io/docker-mailserver/latest/config/security/ssl/#caddy&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://docker-mailserver.github.io/docker-mailserver/latest/config/security/ssl/#caddy&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;蔘考: &lt;a class=&#34;link&#34; href=&#34;https://docker-mailserver.github.io/docker-mailserver/latest/config/best-practices/dkim_dmarc_spf/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://docker-mailserver.github.io/docker-mailserver/latest/config/best-practices/dkim_dmarc_spf/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;更加具體的介紹: &lt;a class=&#34;link&#34; href=&#34;https://www.cloudflare.com/learning/email-security/dmarc-dkim-spf/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;https://www.cloudflare.com/learning/email-security/dmarc-dkim-spf/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:4&#34;&gt;&#xA;&lt;p&gt;在&lt;a class=&#34;link&#34; href=&#34;https://docker-mailserver.github.io/docker-mailserver/latest/config/best-practices/dkim_dmarc_spf/#generating-keys&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;官方文件&lt;/a&gt;中有提及。&amp;#160;&lt;a href=&#34;#fnref:4&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>Firefish 數據庫升級記錄</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2024/08/upgrading-firefish-database-docker/</link>
            <pubDate>Fri, 30 Aug 2024 04:45:12 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2024/08/upgrading-firefish-database-docker/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post Firefish 數據庫升級記錄&#34; /&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://social.l3zc.com&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;我的 Firefish 例項&lt;/a&gt;搭建於去年的 11 月，使用的數據庫版本自然不是最新的，確切的説，是 PGroonga 12，一個基於 5 年前的 Postgres 的遠古版本。為了避免今後的相容性問題和安全問題，同時為了更好的效能，今天這數據庫是非升級不可。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/08/upgrading-firefish-database-docker/image_hu_49fb33e91bcaa665.webp&#34; alt=&#34;PostgreSQL 12 是在 2019 年釋出的&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;升級一個用 Docker 跑起來的數據庫和升級其他的 Docker 容器有很大不同，並不是拉取一個新的映象就可以宣告結束。因為 Postgres 幾乎每個大版本都有 Breaking Changes，新老版本產生的持久化檔案並不相容，如果直接拉取一個新的映象執行，數據庫是無法啓動的，必須要採用一定的手段進行資料的遷移。&lt;/p&gt;&#xA;&lt;p&gt;Postgres 有官方的升級工具&lt;code&gt;pg_upgrade&lt;/code&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;，這一次我不採用，因為我的數據庫跑了一年多，而且用的還是 5 年前的老版本，用這個工具我不確定會不會出問題。這次遷移，大致思路是先匯出 SQL，再將匯出的 SQL 匯入新版本。&lt;/p&gt;&#xA;&lt;h2 id=&#34;升級前的部署概況&#34;&gt;升級前的部署概況&#xA;&lt;/h2&gt;&lt;p&gt;以下是一些升級前需要了解的配置資訊：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;專案&lt;/th&gt;&#xA;          &lt;th&gt;配置&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;例項部署方式&lt;/td&gt;&#xA;          &lt;td&gt;Docker Compose&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;數據庫容器名稱&lt;/td&gt;&#xA;          &lt;td&gt;firefish_db&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;升級前的數據庫容器映象&lt;/td&gt;&#xA;          &lt;td&gt;groonga/pgroonga:3.1.9-alpine-12-slim&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;數據庫用戶&lt;/td&gt;&#xA;          &lt;td&gt;example-firefish-user&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;數據庫名稱&lt;/td&gt;&#xA;          &lt;td&gt;firefish&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Docker Compose 的數據庫部分如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;db:&#xA;  restart: unless-stopped&#xA;  image: groonga/pgroonga:3.1.9-alpine-12-slim&#xA;  container_name: firefish_db&#xA;  networks:&#xA;    - calcnet&#xA;  env_file:&#xA;    - .config/docker.env&#xA;  volumes:&#xA;    - ./db:/var/lib/postgresql/data&#xA;  healthcheck:&#xA;    test: pg_isready --user=&#34;$${POSTGRES_USER}&#34; --dbname=&#34;$${POSTGRES_DB}&#34;&#xA;    interval: 5s&#xA;    timeout: 5s&#xA;    retries: 5&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;匯出當前數據庫&#34;&gt;匯出當前數據庫&#xA;&lt;/h2&gt;&lt;p&gt;對數據庫進行升級之前，首先下線 Firefish 的編排：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose down&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;單獨啓動數據庫容器，匯出當前數據庫為 SQL：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose up -d db&#xA;docker exec -it firefish_db pg_dumpall -U example-firefish-user &gt; backup.sql&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;由於 Firefish 的數據庫比較大，匯出過程可能需要很長一段時間，比如我的個人例項就用了十幾分鍾。&lt;/p&gt;&#xA;&lt;h2 id=&#34;匯出檔案的處理&#34;&gt;匯出檔案的處理&#xA;&lt;/h2&gt;&lt;p&gt;可能是由於新版的 Postgres 認證方式有所變更，如果直接向新數據庫匯入之前匯出的&lt;code&gt;backup.sql&lt;/code&gt;檔案，就會改變新數據庫的 Authentication Scheme，導致之後 Firefish 連線數據庫時認證失敗。要避免這個問題需要對目前的&lt;code&gt;backup.sql&lt;/code&gt;進行一些處理，只抽取出其中的&lt;code&gt;firefish&lt;/code&gt;數據庫的部分，而不是直接匯入所有資料。&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;#!/bin/bash&#xA;[ $# -lt 2 ] &amp;&amp; { echo &#34;Usage: $0 &lt;postgresql dump&gt; &lt;dbname&gt;&#34;; exit 1; }&#xA;sed  &#34;/connect.*$2/,\$!d&#34; $1 | sed &#34;/PostgreSQL database dump complete/,\$d&#34;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;編輯一個 Shell 指令碼為以上內容，儲存至&lt;code&gt;script.sh&lt;/code&gt;，用以處理目前的&lt;code&gt;backup.sql&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;nvim script.sh  # 或者任何你喜歡的編輯器&#xA;chmod +x script.sh&#xA;./script.sh backup.sql firefish &gt;&gt; upgrade.sql&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果一切順利，當前目錄下就會出現一個名為&lt;code&gt;upgrade.sql&lt;/code&gt;的檔案，可以開啓它看一下，確保其被正確匯出。&lt;/p&gt;&#xA;&lt;h2 id=&#34;向新數據庫匯入現有資料&#34;&gt;向新數據庫匯入現有資料&#xA;&lt;/h2&gt;&lt;p&gt;修改&lt;code&gt;docker-compose.yml&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;db:&#xA;  restart: unless-stopped&#xA;  image: groonga/pgroonga:3.2.2-alpine-16-slim # 最新的容器&#xA;  container_name: firefish_db&#xA;  networks:&#xA;    - calcnet&#xA;  env_file:&#xA;    - .config/docker.env&#xA;  volumes:&#xA;    - ./database:/var/lib/postgresql/data # 注意這一行的變動&#xA;  healthcheck:&#xA;    test: pg_isready --user=&#34;$${POSTGRES_USER}&#34; --dbname=&#34;$${POSTGRES_DB}&#34;&#xA;    interval: 5s&#xA;    timeout: 5s&#xA;    retries: 5&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意數據庫目錄對映配置由&lt;code&gt;./db:/var/lib/postgresql/data&lt;/code&gt;變為&lt;code&gt;./database:/var/lib/postgresql/data&lt;/code&gt;，這麼做是為了給新的數據庫一個 Fresh Start，同時也儲存老的持久化資料，即使出現問題，也可以隨時用回老的數據庫。&lt;/p&gt;&#xA;&lt;p&gt;拉取並啓動新容器：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose pull&#xA;docker compose up db -d&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;向新數據庫匯入&lt;code&gt;upgrade.sql&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;cat upgrade.sql | docker exec -i firefish_db psql -U example-firefish-user -d firefish&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;取決於數據庫的大小，匯入過程也會持續較長的時間。&lt;/p&gt;&#xA;&lt;h2 id=&#34;收尾工作&#34;&gt;收尾工作&#xA;&lt;/h2&gt;&lt;p&gt;匯入完成，啓動整個編排：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;docker compose stop db&#xA;docker compose up&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;匯入後的首次啓動不建議帶&lt;code&gt;-d&lt;/code&gt;引數，建議不帶引數啓動，確保啓動過程沒有問題後再以&lt;code&gt;-d&lt;/code&gt;引數啓動。&lt;/p&gt;&#xA;&lt;p&gt;最後，登入剛剛啓動的 Firefish 例項，檢查是否有任何資料損失，沒有問題的話就大功告成啦🎉&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;官方文件：https://www.postgresql.org/docs/current/pgupgrade.html&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;蔘考：https://thomasbandt.com/postgres-docker-major-version-upgrade&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>科學上網：用 Caddy 反向代理 VLESS</title>
            <link>https://blog.l3zc.com/zh-hant-hk/2024/08/caddy-vless-proxy/</link>
            <pubDate>Tue, 13 Aug 2024 08:24:26 +0000</pubDate>
            <guid>https://blog.l3zc.com/zh-hant-hk/2024/08/caddy-vless-proxy/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/&#34; alt=&#34;Featured image of post 科學上網：用 Caddy 反向代理 VLESS&#34; /&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2024/08/aria2-downloading-server/&#34; &gt;上一篇文章&lt;/a&gt;提到，我搭建了一個基於 Aria2 的 BT 離線下載伺服器。為了用 Caddy 反向代理部署好的容器，我把原來偷懶用一鍵指令碼部署的 Trojan 給解除安裝了，問就是因為這指令碼把 80 和 443 埠都佔用了，不解除安裝掉根本沒法繼續。&lt;/p&gt;&#xA;&lt;p&gt;於是離線下載伺服器是搭建好了，可時不時需要的代理卻不得不下線。仔細一想，之前看到過有人 Cloudflare + V2Ray + WS 復活被牆的 VPS，既然是 WebSocket，還能用 Cloudflare 反代，那用 Caddy 反代又有何不可呢？況且 Caddy 還有自動 TLS，比起 Nginx + Certbot 的組合配置起來肯定更簡單。只要配置成功，我就可以在為 Caddy 留住 443 埠的同時跑代理了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;安裝-vless-和-caddy&#34;&gt;安裝 VLESS 和 Caddy&#xA;&lt;/h2&gt;&lt;p&gt;安裝VLESS 可以直接使用 &lt;a class=&#34;link&#34; href=&#34;https://github.com/v2fly/fhs-install-v2ray&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;v2fly/fhs-install-v2ray&lt;/a&gt; 一鍵指令碼：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;# 安裝執行檔和 .dat 資料檔&#xA;bash &lt;(curl -L https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Caddy 的安裝請蔘考&lt;a class=&#34;link&#34; href=&#34;https://caddyserver.com/docs/install&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;官方教程&lt;/a&gt;，例如，我使用 Debian 12，則使用以下命令：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl&#xA;curl -1sLf &#39;https://dl.cloudsmith.io/public/caddy/stable/gpg.key&#39; | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg&#xA;curl -1sLf &#39;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt&#39; | sudo tee /etc/apt/sources.list.d/caddy-stable.list&#xA;sudo apt update&#xA;sudo apt install caddy&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;配置-vless&#34;&gt;配置 VLESS&#xA;&lt;/h2&gt;&lt;p&gt;編輯&lt;code&gt;/usr/local/etc/v2ray/config.json&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-json&#34;&gt;{&#xA;  &#34;log&#34;: {&#xA;    &#34;access&#34;: &#34;/var/log/v2ray/access.log&#34;,&#xA;    &#34;error&#34;: &#34;/var/log/v2ray/error.log&#34;,&#xA;    &#34;loglevel&#34;: &#34;warning&#34;&#xA;  },&#xA;  &#34;inbounds&#34;: [&#xA;    {&#xA;      &#34;port&#34;: 1234, //任意埠&#xA;      &#34;listen&#34;: &#34;127.0.0.1&#34;,&#xA;      &#34;protocol&#34;: &#34;vless&#34;,&#xA;      &#34;settings&#34;: {&#xA;        &#34;clients&#34;: [&#xA;          {&#xA;            &#34;id&#34;: &#34;super-random-uuid&#34;, //隨機生成一個 UUID 替換即可&#xA;            &#34;level&#34;: 0,&#xA;            &#34;email&#34;: &#34;example@example.com&#34;&#xA;          }&#xA;        ],&#xA;        &#34;decryption&#34;: &#34;none&#34;&#xA;      },&#xA;      &#34;streamSettings&#34;: {&#xA;        &#34;network&#34;: &#34;ws&#34;,&#xA;        &#34;security&#34;: &#34;none&#34;,&#xA;        &#34;wsSettings&#34;: {&#xA;          &#34;path&#34;: &#34;/&#34; // 需要與之後的 Caddy 配置保持相同&#xA;        }&#xA;      }&#xA;    }&#xA;  ],&#xA;  &#34;outbounds&#34;: [&#xA;    {&#xA;      &#34;protocol&#34;: &#34;freedom&#34;&#xA;    }&#xA;  ]&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;編輯完成後儲存退出即可。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置-caddy&#34;&gt;配置 Caddy&#xA;&lt;/h2&gt;&lt;p&gt;在你喜歡的位置建立一個 Caddyfile，或者編輯已有的 Caddyfile，加入如下內容，反向代理剛才在 VLESS 配置檔案中設定的埠：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-caddyfile&#34;&gt;yourdomain.com {&#xA;        # 用一個 Matcher 匹配所有指定路徑的 Websocket 請求&#xA;        @websockets {&#xA;                path /      # 與前面 VLESS 的 path 保持一致&#xA;                header Connection Upgrade&#xA;                header Upgrade websocket&#xA;        }&#xA;        reverse_proxy @websockets :1234&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;至此，服務端所有配置檔案都編輯完畢。&lt;/p&gt;&#xA;&lt;h2 id=&#34;啓動服務&#34;&gt;啓動服務&#xA;&lt;/h2&gt;&lt;p&gt;啓動 VLESS，並設定開機自啓動：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;systemtcl enable v2ray &amp;&amp; systemctl start v2ray&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;啓動 Caddy/更新 Caddy 配置：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;caddy start&#xA;caddy reload  # 更新配置用&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以上操作全部完成後，Caddy 反向代理 VLESS 就完成了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;客户端設定&#34;&gt;客户端設定&#xA;&lt;/h2&gt;&lt;p&gt;客户端方面需要手動設定：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;地址是繫結給 VLESS 的域名。&lt;/li&gt;&#xA;&lt;li&gt;埠是 443&lt;/li&gt;&#xA;&lt;li&gt;TLS 開啓&lt;/li&gt;&#xA;&lt;li&gt;傳輸方式選擇 websocket&lt;/li&gt;&#xA;&lt;li&gt;UUID 是之前填入 VLESS 配置檔案的 UUID&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2024/08/caddy-vless-proxy/IMG_0003_hu_844bce19772c475.webp&#34; alt=&#34;Shadowrocket 設定&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;所有的客户端設定大同小異，至於 Clash 的配置檔案，可以蔘考 &lt;a class=&#34;link&#34; href=&#34;https://wiki.metacubex.one/config/proxies/vless/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Mihomo 文件&lt;/a&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;，以下是我的示例配置檔案：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;proxies:&#xA;  - name: &#34;A Random Name&#34;&#xA;    type: vless&#xA;    server: yourdomain.com&#xA;    port: 443&#xA;    udp: true&#xA;    uuid: super-random-uuid&#xA;    flow: xtls-rprx-vision&#xA;    packet-encoding: xudp&#xA;&#xA;    tls: true&#xA;    servername: yourdomain.com&#xA;    alpn:&#xA;      - h2&#xA;      - http/1.1&#xA;    skip-cert-verify: false&#xA;&#xA;    network: ws&#xA;&#xA;    smux:&#xA;      enabled: false&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;需要生成 Clash 配置檔案可以使用 &lt;a class=&#34;link&#34; href=&#34;https://v2rayse.com/clash-template/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;V2RaySE 提供的工具&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;完成&#34;&gt;完成&#xA;&lt;/h2&gt;&lt;p&gt;好了，現在我們已經擁有了一個 VLESS 伺服器，Caddy 會自動為我們申請和維護 TLS 證書，非常好用。&lt;/p&gt;&#xA;&lt;p&gt;只需要這麼小小折騰一下，我彷彿又找到了當年用一鍵指令碼搭建 SSR 時的愉悦，好好享受這種能順利開啓 google.com 時的興奮吧。&lt;/p&gt;&#xA;&lt;h2 id=&#34;todo-list&#34;&gt;TODO List&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;input checked=&#34;&#34; disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 基本搭建&lt;/li&gt;&#xA;&lt;li&gt;&lt;input disabled=&#34;&#34; type=&#34;checkbox&#34;&gt; 偽裝&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;畢竟繼承 Clash Meta 衣缽的 Mihomo 也算是 Clash 正統了。&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item></channel>
</rss>
