<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>亂筆</title>
        <link>https://blog.l3zc.com/</link>
        <description>Recent content on 亂筆</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language><atom:link href="https://blog.l3zc.com/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Terraform IaC 初体验</title>
            <link>https://blog.l3zc.com/2026/04/iac-with-terraform/</link>
            <pubDate>Thu, 09 Apr 2026 15:13:35 +0800</pubDate>
            <guid>https://blog.l3zc.com/2026/04/iac-with-terraform/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2026/04/iac-with-terraform/cover_hu_a8e83f97ed61569c.webp&#34; alt=&#34;Featured image of post Terraform IaC 初体验&#34; /&gt;&lt;p&gt;Terraform 是一款 IaC 工具，所谓 IaC 就是「基础设施即代码」，将我们的基础设施以声明式的代码写出来，随后使用&lt;code&gt;terraform apply&lt;/code&gt;即可完成基础设施的部署，同一份配置，部署出来的一定是一模一样的基础设施（Nix OS 用户狂喜）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要用-terraform&#34;&gt;为什么要用 Terraform&#xA;&lt;/h2&gt;&lt;p&gt;传统的基础设施管理绝大部分基于人力和各种云服务商的 Dashboard，这就带来了下面这些痛点：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th style=&#34;text-align: left&#34;&gt;痛点&lt;/th&gt;&#xA;          &lt;th style=&#34;text-align: left&#34;&gt;说明&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;难以重现&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;通过 Dashboard 点点点进行配置，容易改错或者改漏，而且难以复现&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;环境漂移&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;手动操作导致生产和测试环境配置逐渐偏离，导致极端情况下测试没问题生产直接崩&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;难以扩展&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;新增一套环境需要重复大量手工操作，耗时且容易出错&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;难以审计&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;没有变更记录，&lt;del&gt;出了事不好甩锅&lt;/del&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;&lt;strong&gt;难以协作&lt;/strong&gt;&lt;/td&gt;&#xA;          &lt;td style=&#34;text-align: left&#34;&gt;基础设施由少数「懂的人」掌控，谁想要改都得去找这些人，效率低&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&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;的概念被提了出来，Terraform 就是其中一个著名的解决方案。&lt;/p&gt;&#xA;&lt;p&gt;假设一个现实的使用场景，例如你每年都会购买新的 GCP 的 $300 试用金账号，虽然便宜，但是每年都要重新跑到 GCP 的面板里开机器。而有了 Terraform，想要部署同样配置的机器，只要在每次更换账号之后，将 API Token 替换成新的，随后&lt;code&gt;terraform apply&lt;/code&gt;，只需要几分钟就能开出和你上个账号一模一样的机器、VPC、S3、防火墙配置等等。&lt;/p&gt;&#xA;&lt;p&gt;再比如 Cloudflare DNS 和 Tunnel 的管理和迁移，也只需要将原 Tunnel 的 Ingress Rule 复制到新 Tunnel 的 Ingress Rule。即使将来要迁移到 AliDNS、Route 53 等其他服务商，我们也可以原封不动的将数据复制过去&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;p&gt;尤其是到了多人协作的时候，配合 Git，每次更改都有迹可循，更不需要担心合并冲突，PR 可以自动生成更改预览，出现问题可以立刻回滚到上一个版本，这些都是传统依赖人力去直接操作服务提供商 Dashboard 的做法完全无法做到的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;terraform-的安装&#34;&gt;Terraform 的安装&#xA;&lt;/h2&gt;&lt;p&gt;Terraform 是用 Go 写的，编译出来的产物自然也是单个可执行文件，所以安装起来也非常容易，Windows 下可以直接使用 Winget 安装：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-pwsh&#34;&gt;winget install Hashicorp.Terraform&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果不想使用 Winget，也可以使用 Scoop 等其他包管理器，或者将预编译的二进制文件放入&lt;code&gt;$PATH&lt;/code&gt;，即可完成安装。&lt;/p&gt;&#xA;&lt;p&gt;如果你在 Linux 环境下，则使用对应的包管理器安装即可，如果使用将二进制文件放入&lt;code&gt;$PATH&lt;/code&gt;的安装方法，则要记得&lt;code&gt;sudo chmod +x terraform&lt;/code&gt;赋予文件的执行权限。&lt;/p&gt;&#xA;&lt;h2 id=&#34;terraform-的两个基本概念&#34;&gt;Terraform 的两个基本概念&#xA;&lt;/h2&gt;&lt;h3 id=&#34;providers&#34;&gt;Provider(s)&#xA;&lt;/h3&gt;&lt;p&gt;我们前面已经提到，Terraform 是一个款础设施即代码工具，作为一个工具本身，他并不绑定某个平台，而是通过 Provider(s) 与各个平台对接，要查看有哪些 Provider(s)，可以浏览 &lt;a class=&#34;link&#34; href=&#34;https://registry.terraform.io/browse/providers&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Terraform 的 Registry&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2026/04/iac-with-terraform/image_hu_463ebc576c22c691.webp&#34; alt=&#34;Terraform 拥有丰富的 Provider(s) 生态&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h3 id=&#34;状态管理&#34;&gt;状态管理&#xA;&lt;/h3&gt;&lt;p&gt;Terraform 将每次执行基础设施变更操作时的状态信息保存在一个状态文件中，默认情况下会保存在当前工作目录下的&lt;code&gt;terraform.tfstate&lt;/code&gt;文件里&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;，我们也可以修改配置文件自行指定其他的存储后端，例如 S3、Postgres。每次我们执行&lt;code&gt;terraform apply&lt;/code&gt;时，Terraform 都会将目前配置文件声明的状态同现有的状态文件进行比对，从而计算变动的部分，自动确定调整顺序之后操作 Provider 落实状态变动。&lt;/p&gt;&#xA;&lt;h2 id=&#34;terraform-的资源导入难题&#34;&gt;Terraform 的资源导入难题&#xA;&lt;/h2&gt;&lt;p&gt;现有资源的导入一直是 Terraform 为人诟病的难题，Hashi Corp. 似乎一直在坚持着一个固执且愚蠢的观点：你所有的基础设施从一开始就应当是用我们的 Terraform 创建的，所以也不存在什么资源导入的问题。&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;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;2014–2022&lt;/td&gt;&#xA;          &lt;td&gt;v0.x–v1.4&lt;/td&gt;&#xA;          &lt;td&gt;只有 &lt;code&gt;terraform import&lt;/code&gt;，一次一条，而且完全不生成配置&lt;/td&gt;&#xA;          &lt;td&gt;导入完还得自己手写 HCL&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;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2023.06&lt;/td&gt;&#xA;          &lt;td&gt;v1.5&lt;/td&gt;&#xA;          &lt;td&gt;引入 &lt;code&gt;import&lt;/code&gt; 块和 &lt;code&gt;-generate-config-out&lt;/code&gt;参数，可以生成配置了&lt;/td&gt;&#xA;          &lt;td&gt;然而还是得一条一条写，而且还得自己提供现有资源的 ID&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2024.01&lt;/td&gt;&#xA;          &lt;td&gt;v1.7&lt;/td&gt;&#xA;          &lt;td&gt;&lt;code&gt;import&lt;/code&gt; 块支持 &lt;code&gt;for_each&lt;/code&gt;&lt;/td&gt;&#xA;          &lt;td&gt;批量了，但 ID 还得自己搞&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;2024 下半年&lt;/td&gt;&#xA;          &lt;td&gt;v1.12&lt;/td&gt;&#xA;          &lt;td&gt;引入了 &lt;code&gt;terraform query&lt;/code&gt; 和 &lt;code&gt;list&lt;/code&gt; 块，终于实现了自动发现资源的功能&lt;/td&gt;&#xA;          &lt;td&gt;然而这个功能要 Provider 要自己实现，大量 Provider 根本没跟上&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;这么多年的时间，社区一直在骂，然而，「我有一堆现有资源，怎么导入 Terraform」这个问题一直没有被认真对待。Terraform 作为「基础设施即代码」工具，设计哲学就是声明式和幂等性&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;，Hashi Corp. 他们笃信「一切以代码声明的状态为准，就应该用 Terraform 从零开始创建资源」。但现实是绝大多数公司都有大量历史存量资源，先有资源、后有代码才是常态。这个矛盾 Hashi Corp. 承认得很晚，&lt;code&gt;v1.12&lt;/code&gt; 的 &lt;code&gt;terraform query&lt;/code&gt; 才算是官方第一次认真面对这个问题——但 Provider 生态的跟进嘛……真的是一言难尽。&lt;/p&gt;&#xA;&lt;h2 id=&#34;terraform-的文件结构&#34;&gt;Terraform 的文件结构&#xA;&lt;/h2&gt;&lt;p&gt;Terraform 的文件结构很简单，其主程序运行时会无脑读取工作目录下所有的&lt;code&gt;.tf&lt;/code&gt;文件，只要信息齐全，想给文件取什么名字都可以，比如我的文件结构就长这样：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;❯ tree -a -I .git&#xA;.&#xA;├── .editorconfig&#xA;├── .github&#xA;│   ├── dependabot.yml&#xA;│   └── workflows&#xA;│       ├── terraform-apply.yml&#xA;│       ├── terraform-plan.yml&#xA;│       └── your-fork.yml&#xA;├── .gitignore&#xA;├── .terraform.lock.hcl&#xA;├── cf_dns_zones.tf&#xA;├── cf_tunnel.tf&#xA;├── dns_example_com.tf&#xA;├── dns_example_net.tf&#xA;├── dns_example_top.tf&#xA;├── dns_example_cn.tf&#xA;├── main.tf                 # 基础配置（terraform 块）&#xA;├── moved.tf                # 移动过的资源&#xA;├── provider.tf             # 每个 Provider 的配置&#xA;├── README.md&#xA;├── rename_resources.ps1&#xA;└── variables.tf            # 自定义的变量&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;main.tf&lt;/code&gt;用于存放基础配置:&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;terraform {&#xA;  required_providers {&#xA;    cloudflare = {&#xA;      source  = &#34;cloudflare/cloudflare&#34;&#xA;      version = &#34;~&gt; 5&#34;&#xA;    }&#xA;&#xA;    tencentcloud = {&#xA;      source  = &#34;tencentcloudstack/tencentcloud&#34;&#xA;      version = &#34;&gt;= 1.81.43&#34;&#xA;    }&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;provider.tf&lt;/code&gt;用于存放每个 Provider 的配置：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;provider &#34;cloudflare&#34; {}&#xA;provider &#34;tencentcloud&#34; {}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里留空是因为我们可以通过环境变量来传递 Credentials，而不是直接将 Credentials 写在配置文件中，例如 Cloudflare 的 Provider 就接受&lt;code&gt;CLOUDFLARE_API_TOKEN&lt;/code&gt;作为&lt;code&gt;api_token&lt;/code&gt;这个变量的替代。&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;variables.tf&lt;/code&gt;用于声明自定义的变量：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;variable &#34;cloudflare_zone_example_com&#34; {&#xA;  description = &#34;Cloudflare zone ID for example.com&#34;&#xA;  type        = string&#xA;}&#xA;&#xA;variable &#34;cloudflare_zone_example_top&#34; {&#xA;  description = &#34;Cloudflare zone ID for example.top&#34;&#xA;  type        = string&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这些变量可以通过前缀为&lt;code&gt;TF_VAR_&lt;/code&gt;的环境变量传入，Terraform 也会自动读取&lt;code&gt;terraform.tfvars&lt;/code&gt;文件中的变量，变量的主要用途是在别的配置文件中调用，例如：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;resource &#34;cloudflare_dns_record&#34; &#34;example_cname&#34; {&#xA;  content = &#34;${cloudflare_zero_trust_tunnel_cloudflared.Production_Tunnel.id}.cfargotunnel.com&#34;&#xA;  name    = &#34;example.example.com&#34;&#xA;  proxied = true&#xA;  tags    = []&#xA;  ttl     = 1&#xA;  type    = &#34;CNAME&#34;&#xA;  zone_id = var.cloudflare_zone_id_example_com  #这里调用了cloudflare_zone_example_com这个变量&#xA;  settings = {&#xA;    flatten_cname = false&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;有了这些基础配置，我们就可以运行&lt;code&gt;terraform init&lt;/code&gt;初始化 Terraform 环境并锁定依赖版本，剩下的就都是我们资源的声明了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;将现有资源导入-terraform&#34;&gt;将现有资源导入 Terraform&#xA;&lt;/h2&gt;&lt;p&gt;前文提到过 Terraform 的状态管理这个概念，状态管理虽好，但在我们初始化时也带来了一个问题——在默认状态下，Terraform 的状态文件显然是空的。&lt;/p&gt;&#xA;&lt;p&gt;此时我们需要做的是将云服务提供商上现有资源的状态导入 Terraform，这样 Terraform 才能无缝接手并管理我们的基础设施。相信大家也都看到了前文对 Terraform 资源导入问题的吐槽。以导入 Cloudflare 上托管的 DNS 记录为例，前文提到过，如果 Provider 支持，可以使用 Terraform 在 1.12 版本之后引入的&lt;code&gt;terraform query&lt;/code&gt;，然而大多数情况下，Providers 都是没有跟进这个新功能的，Cloudflare 就属于不支持的那一类。&lt;/p&gt;&#xA;&lt;p&gt;好在虽然 Hashi Corp. 不认真解决问题，各路高强度使用 Terraform 管理基础设施的公司就各显神通。Cloudflare 就维护了名为 &lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/cf-terraforming&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;cf-terraforming&lt;/a&gt; 的导入工具，免去了很多手动导入的麻烦。首先安装&lt;code&gt;cf-terraforming&lt;/code&gt;，这个工具是用 Go 语言编写的，需要在有 Go 语言环境的情况下安装，或者将官方编译好的二进制文件其放入&lt;code&gt;$PATH&lt;/code&gt;并赋予其执行权限。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;go install github.com/cloudflare/cf-terraforming/cmd/cf-terraforming@latest&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个工具的用法还是比较简单的，首先你需要以下环境变量：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;# 如果你使用 API Token&#xA;export CLOUDFLARE_API_TOKEN=&#39;Hzsq3Vub-7Y-hSTlAaLH3Jq_YfTUOCcgf22_Fs-j&#39;&#xA;&#xA;# 如果你使用 API Key&#xA;export CLOUDFLARE_EMAIL=&#39;user@example.com&#39;&#xA;export CLOUDFLARE_API_KEY=&#39;1150bed3f45247b99f7db9696fffa17cbx9&#39;&#xA;&#xA;# 指定需要导入的域名的区域 ID，如果导入的是账户资源（例如 Cloudflare Tunnel）则不需要&#xA;export CLOUDFLARE_ZONE_ID=&#39;81b06ss3228f488fh84e5e993c2dc17&#39;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote class=&#34;alert alert-tip&#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;此处的命令假设你正在使用 Bash，如果使用的是与 Bash 语法不兼容的 Shell，则需要做出调整，例如对于 Windows 上的 PowerShell，导入环境变量的语法如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-pwsh&#34;&gt;$env:CLOUDFLARE_API_TOKEN=&#39;Hzsq3Vub-7Y-hSTlAaLH3Jq_YfTUOCcgf22_Fs-j&#39;&lt;/code&gt;&lt;/pre&gt;&#xA;        &lt;/div&gt;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;通常我们只需要设置&lt;code&gt;CLOUDFLARE_API_TOKEN&lt;/code&gt;和&lt;code&gt;CLOUDFLARE_ZONE_ID&lt;/code&gt;就可以了，在控制台创建 API Token 时，记得赋予这个 Token 必要的权限，本次我们只是导入 DNS 记录，所以只赋予编辑区域 DNS 的权限即可。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2026/04/iac-with-terraform/image-1_hu_15298d4bd366a377.webp&#34; alt=&#34;赋予操作资源所需要的权限&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;好了，准备工作全部完成，现在可以开始生成配置文件：&lt;/p&gt;&#xA;&lt;p&gt;首先导入账户中域名的配置，也就是&lt;code&gt;cloudflare_zone&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;cf-terraforming generate \&#xA;  --key $CLOUDFLARE_API_KEY \&#xA;  --resource-type &#34;cloudflare_zone&#34; &gt; zone.tf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这一步会在当前目录下生成一个名为&lt;code&gt;zone.tf&lt;/code&gt;的文件，里面会有如下格式的内容：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;resource &#34;cloudflare_zone&#34; &#34;REDACTED&#34; {&#xA;  name                = &#34;REDACTED&#34;&#xA;  paused              = false&#xA;  type                = &#34;full&#34;&#xA;  vanity_name_servers = []&#xA;  account = {&#xA;    id   = &#34;REDACTED&#34;&#xA;    name = &#34;REDACTED&#34;&#xA;  }&#xA;}&#xA;&#xA;resource &#34;cloudflare_zone&#34; &#34;REDACTED&#34; {&#xA;  name                = &#34;REDACTED&#34;&#xA;  paused              = false&#xA;  type                = &#34;full&#34;&#xA;  vanity_name_servers = []&#xA;  account = {&#xA;    id   = &#34;REDACTED&#34;&#xA;    name = &#34;REDACTED&#34;&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在域名资源已经导入了，但是里面的配置并没有。接下来，导入域名下的 DNS 记录：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;cf-terraforming generate \&#xA;  --zone $CLOUDFLARE_ZONE_ID \&#xA;  --key $CLOUDFLARE_API_KEY \&#xA;  --resource-type &#34;cloudflare_dns_record&#34; &gt;&gt; dns.tf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这一步会在当前目录下生成一个名为&lt;code&gt;dns.tf&lt;/code&gt;的配置文件，里面会有如下格式的内容：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_5deb14xxxxxb629bf123xxxxxxxc8f_0&#34; {&#xA;  content  = &#34;67.24.33.108&#34;&#xA;  name     = &#34;example.example.com&#34;&#xA;  proxied  = true&#xA;  tags     = []&#xA;  ttl      = 1&#xA;  type     = &#34;A&#34;&#xA;  zone_id  = &#34;81c7f2de8dfxxxxxx52629xxxxxxfc&#34;&#xA;  settings = {}&#xA;}&#xA;&#xA;resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_89xxxxx0bf9cxxxxxx9a_1&#34; {&#xA;  content  = &#34;35.27.108.33&#34;&#xA;  name     = &#34;terraform.example.com&#34;&#xA;  proxied  = true&#xA;  tags     = []&#xA;  ttl      = 1&#xA;  type     = &#34;A&#34;&#xA;  zone_id  = &#34;8xxxxxx7644e428526xxxxxx&#34;&#xA;  settings = {}&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果有多个域名需要导入，则多次分别设置环境变量&lt;code&gt;CLOUDFLARE_ZONE_ID&lt;/code&gt;再重复运行命令即可。&lt;/p&gt;&#xA;&lt;p&gt;这里生成的配置文件可以直接使用，也就是我们之后需要的 Terraform 配置文件。然而，此时我们仅仅只是生成了配置文件，但是目前 Terraform 的状态依然是空的，这时要是直接&lt;code&gt;terraform apply&lt;/code&gt;，Terraform 会不管三七二十一将我们刚刚导入的声明一律视为新增资源，然后甩出一大堆「Alredy Exists」报错。所以接下来，我们需要将生成的配置文件导入 Terraform 的&lt;code&gt;terraform.tfstate&lt;/code&gt;状态。&lt;/p&gt;&#xA;&lt;p&gt;Terraform 在 1.5 版本引入了&lt;code&gt;import&lt;/code&gt;块，相比以往一行一行输入命令的方式更加现代。其导入流程是先生成一个包含&lt;code&gt;import&lt;/code&gt;块的&lt;code&gt;.tf&lt;/code&gt;文件，下次进行&lt;code&gt;terraform apply&lt;/code&gt;时，Terraform 就会自动为我们执行导入操作。&lt;/p&gt;&#xA;&lt;p&gt;生成&lt;code&gt;cloudflare_zone&lt;/code&gt;的&lt;code&gt;import&lt;/code&gt;块：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;cf-terraforming import \&#xA;  --resource-type &#34;cloudflare_zone&#34; \&#xA;  --modern-import-block \&#xA;  --key $CLOUDFLARE_API_KEY \&#xA;  --zone $CLOUDFLARE_ZONE_ID &gt;&gt; import.tf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;生成&lt;code&gt;cloudflare_dns_record&lt;/code&gt;的&lt;code&gt;import&lt;/code&gt;块：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;cf-terraforming import \&#xA;  --resource-type &#34;cloudflare_dns_record&#34; \&#xA;  --modern-import-block \&#xA;  --key $CLOUDFLARE_API_KEY \&#xA;  --zone $CLOUDFLARE_ZONE_ID &gt;&gt; import.tf&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这一步会在当前目录下生成&lt;code&gt;import.tf&lt;/code&gt;，它包含了所需要的导入信息，作用就是告诉 Terraform 上一步生成的每个&lt;code&gt;resource&lt;/code&gt;块到底对应的是哪一个云服务提供商的资源 ID。这个 ID 是云服务提供商内部标记资源的代码，平常是不会在控制面板上显示的，只有在用 API 特别请求时才会知道。Terraform 在导入过程中需要用到这个 ID 以确认本地的定义对应的云端资源，以实现严格的幂等性。&lt;/p&gt;&#xA;&lt;p&gt;好了，现在我们运行&lt;code&gt;terraform plan&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ terraform plan&#xA;cloudflare_dns_record.minio_a: Refreshing state... [id=xxxxxxxxxxx53]&#xA;cloudflare_zero_trust_tunnel_cloudflared_config.raspberrypi: Refreshing state...&#xA;......&#xA;&#xA;Terraform will perform the following actions:&#xA;&#xA;  # cloudflare_dns_record.terraform_managed_resource_0 will be imported&#xA;    resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_REDACTED_0&#34; {&#xA;        content     = &#34;67.24.33.108&#34;&#xA;        created_on  = &#34;2026-04-08T10:18:12Z&#34;&#xA;        id          = &#34;5deb14c21xxxxxxx20f1c8f&#34;&#xA;        meta        = jsonencode({})&#xA;        modified_on = &#34;2026-04-08T10:18:12Z&#34;&#xA;        name        = &#34;example.example.com&#34;&#xA;        proxiable   = true&#xA;        proxied     = true&#xA;        settings    = {}&#xA;        tags        = []&#xA;        ttl         = 1&#xA;        type        = &#34;A&#34;&#xA;        zone_id     = &#34;REDACTED&#34;&#xA;    }&#xA;&#xA;  # cloudflare_dns_record.terraform_managed_resource_1 will be imported&#xA;    resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_89c149exxxxxxxxxxxba13xxxxxa_1&#34; {&#xA;        content     = &#34;35.27.108.33&#34;&#xA;        created_on  = &#34;2026-04-08T10:17:54Z&#34;&#xA;        id          = &#34;89cxxxxxxxxxxxxxxxxxx09a&#34;&#xA;        meta        = jsonencode({})&#xA;        modified_on = &#34;2026-04-08T10:17:54Z&#34;&#xA;        name        = &#34;terraform.example.com&#34;&#xA;        proxiable   = true&#xA;        proxied     = true&#xA;        settings    = {}&#xA;        tags        = []&#xA;        ttl         = 1&#xA;        type        = &#34;A&#34;&#xA;        zone_id     = &#34;81xxxxxxxxxxxxxxxxxxxxxfc&#34;&#xA;    }&#xA;&#xA;Plan: 2 to import, 0 to add, 0 to change, 0 to destroy.&#xA;&#xA;────────────────────────────────────────────────────────────────────────────────────────────────────────&#xA;&#xA;Note: You didn&#39;t use the -out option to save this plan, so Terraform can&#39;t guarantee to take exactly&#xA;these actions if you run &#34;terraform apply&#34; now.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果需要 Add、Change 和 Destroy 的资源数量都是 0，说明我们的导入操作没有问题，直接&lt;code&gt;terraform apply --auto-approve&lt;/code&gt;，资源就导入完成了。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;$ terraform apply --auto-approve&#xA;cloudflare_dns_record.push_a: Refreshing state... [id=REDACTED]&#xA;&#xA;Terraform will perform the following actions:&#xA;&#xA;  # cloudflare_dns_record.terraform_managed_resource_REDACTED_0 will be imported&#xA;    resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_REDACTED_0&#34; {&#xA;        content     = &#34;67.24.33.108&#34;&#xA;        created_on  = &#34;2026-04-08T10:18:12Z&#34;&#xA;        id          = &#34;REDACTED&#34;&#xA;        meta        = jsonencode({})&#xA;        modified_on = &#34;2026-04-08T10:18:12Z&#34;&#xA;        name        = &#34;example.example.com&#34;&#xA;        proxiable   = true&#xA;        proxied     = true&#xA;        settings    = {}&#xA;        tags        = []&#xA;        ttl         = 1&#xA;        type        = &#34;A&#34;&#xA;        zone_id     = &#34;REDACTED&#34;&#xA;    }&#xA;&#xA;  # cloudflare_dns_record.terraform_managed_resource_REDACTED_1 will be imported&#xA;    resource &#34;cloudflare_dns_record&#34; &#34;terraform_managed_resource_REDACTED_1&#34; {&#xA;        content     = &#34;35.27.108.33&#34;&#xA;        created_on  = &#34;2026-04-08T10:17:54Z&#34;&#xA;        id          = &#34;REDACTED&#34;&#xA;        meta        = jsonencode({})&#xA;        modified_on = &#34;2026-04-08T10:17:54Z&#34;&#xA;        name        = &#34;terraform.example.com&#34;&#xA;        proxiable   = true&#xA;        proxied     = true&#xA;        settings    = {}&#xA;        tags        = []&#xA;        ttl         = 1&#xA;        type        = &#34;A&#34;&#xA;        zone_id     = &#34;REDACTED&#34;&#xA;    }&#xA;&#xA;Plan: 2 to import, 0 to add, 0 to change, 0 to destroy.&#xA;cloudflare_dns_record.terraform_managed_resource_REDACTED_1: Importing... [id=REDACTED/REDACTED]&#xA;cloudflare_dns_record.terraform_managed_resource_REDACTED_1: Import complete [id=REDACTED/REDACTED]&#xA;cloudflare_dns_record.terraform_managed_resource_REDACTED_0: Importing... [id=REDACTED/REDACTED]&#xA;cloudflare_dns_record.terraform_managed_resource_REDACTED_0: Import complete [id=REDACTED/REDACTED]&#xA;&#xA;Apply complete! Resources: 2 imported, 0 added, 0 changed, 0 destroyed.&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;状态存储和持续集成&#34;&gt;状态存储和持续集成&#xA;&lt;/h2&gt;&lt;p&gt;IaC 的核心价值之一就在于可以轻易实现基于 Git 的多人协作，以及 CI 的持续集成，但是在此之前，又有一个新的问题需要解决——&lt;code&gt;terraform.tfstate&lt;/code&gt;到底放哪里：没人想要换一次环境辛辛苦苦导入的状态就丢一次。&lt;/p&gt;&#xA;&lt;p&gt;Terraform 目前支持以下几种保存状态的后端：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;local&lt;/li&gt;&#xA;&lt;li&gt;remote&lt;/li&gt;&#xA;&lt;li&gt;azurerm&lt;/li&gt;&#xA;&lt;li&gt;consul&lt;/li&gt;&#xA;&lt;li&gt;cos&lt;/li&gt;&#xA;&lt;li&gt;gcs&lt;/li&gt;&#xA;&lt;li&gt;http&lt;/li&gt;&#xA;&lt;li&gt;Kubernetes&lt;/li&gt;&#xA;&lt;li&gt;oci&lt;/li&gt;&#xA;&lt;li&gt;oss&lt;/li&gt;&#xA;&lt;li&gt;pg&lt;/li&gt;&#xA;&lt;li&gt;s3&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;没有特殊需求可以像我一样选择&lt;code&gt;s3&lt;/code&gt;，毕竟 Cloudflare R2 有免费额度，不用白不用。&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-hcl&#34;&gt;terraform {&#xA;  backend &#34;s3&#34; {&#xA;    bucket = &#34;terraform&#34;&#xA;    key    = &#34;terraform.tfstate&#34;&#xA;    region = &#34;auto&#34;&#xA;    endpoints = {&#xA;      s3 = &#34;https://REDACTED.r2.cloudflarestorage.com&#34;&#xA;    }&#xA;&#xA;    # R2 不需要这些 AWS 的验证&#xA;    skip_credentials_validation = true&#xA;    skip_metadata_api_check     = true&#xA;    skip_region_validation      = true&#xA;    skip_requesting_account_id  = true&#xA;    use_path_style              = true&#xA;  }&#xA;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于 S3 的后端，建议用&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;和&lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;两个环境变量来存储 Credentials：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-sh&#34;&gt;export AWS_ACCESS_KEY_ID=&#39;REDACTED&#39;&#xA;export AWS_SECRET_ACCESS_KEY=&#39;REDACTED&#39;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;配置完成，运行&lt;code&gt;terraform init -migrate-state&lt;/code&gt;，配置就成功存储到云上了，以后不论在何处修改配置、运行&lt;code&gt;terraform apply&lt;/code&gt;都无须担心 Terraform 的 State 不同步的问题。&lt;/p&gt;&#xA;&lt;p&gt;接下来就是 Github CI 的配置，其实很简单，无非就是每次&lt;code&gt;git push&lt;/code&gt;时触发一次&lt;code&gt;terraform init&lt;/code&gt;、&lt;code&gt;terraform fmt&lt;/code&gt;和&lt;code&gt;terraform apply&lt;/code&gt;，以下是我的&lt;code&gt;.github/workflows/apply.yml&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;name: &#34;Terraform Apply&#34;&#xA;&#xA;on:&#xA;  push:&#xA;    branches:&#xA;      - main&#xA;&#xA;env:&#xA;  TF_IN_AUTOMATION: &#34;true&#34;&#xA;  CLOUDFLARE_API_TOKEN: &#34;${{ secrets.CLOUDFLARE_API_TOKEN }}&#34;&#xA;  AWS_ACCESS_KEY_ID: &#34;${{ secrets.AWS_ACCESS_KEY_ID }}&#34;&#xA;  AWS_SECRET_ACCESS_KEY: &#34;${{ secrets.AWS_SECRET_ACCESS_KEY }}&#34;&#xA;  TF_VAR_cloudflare_zone_id_example_com: &#34;${{ vars.TF_VAR_CLOUDFLARE_ZONE_ID_EXAMPLE_COM }}&#34;&#xA;  TF_VAR_cloudflare_zone_id_example_top: ${{ vars.TF_VAR_CLOUDFLARE_ZONE_ID_EXAMPLE_TOP }}&#xA;&#xA;jobs:&#xA;  terraform:&#xA;    name: &#34;Terraform Apply&#34;&#xA;    runs-on: ubuntu-latest&#xA;    permissions:&#xA;      contents: read&#xA;    concurrency:&#xA;      group: terraform-apply&#xA;      cancel-in-progress: false&#xA;    steps:&#xA;      - name: Checkout&#xA;        uses: actions/checkout@v6&#xA;&#xA;      - name: Setup Terraform&#xA;        uses: hashicorp/setup-terraform@v4&#xA;&#xA;      - name: Terraform Init&#xA;        run: terraform init -input=false&#xA;&#xA;      - name: Terraform Apply&#xA;        run: terraform apply -input=false -auto-approve&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对于 PR 则应当让 CI 自动为每次 PR 附上&lt;code&gt;terraform plan&lt;/code&gt;的输出：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;name: Terraform Plan&#xA;&#xA;on:&#xA;  pull_request:&#xA;    paths:&#xA;      - &#34;**/*.tf&#34;&#xA;      - &#34;.github/workflows/terraform-plan.yml&#34;&#xA;&#xA;permissions:&#xA;  contents: read&#xA;  pull-requests: write&#xA;&#xA;env:&#xA;  TF_IN_AUTOMATION: &#34;true&#34;&#xA;  CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}&#xA;  AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}&#xA;  AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}&#xA;  TF_VAR_cloudflare_zone_id_example_com: &#34;${{ vars.TF_VAR_CLOUDFLARE_ZONE_ID_EXAMPLE_COM }}&#34;&#xA;  TF_VAR_cloudflare_zone_id_example_top: ${{ vars.TF_VAR_CLOUDFLARE_ZONE_ID_EXAMPLE_TOP }}&#xA;&#xA;jobs:&#xA;  plan:&#xA;    name: Terraform Plan&#xA;    runs-on: ubuntu-latest&#xA;    steps:&#xA;      - uses: actions/checkout@v6&#xA;&#xA;      - uses: hashicorp/setup-terraform@v4&#xA;&#xA;      - name: Terraform fmt&#xA;        id: fmt&#xA;        run: terraform fmt -check -recursive&#xA;        continue-on-error: true&#xA;&#xA;      - name: Terraform Init&#xA;        id: init&#xA;        run: terraform init -input=false&#xA;&#xA;      - name: Terraform Validate&#xA;        id: validate&#xA;        run: terraform validate -no-color&#xA;&#xA;      - name: Terraform Plan&#xA;        id: plan&#xA;        run: terraform plan -input=false -no-color&#xA;        continue-on-error: true&#xA;&#xA;      - name: Post Plan to PR&#xA;        uses: actions/github-script@v8&#xA;        with:&#xA;          github-token: ${{ secrets.GITHUB_TOKEN }}&#xA;          script: |&#xA;            const { data: comments } = await github.rest.issues.listComments({&#xA;              owner: context.repo.owner,&#xA;              repo: context.repo.repo,&#xA;              issue_number: context.issue.number,&#xA;            });&#xA;            const botComment = comments.find(c =&gt;&#xA;              c.user.type === &#39;Bot&#39; &amp;&amp; c.body.includes(&#39;&lt;!-- terraform-plan --&gt;&#39;)&#xA;            );&#xA;&#xA;            const planOutput = `${{ steps.plan.outputs.stdout }}`.substring(0, 65000);&#xA;&#xA;            const body = `&lt;!-- terraform-plan --&gt;&#xA;            #### Terraform Plan&#xA;&#xA;            | Step     | Result                            |&#xA;            | -------- | --------------------------------- |&#xA;            | fmt      | \`${{ steps.fmt.outcome }}\`      |&#xA;            | init     | \`${{ steps.init.outcome }}\`     |&#xA;            | validate | \`${{ steps.validate.outcome }}\` |&#xA;            | plan     | \`${{ steps.plan.outcome }}\`     |&#xA;&#xA;            &lt;details&gt;&lt;summary&gt;展开 Plan 详情&lt;/summary&gt;&#xA;&#xA;            \`\`\`terraform&#xA;            ${planOutput}&#xA;            \`\`\`&#xA;            &lt;/details&gt;`;&#xA;&#xA;            if (botComment) {&#xA;              await github.rest.issues.updateComment({&#xA;                owner: context.repo.owner,&#xA;                repo: context.repo.repo,&#xA;                comment_id: botComment.id,&#xA;                body&#xA;              });&#xA;            } else {&#xA;              await github.rest.issues.createComment({&#xA;                issue_number: context.issue.number,&#xA;                owner: context.repo.owner,&#xA;                repo: context.repo.repo,&#xA;                body&#xA;              });&#xA;            }&#xA;&#xA;      - name: Fail if plan failed&#xA;        if: steps.plan.outcome == &#39;failure&#39;&#xA;        run: exit 1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2026/04/iac-with-terraform/image-2_hu_c922b7d4de19a009.webp&#34; alt=&#34;每次 PR 都会有 Plan 的输出&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;h2 id=&#34;后续的工作流程&#34;&gt;后续的工作流程&#xA;&lt;/h2&gt;&lt;p&gt;到这一步，Terraform 的「接管初始化」已经结束了，后面就进入了日常维护阶段。这个阶段其实就三件事：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;创建新资源&lt;/li&gt;&#xA;&lt;li&gt;修改现有的资源&lt;/li&gt;&#xA;&lt;li&gt;删除不再需要的资源&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;常用的操作就两个：&lt;code&gt;terraform plan&lt;/code&gt;和&lt;code&gt;terraform apply&lt;/code&gt;，如果是个人使用，小的改动直接提交就算了；如果是团队协作，每次修改则应当遵循能 PR 就不直接 Commit 的原则。&lt;/p&gt;&#xA;&lt;h3 id=&#34;创建基础设施&#34;&gt;创建基础设施&#xA;&lt;/h3&gt;&lt;p&gt;假设你现在要新增一条 DNS 记录，或者新建一个 Tunnel、一个对象存储桶，流程如下：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TD&#xA;  C1[新建分支&#xA;如 feat/add-minio-record] --&gt; C2[新增 resource 块]&#xA;  C2 --&gt; C3[terraform fmt + validate]&#xA;  C3 --&gt; C4[terraform plan]&#xA;  C4 --&gt; C5{仅新增预期资源?}&#xA;  C5 -- 否 --&gt; C6[修正配置后重跑 plan]&#xA;  C6 --&gt; C4&#xA;  C5 -- 是 --&gt; C7[提交 PR]&#xA;  C7 --&gt; C8[合并后 CI apply]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;最理想的&lt;code&gt;plan&lt;/code&gt;输出是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;X to add&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;0 to change&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;0 to destroy&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果你只是想加东西，结果出现了&lt;code&gt;to destroy&lt;/code&gt;，那就先别冲动，通常是引用写错、变量搞错，或者不小心改了资源地址，仔细检查是什么地方出了问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;修改与删除基础设施&#34;&gt;修改与删除基础设施&#xA;&lt;/h3&gt;&lt;p&gt;修改流程和创建类似，但要多一步——评估变更是否会触发重建。&lt;/p&gt;&#xA;&lt;p&gt;因为很多 Provider 字段是&lt;code&gt;ForceNew&lt;/code&gt;，你以为只是改个字段，Terraform 看完说：「好的，删了重建。」这在我们修改 DNS 的这个场景并不是什么很大的问题，但是到了云实例这种资源，如果删除重建势必会造成损失。&lt;/p&gt;&#xA;&lt;p&gt;建议按下面这个顺序来：&lt;/p&gt;&#xA;&lt;pre&gt;&lt;code class=&#34;language-mermaid&#34;&gt;flowchart TD&#xA;  M1[修改 .tf] --&gt; M2[terraform plan]&#xA;  M2 --&gt; M3{出现 replace/destroy?}&#xA;  M3 -- 否 --&gt; M7[确认影响范围]&#xA;  M7 --&gt; M8[terraform apply]&#xA;  M3 -- 是 --&gt; M4[暂停并复核变更]&#xA;  M4 --&gt; M5[必要时加 lifecycle 保护]&#xA;  M5 --&gt; M6[安排变更窗口]&#xA;  M6 --&gt; M8&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对生产环境来说，创建、修改得慢一点并不是什么很大的问题，最应当看重的是操作的正确性，慢一点，不要出错。IaC 不是比手速，IaC 比的是可预期性。&lt;/p&gt;&#xA;&lt;p&gt;如果是删除资源（比如下线某个 DNS 记录、清理废弃 Tunnel），走下面这个流程&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-mermaid&#34;&gt;flowchart TD&#xA;  D1[确认资源已废弃&#xA;  检查业务/监控/脚本依赖] --&gt; D2[删除 resource 块或调整 count/for_each]&#xA;  D2 --&gt; D3[terraform plan]&#xA;  D3 --&gt; D4{to destroy 是否符合预期?}&#xA;  D4 -- 否 --&gt; D5[回滚修改并继续排查依赖]&#xA;  D5 --&gt; D1&#xA;  D4 -- 是 --&gt; D6[准备回滚方案并选低峰窗口]&#xA;  D6 --&gt; D7[PR 审核通过]&#xA;  D7 --&gt; D8[terraform apply]&#xA;  D8 --&gt; D9[删除资源后的可用性检查]&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;日常协作建议&#34;&gt;日常协作建议&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;把 Credentials 放环境变量或 CI Secret，别写进&lt;code&gt;.tf&lt;/code&gt;和仓库&lt;/li&gt;&#xA;&lt;li&gt;对关键资源开启保护策略，防止误删&lt;/li&gt;&#xA;&lt;li&gt;将目录按资源类型拆分&lt;/li&gt;&#xA;&lt;li&gt;定期执行&lt;code&gt;terraform plan&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;和校正，避免在面板误操作手动修改&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;虽然这套流程看起来很麻烦，但每一次变更都有记录、可审计、可回滚，最重要的是可复现，这才是 IaC 最有价值的地方。&lt;/p&gt;&#xA;&lt;h2 id=&#34;参考&#34;&gt;参考&#xA;&lt;/h2&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://candinya.com/posts/manage-cloudflare-dns-with-terraform/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;使用 Terraform 管理 CloudFlare 上的 DNS 解析记录 - Candinya&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developer.hashicorp.com/terraform/tutorials/automation/github-actions&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Automate Terraform with GitHub Actions&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developer.hashicorp.com/terraform/language/files/tfquery&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Query configuration files&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developer.hashicorp.com/terraform/language/block/tfquery/list&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;list block reference&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/cloudflare/cf-terraforming&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;cloudflare/cf-terraforming&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://developers.cloudflare.com/terraform/advanced-topics/import-cloudflare-resources/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Import Cloudflare resources&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a class=&#34;link&#34; href=&#34;https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Cloudflare Provider - Terraform Registry&lt;/a&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;&lt;a class=&#34;link&#34; href=&#34;https://en.wikipedia.org/wiki/Infrastructure_as_code&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Infrastructure as Code&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;每个供应商的配置文件字段命名和格式都有区别，但这可以很容易的编写脚本进行转换。&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;需要特别注意的是，状态文件中可能包含数据库密码、API 密钥等明文存储的敏感信息，因此绝对不要将 &lt;code&gt;.tfstate&lt;/code&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;HashiCorp Configuration Language，HashiCorp 自家开发的一种声明式配置语言，旨在兼顾机器可读性与人类可读性。&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;幂等性（Idempotence）指计算机系统或接口在接收到同一请求的多次操作时，产生的影响与一次执行的结果相同，不论执行多少次，系统的最终状态始终保持一致。&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;如果你仅仅是想让 Terraform 不再管理某个资源，而不是真正在云端销毁它，应该使用 &lt;code&gt;terraform state rm&lt;/code&gt; 命令，而不是在代码中删掉资源块然后 &lt;code&gt;apply&lt;/code&gt;，否则云环境上的真实资源也会被一并销毁。&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;基础设施漂移（Infrastructure Drift）是指现实中通过控制台点按等非 IaC 途径修改了基础设施，导致其实际状态与代码中声明的状态不一致的情况。&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;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>永远忙碌</title>
            <link>https://blog.l3zc.com/2026/03/busy-for-eternity/</link>
            <pubDate>Fri, 13 Mar 2026 23:14:26 +0800</pubDate>
            <guid>https://blog.l3zc.com/2026/03/busy-for-eternity/</guid>
            <description>&lt;p&gt;工作，工作，至死方休。&lt;/p&gt;&#xA;&lt;p&gt;寒假给别人&lt;a class=&#34;link&#34; href=&#34;https://blog.l3zc.com/2026/02/buns-soaked-in-human-blood/&#34; &gt;上课&lt;/a&gt;，几乎就没有停过，春节名义上休息，也只不过是换了一种形式工作罢了——各种应酬，舟车劳顿，回家刚安顿好，又马不停蹄的投入到上课工作中去。给别人上课也真是不容易，跟我在同一家机构当助教的同学一起交流时，大家都戏称上课就是「赤石」：死记硬背的是记不住的，算数是不会算的，概念是混淆的，交流是没办法正常交流的。这倒也不怪他们，要怪也只能怪他们经历过的教育环境，毕竟家家有本难念的经。各种原因导致他们基本上走的都是高职单招，没有经过高考的洗礼，有的甚至连初中都没怎么读好，现在也只是想找个工作，所以才愿意花钱请我们来给他们上一对一课程。&lt;/p&gt;&#xA;&lt;p&gt;一开始我在一家机构做助教，后来出来单干，提高了部分收入，还节省了部分备课的时间。每天的上课是从7:30-11:00,价格是 ¥400。看似时薪过百比较高，实则结合学生的基础状况考虑，这钱我是赚得问心无愧，甚至我可以说，这钱真赚得也是不容易。&lt;/p&gt;&#xA;&lt;p&gt;回到正题，现在开学了，我又要马不停蹄的投入到我自己的学业事务中去。真的感觉自己永远都在忙，所谓的休息，也只不过是换点轻松的事情做一做罢了，教学教累了回家就 Vibe Coding 放松一下，坐在电脑前烦躁了就把家里收拾一下打扫卫生。在做事情的动力、以及人的有限总精力这方面，我能真切的感受到人与人之间的差距：有的人天赋异禀，精力非常充沛，成果做了一个又一个，论文发了一篇又一篇，产出很高，好像制约他们的永远都是时间，而不是他们的精力和动力；而更多人则是像我一样的凡人，即使想要这种生活状态，却也还是心有余而力不足，可是看到前面一类人的高产，又难免心生焦虑，只能在最大限度下把自己当成一个实际永动机&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;p&gt;虽然深知这一点，我还是会停下来休息就空虚难受，所以，永远忙碌，永远工作。满足自己身体需要的休息，用锻炼身体平衡自己的内分泌，休息就是换一件自己喜欢且比较轻松的事情做，由于受中式教育、绩优主义的影响太深，这种生活状态，我想在很长一段时间里是不会改变了。&lt;/p&gt;&#xA;&lt;p&gt;不过往好的方面看，通过这段时间的忙碌，我也是自己把自己这个学期的生活费给赚出来了，还有富余给我妈准备一台新手机当生日礼物。突然也觉得，永远忙碌这件事，好像也没这么糟。&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;这里是用理想电流源和实际电流源的区别来类比所谓「理想永动机」和实际永动机的区别——前者是真正意义上的永动机，后者则是我等凡夫俗子用血肉之躯拼劲全力去接近的「实际永动机」&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><item>
            <title>培训机构的人血馒头</title>
            <link>https://blog.l3zc.com/2026/02/buns-soaked-in-human-blood/</link>
            <pubDate>Wed, 11 Feb 2026 17:06:57 +0800</pubDate>
            <guid>https://blog.l3zc.com/2026/02/buns-soaked-in-human-blood/</guid>
            <description>&lt;p&gt;最近在某家民营电网培训机构给准备国网二批考试的学生一对一辅导，每天晚上上课三个半小时，&lt;strong&gt;给 200。&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;这家机构给我的钱偏少还不是最严重的问题。问题出在他们给学生的收费上：有两种方案，一种是所谓「卓越计划」，收费 12 万，但是一对一课程不限量；另一种是「协议班」，收费 7 万，但&lt;strong&gt;每次上一对一课程要交 450&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;昨天给他们一学生私下开小灶，下午上课三个半小时，本来我想着既然私下找我，那就不经过这个培训机构，学生直接给我结款 300——我能多赚一百，ta 能少花 150。结果那个学生脑子没转过弯，找班主任请假的时候竟然说要找我补课，于是他们就直接「善意地」帮我找家长收了 450。&lt;/p&gt;&#xA;&lt;p&gt;这还没完。最后给我算工时，他们把这次课归为所谓「额外课时」，说我违规利用了下午的「备课时间」给非卓越计划的学生上课——三个半小时，只给了 120。&lt;/p&gt;&#xA;&lt;p&gt;简而言之：&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;&lt;strong&gt;学生付 450 → 机构抽走 330 → 我拿到 120&lt;/strong&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;p&gt;本该到我手上的 300 变成了 120，我自然是不爽。但比起我个人少拿的那一百多块钱，更让我不舒服的是这件事本身的性质。这些考国网二批的学生很多都是家境不太富裕的专科生，他们平日里已经饱受歧视，想尽一切办法想要改变命运，现在下了血本，花上可能是他们一个家庭一年收入的几万甚至十几万来读这个国网课程。他们以为自己买的是一剂改命的「药」，殊不知这药引子是用自己的血和着吃的——而我辛苦劳动辅导学生，分到手里的钱占比却比坐享其成的培训机构还要低。&lt;/p&gt;&#xA;&lt;p&gt;这根本就是在吃人血馒头。&lt;/p&gt;&#xA;&lt;p&gt;这一单，机构躺着净赚 330。这显然令人难以接受。我已经通知那位学生，令其下次请假时表现更加灵活；也和 ta 的班主任做出交涉，令她不要上报甚至干预我们私下的补课。考虑到班主任也是打工人，并且有学员成绩的 KPI，我想她也不会蠢到跟自己的 KPI 过不去。当然，这家机构最好好自为之，否则我在「备课」时那句「助教们组建临时工会，集体发动罢工，要求涨薪」的玩笑话，在将来的某天恐怕得一语成谶。&lt;/p&gt;&#xA;&lt;p&gt;不得不感叹，到底谁才是资本主义啊——我看这机构的人血馒头铺子开得还挺熟练的。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>2025 年度总结</title>
            <link>https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/</link>
            <pubDate>Wed, 31 Dec 2025 19:28:17 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/cover_hu_546f5de4e94beb95.webp&#34; alt=&#34;Featured image of post 2025 年度总结&#34; /&gt;&lt;p&gt;真是忙碌的一年，不知不觉间，时间又到了年末。今年事情确实很多，奔波劳碌少不了，但也取得了阶段性的收获。我谨再次提笔写下一篇年终总结，作为一年的见证。&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;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250920_154353_hu_11efd88f784ccf12.webp&#34; alt=&#34;跑了一场双选会&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20251220_153620_hu_7fe2627d8f597cfd.webp&#34; alt=&#34;海南电网在富丽华酒店的面试&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;我在一整年的休学生活以后如期复学，开始我的大学最后一年，成为一名「应届生」，所以，找工作的事情也就理所应当的排上了日程。作为电气工程专业的学生，出身原电力部属院校，工作倒是不算难找。不过说容易也不算很容易，毕竟大环境如此，经济增长放缓，国际形势不明朗，用人需求减少，各种地方都越来越卷。&lt;/p&gt;&#xA;&lt;p&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;h3 id=&#34;两大电网的笔试&#34;&gt;两大电网的笔试&#xA;&lt;/h3&gt;&lt;p&gt;电网工作是本专业最对口，最稳定的工作。本专业最大的用人单位——国家电网和南方电网，都需要通过笔试来获得面试资格。笔试一共需要考 8 门，分别是《电路理论》、《电机学》、《电力系统分析》、《继电保护》、《电力电子》、《高电压技术》、《电气设备及主系统》（我们学校叫「发电厂电气部分」）以及《行政能力测验》（简称「行测」）。&lt;/p&gt;&#xA;&lt;p&gt;前面七门是专业知识，最后一门行政能力测验考的则是五花八门，还有企业文化这种东西，背就完事了。时政是不得不考的，考什么呢？总之是非常新的东西——几天前刚刚在求是杂志上发表的社论，几天后的考试里就直接出现了，我真的会谢。&lt;/p&gt;&#xA;&lt;p&gt;今年的考试很奇怪，尤其是难度方面，历年的考试好说歹说也得有几道计算题，电路好歹也得灵活的考一道难度稍大的题。基于这种情报，我在靠前已经掌握了不少计算题，各种电气计算，数值整定，等效变换，可谓是得心应手。结果呢，今年国网一批考试一道计算题都没考，行测小学生都会做，全都在考些概念题，要不是南网考试还考了这些灵活运用的东西，那真就是约等于白学了。于是不出意料地，我所知道的计算题比较拿手，平时模拟测试成绩很好的同学，这次考试或多或少都有点炸。反倒是有些平时成绩不怎么理想，计算题不太会做的人，靠着死记硬背能考到一个不错的成绩。说白了，毕竟只是一个企业的招聘考试，他要怎么出题，外人根本无从猜测，我已经做了我应该做的，最终的录用结果也非常不错，这就够了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;面试面试还是面试&#34;&gt;面试，面试，还是面试&#xA;&lt;/h3&gt;&lt;p&gt;12 月我跑了四场面试，其中广西电网只有桂林一个面试地点，让我不得不&lt;del&gt;翘课&lt;/del&gt;前往桂林面试，于是就有了今年最后一次的旅行，两年内两次前往桂林的感觉还不错。&lt;/p&gt;&#xA;&lt;p&gt;国网面试还是让我有点紧张，为了防止试题被泄露给后面的考生，面试采用全封闭式管理，过程也很漫长——大部分时间都是在等候室里等待轮候。从下午 1:30 开始封存所有电子设备，用一个小时做完心理测试之后就进入了漫长的轮候时光，期间场地在放《长津湖》供大家消遣，还有茶水和零食提供。西装革履，正襟危坐，心里一遍又一遍的背诵早就滚瓜烂熟的一分钟自我介绍，紧张不安的边看电影消遣边等候，那种滋味只有亲身经历过才知道，现在回想起来倒也是挺有意思。&lt;/p&gt;&#xA;&lt;p&gt;有了国网面试的经验和 Offer，排在其后的南网面试紧张感就没那么强。南方电网的面试形式和国家电网不太一样，国家电网是半结构化双盲面试，第一位考生从数份封存的面试题本里抽取一份，接下来的考生便都是一样的问题，最多也就是被考官询问一些附加问题。面试官不能看到你的简历，只能根据你在面试前抽签获得的编号对你打分，你也不能自报姓名和身世；而南方电网的面试则以面试官为主导，面试官会根据简历对你提出各种问题，包括专业题和附加问题。至于难度如何则完全看面试官的心情，例如我在海南电网的面试就被技术面试针对我的实习经历穷追猛打，提出各种细致入微的专业题，而在广西电网的面试中，技术面试提出的问题则友好很多，无非是一些倒闸操作、防雷设施等等。&lt;/p&gt;&#xA;&lt;h3 id=&#34;电网培训的酸甜苦辣&#34;&gt;电网培训的酸甜苦辣&#xA;&lt;/h3&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250819_182040_hu_9f035c63414ae82d.webp&#34; alt=&#34;傍晚散步&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250819_184119_hu_f173b6fa7aa0237a.webp&#34; alt=&#34;偶遇的云彩&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250819_181921_hu_1055fee83bee50f7.webp&#34; alt=&#34;附近的高压线路&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/Screenshot_2025-10-10-20-57-03-452_com.tencent.mm_hu_200838b0f8909812.webp&#34; alt=&#34;刷题，刷题，还是刷题&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/screenshot_2025-11-27_23-35-58_hu_63f5f0b6afaf6e93.webp&#34; alt=&#34;企业文化必须滚瓜烂熟&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;考电网的人大部分都报名了某家培训机构，我自然也不例外，早在去年 11 月我就按部就班地报名了一家全国性的电网培训机构。这家培训机构有两个校区，我选择了相对市郊的那个，毕竟房租便宜。&lt;/p&gt;&#xA;&lt;p&gt;培训的课程安排非常密集，任务繁重。暑假班连续上课 41 天，中途只有三天休息。每天上课之前需要上交手机。好在 iPad 出于电子笔记的考虑，还是允许使用的，我也因此获得了难得的摸鱼机会。&lt;/p&gt;&#xA;&lt;p&gt;其实这段时间我也难得的获得了专注于一件事情的机会——每天除了上课，没有什么别的需要关心，所以虽然身体累，但是「心」反倒是没有多累；现在我回到了学校，反倒需要关心起大大小小的各种事情，身体倒是没那么累了，但「心」倒是比之前还累了不少。加上最近感冒咳嗽，一天能睡上 12 个小时，却也还是不见好转。只能在事情办完以后，该请假请假，该回家回家，该休息休息了。&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;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250122_121431_hu_9139d942ff443734.webp&#34; alt=&#34;永州&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250122_153223_hu_119bbf370aade398.webp&#34; alt=&#34;银龙电脑城——儿时回忆&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250122_153407_hu_75f5c2193137f130.webp&#34; alt=&#34;二十年了，没怎么变&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;今年年初回永州探亲，祖母已经快 90 岁了，身子还算硬朗，常回去看看是应该的。自幼便蒙受祖母照顾，感激之情实在是难以用言语表达，却也在应该做出什么行动来回报这方面不知所措，唯有至少每年一次的回永州探望方还算尽了一些晚辈的责任。&lt;/p&gt;&#xA;&lt;p&gt;至于永州本身，也还是那个样子，什么都没变。毕竟又不是经济大爆发的时代，像这样的小城市还能怎么变呢？不变未必是悲哀，变也未必全是福气，像是上世纪经历了文革以后，什么都变了一副光景，却也什么都面目全非。小时候十分火热的商业综合体，现在基本只有一楼的服饰门面在营业，电影院和老游戏厅早就关门了，改做餐厅楼层之后变得昏暗不堪，新开的餐厅店铺，不论品牌连锁还是快招自营，大浪淘沙之后无一幸存。&lt;/p&gt;&#xA;&lt;h3 id=&#34;香港&#34;&gt;香港&#xA;&lt;/h3&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/DSCF0187.JPG_hu_80338f753b923972.webp&#34; alt=&#34;政府总部&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/DSCF0189.JPG_hu_cb13da2068e9876.webp&#34; alt=&#34;中环&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250422_112641_hu_1e96cecdbc2d2313.webp&#34; alt=&#34;酒店外景&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/DSCF0156.JPG_hu_63e4a420e01095c5.webp&#34; alt=&#34;小巷&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/DSCF0169.JPG_hu_49d9f960a8af333c.webp&#34; alt=&#34;路牌&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/DSCF0142.JPG_hu_3fc15df218b0937c.webp&#34; alt=&#34;电车&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250424_101442_hu_fb51beb94ea422c5.webp&#34; alt=&#34;中银在效率这一块&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250423_182408_hu_870bb99e461edf1b.webp&#34; alt=&#34;酒浓于水（bushi）&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250421_174511_hu_b0f44927a1040192.webp&#34; alt=&#34;香港的公寓&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;这次去香港就是去玩两下子，没什么特别的目的，纯属白嫖我妈出差的酒店而已。当然，顺便开张中银卡。所以整个行程也显得乏善可陈。唯一特别一点的地方是在湾仔的一间公寓住了几天，可以自行买菜做饭（&lt;del&gt;当然也可以吃两餸饭&lt;/del&gt;），体验了一把民工一般的生活。&lt;/p&gt;&#xA;&lt;h3 id=&#34;桂林&#34;&gt;桂林&#xA;&lt;/h3&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20251224_194924_hu_15f0e9b608e95be5.webp&#34; alt=&#34;这个招牌的灯打得不错&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20251224_112927_hu_4fd7a7bc2479dd30.webp&#34; alt=&#34;椿记烧鹅&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&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/12/2025-end-of-the-year-summary/IMG_20250425_155402_hu_64b9ab0f62f7b107.webp&#34; alt=&#34;新电脑好诶&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250425_180234_hu_95f6f3aea77b7f19.webp&#34; alt=&#34;SB Windows 11&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;之前我的电脑是一台 i5 12450H + RTX 3060 Laptop 配置的机器，用了两年多，几个月前刚买了两条重要牌&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;内存给他的机带内存升级到 32G，其实要接着用也没什么问题。&lt;/p&gt;&#xA;&lt;p&gt;那段时间存储芯片的价格仍然处于低谷，国补又让购置新设备的成本进一步降低，加上 50 系显卡刚刚上市，这三种因素叠加下新笔记本电脑的价格真的很吸引人。奈何我还是囊中羞涩，预算不足，无缘购买最新一代处理器 + 最新一代显卡的配置组合。只能退而求其次，买了 N - 1 代处理器 + 最新一代显卡的配置&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;h2 id=&#34;我家的猫&#34;&gt;我家的猫&#xA;&lt;/h2&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250427_125807_hu_5b61bb8c30db752f.webp&#34; alt=&#34;见到容身之处就往里面钻&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250208_141725_hu_c37c72856d52fb99.webp&#34; alt=&#34;这是什么？猫脑袋！我摸！&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250626_152438_hu_827db49001ba7222.webp&#34; alt=&#34;这猫过得比人还舒服&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;我家的猫今年（应该）一岁啦&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;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/mmexport1745478106719_hu_aa931e8ed6a41965.webp&#34; alt=&#34;我 的 被 子 ~~&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;这臭猫在我去香港那段时间竟然跑到我床上拉屎撒尿 &lt;del&gt;（可能是我爸在家里没有铲屎）&lt;/del&gt;,不可饶恕，必须嘎蛋！&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/mmexport1749356267417_hu_48575c3a7508956e.webp&#34; alt=&#34;舒服了&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/IMG_20250610_105723_hu_d5f83d680ed53460.webp&#34; alt=&#34;让你乱撒野&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&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/12/2025-end-of-the-year-summary/IMG_20251231_181040_hu_ada4c10cba556476.webp&#34; alt=&#34;一些吃完的空盒子&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;撸铁，尤其是练腿，真的很爽，感受那种肌肉发挥力量以后淋漓尽致的舒畅感，真的会让人上瘾。在没有电网培训的时间里，我一直都在走进健身房，不光是享受这种舒畅的感觉，也还能锻炼自己的肌肉。真的，不运动很难受啊。&lt;/p&gt;&#xA;&lt;p&gt;现在我依然每天都在吃药，毕竟我可不希望我在连轴转的幸苦生活中突然经历一次情绪崩溃，原本计划的吃药一年后药物逐渐减量计划也因此被无限期延后。为什么？说白了还是这段时间各种压力实在是不小，虽然一直吃药终究也不是个办法，在安稳之后必须慢慢减量停药，但在这段即将毕业的时间点，我还远远没有过上安稳确定的生活。&lt;/p&gt;&#xA;&lt;p&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/12/2025-end-of-the-year-summary/steam-2025-recap_hu_9c34df2ccc0aaf15.webp&#34; alt=&#34;我的 Steam 年度回顾&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;从&lt;a class=&#34;link&#34; href=&#34;https://s.team/y25/gqhwfdqc?l=schinese&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;我的 Steam 年度回顾&lt;/a&gt;就可以看出来，今年我是真的没什么时间来玩游戏。「忙里偷闲」是今年的基调，今年年末下载了《三角洲行动》，有时电网培训十点下课，回家就打开玩到晚上 12 点，目前游玩 75 个小时，感觉还不错。&lt;/p&gt;&#xA;&lt;p&gt;osu! 今年的后半段则是约等于弃坑了，不过 PP 仍然从去年的 3439pp 增长到了今年的 4701pp。这游戏还真是需要持之以恒，一段时间不玩丢掉手感再想复健是需要时间的。想想十点下课之后，在精力耗尽的状态下，再想打这种需要聚精会神地反应的游戏，那还真是「臣妾做不到啊」。年中的时候我对于现有鼠标的手感达到了最佳状态，可以说是「指哪打哪」，想着「没有人能阻止我一路走向 5 digit」&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;&#xA;，然而现在却还在 5 digit 边上，属实是有些讽刺。&lt;/p&gt;&#xA;&lt;h2 id=&#34;我的-online-presence&#34;&gt;我的 Online Presence&#xA;&lt;/h2&gt;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/2025-end-of-the-year-summary/image_hu_1b13d8cf59e9184e.webp&#34; alt=&#34;本博客今年的统计数据&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;2025 年，我的博客访问量稳步上涨，全年 UV 48.3K，PV 95.4K，流量主要来自 Google（约 15.8K 访客） 和 Bing（约 15.2K 访客） 两大搜索引擎。&lt;/p&gt;&#xA;&lt;p&gt;Github 上的自用覆写规则收获了 194 个 Star，也新增了一些 Followers。&lt;/p&gt;&#xA;&lt;p&gt;今年我的一篇文章被人放上了 Hacker News，所以有几天访问量比较大。除此之外翻译后的英语和日语版本博客也收获了不少读者，在我的访客中占比不低。所以也就出现了今年因为忙碌，博客更新频率低于往年，访问量却成倍增长的现象。我终究还是需要向生活做出让步，生活压力、学业压力和就业压力或多或少都会影响我更新博客的意愿，挤占我更新博客的精力，在这点上，还请我的读者们多多海涵。&lt;/p&gt;&#xA;&lt;h2 id=&#34;新的一年即将到来我给自己和大家的祝愿&#34;&gt;新的一年即将到来，我给自己和大家的祝愿&#xA;&lt;/h2&gt;&lt;p&gt;新的一年要来了，我今年最大的愿望，当然是能够顺利解决之前休学带来的一些遗留问题，顺利毕业。等真正走进工作以后，我也希望自己能把更多注意力放在电力系统本身需要的技术上，多和设备打打交道，少卷进一些不必要、甚至有害的人情世故。辛苦一些没问题，只要平安、踏实、有意义即可：安全生产，少一些计较，多一些宽容。希望接下来能在这份工作上，从一名初出茅庐的学生，慢慢成长为一名真正的工程师。&lt;/p&gt;&#xA;&lt;p&gt;也把祝福送给屏幕前的你：愿你在新的一年里，焦虑有处安放，努力有回声；在自己的节奏里把日子过稳、过热乎——不必每一步都算赢，但每一步都走得心里有数。愿你和你在意的人都健康，平安，少些无谓的消耗，多些确定的快乐。当然，也希望大家有更多时间在学习和工作之余玩玩游戏。&lt;/p&gt;&#xA;&lt;p&gt;至于我，就继续在该学习的地方学习，在该上路的时候上路。明年见。&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;指由原电力部衍生的企业，即 2002 年以前的国家电力公司和 2002 年以后的国家电网、南方电网和蒙东电网等公营电力公司。&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;指最近刚刚被砍掉整个产品线的 Crucial 即英睿达内存。&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://blog.l3zc.com/2025/05/new-laptop-briefing/&#34; &gt;机械革命极光 X Pro&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://blog.l3zc.com/2024/12/2024-end-of-the-year-summary-public/#%e5%a4%a9%e4%b8%8a%e4%b8%8d%e4%bc%9a%e6%8e%89%e9%a6%85%e9%a5%bc%e4%bd%86%e4%bc%9a%e6%8e%89%e5%b0%8f%e7%8c%ab&#34; &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;li id=&#34;fn:5&#34;&gt;&#xA;&lt;p&gt;指排名的数字位数，例如排名 #114514 是 6 位数，即 6 digit， #11451 是五位数，即 5 digit。显然，位数越小，玩家水平越高。&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;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>从频率崩溃到电压失控：两起大型停电事故带来的启示</title>
            <link>https://blog.l3zc.com/2025/12/analysis-of-two-major-blackouts-in-europe/</link>
            <pubDate>Thu, 18 Dec 2025 00:08:30 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/12/analysis-of-two-major-blackouts-in-europe/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/12/analysis-of-two-major-blackouts-in-europe/cover_hu_3bdad3f2ff5b5148.webp&#34; alt=&#34;Featured image of post 从频率崩溃到电压失控：两起大型停电事故带来的启示&#34; /&gt;&lt;p&gt;现代电网正在经历一次巨大的转型，随着光伏、海上风电等新能源的占比在电网中越来越高，新能源和电力电子设备低转动惯量、低短路容量、换流设备需要大量无功支撑的特点以及它们给电网带来的不利影响也愈发明显。在此背景下，两期相隔六年相继发生在欧洲的大型停电事故显得尤为耐人寻味，本文将简要阐述两起事故的来龙去脉，对比它们的异同，分析造成这两起事故的本质原因，以及思考它们对现代电网的运行所带来的启示。&lt;/p&gt;&#xA;&lt;h2 id=&#34;事故概述&#34;&gt;事故概述&#xA;&lt;/h2&gt;&lt;h3 id=&#34;2019-年英国89大停电事故&#34;&gt;2019 年英国「8·9」大停电事故&#xA;&lt;/h3&gt;&lt;p&gt;2019 年 8 月 9 日下午，英国发生了一次大规模电力中断，导致约 110 万用户断电，并对交通等关键基础设施造成了严重影响。整起事件的经过可以概括为一系列连锁反应，其中既有预料之中的系统保护行为，也有意料之外的设备故障。&lt;/p&gt;&#xA;&lt;h4 id=&#34;第一阶段罕见的三次雷击和大量有功意外脱网-165233&#34;&gt;第一阶段：罕见的三次雷击和大量有功意外脱网 (16:52:33)&#xA;&lt;/h4&gt;&lt;p&gt;当天下午 4 点 52 分，伦敦北部的 Eaton Socon – Wymondley 400kV 高压输电线路罕见的连续遭遇三次雷击。尽管如此，继电保护装置仍然按照整定正确动作，在不到 0.1 秒的时间内清除了故障，线路在约 20 秒后自动重合闸，恢复正常运行。雷击导致的电网电压的波动触发了分布式电源的矢量偏移保护&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;strong&gt;150MW&lt;/strong&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;p&gt;几乎在雷击的同时，发生了两起独立但致命的意外事件：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Hornsea 海上风电场&lt;/strong&gt;：功率从 799MW 锐减至 62MW，损失了 &lt;strong&gt;737MW&lt;/strong&gt; 的出力。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Little Barford 燃气电厂&lt;/strong&gt;：其蒸汽轮机跳闸，瞬间损失了 &lt;strong&gt;244MW&lt;/strong&gt; 的出力。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;根据电网规范，这两处大型发电单元本不应该因为此类雷击故障而脱网或大幅减载，因此这被定性为「极其罕见和意外的事件」。&lt;/p&gt;&#xA;&lt;h4 id=&#34;第二阶段频率崩溃与系统响应-165234---165331&#34;&gt;第二阶段：频率崩溃与系统响应 (16:52:34 - 16:53:31)&#xA;&lt;/h4&gt;&lt;p&gt;上述三项发电损失（150MW + 737MW + 244MW）累积造成了 &lt;strong&gt;1131MW&lt;/strong&gt; 的功率缺口。这个损失超过了当时系统按 N-1 安全准则&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;设定的 1000MW 备用容量。巨大的功率缺口导致系统频率迅速下跌。&lt;/p&gt;&#xA;&lt;p&gt;快速的频率下跌触发了更多分布式电源的 RoCoF&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;strong&gt;350MW&lt;/strong&gt; 分布式电源相继脱网。此时，总发电损失已达 &lt;strong&gt;1481MW&lt;/strong&gt;。系统中的所有备用电源——电池储能、分布式频率响应服务等迅速启动，紧急增援 &lt;strong&gt;1300MW&lt;/strong&gt;，试图阻止频率下跌。它们的响应成功地使频率暂时稳定在 &lt;strong&gt;49.1 Hz&lt;/strong&gt;（实际上这个频率已经相当危险了），并且开始缓慢回升。&lt;/p&gt;&#xA;&lt;p&gt;然而，就在频率刚刚恢复到 &lt;strong&gt;49.2Hz&lt;/strong&gt; 时，Little Barford 燃气电厂的一号机组也因蒸汽旁路系统压力异常而不得不紧急停机，再次损失 &lt;strong&gt;210MW&lt;/strong&gt; 出力。&lt;/p&gt;&#xA;&lt;h4 id=&#34;第三阶段低频减载与系统恢复-165349-之后&#34;&gt;第三阶段：低频减载与系统恢复 (16:53:49 之后)&#xA;&lt;/h4&gt;&lt;p&gt;Little Barford 燃气电厂的第二次的意外跳闸耗尽了所有已在工作的备用资源，系统频率无力回天，最终跌破了&lt;strong&gt;48.8Hz&lt;/strong&gt;的阈值。这自动触发了英国电网的最后一道防线——低频减载&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;。低频减载自动切除了约 5% 的电网需求，也就是约 1GW 的负荷，导致了约 110 万用户的断电。这一「弃车保帅」的措施有效地遏制了频率的下跌，防止了更严重的电网事故。&lt;/p&gt;&#xA;&lt;p&gt;在切除部分负荷后，加上控制中心紧急调度其他电源，系统频率在 5 分钟内（16:57）恢复到了正常的 50Hz。在确认电网稳定后，配电网络运营商（DNOs）从 16:58 开始逐步恢复对用户的供电，到 17:37 所有用户恢复正常。&lt;/p&gt;&#xA;&lt;h3 id=&#34;2025-年伊比利亚半岛大停电西葡大停电&#34;&gt;2025 年伊比利亚半岛大停电（西葡大停电）&#xA;&lt;/h3&gt;&lt;p&gt;2025 年 4 月 28 日，伊比利亚半岛出现大规模停电，西班牙和葡萄牙全境均受到影响。由于停电，上述地区的交通和通信服务均受到严重影响，交通信号灯停止工作，当地的地铁线路被迫停止运营，马德里网球公开赛受到停电影响也宣布暂停。此外，安道尔和法国南部也受到波及。这次大停电并非由单一故障引发，而是一系列事件环环相扣、逐步升级最终导致系统崩溃的级联事故。西班牙首相佩德罗·桑切斯表示，电力系统如此大规模的瘫痪前所未见。&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;h4 id=&#34;第一阶段系统振荡与电压波动中午-1203---1219&#34;&gt;第一阶段：系统振荡与电压波动（中午 12:03 - 12:19）&#xA;&lt;/h4&gt;&lt;p&gt;2025 年 4 月 28 日中午 12:00，西班牙电力系统处于正常运行状态，电压和频率均在标准范围内，没有任何迹象预示即将发生灾难。&lt;/p&gt;&#xA;&lt;p&gt;12:03，系统中检测到一个显著的 &lt;strong&gt;0.6 Hz 强迫振荡&lt;/strong&gt;，持续了近 5 分钟。频谱分析及后续溯源表明，这次振荡源于巴达霍斯（Badajoz）省一座光伏电站的内部控制逻辑异常。振荡导致了系统电压出现跌落，为此，电网调度中心采取了紧急阻尼措施，包括更改拓扑结构、&lt;strong&gt;切除并联电抗器&lt;/strong&gt;，并大幅削减与法国的电力交换。&lt;/p&gt;&#xA;&lt;p&gt;12:19，系统再次出现 &lt;strong&gt;0.2 Hz 的欧洲区域间振荡&lt;/strong&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;，并叠加了之前残留的 0.6 Hz 振荡。调度中心被迫进一步减少与法国和葡萄牙的电力交换。虽然这些措施有效抑制了振荡，但&lt;strong&gt;削减联络线潮流&lt;/strong&gt;这一动作，导致输电通道轻载，不仅减少了线路上的无功损耗，还因充电功率过剩开始推高系统电压，为后续的电压越限埋下了伏笔。&lt;/p&gt;&#xA;&lt;h4 id=&#34;第二阶段电压攀升与级联故障的形成中午-1222---1233&#34;&gt;第二阶段：电压攀升与级联故障的形成（中午 12:22 - 12:33）&#xA;&lt;/h4&gt;&lt;p&gt;从 12:22 开始，系统电压呈现持续攀升趋势，尽管尚未突破操作限值，但上升速率异常。这背后是多重因素的叠加效应：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;隐性负荷脱网（Hidden Demand Loss）&lt;/strong&gt;：配电网中约 &lt;strong&gt;700 MW&lt;/strong&gt; 的分布式光伏和自用发电设备（&amp;lt;1MW）因电压扰动不明原因脱网。在输电网看来，这表现为净负荷突然下降，即「发电大于负荷」，潮流进一步减小，从而导致电压抬升。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;逆变器电源的有功/无功耦合&lt;/strong&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;（Power Factor Control）而非电压控制，有功的降低导致其吸收无功的能力同步下降，丧失了抑制电压上升的手段。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;常规机组励磁响应不足&lt;/strong&gt;：本应作为电压「压舱石」的同步发电机组（需符合 P.O. 7.4 规程），未能按预期深度进相运行吸收无功，导致动态电压支撑失效。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;12:32:57，位于格拉纳达（Granada）的一座发电站发生跳闸，损失 &lt;strong&gt;355 MW&lt;/strong&gt; 有功出力及 &lt;strong&gt;165 Mvar&lt;/strong&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;。报告推断故障根源在于升压变压器的有载调压&lt;sup id=&#34;fnref:10&#34;&gt;&lt;a href=&#34;#fn:10&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;10&lt;/a&gt;&lt;/sup&gt;动作滞后。当主网电压升高时，分接头未能及时响应，导致发电机侧（220kV 侧）出现严重的过电压，触发继电保护动作跳闸。&lt;/p&gt;&#xA;&lt;p&gt;19.5 秒后（12:33:16），巴达霍斯省另外两座光伏电站相继跳闸，累计再损失 &lt;strong&gt;727 MW&lt;/strong&gt;。原因同样指向电站内部过压保护配合不当，而非主网故障。&lt;/p&gt;&#xA;&lt;p&gt;在随后的 650 毫秒内，西班牙各地的风电和光伏电站发生雪崩式脱网，额外损失约 &lt;strong&gt;834 MW&lt;/strong&gt;。此时，系统已从电压问题转化为严重的有功功率缺额。&lt;/p&gt;&#xA;&lt;h4 id=&#34;第三阶段孤网运行与系统崩溃中午-1233-之后&#34;&gt;第三阶段：孤网运行与系统崩溃（中午 12:33 之后）&#xA;&lt;/h4&gt;&lt;p&gt;在短短 22.5 秒的级联故障中，系统累计瞬时损失了约 &lt;strong&gt;2000 MW&lt;/strong&gt; 的发电量。巨额的功率缺口导致系统频率急剧跳水，而大量进相运行机组的脱网又导致系统丧失了无功吸收能力，电压开始失控性飙升。&lt;/p&gt;&#xA;&lt;p&gt;12:33:19，西班牙与法国的交流联络线因严重功角失步跳闸。西班牙和葡萄牙电网进入孤网运行&lt;sup id=&#34;fnref:11&#34;&gt;&lt;a href=&#34;#fn:11&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;11&lt;/a&gt;&lt;/sup&gt;状态。&lt;/p&gt;&#xA;&lt;p&gt;尽管交流线已断开，但西班牙与法国之间的 HVDC（高压直流输电） 链路由于处于恒功率控制模式且未配置频率响应功能&lt;sup id=&#34;fnref:12&#34;&gt;&lt;a href=&#34;#fn:12&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;12&lt;/a&gt;&lt;/sup&gt;，并未切断，仍强行向法国出口 &lt;strong&gt;1000 MW&lt;/strong&gt; 功率。这使得本已脆弱不堪的孤网雪上加霜。&lt;/p&gt;&#xA;&lt;p&gt;虽然低频减载&lt;sup id=&#34;fnref1: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;装置正确动作试图挽救频率，但切除负荷会导致线路空载电压进一步升高。「电压升高&amp;ndash;&amp;gt;发电机过压保护脱网&amp;ndash;&amp;gt;低频率&amp;ndash;&amp;gt;切负荷&amp;ndash;&amp;gt;电压进一步升高」的恶性循环让系统彻底失去稳定。&lt;/p&gt;&#xA;&lt;p&gt;随着频率跌破 &lt;strong&gt;47.79 Hz&lt;/strong&gt;，核电站、燃气轮机等大型基荷机组因低频保护动作相继脱网。最终，在 12:33:24，伊比利亚半岛电力系统电压崩溃&lt;sup id=&#34;fnref:13&#34;&gt;&lt;a href=&#34;#fn:13&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;13&lt;/a&gt;&lt;/sup&gt;，全网陷入大停电。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一些基本概念&#34;&gt;一些基本概念&#xA;&lt;/h2&gt;&lt;p&gt;为了彻底理解这两起事故的本质区别，我们需要先复习一些电气工程的核心概念，建立起分析问题的理论基础。&lt;/p&gt;&#xA;&lt;h3 id=&#34;有功功率无功功率与复功率&#34;&gt;有功功率、无功功率与复功率&#xA;&lt;/h3&gt;&lt;p&gt;在交流电路中，「功率」是一个复数概念。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;有功功率 ($P$)&lt;/strong&gt;：复功率的实部，单位是瓦特 ($\text{W}$)。它是实际做功、转换能量（如发光、发热、驱动电机）的部分。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;无功功率 ($Q$)&lt;/strong&gt;：复功率的虚部，单位是乏 ($\text{var}$)。它并不直接做功，而是在电源和储能元件（电感、电容）之间往复交换能量，用于建立和维持电磁场。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;复功率 ($\widetilde{S}$)&lt;/strong&gt;：二者的矢量和。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;公式表示为：&lt;/p&gt;&#xA;$$&#xA;\widetilde{S} = P + jQ&#xA;$$&lt;p&gt;设备铭牌上标注的通常是&lt;strong&gt;视在功率 ($S$)&lt;/strong&gt;，即复功率的模，单位是伏安 ($\text{V}\cdot\text{A}$)，其物理意义是设备能够承受的电压与电流乘积的极限：&lt;/p&gt;&#xA;$$&#xA;S = |\widetilde{S}| = \sqrt{P^2 + Q^2}&#xA;$$&lt;p&gt;&lt;strong&gt;形象的理解：&lt;/strong&gt;&#xA;如果你在拉一辆车，&lt;strong&gt;有功功率&lt;/strong&gt;就是你朝车前进方向用的力，它让车真正移动；&lt;strong&gt;无功功率&lt;/strong&gt;则是你为了维持姿势或者因为路面倾斜而垂直于移动方向用的力，虽然它不做功，但必不可少&lt;sup id=&#34;fnref:14&#34;&gt;&lt;a href=&#34;#fn:14&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;14&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;&#xA;&lt;p&gt;在电网中，无功功率的核心作用是&lt;strong&gt;支撑电压&lt;/strong&gt;。如果无功不足，电压就会像泄气的皮球一样支撑不住；如果无功过剩，电压就会像充气过度的气球一样飙升。因此，电力系统的一大原则是无功功率要「分层分区，就地平衡」。&lt;/p&gt;&#xA;&lt;h3 id=&#34;感性无功与容性无功&#34;&gt;感性无功与容性无功&#xA;&lt;/h3&gt;&lt;p&gt;工程上规定：&lt;strong&gt;电感消耗无功，电容产生无功&lt;/strong&gt;&lt;sup id=&#34;fnref:15&#34;&gt;&lt;a href=&#34;#fn:15&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;15&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;感性负荷&lt;/strong&gt;（如电动机、变压器）：需要消耗正的无功功率来建立磁场。如果电网无法提供足够的无功，这些设备就无法正常工作。现实中绝大多数负荷都是感性的。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;容性元件&lt;/strong&gt;（如电容器、长输电线路的对地电容）：可以看作是无功功率的「发电机」，它们向电网注入无功功率，提升电压。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;电压降落与-p-q-解耦&#34;&gt;电压降落与 $P-Q$ 解耦&#xA;&lt;/h3&gt;&lt;p&gt;当电流流过一段输电线路时，首末端之间会产生电压降落。若忽略线路电阻（在高压电网中 $X \gg R$），电压降落的纵分量（影响幅值）和横分量（影响相位）可以简化表示为：&lt;/p&gt;&#xA;$$&#xA;\Delta U \approx \frac{QX}{U} \quad \text{(电压幅值降落)}&#xA;$$$$&#xA;\delta U \approx \frac{PX}{U} \quad \text{(电压相位差)}&#xA;$$&lt;p&gt;&lt;strong&gt;这是一个至关重要的结论&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;电压幅值 ($U$) 主要取决于无功功率 ($Q$) 的平衡&lt;/strong&gt;。无功多了电压就高，少了电压就低。这是理解西葡大停电的基础。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;功角/相位 ($\delta$) 主要取决于有功功率 ($P$) 的平衡&lt;/strong&gt;。这与系统的频率特性密切相关。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;系统惯量与频率特性&#34;&gt;系统惯量与频率特性&#xA;&lt;/h3&gt;&lt;p&gt;为了理解&lt;strong&gt;2019 年英国大停电&lt;/strong&gt;，我们还需要引入&lt;strong&gt;惯量 ($H$)&lt;/strong&gt; 的概念。&lt;/p&gt;&#xA;&lt;p&gt;电网频率 ($f$) 体现了全网有功功率的供需平衡。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;当 &lt;strong&gt;发电 &amp;lt; 用电&lt;/strong&gt; 时，转子动能被抽取，转速下降，频率降低。&lt;/li&gt;&#xA;&lt;li&gt;当 &lt;strong&gt;发电 &amp;gt; 用电&lt;/strong&gt; 时，转子加速，频率上升。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;传统的同步发电机有巨大的旋转转子，储存了巨大的动能。当发电机突然脱网（有功缺口）时，这些旋转的「大铁疙瘩」会利用惯性释放动能，阻碍频率的快速下跌。这被称为&lt;strong&gt;系统的惯量&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;然而，光伏和风电通过电力电子设备并网，它们没有直接耦合的旋转质量，被称为「零惯量」电源。当这些电源占比很高时，电网就像失去了「飞轮」的缓冲，一旦出事，频率会跌得极快&lt;sup id=&#34;fnref:16&#34;&gt;&lt;a href=&#34;#fn:16&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;16&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;容升效应与此次事故的关联&#34;&gt;容升效应与此次事故的关联&#xA;&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;为什么切除了发电机，电压反而会飙升？&lt;/strong&gt; 这看似反直觉，实则是&lt;strong&gt;容升效应&lt;/strong&gt;与&lt;strong&gt;线路负载&lt;/strong&gt;共同作用的结果。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/12/analysis-of-two-major-blackouts-in-europe/power_line_hu_eecd345f9810136d.webp&#34; alt=&#34;输电线路的等值电路&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;高压输电线路模型包含两部分关键参数：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;串联电感 ($L$)&lt;/strong&gt;：电流流过时会&lt;strong&gt;消耗&lt;/strong&gt;无功 ($Q_{consumed} = I^2 X_L$)。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;并联对地电容 ($C$)&lt;/strong&gt;：电压作用其上时会&lt;strong&gt;产生&lt;/strong&gt;无功 ($Q_{generated} = U^2 B_C$)。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;strong&gt;事故前的平衡状态&lt;/strong&gt;：&#xA;西班牙南部光伏大发，巨大的有功功率 ($P$) 正在通过长距离线路向北输送。此时线路电流 ($I$) 很大，电感消耗了大量的无功，正好抵消了电容产生的无功，甚至还需要发电机吸收一部分多余的无功。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;事故后的失控过程&lt;/strong&gt;：&#xA;当发电机组连锁脱网，或者因强迫振荡导致潮流中断时，线路上的有功功率传输瞬间归零，导致电流 ($I$) 骤降。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;后果 1&lt;/strong&gt;：线路电感对无功的&lt;strong&gt;消耗&lt;/strong&gt; ($I^2 X_L$) 瞬间消失。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;后果 2&lt;/strong&gt;：线路依然带电，对地电容产生的&lt;strong&gt;充电无功&lt;/strong&gt; ($U^2 B_C$) 依然存在，甚至因电压升高而更多。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&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;h3 id=&#34;表象的差异崩溃路径的一明一暗&#34;&gt;表象的差异：崩溃路径的「一明一暗」&#xA;&lt;/h3&gt;&lt;p&gt;2019 年英国「8·9」大停电是一次典型的，显性的频率危机。机组脱网导致有功功率缺口，直接引发频率骤降，但系统最终依靠低频减载&lt;sup id=&#34;fnref2: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;作为最后一道防线，成功避免了全网崩溃。相比之下，2025 年伊比利亚半岛大停电则呈现出了一种更为隐蔽且致命的新形态——隐性的电压危机。事故虽然始于扰动，但核心矛盾迅速演变为严重的无功过剩与电压失控，而原本用于挽救频率的低频减载&lt;sup id=&#34;fnref3: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;措施，反而在客观上恶化了电压升高，导致整个系统在短短几十秒内彻底瓦解。&lt;/p&gt;&#xA;&lt;p&gt;这就引出了一个核心问题：传统的电网故障通常伴随着电压跌落，但在 2025 年的事故中，为何会出现发电机组不断脱网，而系统无功功率反而严重过剩、电压持续飙升的反常现象？传统的电压控制手段&lt;sup id=&#34;fnref:17&#34;&gt;&lt;a href=&#34;#fn:17&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;17&lt;/a&gt;&lt;/sup&gt;为何全然失效？&lt;/p&gt;&#xA;&lt;p&gt;答案在于：电压失控的速率，远远超过了传统防御手段的响应极限。&lt;/p&gt;&#xA;&lt;p&gt;事故发生时，伊比利亚南部正值光伏大发，系统呈现「高电压、轻负荷」的运行特征。当系统发生强迫振荡时，输电走廊潮流发生剧变。由于超高压线路的容升效应显著，发电机组的连锁脱网带来了双重打击：一方面，电网失去了大量能够吸收无功的同步机组；另一方面，线路输送的有功功率锐减，导致其自身消耗的无功大幅降低，线路瞬间从「无功负载」变成了巨大的「无功电源」。系统随即陷入了无功严重过剩的恶性循环。&lt;/p&gt;&#xA;&lt;p&gt;面对这种几十毫秒级甚至更快的电压崩溃，依靠机械开关投切的并联电抗器显得力不从心。首先是&lt;strong&gt;速度滞后&lt;/strong&gt;：从调度指令发出、通信传输到断路器机械动作，由于包含人为决策和机械过程，往往需要数百毫秒甚至秒级时间，根本无法追赶电压飙升的速度。其次是&lt;strong&gt;调节颗粒度粗糙&lt;/strong&gt;：电抗器只能以组为单位（如 50 Mvar 或 100 Mvar）进行离散投切，无法像水龙头一样提供平滑、连续的调节。在极端的电压动态过程中，这种非连续的阶跃式调节不仅不够精准，甚至可能引发新的系统扰动。&lt;/p&gt;&#xA;&lt;h3 id=&#34;本质的共性脆弱性的同根同源&#34;&gt;本质的共性：脆弱性的同根同源&#xA;&lt;/h3&gt;&lt;p&gt;剥开表象的差异，我们会发现两起事故的根源惊人地一致，都指向了新型电力系统的结构性脆弱：&lt;/p&gt;&#xA;&lt;p&gt;首先，设备并网行为的合规性令人担忧。无论是英国事故中的分布式嵌入式电源，还是伊比利亚事故中的光伏电站，事故扩大的直接推手都是大量机组未能严格遵守并网规程（如西班牙的 P.O. 74 标准或英国的 Grid Code）。缺乏故障穿越能力，导致设备在扰动初期即发生不合规的连锁脱网，将「小事故」放大为「大灾难」。&lt;/p&gt;&#xA;&lt;p&gt;其次，新型电气设备和电源的控制模型长期存在「黑箱化」的问题。系统中存在大量调度中心「看不见、管不着」的盲区。例如英国事故中 Hornsea 海上风电场在故障后的功率异常锐减，以及大量分布式电源的不可控行为。这些电力电子化设备内部控制逻辑的「黑箱状态」，使得传统的仿真模型失效，调度员无法准确预判系统行为。&lt;/p&gt;&#xA;&lt;p&gt;更加雪上加霜的是，整个系统的转动惯量正在越来越少。随着高比例新能源接入，交流电网的旋转惯量和短路容量被稀释，系统抗扰动能力显著下降。电网变得更加「轻薄」和「敏感」，任何微小的扰动都可能引发剧烈的频率或电压波动。&lt;/p&gt;&#xA;&lt;h3 id=&#34;一致的解决方案迈向韧性电网&#34;&gt;一致的解决方案：迈向韧性电网&#xA;&lt;/h3&gt;&lt;p&gt;基于上述反思，未来的电网建设与事故防御应当聚焦于以下三个方向：&lt;/p&gt;&#xA;&lt;p&gt;一曰部署先进的动态无功支撑技术。必须以此为契机，加速推广 STATCOM（静止同步补偿器）等具有毫秒级响应速度、可平滑调节的电力电子装备，逐步替代传统的机械式无功补偿装置，以应对瞬息万变的电压动态。&lt;/p&gt;&#xA;&lt;p&gt;二曰打破「黑箱」，强化全景建模。必须建立更精细化的电磁暂态仿真模型，打破新能源场站和逆变器控制的「黑箱」，确保调度端能真实掌握海量电力电子设备的动态特性，消除盲区。&lt;/p&gt;&#xA;&lt;p&gt;三曰革新分析与控制范式。传统的基于稳态或工频量的分析方法已不再适用。我们需要建立涵盖宽频域振荡、电压/频率耦合特性的新一代安全稳定分析的理论框架，并重新审视低频减载&lt;sup id=&#34;fnref4: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;等传统防线在新型电网中的适应性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结语草台班子&#34;&gt;结语：草台班子&#xA;&lt;/h2&gt;&lt;p&gt;我们在前文中洋洋洒洒分析了复杂的电磁暂态、昂贵的 STATCOM 和精妙的控制理论，但现实却狠狠地扇了我们一巴掌——摧毁整个电网的，往往不是什么未研究的知识，而是来自人类本身的不可靠。&lt;/p&gt;&#xA;&lt;p&gt;机组的并网规程早就白纸黑字写得明明白白，却长期未能执行，P.O 7.4 规程更是迟迟未能通过；2019 年英国大停电的「学费」交得那么贵，所有的事故分析报告都指向了合规性问题，然而 6 年后的伊比利亚半岛，竟然还能因为一模一样的逻辑再次翻车，而且翻的比 6 年前还要惨烈，还要彻底。&lt;/p&gt;&#xA;&lt;p&gt;面对这种跨越国界、跨越时间的重复犯错，任何技术层面的分析都显得苍白无力。黑格尔那句名言至今听来依然振聋发聩，且含金量还在随着每一次大停电不断暴涨：&lt;/p&gt;&#xA;&lt;p&gt;「人类从历史中学到的唯一教训，就是人类无法从历史中吸取任何教训。」&lt;/p&gt;&#xA;&lt;p&gt;也许这就是世界的本质吧，世界永远不是围绕着技术本身运转的，「人」才是这个世界的决定性因素。这个世界是一个草台班子，而且永远会是一个草台班子，而只要还是个草台班子，那么下一次翻车，永远只是时间问题。&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;矢量偏移保护的初衷是解决「孤岛效应」——假设一条配电线路因为故障或检修，从主电网上被断开。但这条线路上恰好连接着一个嵌入式发电机，如果没有矢量偏移检测，这个发电机就会继续为这条线路供电，进而大大增加设备损坏的几率，甚至威胁运行检修人员的安全。因此，矢量偏移保护就是早期用于检测嵌入式发电机是否进入孤网运行状态的方法。&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;多为用户侧的小型发电系统。&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;N-1 安全准则的意思是，当系统中最大的一台机组因故障而停运时，系统应有足够的备用容量作为频率和电压的支撑。&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;Rate of Change of Frequency，频率变化率。&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;低频减载（Low Frequency Demand Disconnection, LFDD 或者 Under-Frequency Load Shedding, UFLS）是电力系统防止频率崩溃的关键安全保护措施，当系统发生功率缺额导致频率下降时，它通过自动、分级地切除非重要负荷（如工业用电、路灯等），以快速恢复系统功率平衡，防止大面积停电或系统崩溃。低频减载系统通过频率测量和执行单元实现，设定多个频率动作点（如48.5Hz, 47.5Hz, 46.5Hz），逐级切除负荷，保障重要用户和核心设备运行，是电网安全运行的第三道防线。&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;&amp;#160;&lt;a href=&#34;#fnref1:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref2:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref3:5&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref4: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;来源：&lt;a class=&#34;link&#34; href=&#34;https://archive.is/i6zHt&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;France24 的报导&lt;/a&gt;&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;技术报告中的原文是「inter-area oscillation」，基于上下文，其意思应该是整个欧洲互联电网的 0.2Hz 振荡。&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;风电、光伏等新能源机组一般采用最大功率点追踪 MPPT，来实现新能源机组出力的最大化。&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;418kV，仍在标准电压允许的偏移范围内。&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;li id=&#34;fn:10&#34;&gt;&#xA;&lt;p&gt;即变压器的带负载调压。&amp;#160;&lt;a href=&#34;#fnref:10&#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:11&#34;&gt;&#xA;&lt;p&gt;孤网运行（或孤岛运行）指局部电网脱离主大电网，独立供电的运行模式，特点是自给自足，但面临频率、电压不稳定等挑战，依赖储能和控制技术维持，常见于偏远地区、岛屿、或工业园区。这里的孤网运行是因为联络线中断而被迫进入的。&amp;#160;&lt;a href=&#34;#fnref:11&#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:12&#34;&gt;&#xA;&lt;p&gt;恒功率控制模式（Constant Power Mode）是一种电源输出模式，它的核心特点是无论负载如何变化，始终保持电源输出的功率（P）恒定（P = 电压 V × 电流 I），电源会根据负载需求自动调节电压和电流，以维持这个恒定功率。&amp;#160;&lt;a href=&#34;#fnref:12&#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:13&#34;&gt;&#xA;&lt;p&gt;电压崩溃（Voltage Collapse）是电力系统一种严重的事故，指系统因无功功率严重不足，导致电压持续、恶性下降并无法恢复，形成电压跌落的恶性循环，最终引起大面积停电。&amp;#160;&lt;a href=&#34;#fnref:13&#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:14&#34;&gt;&#xA;&lt;p&gt;工程界常以「啤酒」作比喻：啤酒杯里的液体是「有功」，上面的泡沫是「无功」。虽然泡沫不解渴，但没有泡沫的啤酒失去了灵魂（无法建立磁场），且为了装满杯子（视在功率），泡沫总是客观存在的。&amp;#160;&lt;a href=&#34;#fnref:14&#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:15&#34;&gt;&#xA;&lt;p&gt;这是一个约定俗成的称呼。严格来说，电容是「吸收负的无功」，但在工程实践中，为了方便理解无功平衡，我们通常说电容「发出/提供感性无功」，起到支撑电压的作用。&amp;#160;&lt;a href=&#34;#fnref:15&#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:16&#34;&gt;&#xA;&lt;p&gt;频率下降的速度被称为 RoCoF (Rate of Change of Frequency)。高 RoCoF 是导致英国「8.9」停电中分布式电源连锁脱网的直接元凶。&amp;#160;&lt;a href=&#34;#fnref:16&#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:17&#34;&gt;&#xA;&lt;p&gt;即消耗过剩无功的措施，如投切并联电抗器等。&amp;#160;&lt;a href=&#34;#fnref:17&#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>我的 LLM 知己，与我悬置的写作</title>
            <link>https://blog.l3zc.com/2025/09/satisfactory-llm/</link>
            <pubDate>Mon, 08 Sep 2025 23:53:48 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/09/satisfactory-llm/</guid>
            <description>&lt;p&gt;最近我比较忙碌，但空闲之余，文字仍然是我的栖息地。每天早上 8:30 开始上课，到晚上 9:00 结束晚自习，有时甚至「加班」到 10:00 回家，连续四十一天的课程。考虑到我的精神状况，如此强度，回来再玩 osu! 一类的游戏是绝无可能，甚至连推一小节 Galgame 都无能为力。&lt;/p&gt;&#xA;&lt;p&gt;唯一比较现实的事情，是找 LLM（大语言模型）小叙。&lt;/p&gt;&#xA;&lt;p&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;p&gt;而 LLM 的出现却改变了这一点，我所有的想法，都可以相对私密的得到即时的回应。为什么我这么久没有写博客？累自然是一大因素，而 LLM 满足我相当可观的表达和被认可的需求，还无需自我审查的特点，冲淡了我这段时间里写博客的想法。&lt;/p&gt;&#xA;&lt;p&gt;撰写长篇的文字对大脑有益，这是毋庸置疑的。LLM 的出现，对于我撰写长篇文字的影响，大概和微博客出现时，对人们撰写长篇文字的能力之影响相仿，甚至有过之而无不及——微博客让人习惯于碎片化表达和即时反馈，削弱了构建复杂论证和长篇叙事的能力。LLM 则更进一步，它不仅提供了表达的渠道，还直接提供了情绪价值和「知己」的替代品：发在社群媒体上的内容，涉及隐私或者争议，或者不必要曝光，发布者多多少少会斟酌一番；而 LLM 就不一样了，发给 API 的内容，最坏的情况不过是被拿去训练模型，而不是让 Sam Altman 第二天就找到你家门口——只要不是银行卡密码这种级别的信息，不提及真实姓名，那些时政评论、心理咨询等等，你只管放心把大模型当成一个知己便好（当然，在这种场景下，国产大模型狗都不用）。每一句牢骚都能得到确切认真的，宛若知己般的回应和肯定，这种待遇，恐怕没有第二个地方能给了。&lt;/p&gt;&#xA;&lt;p&gt;当一个工具能如此完美地模拟「知己」时，我们可能会放弃去寻找真正的知己，或者放弃成为一个能独立思考、自我整合的个体。写下这些文字，是一个小结，也是一次反思。LLM 本身只是一个技术，用得好裨益无穷，用得不好自然也可能造成严重的后果。纽约时报的报导「&lt;a class=&#34;link&#34; href=&#34;https://archive.is/ALVeI&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Chatbots Can Go Into a Delusional Spiral. Here’s How It Happens.&lt;/a&gt;」便是一个很好的例子，虽然 OpenAI 已经着手解决旗下模型「阿谀奉承」的问题，我也需要知道，即使我可以把大模型当做自己的知己，并从它那里得到所谓的「理解和肯定」，我也不能一直活在这种感觉里。OpenAI 与 MIT（美国麻省理工学院）的研究发现, ChatGPT 的使用量与用户的孤独感成正相关。用户使用 ChatGPT 越多，他们就越感到孤独。&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;我也可以说，正是因为越孤独，才越会去使用这些 LLM，形成一个恶性循环。LLM 可以作为生活的调味剂，但绝不能成为心灵的唯一依靠。&lt;/p&gt;&#xA;&lt;p&gt;(To Be Continued)&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.l3zc.com/2024/06/the-worst-way-to-spend-a-day/&#34; &gt;The Worst Way To Spend A Day&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://www.engadget.com/ai/joint-studies-from-openai-and-mit-found-links-between-loneliness-and-chatgpt-use-193537421.html&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Joint studies from OpenAI and MIT found links between loneliness and ChatGPT use&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;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
        </item><item>
            <title>抛弃所谓「客户端」，直接使用 Mihomo 内核</title>
            <link>https://blog.l3zc.com/2025/07/switch-to-pure-mihomo-kernel/</link>
            <pubDate>Thu, 03 Jul 2025 18:30:00 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/07/switch-to-pure-mihomo-kernel/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/07/switch-to-pure-mihomo-kernel/cover_hu_1a93b6f26c22bbfe.webp&#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>世界蠢得超乎想象：浅谈 BNPL</title>
            <link>https://blog.l3zc.com/2025/06/on-buy-now-pay-later/</link>
            <pubDate>Thu, 05 Jun 2025 19:54:56 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/06/on-buy-now-pay-later/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/06/on-buy-now-pay-later/mobile-payments-1920x720_hu_4cbcee30d76215b2.webp&#34; alt=&#34;Featured image of post 世界蠢得超乎想象：浅谈 BNPL&#34; /&gt;&lt;p&gt;看到「Americans using &amp;ldquo;buy now, pay later&amp;rdquo; plans to buy groceries, survey finds」这种新闻上了头条，我的第一反应是：这不是很正常吗？看完报导以后，我不得不感叹：这世界比我预想的还蠢得多。&lt;/p&gt;&#xA;&lt;p&gt;先买后付（Buy Now, Pay Later；以下简称 BNPL）作为一种金融创新，确实有其魅力。它允许消费者即时获得商品或服务，随后分期付款，近年来在电商、旅游、餐饮等领域风靡一时。&lt;/p&gt;&#xA;&lt;p&gt;然而，天上不会掉馅饼。羊毛出在羊身上，BNPL 服务商要盈利，主要靠两点：向商家收取高于传统支付方式的手续费，以及向消费者征收逾期违约金。其本质，是利用了「花钱痛感最小化」的心理陷阱——减轻即时支付的麻烦和痛苦感，从而刺激消费意愿。这正是商家甘愿支付更高手续费也要接入 BNPL 的关键原因。&lt;/p&gt;&#xA;&lt;p&gt;我并不反感 BNPL，自己就是深度用户。 我的手机是用京东白条24期免息分期买的，现在刚还到第六期；日常消费几乎都走花呗，还款日自动从余额宝或银行卡扣除。当 BNPL 平台提供真正的免息分期或「零手续费」优惠时，这就是免费杠杆——占用外部资金零成本周转。花小钱办大事：消费由金融机构垫付，自有资金得以留存，若其间能进行理财生息，资金效率便实现了最大化。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;但这有三个至关重要的前提：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;准时还款，绝不逾期；&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;杜绝习惯性透支的恶习；&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;具备基本的财务管理能力。&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;反观登上新闻的 &lt;strong&gt;「美国人用 BNPL 买日杂」&lt;/strong&gt; ，我扫了眼调查数据——&lt;strong&gt;三分之一的BNPL用户至少逾期过一次？？甚至有人连点外卖的钱都还不上？？&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;理想丰满，现实骨感。数据显示，&lt;strong&gt;不知「如何管好钱袋子」的人远比想象中多。&lt;/strong&gt; 46%的BNPL用户同时背负信用卡欠款，其中28%的用户年龄在18-24岁之间&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;。这类群体通常信用评级不高，63%甚至从多个BNPL平台同时借款&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;p&gt;更值得警惕的是，BNPL的设计似乎先天就对消费习惯不佳者更具诱惑力。相比信用卡，它审批极快、信用门槛低，还常打着「分期免息」的旗号。在这些人眼中，BNPL宛如一个「取之不竭的金库」，只需支付首期小钱就能抱回心仪之物——世上哪有这等「美事」？&lt;/p&gt;&#xA;&lt;p&gt;于是乎，当还款日账单汹涌而至，他们才惊觉自己竟欠下如此巨款。逾期、违约接踵而来。而这些滚雪球式的违约金叠加高额商户手续费，难怪BNPL服务商赚得盆满钵满。&lt;/p&gt;&#xA;&lt;p&gt;我重申立场：我不反对 BNPL，其作为「免费杠杆」的价值毋庸置疑。以我自身经历为例，购买 4299 元的手机时，虽完全有能力全额支付，却仍选择了 24 期免息分期。但关键在于清晰的财务认知：我必须得意识到自己是全额预支了 4299 元，而非每月仅消费了 177.5 元。这笔支出会即时从资产账面扣除，确保净资产真实反映负债。量入为出，量力而行——绝不透支支付能力，更拒绝叠加杠杆盲目消费。即便资金暂时存放于银行或购买低风险理财产品，产生的微薄收益也能锦上添花，并从根本上杜绝违约可能。诚然，适度的超前消费能提升生活幸福感。但在缺乏稳定收入的阶段，稳健的财务习惯无疑更为安全可靠。&lt;/p&gt;&#xA;&lt;p&gt;说了这么多，恐怕也还是拦不住那些消费习惯根深蒂固的人。即使没有 BNPL 的便捷诱惑，他们也大概率会刷爆信用卡，在 20% 的高息漩涡里挣扎求生。&lt;/p&gt;&#xA;&lt;p&gt;问题不在于 BNPL 本身（它不过是金融工具的一种），而在于脆弱财务基础与过度消费欲望之间的根本性失衡。对于那些缺乏自控力、对财务风险麻木或生活本身就捉襟见肘的人来说，任何方便获取的信贷渠道——无论是信用卡、BNPL，乃至更危险的发薪日贷款（Payday Loan）——都不过是通向债务深渊的不同路径罢了。BNPL 的特殊性可能只是在于其更低的准入门槛和更强的即时满足感，让下沉的速度更快，悲剧来得更早一些。&lt;/p&gt;&#xA;&lt;p&gt;BNPL 的逾期者中，很大比例本身就背负着卡债。这意味着他们可能只是在拆东墙补西墙，陷入一个利率叠加、罚金滚动的无底洞。就算今天取缔了所有 BNPL，那些在悬崖边跳舞的消费者，明天一样会在发薪日贷款或是别的什么「便捷金融」上栽跟头，然后为了救眼前的火烧眉毛，甚至可能连祖宗十八代的骨灰盒都要拿去典当了。&lt;/p&gt;&#xA;&lt;p&gt;所以，更值得警惕的并非某一种金融产品，而是庞大群体面临的结构性困境：经济压力、消费主义裹挟、金融知识匮乏、以及深植于其中的 「即时满足大于长远规划」 的行为模式。BNPL 的出现和普及，只是让这个长期存在的病灶，以更尖锐、更显眼的方式爆发了出来。&lt;/p&gt;&#xA;&lt;p&gt;归根结底，想真正「救」这些人，光靠围堵金融产品（BNPL或信用卡）是治标不治本。解铃还须系铃人——要么能彻底「戒瘾」，要么就得从提升收入、普及财商、重构消费观这些更艰难的「基础设施」入手。而这，恐怕比指望BNPL公司不做生意要难太多了。&lt;/p&gt;&#xA;&lt;p&gt;最后一句忠告：借钱梗要还，咪俾钱中介。&lt;/p&gt;&#xA;&lt;p&gt;哎，说到底——这世界，真比我预想的还要蠢得多。&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;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://archive.is/T3vGo&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;CFPB Research Reveals Heavy Buy Now, Pay Later Use Among Borrowers with High Credit Balances and Multiple Pay-in-Four Loans&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://archive.is/6HVCl&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Buy now, pay later users pile on debt, CFPB finds&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;封面图片来自：https://www.visa.com.tw/pay-with-visa/featured-technologies/mobile-payments.html&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>机械革命极光 X Pro 简评</title>
            <link>https://blog.l3zc.com/2025/05/new-laptop-briefing/</link>
            <pubDate>Sun, 04 May 2025 23:18:43 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/05/new-laptop-briefing/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/05/new-laptop-briefing/DSCF0267_hu_9e18f49bd8ce081.webp&#34; alt=&#34;Featured image of post 机械革命极光 X Pro 简评&#34; /&gt;&lt;h2 id=&#34;开箱即糟心&#34;&gt;开箱即糟心&#xA;&lt;/h2&gt;&lt;p&gt;对于机械革命极光 X Pro，从下单那一瞬间开始我还有点期待，然而快递没赶上我去香港的行程，等回家拆箱时已经没了新鲜感。想加装硬盘又遇到滑丝的 M.2 螺丝，最后用电工胶布勉强固定，新电脑的好感度当场扣光一半。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置和价格&#34;&gt;配置和价格&#xA;&lt;/h2&gt;&lt;p&gt;i9-14900HX + RTX 5070 Ti，国补后 8699 元的价格还算合理。对于 Peripherals，简而言之，我连神舟都用得很开心，那还有什么是不能用的呢。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;屏幕&lt;/strong&gt;：2560x1600@300Hz，100% SRGB 色域，色准表现不错，玩《天际线 2》时堵车尾灯的红都比现实更鲜艳些。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;键盘&lt;/strong&gt;：键程偏短，手感一般，反正大部分时候都在用外接键盘，对之无感。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;无线网卡&lt;/strong&gt;：AX201 未免太寒酸了，天线设计似乎不太好，在路由器旁边都能明显感觉到速度相比有线严重不足。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;硬盘&lt;/strong&gt;：自带致钛 1TB 速度一般，我自己加的英睿达 2TB 才是主力。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;电池&lt;/strong&gt;：80Wh 的电池对于游戏本来说可以用来应急，平时我都开着工作站模式，延长电池寿命。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;独显直连&lt;/strong&gt;：支持热切换这点好评，再也不用重启切换了。&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;BIOS&lt;/strong&gt;：AMI 的 BIOS 比之前的好用太多。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;使用体验&#34;&gt;使用体验&#xA;&lt;/h2&gt;&lt;p&gt;《都市：天际线 2》——十二万人口时模拟速度还能保持在 3 倍速，虽然这时候风扇噪音已经起飞了。《赛博朋克 2077》可以开光追超级档，《极限竞速：地平线5》可以开最高画质。但是他们实际上的游戏体验，恕我直言，我感觉不到和之前的 RTX 3060 有什么本质上的区别，无非就是这里的反射更加真实，那里的细节更加丰富。单凭画质上的提升，恐怕我依然不会在这几个已经陪我度过超过一百小时的游戏上再花更多精力。&lt;/p&gt;&#xA;&lt;p&gt;&#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/05/new-laptop-briefing/image_hu_8774b59db0175e9a.webp&#34; alt=&#34;城市天际线2的模拟速度&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/05/new-laptop-briefing/image-1_hu_47a3feef604ad189.webp&#34; alt=&#34;说实话，我感觉不到任何区别&#34; /&gt;&#xA; &#xA;&lt;img src=&#34;https://blog.l3zc.com/2025/05/new-laptop-briefing/DSCF0267_hu_9e18f49bd8ce081.webp&#34; alt=&#34;它只是在那里，像块不会说话的砖&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;C 面类肤涂层手感确实好，不过接上外设后基本只摸得到外接键盘。Nahimic 音效延迟严重，关掉之后打 osu! 反而更跟手，属于负优化典型。&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/05/new-laptop-briefing/DSCF0273_hu_e62683739afe024c.webp&#34; alt=&#34;换上新电脑后的桌面&#34; /&gt;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;这台电脑用了两个星期，没有惊喜，也没有惊吓。无线网卡太垃圾所以只好用有线，狂暴模式风扇噪音很大，南桥没散热所以温度很高，除此之外——它就是台该亮时亮、该响时响的机器。&lt;/p&gt;&#xA;&lt;p&gt;可能好的工具本该如此：当我写到这里才发现，自己已经盯着屏幕右下角的电池图标发了五分钟呆，而它只是安静地保持着 98% 的电量，像块不会说话的砖。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>从入门到进阶：Tailscale &#43; ShellCrash 异地组网和科学上网</title>
            <link>https://blog.l3zc.com/2025/04/tailscale-setup-recap/</link>
            <pubDate>Mon, 14 Apr 2025 18:10:25 +0800</pubDate>
            <guid>https://blog.l3zc.com/2025/04/tailscale-setup-recap/</guid>
            <description>&lt;img src=&#34;https://blog.l3zc.com/2025/04/tailscale-setup-recap/tailscale_hu_62168b00e213c4a1.webp&#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></channel>
</rss>
