<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>首页 on CHEN 的博客</title>
        <link>https://blog.chen-api.cloud/</link>
        <description>Recent content in 首页 on CHEN 的博客</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <lastBuildDate>Tue, 26 May 2026 13:25:00 +0800</lastBuildDate><atom:link href="https://blog.chen-api.cloud/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>从申请服务器到搭建 sub2api 中转站：一份完整实践记录</title>
            <link>https://blog.chen-api.cloud/posts/sub2api-relay-setup-notes/</link>
            <pubDate>Tue, 26 May 2026 13:25:00 +0800</pubDate>
            <guid>https://blog.chen-api.cloud/posts/sub2api-relay-setup-notes/</guid>
            <description>&lt;p&gt;这篇文章记录一下我从零准备一台服务器，到最终把 &lt;code&gt;sub2api&lt;/code&gt; 跑起来并作为反代中转站使用的完整过程。&lt;/p&gt;&#xA;&lt;p&gt;整个过程并不是单点安装某个程序，而是一条完整链路：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;先选服务器&lt;/li&gt;&#xA;&lt;li&gt;再选域名&lt;/li&gt;&#xA;&lt;li&gt;配好基础网络出口&lt;/li&gt;&#xA;&lt;li&gt;然后部署 &lt;code&gt;sub2api&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;再接上 &lt;code&gt;Nginx&lt;/code&gt; 和 &lt;code&gt;HTTPS&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;最后完成账号绑定和实际可用验证&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;p&gt;我当时的思路很明确：这台机器主要是跑一个轻量级中转服务，不是数据库重负载场景，也不是需要高性能计算的业务，所以重点不是极限性能，而是下面几项：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;价格是否足够低&lt;/li&gt;&#xA;&lt;li&gt;海外线路是否相对稳定&lt;/li&gt;&#xA;&lt;li&gt;带宽和流量是否够用&lt;/li&gt;&#xA;&lt;li&gt;系统镜像是否方便直接上 Ubuntu&lt;/li&gt;&#xA;&lt;li&gt;控制台和安全组是否省心&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这一类场景里，常见可选项一般会包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;腾讯云轻量应用服务器&lt;/li&gt;&#xA;&lt;li&gt;阿里云轻量应用服务器&lt;/li&gt;&#xA;&lt;li&gt;部分海外 VPS 厂商&lt;/li&gt;&#xA;&lt;li&gt;传统云服务器标准实例&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果只是部署 &lt;code&gt;sub2api&lt;/code&gt; 这种中小型服务，轻量服务器通常比传统 CVM / ECS 更合适，因为：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;价格更直接&lt;/li&gt;&#xA;&lt;li&gt;自带公网 IP&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;/p&gt;&#xA;&lt;p&gt;这个选择背后的考虑大致有三点：&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;后续配域名、Nginx 和证书都很常规，资料比较多&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;系统方面，直接选择 Ubuntu 就够了。后续所有部署动作基本都围绕下面这些组件展开：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;apt&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;systemd&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;certbot&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;tailscale&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;二域名不需要贵但最好专业好记能长期用&#34;&gt;二、域名不需要贵，但最好专业、好记、能长期用&#xA;&lt;/h2&gt;&lt;p&gt;服务器确定之后，下一步就是域名。&lt;/p&gt;&#xA;&lt;p&gt;我当时没有去买特别昂贵或者过于花哨的后缀，而是选择了一个 &lt;code&gt;cloud&lt;/code&gt; 结尾的域名。原因很现实：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;价格便宜&lt;/li&gt;&#xA;&lt;li&gt;可选空间相对多&lt;/li&gt;&#xA;&lt;li&gt;看起来比很多冷门后缀更正式&lt;/li&gt;&#xA;&lt;li&gt;用在技术服务和工具站上违和感小&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;对个人项目来说，域名最重要的不是“看起来很高级”，而是：&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;li&gt;作为主域名时不显得太随意&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;最后我用这个域名同时承载了不同用途：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;主服务走主域名&lt;/li&gt;&#xA;&lt;li&gt;博客走子域名&lt;/li&gt;&#xA;&lt;li&gt;后续不同组件都可以拆分到不同子域名下&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这种方式的好处是结构清晰，后续扩展也方便。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三先把流量出口问题想清楚用-tailscale-把本机作为出口&#34;&gt;三、先把流量出口问题想清楚：用 Tailscale 把本机作为出口&#xA;&lt;/h2&gt;&lt;p&gt;部署 &lt;code&gt;sub2api&lt;/code&gt; 这种服务时，一个非常实际的问题是：服务运行在服务器上，但某些访问链路未必适合直接走服务器本地网络。&lt;/p&gt;&#xA;&lt;p&gt;所以我当时的处理思路是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在服务器上安装 &lt;code&gt;Tailscale&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;把自己的本地设备加入同一个 tailnet&lt;/li&gt;&#xA;&lt;li&gt;让本机作为出口节点&lt;/li&gt;&#xA;&lt;li&gt;使服务器的相关流量通过本机出口转发&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这么做的核心价值，不在于“更酷”，而在于网络路径可控。&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-tailscale-的角色&#34;&gt;1. Tailscale 的角色&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Tailscale&lt;/code&gt; 本质上是一个基于 WireGuard 的组网方案。它的优点是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;安装简单&lt;/li&gt;&#xA;&lt;li&gt;节点互联快&lt;/li&gt;&#xA;&lt;li&gt;不需要自己维护传统 VPN&lt;/li&gt;&#xA;&lt;li&gt;可以很方便地指定出口节点&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这类方案特别适合：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;个人多设备协同&lt;/li&gt;&#xA;&lt;li&gt;家里电脑和云服务器互通&lt;/li&gt;&#xA;&lt;li&gt;临时把一台设备当作统一出口&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;2-典型操作思路&#34;&gt;2. 典型操作思路&#xA;&lt;/h3&gt;&lt;p&gt;这一部分大致会包含下面几个动作：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;在本机安装 &lt;code&gt;Tailscale&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;在云服务器安装 &lt;code&gt;Tailscale&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;登录同一个账号或组织网络&lt;/li&gt;&#xA;&lt;li&gt;在本机开启 exit node 能力&lt;/li&gt;&#xA;&lt;li&gt;在服务器侧指定该 exit node&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;从结果上说，就是服务器虽然部署在云端，但某些流量可以按你的规划经由本机网络出去。&lt;/p&gt;&#xA;&lt;h3 id=&#34;3-这一步为什么重要&#34;&gt;3. 这一步为什么重要&#xA;&lt;/h3&gt;&lt;p&gt;很多人搭服务时，默认认为“服务器能联网就够了”。但实际一旦进入真实使用，网络出口路径、可访问性、登录状态和上游连接稳定性都会影响最终可用性。&lt;/p&gt;&#xA;&lt;p&gt;所以我认为，&lt;code&gt;Tailscale + exit node&lt;/code&gt; 并不是额外花活，而是这类中转服务里非常实用的一环。&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;ul&gt;&#xA;&lt;li&gt;尽量把账号环境准备和服务器部署分开处理&lt;/li&gt;&#xA;&lt;li&gt;优先保证账号本身状态正常可登录&lt;/li&gt;&#xA;&lt;li&gt;再去做后面的 OAuth 绑定&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这样做的好处是排障更清楚。否则一旦失败，你很难判断问题到底出在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;服务器网络&lt;/li&gt;&#xA;&lt;li&gt;反向代理&lt;/li&gt;&#xA;&lt;li&gt;HTTPS&lt;/li&gt;&#xA;&lt;li&gt;OAuth 回调&lt;/li&gt;&#xA;&lt;li&gt;还是账号自身状态&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;五正式部署-sub2api先让服务能跑起来&#34;&gt;五、正式部署 sub2api：先让服务能跑起来&#xA;&lt;/h2&gt;&lt;p&gt;当服务器、域名和网络出口都准备好之后，就可以进入真正的服务部署阶段。&lt;/p&gt;&#xA;&lt;p&gt;这一部分的目标不是先追求“最优雅”，而是先让 &lt;code&gt;sub2api&lt;/code&gt; 在服务器上稳定跑起来。&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-基础环境准备&#34;&gt;1. 基础环境准备&#xA;&lt;/h3&gt;&lt;p&gt;最常规的准备动作一般包括：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;更新系统软件包&lt;/li&gt;&#xA;&lt;li&gt;安装 Git、Nginx 等基础依赖&lt;/li&gt;&#xA;&lt;li&gt;准备运行目录&lt;/li&gt;&#xA;&lt;li&gt;规划监听端口&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果服务本身有独立的启动方式，还需要考虑：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;二进制部署&lt;/li&gt;&#xA;&lt;li&gt;Docker 部署&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;systemd&lt;/code&gt; 托管&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;从长期维护角度看，我更偏向把服务交给 &lt;code&gt;systemd&lt;/code&gt; 或容器托管，而不是单纯用一个前台命令挂着。&lt;/p&gt;&#xA;&lt;h3 id=&#34;2-先本地端口可访问再接入反代&#34;&gt;2. 先本地端口可访问，再接入反代&#xA;&lt;/h3&gt;&lt;p&gt;这一类服务的正确调试顺序通常是：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;先确认程序在本机端口已经成功启动&lt;/li&gt;&#xA;&lt;li&gt;再用 &lt;code&gt;curl http://127.0.0.1:端口&lt;/code&gt; 验证是否有响应&lt;/li&gt;&#xA;&lt;li&gt;最后才挂到 &lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;如果一上来就把所有东西混在一起，很容易出现：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;服务本身没起来&lt;/li&gt;&#xA;&lt;li&gt;Nginx 也没配对&lt;/li&gt;&#xA;&lt;li&gt;证书还没签&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;然后排障就会变得很乱。&lt;/p&gt;&#xA;&lt;h2 id=&#34;六nginx-反代把服务挂到域名上&#34;&gt;六、Nginx 反代：把服务挂到域名上&#xA;&lt;/h2&gt;&lt;p&gt;&lt;code&gt;sub2api&lt;/code&gt; 真正对外可用，关键还是靠 &lt;code&gt;Nginx&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;常见结构就是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;上游应用监听本地端口，例如 &lt;code&gt;127.0.0.1:3000&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Nginx&lt;/code&gt; 对外监听 &lt;code&gt;80&lt;/code&gt; 和 &lt;code&gt;443&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;外部流量先到 &lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;再由 &lt;code&gt;Nginx&lt;/code&gt; 转发给 &lt;code&gt;sub2api&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;一个典型的反代思路会像这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;chen-api.cloud&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;proxy_pass&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;http://127.0.0.1:3000&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;Host&lt;/span&gt; $host;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-Real-IP&lt;/span&gt; $remote_addr;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-Forwarded-For&lt;/span&gt; $proxy_add_x_forwarded_for;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;X-Forwarded-Proto&lt;/span&gt; $scheme;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的关键不是把配置背下来，而是理解这几个事实：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;应用服务尽量只监听本地&lt;/li&gt;&#xA;&lt;li&gt;公网入口统一交给 &lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;反代时要把请求头带完整&lt;/li&gt;&#xA;&lt;li&gt;后面签 HTTPS 会更顺&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;七https-证书是上线的必要条件不是可选项&#34;&gt;七、HTTPS 证书是上线的必要条件，不是可选项&#xA;&lt;/h2&gt;&lt;p&gt;当 HTTP 反代已经打通之后，下一步就应该立刻上 HTTPS。&lt;/p&gt;&#xA;&lt;p&gt;这一步通常会用 &lt;code&gt;certbot + nginx&lt;/code&gt; 组合完成。它的好处是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;配置直接&lt;/li&gt;&#xA;&lt;li&gt;自动改 Nginx&lt;/li&gt;&#xA;&lt;li&gt;自动续期方便&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;只要满足下面几个条件，一般就可以顺利签证书：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;域名已经正确解析到服务器公网 IP&lt;/li&gt;&#xA;&lt;li&gt;安全组放通了 &lt;code&gt;80&lt;/code&gt; 和 &lt;code&gt;443&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Nginx&lt;/code&gt; 对该域名的 &lt;code&gt;server_name&lt;/code&gt; 配置正确&lt;/li&gt;&#xA;&lt;li&gt;外部可以通过 HTTP 正常访问到站点&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;完成后，服务会从：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;http://chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;变成：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;https://chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这不仅是为了浏览器地址栏更好看，更重要的是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;OAuth 回调通常更依赖稳定的 HTTPS 环境&lt;/li&gt;&#xA;&lt;li&gt;中转服务对安全链路要求更高&lt;/li&gt;&#xA;&lt;li&gt;长期使用时也更规范&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;八登录-sub2api-后通过-oauth-绑定上游账号&#34;&gt;八、登录 sub2api 后，通过 OAuth 绑定上游账号&#xA;&lt;/h2&gt;&lt;p&gt;当反代和 HTTPS 都打通之后，才真正进入“业务可用”阶段。&lt;/p&gt;&#xA;&lt;p&gt;这时一般会做下面几件事：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;打开 &lt;code&gt;sub2api&lt;/code&gt; 的管理界面&lt;/li&gt;&#xA;&lt;li&gt;登录后台&lt;/li&gt;&#xA;&lt;li&gt;找到账号绑定或授权入口&lt;/li&gt;&#xA;&lt;li&gt;通过 OAuth 流程绑定 GPT 账号&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;这一部分最重要的其实不是“点哪个按钮”，而是确保下面三个前置条件已经成立：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;站点已经能被公网稳定访问&lt;/li&gt;&#xA;&lt;li&gt;HTTPS 正常&lt;/li&gt;&#xA;&lt;li&gt;回调链路没有被错误代理或拦截&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;如果 OAuth 绑定异常，大概率优先排查这些问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;域名是否正确&lt;/li&gt;&#xA;&lt;li&gt;证书是否正常&lt;/li&gt;&#xA;&lt;li&gt;Nginx 是否正确转发头信息&lt;/li&gt;&#xA;&lt;li&gt;服务端日志里有没有回调报错&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;九整套链路里最容易出问题的地方&#34;&gt;九、整套链路里最容易出问题的地方&#xA;&lt;/h2&gt;&lt;p&gt;回头看，这一套流程真正容易卡住的地方并不只在安装服务本身，而是在几个看似琐碎的环节：&lt;/p&gt;&#xA;&lt;h3 id=&#34;1-域名解析没生效&#34;&gt;1. 域名解析没生效&#xA;&lt;/h3&gt;&lt;p&gt;很多“站点打不开”的问题，其实不是程序没跑，而是域名还没指到服务器。&lt;/p&gt;&#xA;&lt;h3 id=&#34;2-服务没起来就开始配-nginx&#34;&gt;2. 服务没起来就开始配 Nginx&#xA;&lt;/h3&gt;&lt;p&gt;正确顺序应该始终是：&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;li&gt;再签证书&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;3-https-没配置完整&#34;&gt;3. HTTPS 没配置完整&#xA;&lt;/h3&gt;&lt;p&gt;证书签发成功，不代表整个 HTTPS 链路一定完全可用。还要看：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Nginx 是否正确加载证书&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;443&lt;/code&gt; 是否放行&lt;/li&gt;&#xA;&lt;li&gt;回调链路是否仍然走错地址&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;4-把账号问题误判成部署问题&#34;&gt;4. 把账号问题误判成部署问题&#xA;&lt;/h3&gt;&lt;p&gt;如果上游账号本身状态不对，哪怕服务器、Nginx、证书全都正确，也依然会表现成“服务不可用”。&lt;/p&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;ul&gt;&#xA;&lt;li&gt;一台海外 Ubuntu 服务器&lt;/li&gt;&#xA;&lt;li&gt;一个正式域名&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Tailscale&lt;/code&gt; 作为可控网络出口方案&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;sub2api&lt;/code&gt; 作为核心服务&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Nginx&lt;/code&gt; 负责公网入口与反向代理&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Let&#39;s Encrypt&lt;/code&gt; 负责 HTTPS&lt;/li&gt;&#xA;&lt;li&gt;OAuth 完成上游账号绑定&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;从结果上说，这已经是一套足够个人长期使用的中转服务结构。&lt;/p&gt;&#xA;&lt;p&gt;它未必是唯一方案，也不一定是最“高级”的方案，但对个人部署来说，胜在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;成本可控&lt;/li&gt;&#xA;&lt;li&gt;结构清晰&lt;/li&gt;&#xA;&lt;li&gt;易于维护&lt;/li&gt;&#xA;&lt;li&gt;扩展方便&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;十一如果让我再做一次我会坚持这个顺序&#34;&gt;十一、如果让我再做一次，我会坚持这个顺序&#xA;&lt;/h2&gt;&lt;p&gt;最后总结一下，如果让我重新从零做一遍，我仍然会按这个顺序来：&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;li&gt;再部署 &lt;code&gt;sub2api&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;然后配置 &lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;最后接 HTTPS 和 OAuth&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;因为只有按这个顺序，排障成本才最低。&lt;/p&gt;&#xA;&lt;p&gt;很多时候，真正节省时间的不是命令敲得有多快，而是步骤顺序有没有走对。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>从 0 到上线：我如何搭建自己的 Hugo 博客</title>
            <link>https://blog.chen-api.cloud/posts/from-zero-to-hugo-blog/</link>
            <pubDate>Tue, 26 May 2026 13:05:00 +0800</pubDate>
            <guid>https://blog.chen-api.cloud/posts/from-zero-to-hugo-blog/</guid>
            <description>&lt;p&gt;这篇笔记记录了我从一台空白 Ubuntu 服务器开始，搭建并发布自己 Hugo 博客的全过程。&lt;/p&gt;&#xA;&lt;p&gt;这次没有走现成面板，也没有用一键脚本，而是一步一步把域名、Nginx、HTTPS、Hugo 和主题都接起来。中间踩了不少坑，但也因此把整个链路摸清了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一准备工作&#34;&gt;一、准备工作&#xA;&lt;/h2&gt;&lt;p&gt;开始之前，服务器上已经跑着一个现有站点 &lt;code&gt;sub2api&lt;/code&gt;，域名是 &lt;code&gt;chen-api.cloud&lt;/code&gt;。因此这次部署博客时，有一个约束条件很明确：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不能影响现有的 &lt;code&gt;sub2api&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;博客要部署到新子域名 &lt;code&gt;blog.chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这个前提决定了后面的 Nginx 配置不能覆盖原站点，只能新增一个独立 &lt;code&gt;server&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;二先把-hugo-站点跑起来&#34;&gt;二、先把 Hugo 站点跑起来&#xA;&lt;/h2&gt;&lt;p&gt;一开始最先遇到的是两个典型问题。&lt;/p&gt;&#xA;&lt;p&gt;第一个问题是命令本身输错了。我先输入了大写的 &lt;code&gt;HUGO&lt;/code&gt;，系统直接报错：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;HUGO: command not found&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后来确认应该使用小写命令：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hugo&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第二个问题是配置文件 &lt;code&gt;config.toml&lt;/code&gt; 写坏了。因为我最开始用 heredoc 写文件时，把 &lt;code&gt;EOF&lt;/code&gt; 缩进了，结果它真的被写进了文件里，Hugo 解析时报错：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unmarshal failed: toml: expected character &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修正之后，最小配置大概是这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-toml&#34; data-lang=&#34;toml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;baseURL&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://blog.chen-api.cloud/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;locale&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;zh-cn&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CHEN 的博客&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里最大的教训是：如果不熟悉 shell heredoc，短文件直接用 &lt;code&gt;printf&lt;/code&gt; 或者 &lt;code&gt;nano&lt;/code&gt; 会稳很多。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三给博客准备最小内容&#34;&gt;三、给博客准备最小内容&#xA;&lt;/h2&gt;&lt;p&gt;为了先验证整条发布链路，我没有一开始就上复杂主题，而是先做了一个最小首页。&lt;/p&gt;&#xA;&lt;p&gt;最早的问题并不是 Nginx，而是 Hugo 内容文件 &lt;code&gt;_index.md&lt;/code&gt; 写坏了。比如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;YAML 头信息没有正确闭合&lt;/li&gt;&#xA;&lt;li&gt;每行前面多了空格&lt;/li&gt;&#xA;&lt;li&gt;文件末尾多写了一行 &lt;code&gt;EOF&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这会导致 Hugo 报错：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EOF looking &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; end YAML front matter delimiter&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修正之后，一个最小可用首页类似这样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-markdown&#34; data-lang=&#34;markdown&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title: &amp;#34;首页&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;这是我的 Hugo 博客，已经部署成功。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;等 Hugo 能正常构建出 &lt;code&gt;index.html&lt;/code&gt; 之后，才适合继续往下接 Nginx。&lt;/p&gt;&#xA;&lt;h2 id=&#34;四nginx-配置必须与现有业务并存&#34;&gt;四、Nginx 配置必须与现有业务并存&#xA;&lt;/h2&gt;&lt;p&gt;由于服务器上已经有 &lt;code&gt;sub2api&lt;/code&gt;，部署前先检查了当前站点配置：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;sites-enabled&lt;/code&gt; 里已有 &lt;code&gt;sub2api&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;它处理的是 &lt;code&gt;chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;没有占用 &lt;code&gt;blog.chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这说明博客可以安全新增一个站点，而不必修改原服务。&lt;/p&gt;&#xA;&lt;p&gt;博客对应的 Nginx 配置逻辑非常简单：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;[::]:80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;blog.chen-api.cloud&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/var/www/blog&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;index.html&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;try_files&lt;/span&gt; $uri $uri/ &lt;span style=&#34;color:#e6db74&#34;&gt;/index.html&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有个关键判断过程。当时博客域名第一次访问并不是 &lt;code&gt;404&lt;/code&gt;，而是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl: &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;6&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; Could not resolve host: blog.chen-api.cloud&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这说明问题根本不在 Nginx，而在 DNS。&lt;/p&gt;&#xA;&lt;h2 id=&#34;五域名解析是最容易忽略的一步&#34;&gt;五、域名解析是最容易忽略的一步&#xA;&lt;/h2&gt;&lt;p&gt;之后用 &lt;code&gt;nslookup&lt;/code&gt; 检查，发现子域名一开始是 &lt;code&gt;NXDOMAIN&lt;/code&gt;，也就是根本没有这条记录。&lt;/p&gt;&#xA;&lt;p&gt;必须先去 DNS 后台添加：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类型：&lt;code&gt;A&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;主机记录：&lt;code&gt;blog&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;记录值：服务器公网 IP&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;等 DNS 生效之后，再次检查：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nslookup blog.chen-api.cloud&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;已经能正确解析到服务器 IP，这时候再访问 HTTP，才真正走到了 Nginx。&lt;/p&gt;&#xA;&lt;h2 id=&#34;六403-的根因不是权限而是没生成首页&#34;&gt;六、403 的根因不是权限，而是没生成首页&#xA;&lt;/h2&gt;&lt;p&gt;DNS 生效之后，博客域名开始返回 &lt;code&gt;403 Forbidden&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这一步很容易误判成目录权限问题，但实际排查后发现根因是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;/var/www/blog&lt;/code&gt; 目录里没有 &lt;code&gt;index.html&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Hugo 因为内容文件错误，根本没有生成首页&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;也就是说，&lt;code&gt;403&lt;/code&gt; 只是结果，真正的问题还是构建失败。&lt;/p&gt;&#xA;&lt;p&gt;这次部署最大的经验之一就是：先看生成目录里有没有实际产物，再怀疑 Nginx。&lt;/p&gt;&#xA;&lt;h2 id=&#34;七https-比部署本身更顺利&#34;&gt;七、HTTPS 比部署本身更顺利&#xA;&lt;/h2&gt;&lt;p&gt;当 &lt;code&gt;http://blog.chen-api.cloud&lt;/code&gt; 能返回 &lt;code&gt;200 OK&lt;/code&gt; 后，HTTPS 基本就是顺水推舟了。&lt;/p&gt;&#xA;&lt;p&gt;直接使用 &lt;code&gt;certbot --nginx&lt;/code&gt; 申请并挂载证书。过程中系统提示这个域名已经存在证书，于是选择了“重新安装已有证书”，而不是重新签发。&lt;/p&gt;&#xA;&lt;p&gt;最终验证结果：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;https://blog.chen-api.cloud&lt;/code&gt; 返回 &lt;code&gt;200 OK&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;certbot.timer&lt;/code&gt; 已启用&lt;/li&gt;&#xA;&lt;li&gt;证书会自动续期&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;到这里，博客已经算正式上线。&lt;/p&gt;&#xA;&lt;h2 id=&#34;八换主题时又踩到了-hugo-版本坑&#34;&gt;八、换主题时又踩到了 Hugo 版本坑&#xA;&lt;/h2&gt;&lt;p&gt;博客最初虽然可用，但只是一个临时首页，不像正式博客。后来我选择切换到 &lt;code&gt;Hugo Theme Stack&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;主题装上之后，新的问题出现了：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;hash&amp;#34;&lt;/span&gt; not defined&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;排查后发现并不是主题坏了，而是服务器自带 Hugo 版本太旧：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;当前版本：&lt;code&gt;0.92.2&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;Stack&lt;/code&gt; 主题最低要求：&lt;code&gt;0.157.0&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;所以必须升级 Hugo。&lt;/p&gt;&#xA;&lt;h2 id=&#34;九普通版-hugo-还不够必须用-extended&#34;&gt;九、普通版 Hugo 还不够，必须用 extended&#xA;&lt;/h2&gt;&lt;p&gt;升级到新版本之后，构建又报了另一个错误：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TOCSS: failed to transform &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/scss/style.scss&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这说明我虽然把 Hugo 升级了，但装的是普通版，不是 &lt;code&gt;extended&lt;/code&gt; 版。&lt;/p&gt;&#xA;&lt;p&gt;而 &lt;code&gt;Stack&lt;/code&gt; 主题会编译 SCSS，因此必须安装官方 &lt;code&gt;extended&lt;/code&gt; 版本。&lt;/p&gt;&#xA;&lt;p&gt;替换完成后，最终版本变成：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hugo v0.161.1+extended&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到这一步，主题才真正构建成功，博客首页也切换成了卡片式布局。&lt;/p&gt;&#xA;&lt;h2 id=&#34;十最终结果&#34;&gt;十、最终结果&#xA;&lt;/h2&gt;&lt;p&gt;现在这套博客已经具备了基础可用状态：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;域名：&lt;code&gt;blog.chen-api.cloud&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Web 服务：&lt;code&gt;Nginx&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;证书：&lt;code&gt;Let&#39;s Encrypt&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;博客引擎：&lt;code&gt;Hugo&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;主题：&lt;code&gt;Stack&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;自动续期：&lt;code&gt;certbot.timer&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;而且整个过程没有影响服务器上原来的 &lt;code&gt;sub2api&lt;/code&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;1-不要过早怀疑-nginx&#34;&gt;1. 不要过早怀疑 Nginx&#xA;&lt;/h3&gt;&lt;p&gt;访问异常不一定是 Nginx 配错了，也可能是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;DNS 没生效&lt;/li&gt;&#xA;&lt;li&gt;Hugo 没生成文件&lt;/li&gt;&#xA;&lt;li&gt;内容文件格式写坏&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;2-heredoc-对新手并不友好&#34;&gt;2. heredoc 对新手并不友好&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF&lt;/code&gt; 看起来方便，但实际非常容易因为缩进、结尾位置或者误输入，把 &lt;code&gt;EOF&lt;/code&gt; 写进文件里。&lt;/p&gt;&#xA;&lt;p&gt;短配置更推荐：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;printf&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;nano&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;3-主题和-hugo-版本必须一起看&#34;&gt;3. 主题和 Hugo 版本必须一起看&#xA;&lt;/h3&gt;&lt;p&gt;很多 Hugo 主题页面能打开，不代表你的本地环境就能跑。&lt;/p&gt;&#xA;&lt;p&gt;一定要先确认：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;主题最低支持版本&lt;/li&gt;&#xA;&lt;li&gt;是否要求 &lt;code&gt;extended&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;4-先打通最小链路再追求美观&#34;&gt;4. 先打通最小链路，再追求美观&#xA;&lt;/h3&gt;&lt;p&gt;这次如果一开始就折腾主题、菜单、页面细节，排障会困难很多。&lt;/p&gt;&#xA;&lt;p&gt;正确顺序应该是：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Hugo 能构建&lt;/li&gt;&#xA;&lt;li&gt;Nginx 能访问&lt;/li&gt;&#xA;&lt;li&gt;DNS 正常&lt;/li&gt;&#xA;&lt;li&gt;HTTPS 正常&lt;/li&gt;&#xA;&lt;li&gt;再换主题和美化&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;十二下一步&#34;&gt;十二、下一步&#xA;&lt;/h2&gt;&lt;p&gt;博客虽然已经上线，但现在还只是第一阶段。接下来我准备继续补这些内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;关于页&lt;/li&gt;&#xA;&lt;li&gt;归档页&lt;/li&gt;&#xA;&lt;li&gt;搜索页&lt;/li&gt;&#xA;&lt;li&gt;头像和侧边栏资料&lt;/li&gt;&#xA;&lt;li&gt;更多正式文章&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这篇文章本身，就是这个博客发布出去的第一篇“建站记录”。&lt;/p&gt;&#xA;</description>
        </item><item>
            <title>博客已切换到 Stack 主题</title>
            <link>https://blog.chen-api.cloud/posts/hello-stack/</link>
            <pubDate>Tue, 26 May 2026 12:00:00 +0800</pubDate>
            <guid>https://blog.chen-api.cloud/posts/hello-stack/</guid>
            <description>&lt;p&gt;博客已经部署完成，并切换到了 Hugo Theme Stack。&lt;/p&gt;&#xA;&lt;p&gt;接下来会逐步补充文章、页面和更多配置。&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
