<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<atom:link href="https://gloriar.com/feed" rel="self" type="application/rss+xml"/>
<title>風が憩う - 慎虚怀，守静宁</title>
<link>https://gloriar.com</link>
<description>这里记录游戏、日常与一些安静的思考。</description>
<language>zh-CN</language>
<copyright>© 風憩 </copyright>
<pubDate>Mon, 25 May 2026 09:31:12 GMT</pubDate>
<generator>Mix Space CMS (https://github.com/mx-space)</generator>
<docs>https://mx-space.js.org</docs>
<image>
    <url>https://img.gloriar.com/uploads/20260516/8b85a27fb4224e49386181656b92adc4.webp</url>
    <title>風が憩う - 慎虚怀，守静宁</title>
    <link>https://gloriar.com</link>
</image>
<item>
    <title>从零把博客重新搭起来：Mix Space、Yohaku 和一点点回滚经验</title>
    <link>https://gloriar.com/posts/tech-record/rebuild-blog-with-mix-space-yohaku</link>
    <pubDate>Sun, 24 May 2026 09:39:28 GMT</pubDate>
    <description>风停下来的地方，也需要有人先把屋檐搭好。
这篇算是一份回头看的部署记录：从后端、前端、反向代理，到最</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://gloriar.com/posts/tech-record/rebuild-blog-with-mix-space-yohaku'>https://gloriar.com/posts/tech-record/rebuild-blog-with-mix-space-yohaku</a></blockquote>
          <blockquote>
<p>风停下来的地方，也需要有人先把屋檐搭好。</p>
<p>这篇算是一份回头看的部署记录：从后端、前端、反向代理，到最后的升级尝试和回滚。它不是一篇“照着复制就一定成功”的教程，更像是一次把过程摊开来的折腾日志。</p>
</blockquote>
<h2>起点</h2>
<p>我想给 <code>gloriar.com</code> 搭一个属于自己的博客。</p>
<p>最后选下来的组合是：</p>
<ul>
<li><strong>后端</strong>：Mix Space / <code>mx-server</code></li>
<li><strong>前端</strong>：Yohaku</li>
<li><strong>数据库</strong>：PostgreSQL</li>
<li><strong>缓存</strong>：Redis</li>
<li><strong>入口</strong>：1Panel 里的 OpenResty 反向代理</li>
<li><strong>部署方式</strong>：Docker Compose</li>
</ul>
<p>现在稳定运行的结构大概是这样：</p>
<pre><code class="language-text">访客
  │
  ▼
https://gloriar.com
  │
  ├─ /                 -&gt; Yohaku 前端 :2323
  ├─ /about            -&gt; Yohaku 前端 :2323
  ├─ /message          -&gt; Yohaku 前端 :2323
  │
  ├─ /api/v2/*         -&gt; Mix Space 后端 :2333
  ├─ /proxy/qaqdmin    -&gt; Mix Space 后台 :2333
  ├─ /feed             -&gt; Mix Space 后端 :2333
  └─ /sitemap          -&gt; Mix Space 后端 :2333</code></pre><p>这套结构的好处是：访客看到的是 Yohaku 的页面，后台和 API 仍然由 Mix Space 接管；对外只暴露一个域名，看起来比较干净。</p>
<h2>后端：先把 Mix Space 跑起来</h2>
<p>后端放在：</p>
<pre><code class="language-bash">/root/mx-space/core</code></pre><p>核心服务包括：</p>
<pre><code class="language-text">mx-server     # Mix Space 后端
mx-postgres   # PostgreSQL
mx-redis      # Redis
mx-migrate    # 启动前执行迁移的一次性容器</code></pre><p>一开始最容易踩坑的是版本变化。新版 Mix Space 已经不再是早期那种只依赖 MongoDB 的形态，而是需要 PostgreSQL。</p>
<p>所以 compose 里最关键的是这几组环境变量：</p>
<pre><code class="language-yaml">PG_HOST: mx-postgres
PG_PORT: "5432"
PG_USER: ${PG_USER:-mx}
PG_PASSWORD: ${PG_PASSWORD:-mx}
PG_DATABASE: ${PG_DATABASE:-mx_core}

REDIS_HOST: mx-redis
REDIS_PORT: "6379"

ALLOWED_ORIGINS: https://gloriar.com,http://localhost:2323,http://127.0.0.1:2323
BETTER_AUTH_URL: https://gloriar.com</code></pre><p>其中 <code>BETTER_AUTH_URL</code> 这个变量很容易漏。只写进 <code>.env</code> 还不够，还要确认 <code>docker-compose.yml</code> 真的把它传进容器。否则后台登录、Passkey / WebAuthn 一类功能会出现一些看起来很“玄学”的问题。</p>
<p>后端起来之后，最小验证是：</p>
<pre><code class="language-bash">curl http://127.0.0.1:2333/api/v2/ping</code></pre><p>期望返回：</p>
<pre><code class="language-json">{"data":"pong"}</code></pre><p>这个接口很小，但很重要。它能确认后端应用、数据库连接、容器端口至少是通的。</p>
<h2>前端：Yohaku 作为访客侧主题</h2>
<p>Yohaku 放在：</p>
<pre><code class="language-bash">/root/yohaku-docker</code></pre><p>当前稳定镜像是：</p>
<pre><code class="language-text">ghcr.io/db52/yohaku:sha-0c803b3</code></pre><p>Compose 里主要是这些配置：</p>
<pre><code class="language-yaml">services:
  yohaku:
    image: ghcr.io/db52/yohaku:sha-0c803b3
    pull_policy: if_not_present
    environment:
      - NEXT_PUBLIC_API_URL=https://gloriar.com/api/v2
      - NEXT_PUBLIC_GATEWAY_URL=https://gloriar.com
      - BASE_URL=https://gloriar.com
    ports:
      - 127.0.0.1:2323:2323</code></pre><p>这里我选择只把 <code>2323</code> 绑定在 <code>127.0.0.1</code>，不直接对公网开放。外部访问全部交给 OpenResty。</p>
<p>这样一来，前端容器只需要专心服务页面，HTTPS、域名、路径分流都在反代层处理。</p>
<h2>反向代理：同一个域名下分流</h2>
<p>OpenResty 是 1Panel 管的容器，不是宿主机裸装的 nginx。</p>
<p>这点非常关键。</p>
<p>配置文件实际在：</p>
<pre><code class="language-text">/opt/1panel/1panel/www/sites/gloriar.com/proxy/root.conf</code></pre><p>改完之后需要在 OpenResty 容器里 reload：</p>
<pre><code class="language-bash">docker exec 1Panel-openresty-rQKp nginx -t
docker exec 1Panel-openresty-rQKp nginx -s reload</code></pre><p>主要分流规则是：</p>
<pre><code class="language-nginx">location ^~ /api/v2 {
    proxy_pass http://127.0.0.1:2333;
}

location ^~ /proxy {
    proxy_pass http://127.0.0.1:2333;
}

location ^~ /render {
    proxy_pass http://127.0.0.1:2333;
}

location ^~ /socket.io {
    proxy_pass http://127.0.0.1:2333;
}

location ^~ / {
    proxy_pass http://127.0.0.1:2323;
}</code></pre><p>后来又补了 <code>/feed</code>、<code>/atom.xml</code>、<code>/sitemap</code>，否则 RSS / Sitemap 会落到 Yohaku 前端那边，出现 500 或找不到路由。</p>
<p>也就是说，这个站点不是简单地“一个容器一个域名”，而是在同一个域名下把前端和后端路径拆开。</p>
<h2>初始化内容：让首页先活起来</h2>
<p>部署过程里还有一个小坑：站点刚初始化时内容太少，某些聚合接口和首页逻辑会踩到边界情况。</p>
<p>比如没有 note 的时候，首页或 <code>/notes</code> 可能会出现：</p>
<pre><code class="language-text">error.api_fetchError
Cannot read properties of null</code></pre><p>最后通过补一条最小的 note，让首页依赖的数据结构完整起来。</p>
<p>这件事挺像搭房子时先放一张桌子：它不是最终内容，却能让空间开始成立。</p>
<h2>页面与导航：不是所有入口都该靠前端注入</h2>
<p>后来我加了几个页面，比如：</p>
<ul>
<li><code>/about</code></li>
<li><code>/bangumi</code></li>
<li><code>/message</code></li>
</ul>
<p>一开始很容易想到用前端注入链接，但这不是最稳的方式。</p>
<p>Yohaku 顶部 Home 下拉里的页面，实际上来自 Mix Space 的 <code>pages</code> 数据。也就是说，如果想让 <code>/message</code> 和 <code>/about</code> 同级，正确做法是创建一个真实页面记录：</p>
<pre><code class="language-text">title: 留言
slug: message
order: 3</code></pre><p>这样 Yohaku 会自然把它列出来，而不是靠一段临时 JS 去“假装存在”。</p>
<p>留言页后来也补了一点内容，不再只是单调的一句话：</p>
<blockquote>
<p>风偶尔会停下来，文字也是。</p>
<p>如果你路过这里，想打个招呼、聊聊最近看到的东西，或者只是留下一句无关紧要的话，都可以写在下面。</p>
</blockquote>
<p>这种内容不复杂，但它让页面有了自己的气质。</p>
<h2>更新与回滚：不要迷信 latest</h2>
<p>这次部署里最大的教训是：不要迷信 <code>latest</code>。</p>
<p>Mix Space 和 Yohaku 都更新很快，而且两边是强耦合的。后端 API 形态变了，前端不一定马上兼容；前端新镜像改了读取假设，旧数据也可能让它炸。</p>
<p>我后来试过 v13。</p>
<p>官方 v12 → v13 文档里说得很清楚：</p>
<ul>
<li><code>/api/v2/*</code> 改成 <code>/api/v3/*</code></li>
<li>响应结构变成 <code>{ data, meta }</code></li>
<li>字段统一 <code>snake_case</code></li>
<li>数据库本身不需要迁移</li>
<li>前端消费者需要适配 <code>@mx-space/api-client@5</code> 或 V3 envelope</li>
</ul>
<p>后端 v13 本身可以启动，<code>/api/v3/aggregate</code> 也能返回 200。</p>
<p>但最新 Yohaku 配合 v3 后端时，首页和 OG 仍然会炸：</p>
<pre><code class="language-text">/        -&gt; 500
/home-og -&gt; 500</code></pre><p>日志里是：</p>
<pre><code class="language-text">Cannot destructure property 'seo' of '(intermediate value)' as it is null
Cannot read properties of null (reading '$serialized')</code></pre><p>所以最后还是回退到稳定组合：</p>
<pre><code class="language-text">mx-server: local/mx-server-rollback:20260524-145133
Yohaku: ghcr.io/db52/yohaku:sha-0c803b3
API: /api/v2</code></pre><p>回滚不是失败。很多时候，回滚是让服务继续稳定在线的必要动作。</p>
<h2>我现在的检查清单</h2>
<p>每次更新之后，我都会至少检查这些：</p>
<pre><code class="language-bash">curl -I https://gloriar.com/
curl -I https://gloriar.com/about
curl -I https://gloriar.com/message
curl -I https://gloriar.com/home-og
curl https://gloriar.com/api/v2/ping</code></pre><p>对应期望：</p>
<table>
<thead>
<tr>
<th>路径</th>
<th>期望</th>
</tr>
</thead>
<tbody><tr>
<td><code>/</code></td>
<td>200</td>
</tr>
<tr>
<td><code>/about</code></td>
<td>200</td>
</tr>
<tr>
<td><code>/message</code></td>
<td>200</td>
</tr>
<tr>
<td><code>/home-og</code></td>
<td>200 image/png</td>
</tr>
<tr>
<td><code>/api/v2/ping</code></td>
<td><code>{&quot;data&quot;:&quot;pong&quot;}</code></td>
</tr>
</tbody></table>
<p>只看容器 <code>Up</code> 是不够的。容器活着，不代表首页能 SSR；API 200，也不代表前端能正确吃下数据。</p>
<h2>最后</h2>
<p>这次部署不像“按教程一步一步就完成”的那种过程，更像是很多小判断叠在一起：</p>
<ul>
<li>哪些路径该走后端，哪些路径该走前端；</li>
<li>哪些配置写了但没有传进容器；</li>
<li>哪些错误是数据边界，哪些错误是版本不兼容；</li>
<li>什么时候该继续修，什么时候该先回退。</li>
</ul>
<p>现在回头看，这个博客真正被搭起来，不只是因为几个容器跑起来了。</p>
<p>而是因为它终于有了一个比较清晰的边界：</p>
<pre><code class="language-text">内容在 Mix Space，呈现在 Yohaku，入口交给 OpenResty。</code></pre><p>剩下的，就是慢慢往里面写东西了。</p>

          <p style='text-align: right'>
          <a href='https://gloriar.com/posts/tech-record/rebuild-blog-with-mix-space-yohaku#comments'>看完了？说点什么呢</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">177961556811181166</guid>
  <category>post</category>
<category>技术记录</category>
 </item>
  <item>
    <title>初始化测试</title>
    <link>https://gloriar.com/notes/1</link>
    <pubDate>Fri, 22 May 2026 14:53:39 GMT</pubDate>
    <description>初始化测试。</description>
    <content:encoded><![CDATA[
      <blockquote>该渲染由 marked 生成，可能存在排版问题，最佳体验请前往：<a href='https://gloriar.com/notes/1'>https://gloriar.com/notes/1</a></blockquote>
          <p>初始化测试。</p>

          <p style='text-align: right'>
          <a href='https://gloriar.com/notes/1#comments'>看完了？说点什么呢</a>
          </p>
    ]]>
    </content:encoded>
  <guid isPermaLink="false">139743919658242048</guid>
  <category>note</category>
false
 </item>
  
</channel>
</rss>