<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>云雀通 Blog</title>
        <link>https://docs.larktun.com/blog</link>
        <description>云雀通 Blog</description>
        <lastBuildDate>Wed, 22 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[headscale 多租户改造：ACL、路由、DNS 等全隔离]]></title>
            <link>https://docs.larktun.com/blog/headscale-multi-tenant-isolation</link>
            <guid>https://docs.larktun.com/blog/headscale-multi-tenant-isolation</guid>
            <pubDate>Wed, 22 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[这篇文章展示在单实例 headscale 中实现多租户隔离的改造结果，重点覆盖 tailnet、ACL、路由、MagicDNS、CLI 和中继策略。]]></description>
            <content:encoded><![CDATA[<p>这篇文章展示在单实例 <code>headscale</code> 中实现多租户隔离的改造结果，重点覆盖 <code>tailnet</code>、ACL、路由、MagicDNS、CLI 和中继策略。</p>
<p>原文链接：
<a href="https://ownding.com/2026/04/22/headscale%E5%A4%9A%E7%A7%9F%E6%88%B7%E6%94%B9%E9%80%A0%EF%BC%8CACL%E3%80%81%E8%B7%AF%E7%94%B1%E3%80%81DNS%E7%AD%89%E5%85%A8%E9%9A%94%E7%A6%BB/" target="_blank" rel="noopener noreferrer" class="">headscale多租户改造，ACL、路由、DNS等全隔离</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="改造目标">改造目标<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#%E6%94%B9%E9%80%A0%E7%9B%AE%E6%A0%87" class="hash-link" aria-label="改造目标的直接链接" title="改造目标的直接链接" translate="no">​</a></h2>
<p>原始 headscale 默认是单实例、单 tailnet。多租户化的关键是把下面能力全部按租户隔离：</p>
<ul>
<li class="">tailnet 地址空间</li>
<li class="">ACL 规则</li>
<li class="">路由配置</li>
<li class="">MagicDNS 命名空间</li>
<li class="">CLI 管理入口</li>
<li class="">中继服务策略</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="关键点">关键点<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#%E5%85%B3%E9%94%AE%E7%82%B9" class="hash-link" aria-label="关键点的直接链接" title="关键点的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="tailnet">tailnet<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#tailnet" class="hash-link" aria-label="tailnet的直接链接" title="tailnet的直接链接" translate="no">​</a></h3>
<ul>
<li class="">每个租户独立 tailnet。</li>
<li class="">地址池可保持默认 <code>10.64.0.0/10</code>，也可以按租户自定义（例如 <code>192.168.6.0/24</code>）。</li>
<li class="">保留 <code>default</code> 租户，兼容原有单租户使用习惯。</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="acl--路由">ACL / 路由<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#acl--%E8%B7%AF%E7%94%B1" class="hash-link" aria-label="ACL / 路由的直接链接" title="ACL / 路由的直接链接" translate="no">​</a></h3>
<ul>
<li class="">ACL 按租户独立维护。</li>
<li class="">路由按租户独立配置与生效。</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="magicdns">MagicDNS<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#magicdns" class="hash-link" aria-label="MagicDNS的直接链接" title="MagicDNS的直接链接" translate="no">​</a></h3>
<ul>
<li class="">FQDN 格式：<code>hostname.&lt;tenant_key&gt;.&lt;dns.base_domain&gt;</code>。</li>
<li class=""><code>default</code> 租户使用 <code>default</code> 子域名。</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="cli">CLI<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#cli" class="hash-link" aria-label="CLI的直接链接" title="CLI的直接链接" translate="no">​</a></h3>
<ul>
<li class="">命令行增加租户参数（例如 <code>-t</code> 指定租户）。</li>
</ul>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="中继服务器">中继服务器<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#%E4%B8%AD%E7%BB%A7%E6%9C%8D%E5%8A%A1%E5%99%A8" class="hash-link" aria-label="中继服务器的直接链接" title="中继服务器的直接链接" translate="no">​</a></h3>
<ul>
<li class="">可选择共享中继。</li>
<li class="">也可为租户分配独立中继，实现更强隔离。</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="示例截图">示例截图<a href="https://docs.larktun.com/blog/headscale-multi-tenant-isolation#%E7%A4%BA%E4%BE%8B%E6%88%AA%E5%9B%BE" class="hash-link" aria-label="示例截图的直接链接" title="示例截图的直接链接" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="users with tenant" src="https://docs.larktun.com/assets/images/user-t-ba83054720a967a68423cd6545f041a4.webp" width="815" height="301" class="img_ev3q">
<img decoding="async" loading="lazy" alt="nodes overview" src="https://docs.larktun.com/assets/images/node-c8cd4b51a500de75df667181d8b7aae0.webp" width="1752" height="367" class="img_ev3q">
<img decoding="async" loading="lazy" alt="nodes with tenant" src="https://docs.larktun.com/assets/images/node-t-04b69f31b904472c20b63553c268d661.webp" width="1741" height="153" class="img_ev3q"></p>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2026/04/22/headscale%E5%A4%9A%E7%A7%9F%E6%88%B7%E6%94%B9%E9%80%A0%EF%BC%8CACL%E3%80%81%E8%B7%AF%E7%94%B1%E3%80%81DNS%E7%AD%89%E5%85%A8%E9%9A%94%E7%A6%BB/" target="_blank" rel="noopener noreferrer" class="">headscale多租户改造，ACL、路由、DNS等全隔离</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>多租户</category>
            <category>ACL</category>
            <category>SaaS</category>
        </item>
        <item>
            <title><![CDATA[headscale 系列：Headscale SaaS 环境下的用户无缝切换实战]]></title>
            <link>https://docs.larktun.com/blog/headscale-saas-seamless-user-switch</link>
            <guid>https://docs.larktun.com/blog/headscale-saas-seamless-user-switch</guid>
            <pubDate>Sat, 25 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[当 Headscale SaaS 需要扩容、维护或做负载再平衡时，核心问题是如何让用户在迁移时尽量“无感”。本文给出一套实战方案：动态路由 + 系统层精准断链 + 自动重连。]]></description>
            <content:encoded><![CDATA[<p>当 Headscale SaaS 需要扩容、维护或做负载再平衡时，核心问题是如何让用户在迁移时尽量“无感”。本文给出一套实战方案：动态路由 + 系统层精准断链 + 自动重连。</p>
<p>原文链接：
<a href="https://ownding.com/2025/10/25/headscale-%E7%B3%BB%E5%88%97%EF%BC%9AHeadscale-SaaS-%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84%E7%94%A8%E6%88%B7%E6%97%A0%E7%BC%9D%E5%88%87%E6%8D%A2%E5%AE%9E%E6%88%98/" target="_blank" rel="noopener noreferrer" class="">headscale-系列：Headscale-SaaS-环境下的用户无缝切换实战</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="架构回顾">架构回顾<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#%E6%9E%B6%E6%9E%84%E5%9B%9E%E9%A1%BE" class="hash-link" aria-label="架构回顾的直接链接" title="架构回顾的直接链接" translate="no">​</a></h2>
<ul>
<li class="">用户域名（如 <code>hsa.demo.com</code>）统一解析到 Traefik。</li>
<li class="">Traefik 按域名把流量转发到对应 headscale 节点。</li>
<li class="">后端通过 <code>cluster_id</code> 维度做数据隔离与迁移。</li>
</ul>
<p><img decoding="async" loading="lazy" alt="saas architecture" src="https://docs.larktun.com/assets/images/arch-8a93c922edde223ea2163cdee96de0f9.webp" width="949" height="390" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="迁移难点">迁移难点<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#%E8%BF%81%E7%A7%BB%E9%9A%BE%E7%82%B9" class="hash-link" aria-label="迁移难点的直接链接" title="迁移难点的直接链接" translate="no">​</a></h2>
<p>即使热更新反向代理路由，已经建立的 TCP 长连接通常不会立刻切换到新后端。</p>
<p><img decoding="async" loading="lazy" alt="tcp long connection" src="https://docs.larktun.com/assets/images/tcp-fe21186a46d8bcc72b4cf360b18fdb6c.webp" width="858" height="698" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="实战迁移步骤">实战迁移步骤<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#%E5%AE%9E%E6%88%98%E8%BF%81%E7%A7%BB%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="实战迁移步骤的直接链接" title="实战迁移步骤的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="1-迁移用户数据">1) 迁移用户数据<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#1-%E8%BF%81%E7%A7%BB%E7%94%A8%E6%88%B7%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="1) 迁移用户数据的直接链接" title="1) 迁移用户数据的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 从旧节点导出用户相关数据</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">pg_dump -h node3-db -U headscale -t nodes -t ip_addresses \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --where="user_id = (SELECT id FROM users WHERE name = 'hsa')" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  &gt; hsa_data.sql</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 修改 cluster_id 并导入新节点</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sed -i 's/cluster_id: 3/cluster_id: 4/g' hsa_data.sql</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">psql -h node4-db -U headscale -d headscale &lt; hsa_data.sql</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="2-热更新-traefik-路由">2) 热更新 Traefik 路由<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#2-%E7%83%AD%E6%9B%B4%E6%96%B0-traefik-%E8%B7%AF%E7%94%B1" class="hash-link" aria-label="2) 热更新 Traefik 路由的直接链接" title="2) 热更新 Traefik 路由的直接链接" translate="no">​</a></h3>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">http</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">routers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">hsa-router</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">rule</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Host(`hsa.demo.com`)"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"headscale-cluster4"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token key atrule" style="color:#00a4db">entryPoints</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">"https"</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">curl -X POST http://traefik/api/providers/file?dynamic=true</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="3-在旧节点精准中断目标连接">3) 在旧节点精准中断目标连接<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#3-%E5%9C%A8%E6%97%A7%E8%8A%82%E7%82%B9%E7%B2%BE%E5%87%86%E4%B8%AD%E6%96%AD%E7%9B%AE%E6%A0%87%E8%BF%9E%E6%8E%A5" class="hash-link" aria-label="3) 在旧节点精准中断目标连接的直接链接" title="3) 在旧节点精准中断目标连接的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ss -K "dport = 7890 and src 203.0.113.5"</span><br></div></code></pre></div></div>
<p>客户端通常会在数秒内自动重连到新节点，继续沿用 node key，不需要重新认证。</p>
<p><img decoding="async" loading="lazy" alt="seamless switch flow" src="https://docs.larktun.com/assets/images/change-5fdae981c99f791275e97d7cc7cc0230.webp" width="889" height="658" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="迁移效果原文实测">迁移效果（原文实测）<a href="https://docs.larktun.com/blog/headscale-saas-seamless-user-switch#%E8%BF%81%E7%A7%BB%E6%95%88%E6%9E%9C%E5%8E%9F%E6%96%87%E5%AE%9E%E6%B5%8B" class="hash-link" aria-label="迁移效果（原文实测）的直接链接" title="迁移效果（原文实测）的直接链接" translate="no">​</a></h2>
<ul>
<li class="">迁移总时长：通常小于 15 秒</li>
<li class="">客户端中断：通常 1-5 秒</li>
<li class="">重新认证率：接近 0%</li>
</ul>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2025/10/25/headscale-%E7%B3%BB%E5%88%97%EF%BC%9AHeadscale-SaaS-%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84%E7%94%A8%E6%88%B7%E6%97%A0%E7%BC%9D%E5%88%87%E6%8D%A2%E5%AE%9E%E6%88%98/" target="_blank" rel="noopener noreferrer" class="">headscale-系列：Headscale-SaaS-环境下的用户无缝切换实战</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>SaaS</category>
            <category>迁移</category>
            <category>traefik</category>
        </item>
        <item>
            <title><![CDATA[headscale 系列：组建 headscale 集群，把设备接入能力做成“无限接近无限”]]></title>
            <link>https://docs.larktun.com/blog/headscale-cluster-infinite-scale</link>
            <guid>https://docs.larktun.com/blog/headscale-cluster-infinite-scale</guid>
            <pubDate>Wed, 01 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[这篇文章分享 headscale 从单体到可线性扩展集群的核心改造路径：cluster_id 分片、共享 PostgreSQL、接入控制程序（ACS）、查询隔离与 netmap 增量化。]]></description>
            <content:encoded><![CDATA[<p>这篇文章分享 <code>headscale</code> 从单体到可线性扩展集群的核心改造路径：<code>cluster_id</code> 分片、共享 PostgreSQL、接入控制程序（ACS）、查询隔离与 netmap 增量化。</p>
<p>原文链接：
<a href="https://ownding.com/2025/10/01/headscale-%E7%B3%BB%E5%88%97%EF%BC%9A%E7%BB%84%E5%BB%BA-headscale-%E9%9B%86%E7%BE%A4%EF%BC%8C%E6%8A%8A%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E8%83%BD%E5%8A%9B%E5%81%9A%E6%88%90%E2%80%9C%E6%97%A0%E9%99%90%E6%8E%A5%E8%BF%91%E6%97%A0%E9%99%90%E2%80%9D/" target="_blank" rel="noopener noreferrer" class="">headscale 系列：组建 headscale 集群，把设备接入能力做成“无限接近无限”</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="核心结论">核心结论<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E6%A0%B8%E5%BF%83%E7%BB%93%E8%AE%BA" class="hash-link" aria-label="核心结论的直接链接" title="核心结论的直接链接" translate="no">​</a></h2>
<p>通过以下组合，可以把 headscale 逐步改造成接近 SaaS 形态的控制面：</p>
<ul>
<li class=""><code>cluster_id</code> 逻辑分片</li>
<li class="">共享 PG/PG 集群</li>
<li class="">接入控制程序（ACS）做分配与黏住</li>
<li class="">DAO/ORM 层强制查询隔离</li>
<li class="">netmap 计算从全量转为增量</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="架构要点">架构要点<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E6%9E%B6%E6%9E%84%E8%A6%81%E7%82%B9" class="hash-link" aria-label="架构要点的直接链接" title="架构要点的直接链接" translate="no">​</a></h2>
<ol>
<li class="">多个 <code>headscale</code> 节点并行运行，每个节点绑定独立 <code>cluster_id</code>。</li>
<li class="">所有节点共享数据库，但查询必须显式包含 <code>cluster_id</code>。</li>
<li class="">ACS 负责首次接入分配、配额策略、区域与负载选择、租户黏住。</li>
<li class="">配合 LISTEN/NOTIFY + 去抖合并，让 netmap 重建聚焦到受影响范围。</li>
</ol>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="启动示例">启动示例<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E5%90%AF%E5%8A%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="启动示例的直接链接" title="启动示例的直接链接" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">CLUSTER_ID=A \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PG_DSN="postgres://..." \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DERP_MAP_URL="https://derp.example.com/map.json" \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./headscale --config ./config.yaml</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="数据与查询隔离示例">数据与查询隔离示例<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E6%95%B0%E6%8D%AE%E4%B8%8E%E6%9F%A5%E8%AF%A2%E9%9A%94%E7%A6%BB%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="数据与查询隔离示例的直接链接" title="数据与查询隔离示例的直接链接" translate="no">​</a></h2>
<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">ALTER</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">TABLE</span><span class="token plain"> nodes </span><span class="token keyword" style="color:#00009f">ADD</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">COLUMN</span><span class="token plain"> cluster_id </span><span class="token keyword" style="color:#00009f">TEXT</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">NOT</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">NULL</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">DEFAULT</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'default'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">INDEX</span><span class="token plain"> idx_nodes_cluster_id </span><span class="token keyword" style="color:#00009f">ON</span><span class="token plain"> nodes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cluster_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></div></code></pre></div></div>
<div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">func</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">c </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">ClusterDB</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Scoped</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain">gorm</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">DB </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">db</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">Where</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"cluster_id = ?"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> c</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">clusterID</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="netmap-增量化思路">netmap 增量化思路<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#netmap-%E5%A2%9E%E9%87%8F%E5%8C%96%E6%80%9D%E8%B7%AF" class="hash-link" aria-label="netmap 增量化思路的直接链接" title="netmap 增量化思路的直接链接" translate="no">​</a></h2>
<ul>
<li class="">变更写入后触发 <code>NOTIFY netmap_dirty(cluster_id, scope_key)</code>。</li>
<li class="">节点只消费本 <code>cluster_id</code> 事件。</li>
<li class="">按 <code>scope_key</code>（用户、tag、路由域）做增量重建与推送。</li>
<li class="">引入缓存与版本号，避免重复全量构建。</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="演示截图">演示截图<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E6%BC%94%E7%A4%BA%E6%88%AA%E5%9B%BE" class="hash-link" aria-label="演示截图的直接链接" title="演示截图的直接链接" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="cluster id 1 nodes" src="https://docs.larktun.com/assets/images/h1-35cf1040c6b5197e5b905e89ba6e8894.webp" width="1280" height="799" class="img_ev3q">
<img decoding="async" loading="lazy" alt="cluster id 2 nodes" src="https://docs.larktun.com/assets/images/h2-b8103230a656ad59e5f72941c7538267.webp" width="1240" height="812" class="img_ev3q">
<img decoding="async" loading="lazy" alt="users table" src="https://docs.larktun.com/assets/images/user-a801867fb05bed413d3a81541e1c574d.webp" width="939" height="603" class="img_ev3q">
<img decoding="async" loading="lazy" alt="nodes table" src="https://docs.larktun.com/assets/images/nodes-469ba0c950c2b2b749b9044a0efce100.webp" width="935" height="593" class="img_ev3q">
<img decoding="async" loading="lazy" alt="preauth keys table" src="https://docs.larktun.com/assets/images/keys-64326793ec4d87f26d1a1128214561a4.webp" width="936" height="299" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="相关链接">相关链接<a href="https://docs.larktun.com/blog/headscale-cluster-infinite-scale#%E7%9B%B8%E5%85%B3%E9%93%BE%E6%8E%A5" class="hash-link" aria-label="相关链接的直接链接" title="相关链接的直接链接" translate="no">​</a></h2>
<ul>
<li class="">项目地址：
<a href="https://github.com/OwnDing/headscale-saas" target="_blank" rel="noopener noreferrer" class="">OwnDing/headscale-saas</a></li>
</ul>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2025/10/01/headscale-%E7%B3%BB%E5%88%97%EF%BC%9A%E7%BB%84%E5%BB%BA-headscale-%E9%9B%86%E7%BE%A4%EF%BC%8C%E6%8A%8A%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E8%83%BD%E5%8A%9B%E5%81%9A%E6%88%90%E2%80%9C%E6%97%A0%E9%99%90%E6%8E%A5%E8%BF%91%E6%97%A0%E9%99%90%E2%80%9D/" target="_blank" rel="noopener noreferrer" class="">headscale 系列：组建 headscale 集群，把设备接入能力做成“无限接近无限”</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>集群</category>
            <category>SaaS</category>
            <category>扩展</category>
        </item>
        <item>
            <title><![CDATA[headscale 系列：headscale 压力测试]]></title>
            <link>https://docs.larktun.com/blog/headscale-stress-test</link>
            <guid>https://docs.larktun.com/blog/headscale-stress-test</guid>
            <pubDate>Sun, 28 Sep 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[这篇文章整理了 headscale 在 200 客户端规模下的压测方法，包括环境建议、一键脚本、抖动测试和流量抽样流程。]]></description>
            <content:encoded><![CDATA[<p>这篇文章整理了 <code>headscale</code> 在 200 客户端规模下的压测方法，包括环境建议、一键脚本、抖动测试和流量抽样流程。</p>
<p>原文链接：
<a href="https://ownding.com/2025/09/28/headscale%E7%B3%BB%E5%88%97%EF%BC%9Aheadsale%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/" target="_blank" rel="noopener noreferrer" class="">headscale系列：headsale压力测试</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="压测脚本">压测脚本<a href="https://docs.larktun.com/blog/headscale-stress-test#%E5%8E%8B%E6%B5%8B%E8%84%9A%E6%9C%AC" class="hash-link" aria-label="压测脚本的直接链接" title="压测脚本的直接链接" translate="no">​</a></h2>
<ul>
<li class="">脚本仓库：
<a href="https://github.com/OwnDing/headscale-test-scripts.git" target="_blank" rel="noopener noreferrer" class="">OwnDing/headscale-test-scripts</a></li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="快速使用流程">快速使用流程<a href="https://docs.larktun.com/blog/headscale-stress-test#%E5%BF%AB%E9%80%9F%E4%BD%BF%E7%94%A8%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="快速使用流程的直接链接" title="快速使用流程的直接链接" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 1) 准备配置</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cp .env.example .env</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 2) 环境检查</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash scripts/00_check_env.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 3) 拉起客户端（默认 200）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash scripts/01_bootstrap_up.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 4) 导出节点列表</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash scripts/02_list_nodes.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 5) 抖动测试（终端 A）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash scripts/03_churn.sh</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 6) 流量抽样（终端 B）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">watch -n 20 'bash scripts/04_traffic_round.sh'</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 7) 清理</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">bash scripts/99_cleanup.sh</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="关键环境变量">关键环境变量<a href="https://docs.larktun.com/blog/headscale-stress-test#%E5%85%B3%E9%94%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F" class="hash-link" aria-label="关键环境变量的直接链接" title="关键环境变量的直接链接" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">HEADSCALE_URL=https://headscale.example.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TS_AUTHKEY=tskey-auth-xxxxxxxxxxxxxxxxxxxxxxxxxxxx</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">REPLICAS=200</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CHURN_INTERVAL=30</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">CHURN_BATCH_PERCENT=10</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TRAFFIC_PAIR_COUNT=30</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TRAFFIC_TCP_DURATION=10</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TRAFFIC_TCP_PARALLEL=4</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TRAFFIC_UDP_DURATION=10</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">TRAFFIC_UDP_BW=50M</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="推荐机器规格200-设备">推荐机器规格（200 设备）<a href="https://docs.larktun.com/blog/headscale-stress-test#%E6%8E%A8%E8%8D%90%E6%9C%BA%E5%99%A8%E8%A7%84%E6%A0%BC200-%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="推荐机器规格（200 设备）的直接链接" title="推荐机器规格（200 设备）的直接链接" translate="no">​</a></h2>
<ul>
<li class="">发压端：16 vCPU / 32 GB / 100 GB NVMe</li>
<li class="">被测 headscale：4 vCPU / 8 GB / 100 GB</li>
<li class="">可选 DERP：2-4 vCPU / 2-4 GB</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="脚本职责速览">脚本职责速览<a href="https://docs.larktun.com/blog/headscale-stress-test#%E8%84%9A%E6%9C%AC%E8%81%8C%E8%B4%A3%E9%80%9F%E8%A7%88" class="hash-link" aria-label="脚本职责速览的直接链接" title="脚本职责速览的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>00_check_env.sh</code>：检查 docker/compose/tun 并预拉镜像。</li>
<li class=""><code>01_bootstrap_up.sh</code>：按 <code>REPLICAS</code> 启动客户端容器。</li>
<li class=""><code>02_list_nodes.sh</code>：导出 <code>nodes.tsv</code>（容器名与 Tailnet IPv4）。</li>
<li class=""><code>03_churn.sh</code>：周期性随机 <code>up/down/restart</code>，模拟不稳定网络与节点波动。</li>
<li class=""><code>04_traffic_round.sh</code>：随机成对做 TCP/UDP 压力抽样。</li>
<li class=""><code>99_cleanup.sh</code>：停止并清理测试容器与 sidecar。</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="测试结果截图">测试结果截图<a href="https://docs.larktun.com/blog/headscale-stress-test#%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C%E6%88%AA%E5%9B%BE" class="hash-link" aria-label="测试结果截图的直接链接" title="测试结果截图的直接链接" translate="no">​</a></h2>
<p><img decoding="async" loading="lazy" alt="200 clients online" src="https://docs.larktun.com/assets/images/clients-a944115873ee7273eb207d1232c228af.webp" width="1772" height="826" class="img_ev3q">
<img decoding="async" loading="lazy" alt="headscale cpu usage" src="https://docs.larktun.com/assets/images/cpus-8bf737c41aabb0138290cf20cebd17a8.webp" width="925" height="128" class="img_ev3q">
<img decoding="async" loading="lazy" alt="client memory usage" src="https://docs.larktun.com/assets/images/mems-8a24e63100eb9ea3d8ec41c739f2b7a2.webp" width="1772" height="826" class="img_ev3q"></p>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2025/09/28/headscale%E7%B3%BB%E5%88%97%EF%BC%9Aheadsale%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/" target="_blank" rel="noopener noreferrer" class="">headscale系列：headsale压力测试</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>压测</category>
            <category>docker</category>
            <category>tailscale</category>
        </item>
        <item>
            <title><![CDATA[headscale 系列：如何在 headscale 中使用 MagicDNS]]></title>
            <link>https://docs.larktun.com/blog/headscale-magicdns</link>
            <guid>https://docs.larktun.com/blog/headscale-magicdns</guid>
            <pubDate>Thu, 14 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[本文记录在 headscale 中启用 MagicDNS 的配置方法，以及 extra-records.json 的实践用法，方便在客户端通过主机名访问设备而不是直接记忆 IP。]]></description>
            <content:encoded><![CDATA[<p>本文记录在 <code>headscale</code> 中启用 <code>MagicDNS</code> 的配置方法，以及 <code>extra-records.json</code> 的实践用法，方便在客户端通过主机名访问设备而不是直接记忆 IP。</p>
<p>原文链接：
<a href="https://ownding.com/2025/08/14/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%9C%A8headscale%E4%B8%AD%E4%BD%BF%E7%94%A8MagicDNS/" target="_blank" rel="noopener noreferrer" class="">headscale系列：如何在headscale中使用MagicDNS</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="场景说明">场景说明<a href="https://docs.larktun.com/blog/headscale-magicdns#%E5%9C%BA%E6%99%AF%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="场景说明的直接链接" title="场景说明的直接链接" translate="no">​</a></h2>
<ul>
<li class="">客户端登录后，除了用 IP 访问设备，也可以直接用主机名。</li>
<li class="">在 Windows 客户端中，<code>tailscale</code> 会把设备主机信息写入 <code>hosts</code> 文件。</li>
<li class="">当开启 <code>4via6</code> 等能力时，用自定义 DNS 名称映射会明显更省心。</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="开启-magicdns">开启 MagicDNS<a href="https://docs.larktun.com/blog/headscale-magicdns#%E5%BC%80%E5%90%AF-magicdns" class="hash-link" aria-label="开启 MagicDNS的直接链接" title="开启 MagicDNS的直接链接" translate="no">​</a></h2>
<p>在 <code>config.yaml</code> 中开启 DNS 相关配置（下面是核心项）：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">dns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">magic_dns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">true</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">base_domain</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> example.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">override_local_dns</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token boolean important" style="color:#36acaa">false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">nameservers</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">global</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> 1.1.1.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> 1.0.0.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">search_domains</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">extra_records_path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /var/lib/headscale/extra</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">records.json</span><br></div></code></pre></div></div>
<p>建议使用 <code>extra_records_path</code> 指向外部 JSON 文件，便于后续动态维护记录。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="extra-recordsjson-示例">extra-records.json 示例<a href="https://docs.larktun.com/blog/headscale-magicdns#extra-recordsjson-%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="extra-records.json 示例的直接链接" title="extra-records.json 示例的直接链接" translate="no">​</a></h2>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">[</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"name"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"192-168-6-1-via-7"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"type"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"AAAA"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"value"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"fd7a:115c:a1e0:b1a:0:7:c0a8:601"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<ul>
<li class=""><code>type</code> 支持 <code>A</code>（IPv4）和 <code>AAAA</code>（IPv6）。</li>
<li class="">首次把配置从 <code>extra_records</code> 切换为 <code>extra_records_path</code> 时，建议重启一次 <code>headscale</code>。</li>
<li class="">后续只改 <code>extra-records.json</code>，通常不需要每次重启。</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="使用示例">使用示例<a href="https://docs.larktun.com/blog/headscale-magicdns#%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B" class="hash-link" aria-label="使用示例的直接链接" title="使用示例的直接链接" translate="no">​</a></h2>
<p>客户端上线后，可以通过自定义记录名直接访问目标设备服务。</p>
<p><img decoding="async" loading="lazy" alt="route table update" src="https://docs.larktun.com/assets/images/route-3f10725f44c1dda24468712ab521d7df.webp" width="855" height="724" class="img_ev3q">
<img decoding="async" loading="lazy" alt="magicdns query example" src="https://docs.larktun.com/assets/images/dns-5bc8042e0638778e3dcf3ba274f2ff5c.webp" width="1129" height="1100" class="img_ev3q"></p>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2025/08/14/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%9C%A8headscale%E4%B8%AD%E4%BD%BF%E7%94%A8MagicDNS/" target="_blank" rel="noopener noreferrer" class="">headscale系列：如何在headscale中使用MagicDNS</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>MagicDNS</category>
            <category>DNS</category>
        </item>
        <item>
            <title><![CDATA[headscale 系列：如何将源码编译的 headscale 打包成 Docker 镜像]]></title>
            <link>https://docs.larktun.com/blog/headscale-source-build-docker-image</link>
            <guid>https://docs.larktun.com/blog/headscale-source-build-docker-image</guid>
            <pubDate>Fri, 08 Aug 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Headscale 官方镜像用 docker images 查看通常只有约 80MB。如果我们直接写 Dockerfile 打包，镜像往往会明显更大。]]></description>
            <content:encoded><![CDATA[<p><code>Headscale</code> 官方镜像用 <code>docker images</code> 查看通常只有约 <code>80MB</code>。如果我们直接写 <code>Dockerfile</code> 打包，镜像往往会明显更大。</p>
<p>这篇文章记录一个更贴近官方体积的做法：使用 <code>ko</code> 构建 Headscale 容器镜像，而不是手写 Dockerfile。</p>
<p>原文链接：
<a href="https://ownding.com/2025/08/08/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%B0%86%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E7%9A%84headscale%E6%89%93%E5%8C%85%E6%88%90docker%E9%95%9C%E5%83%8F/" target="_blank" rel="noopener noreferrer" class="">headscale系列：如何将源码编译的headscale打包成docker镜像</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="为什么使用-ko">为什么使用 ko<a href="https://docs.larktun.com/blog/headscale-source-build-docker-image#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%BF%E7%94%A8-ko" class="hash-link" aria-label="为什么使用 ko的直接链接" title="为什么使用 ko的直接链接" translate="no">​</a></h2>
<p><code>ko</code> 是一个用于构建和打包 Go 应用的轻量工具，适合容器化场景（Docker / Kubernetes）。它可以直接把 Go 项目打包成镜像，省去 Dockerfile 维护成本。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="ko-安装">ko 安装<a href="https://docs.larktun.com/blog/headscale-source-build-docker-image#ko-%E5%AE%89%E8%A3%85" class="hash-link" aria-label="ko 安装的直接链接" title="ko 安装的直接链接" translate="no">​</a></h2>
<p>在普通用户环境下安装 <code>ko</code>：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">go install github.com/google/ko@latest</span><br></div></code></pre></div></div>
<p>安装后可在 <code>~/go/bin/ko</code> 找到可执行文件。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="使用-ko-打包-headscale">使用 ko 打包 headscale<a href="https://docs.larktun.com/blog/headscale-source-build-docker-image#%E4%BD%BF%E7%94%A8-ko-%E6%89%93%E5%8C%85-headscale" class="hash-link" aria-label="使用 ko 打包 headscale的直接链接" title="使用 ko 打包 headscale的直接链接" translate="no">​</a></h2>
<p>在 Headscale 源码目录执行：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># --local 表示不推送镜像到仓库</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">/home/djc/go/bin/ko build --local ./cmd/headscale</span><br></div></code></pre></div></div>
<p>构建完成后，会生成 <code>ko.local/...</code> 命名的本地镜像。可用 <code>docker images</code> 查看：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">REPOSITORY                                            TAG                                                                IMAGE ID       CREATED      SIZE</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">headscale                                             v0.26.1-r                                                          bf66da388ca1   6 days ago   87.5MB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ko.local/headscale-f40b3d8640713cd381403459ebd67e78   38aefca56cab7d9b11692c61968915fb59fdf1dce134e52fed02ae2fa3a0e871   bf66da388ca1   6 days ago   87.5MB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ko.local/headscale-f40b3d8640713cd381403459ebd67e78   latest                                                             bf66da388ca1   6 days ago   87.5MB</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ghcr.io/juanfont/headscale                            v0.26.1                                                            b9e7b75fd3b0   N/A          80.8MB</span><br></div></code></pre></div></div>
<p>后续可通过 <code>docker tag</code> 给镜像重命名。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="镜像运行要点">镜像运行要点<a href="https://docs.larktun.com/blog/headscale-source-build-docker-image#%E9%95%9C%E5%83%8F%E8%BF%90%E8%A1%8C%E8%A6%81%E7%82%B9" class="hash-link" aria-label="镜像运行要点的直接链接" title="镜像运行要点的直接链接" translate="no">​</a></h2>
<p>运行时需要：</p>
<ul>
<li class=""><code>config.yaml</code> 配置文件</li>
<li class=""><code>/var/run/headscale/</code>、<code>/var/lib/headscale/</code> 的读写权限</li>
</ul>
<p>可在 <code>config.yaml</code> 中把：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">unix_socket</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /var/run/headscale/headscale.sock</span><br></div></code></pre></div></div>
<p>改成：</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">unix_socket</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> /var/lib/headscale/headscale.sock</span><br></div></code></pre></div></div>
<p>这样运行容器时只挂载 <code>/var/lib/headscale/</code> 即可：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">docker run -d \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v ./headscale/config.yaml:/etc/headscale/config.yaml \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -v ./doc:/var/lib/headscale \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  --name headscale \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 8080:8080 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  -p 9090:9090 \</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  headscale:v0.26.1-r serve</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="参考">参考<a href="https://docs.larktun.com/blog/headscale-source-build-docker-image#%E5%8F%82%E8%80%83" class="hash-link" aria-label="参考的直接链接" title="参考的直接链接" translate="no">​</a></h2>
<ul>
<li class="">源码编译文章：
<a href="https://ownding.com/2025/07/30/%E4%BD%BF%E7%94%A8Headscale%E6%BA%90%E7%A0%81%E8%87%AA%E8%A1%8C%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85/" target="_blank" rel="noopener noreferrer" class="">使用 Headscale 源码自行编译打包</a></li>
</ul>
<hr>
<p>本文已同步到 Larktun 博客，原始内容与更新请以原文为准：
<a href="https://ownding.com/2025/08/08/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%B0%86%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E7%9A%84headscale%E6%89%93%E5%8C%85%E6%88%90docker%E9%95%9C%E5%83%8F/" target="_blank" rel="noopener noreferrer" class="">headscale系列：如何将源码编译的headscale打包成docker镜像</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>Docker</category>
            <category>ko</category>
            <category>镜像构建</category>
        </item>
        <item>
            <title><![CDATA[使用 Headscale 源码自行编译打包]]></title>
            <link>https://docs.larktun.com/blog/headscale-build-from-source</link>
            <guid>https://docs.larktun.com/blog/headscale-build-from-source</guid>
            <pubDate>Wed, 30 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[本文基于我在个人博客中的实践记录，介绍如何在 Windows + WSL2 + Ubuntu 环境下编译 Headscale 源码，并整理常见报错与处理方式。]]></description>
            <content:encoded><![CDATA[<p>本文基于我在个人博客中的实践记录，介绍如何在 Windows + WSL2 + Ubuntu 环境下编译 Headscale 源码，并整理常见报错与处理方式。</p>
<p>原文链接：
<a href="https://ownding.com/2025/07/30/%E4%BD%BF%E7%94%A8Headscale%E6%BA%90%E7%A0%81%E8%87%AA%E8%A1%8C%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85/" target="_blank" rel="noopener noreferrer" class="">使用Headscale源码自行编译打包</a></p>
<!-- -->
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="说明">说明<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="说明的直接链接" title="说明的直接链接" translate="no">​</a></h2>
<ul>
<li class="">操作系统：Windows 11 + WSL2 Ubuntu 24.04 LTS</li>
<li class="">示例版本：Headscale v0.26.1</li>
<li class="">源码仓库：<a href="https://github.com/juanfont/headscale" target="_blank" rel="noopener noreferrer" class="">github.com/juanfont/headscale</a></li>
<li class="">建议使用 Git 克隆源码，不要直接下载压缩包</li>
</ul>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="环境准备">环境准备<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87" class="hash-link" aria-label="环境准备的直接链接" title="环境准备的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="1-下载源码">1) 下载源码<a href="https://docs.larktun.com/blog/headscale-build-from-source#1-%E4%B8%8B%E8%BD%BD%E6%BA%90%E7%A0%81" class="hash-link" aria-label="1) 下载源码的直接链接" title="1) 下载源码的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">git clone https://github.com/juanfont/headscale.git</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 使用 v0.26.1 的 tag</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">git checkout -b release-v0.26.1 v0.26.1</span><br></div></code></pre></div></div>
<p>然后复制根目录下的 <code>config-example.yaml</code> 并重命名为 <code>config.yaml</code>。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="2-wsl-配置">2) WSL 配置<a href="https://docs.larktun.com/blog/headscale-build-from-source#2-wsl-%E9%85%8D%E7%BD%AE" class="hash-link" aria-label="2) WSL 配置的直接链接" title="2) WSL 配置的直接链接" translate="no">​</a></h3>
<p>在 Windows 用户目录（例如 <code>C:\Users\XXX</code>）创建 <code>.wslconfig</code>：</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">[wsl2]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">nestedVirtualization=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ipv6=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">[experimental]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">autoMemoryReclaim=gradual</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">networkingMode=mirrored</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dnsTunneling=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">firewall=true</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">autoProxy=true</span><br></div></code></pre></div></div>
<p>重启 WSL 后再继续编译流程。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="3-安装-nixmulti-user">3) 安装 Nix（Multi-user）<a href="https://docs.larktun.com/blog/headscale-build-from-source#3-%E5%AE%89%E8%A3%85-nixmulti-user" class="hash-link" aria-label="3) 安装 Nix（Multi-user）的直接链接" title="3) 安装 Nix（Multi-user）的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">sh &lt;(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon</span><br></div></code></pre></div></div>
<p>参考：<a href="https://nixos.org/download/" target="_blank" rel="noopener noreferrer" class="">nixos.org/download</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="编译步骤">编译步骤<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E7%BC%96%E8%AF%91%E6%AD%A5%E9%AA%A4" class="hash-link" aria-label="编译步骤的直接链接" title="编译步骤的直接链接" translate="no">​</a></h2>
<p>编译时请使用普通用户（不要用 <code>root</code> 运行 <code>make build</code>）：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 进入源码目录（WSL 中 Windows 盘通常在 /mnt/c 下）</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd /mnt/c/Users/XXX/Documents/develop/0me/headscale</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 进入构建环境</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">nix develop</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make generate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make test</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">make build</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 查看产物</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ls -la result/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">cd result/bin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">./headscale version</span><br></div></code></pre></div></div>
<p>构建成功后会出现 <code>result</code> 目录。</p>
<p><img decoding="async" loading="lazy" alt="headscale build result" src="https://docs.larktun.com/assets/images/result-890ed849e723f795423053931a08a192.webp" width="859" height="123" class="img_ev3q">
<img decoding="async" loading="lazy" alt="headscale build result on windows" src="https://docs.larktun.com/assets/images/w-result-5be58e4c356927dcbf31a3a25d406e7f.webp" width="718" height="540" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="运行说明">运行说明<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E8%BF%90%E8%A1%8C%E8%AF%B4%E6%98%8E" class="hash-link" aria-label="运行说明的直接链接" title="运行说明的直接链接" translate="no">​</a></h2>
<p>将编译出的 <code>headscale</code> 二进制复制到目标服务器后，建议先检查依赖：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">ldd headscale</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">file headscale</span><br></div></code></pre></div></div>
<p>如果提示解释器路径依赖 Nix store，需要按实际提示补齐对应目录和链接器文件；另外确保 <code>config.yaml</code>、<code>/root/.headscale/</code>、<code>/var/lib/headscale/</code> 等路径存在且权限正确。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="打包为-docker-镜像">打包为 Docker 镜像<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E6%89%93%E5%8C%85%E4%B8%BA-docker-%E9%95%9C%E5%83%8F" class="hash-link" aria-label="打包为 Docker 镜像的直接链接" title="打包为 Docker 镜像的直接链接" translate="no">​</a></h2>
<p>若你希望将源码编译结果打包成 Docker 镜像，可参考：
<a href="https://ownding.com/2025/08/08/headscale%E7%B3%BB%E5%88%97%EF%BC%9A%E5%A6%82%E4%BD%95%E5%B0%86%E6%BA%90%E7%A0%81%E7%BC%96%E8%AF%91%E7%9A%84headscale%E6%89%93%E5%8C%85%E6%88%90docker%E9%95%9C%E5%83%8F/" target="_blank" rel="noopener noreferrer" class="">headscale系列：如何将源码编译的headscale打包成docker镜像</a></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="编译异常汇总">编译异常汇总<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E7%BC%96%E8%AF%91%E5%BC%82%E5%B8%B8%E6%B1%87%E6%80%BB" class="hash-link" aria-label="编译异常汇总的直接链接" title="编译异常汇总的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="问题-1dirtyshortrev-missing">问题 1：<code>dirtyShortRev</code> missing<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E9%97%AE%E9%A2%98-1dirtyshortrev-missing" class="hash-link" aria-label="问题-1dirtyshortrev-missing的直接链接" title="问题-1dirtyshortrev-missing的直接链接" translate="no">​</a></h3>
<p><code>make build</code> 报错 <code>attribute 'dirtyShortRev' missing</code> 时，可在 <code>flake.nix</code> 中为版本号补充兜底：</p>
<div class="language-nix codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nix codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">headscaleVersion = if self ? shortRev</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  then self.shortRev</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  else if self ? dirtyShortRev</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  then self.dirtyShortRev</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">                  else "v0.26.1";</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="问题-2测试阶段找不到-configyaml">问题 2：测试阶段找不到 <code>config.yaml</code><a href="https://docs.larktun.com/blog/headscale-build-from-source#%E9%97%AE%E9%A2%98-2%E6%B5%8B%E8%AF%95%E9%98%B6%E6%AE%B5%E6%89%BE%E4%B8%8D%E5%88%B0-configyaml" class="hash-link" aria-label="问题-2测试阶段找不到-configyaml的直接链接" title="问题-2测试阶段找不到-configyaml的直接链接" translate="no">​</a></h3>
<p>当 <code>make build</code> 在测试阶段失败时，可先准备配置再构建：</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">cp config-example.yaml config.yaml</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">go mod tidy</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">go build -o headscale ./cmd/headscale</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="问题-3nix-command-被禁用">问题 3：<code>nix-command</code> 被禁用<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E9%97%AE%E9%A2%98-3nix-command-%E8%A2%AB%E7%A6%81%E7%94%A8" class="hash-link" aria-label="问题-3nix-command-被禁用的直接链接" title="问题-3nix-command-被禁用的直接链接" translate="no">​</a></h3>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">echo 'experimental-features = nix-command flakes' &gt;&gt; /etc/nix/nix.conf</span><br></div></code></pre></div></div>
<p>请使用 <code>root</code> 用户执行上面的配置命令。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="问题-4找不到-flakenix">问题 4：找不到 <code>flake.nix</code><a href="https://docs.larktun.com/blog/headscale-build-from-source#%E9%97%AE%E9%A2%98-4%E6%89%BE%E4%B8%8D%E5%88%B0-flakenix" class="hash-link" aria-label="问题-4找不到-flakenix的直接链接" title="问题-4找不到-flakenix的直接链接" translate="no">​</a></h3>
<p>出现 <code>could not find a flake.nix file</code> 时，先 <code>cd</code> 到 Headscale 源码目录，再执行 <code>nix develop</code>。</p>
<h3 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="问题-5initdb-不能以-root-运行">问题 5：<code>initdb</code> 不能以 root 运行<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E9%97%AE%E9%A2%98-5initdb-%E4%B8%8D%E8%83%BD%E4%BB%A5-root-%E8%BF%90%E8%A1%8C" class="hash-link" aria-label="问题-5initdb-不能以-root-运行的直接链接" title="问题-5initdb-不能以-root-运行的直接链接" translate="no">​</a></h3>
<p><code>make build</code> 中涉及 PostgreSQL 初始化时，不要用 <code>root</code> 用户运行构建与测试流程。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="手动安装相关依赖">手动安装相关依赖<a href="https://docs.larktun.com/blog/headscale-build-from-source#%E6%89%8B%E5%8A%A8%E5%AE%89%E8%A3%85%E7%9B%B8%E5%85%B3%E4%BE%9D%E8%B5%96" class="hash-link" aria-label="手动安装相关依赖的直接链接" title="手动安装相关依赖的直接链接" translate="no">​</a></h2>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain"># 安装 Buf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">go install github.com/bufbuild/buf/cmd/buf@v1.55.1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"># 安装 Protobuf</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt update</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">sudo apt install protobuf-compiler</span><br></div></code></pre></div></div>
<hr>
<p>本文已同步至 Larktun 博客，原始内容与后续更新请以原文为准：
<a href="https://ownding.com/2025/07/30/%E4%BD%BF%E7%94%A8Headscale%E6%BA%90%E7%A0%81%E8%87%AA%E8%A1%8C%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85/" target="_blank" rel="noopener noreferrer" class="">使用Headscale源码自行编译打包</a></p>]]></content:encoded>
            <category>headscale</category>
            <category>编译打包</category>
            <category>WSL</category>
            <category>Nix</category>
        </item>
    </channel>
</rss>