<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Miike&apos;s Blog</title><description>记录、探索与分享</description><link>https://example.com/</link><language>zh_CN</language><item><title>从 Fuwari 到 Miike&apos;s Blog：一次 Astro 博客的开发、构建与部署记录</title><link>https://example.com/posts/building-and-deploying-miikes-blog/</link><guid isPermaLink="true">https://example.com/posts/building-and-deploying-miikes-blog/</guid><description>记录 Miike&apos;s Blog 从主题定制、构建排错、GitHub 整理到 SSH 与 Nginx 部署的完整过程，以及这次实践中值得留下的经验。</description><pubDate>Thu, 17 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;这几天，我把 &lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt; 改造成了现在的 &lt;strong&gt;Miike&apos;s Blog&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它以 &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; 为框架，用 Tailwind CSS 负责样式，最后通过 GitHub、SSH 和 Nginx 部署到自己的云主机。整个过程看上去只是“改主题、构建、上传”，真正做起来却遇到了不少值得记录的问题。&lt;/p&gt;
&lt;p&gt;这篇文章既是本次开发的复盘，也是一份留给未来自己的部署手册。&lt;/p&gt;
&lt;h2&gt;从模板开始，但不止于模板&lt;/h2&gt;
&lt;p&gt;Fuwari 已经提供了文章系统、归档、搜索、亮暗模式、响应式布局等完整能力，所以这次开发不需要从零搭建博客。我的主要工作是把模板调整成自己的站点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改站点名称、作者信息与页面内容；&lt;/li&gt;
&lt;li&gt;整理项目目录、README 和 Wiki；&lt;/li&gt;
&lt;li&gt;将主题色选择改成四个固定色板；&lt;/li&gt;
&lt;li&gt;修复生产构建中暴露的样式问题；&lt;/li&gt;
&lt;li&gt;将代码推送到 GitHub；&lt;/li&gt;
&lt;li&gt;在云主机上完成构建并通过 Nginx 提供访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使用成熟模板最大的好处是节省基础功能的开发时间，但模板中的配置、依赖和样式约定仍然要认真理解。否则，本地看似正常的修改，很容易在生产构建时暴露问题。&lt;/p&gt;
&lt;h2&gt;主题色：从滑块改成四个色板&lt;/h2&gt;
&lt;p&gt;原主题通过滑块自由选择色相。对个人博客而言，自由度太高反而会让界面缺少统一感。我最终保留了四个预设：淡粉色、粉白色、超浅紫色和奶蓝色，并把淡粉色设为默认值。&lt;/p&gt;
&lt;p&gt;主题色仍然使用 OKLCH 的色相值，只把可选范围限制成固定数组：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export const themeColorOptions = [
  { name: &quot;淡粉色&quot;, hue: 350 },
  { name: &quot;粉白色&quot;, hue: 12 },
  { name: &quot;超浅紫色&quot;, hue: 285 },
  { name: &quot;奶蓝色&quot;, hue: 220 },
] as const;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显示设置中的滑块则被替换成四个按钮。界面上只显示颜色预览，不显示文字；名称保留在 &lt;code&gt;aria-label&lt;/code&gt; 中，方便屏幕阅读器识别：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{#each themeColorOptions as option}
  &amp;lt;button
    type=&quot;button&quot;
    aria-label={`切换到${option.name}`}
    aria-pressed={hue === option.hue}
    on:click={() =&amp;gt; hue = option.hue}
  &amp;gt;
    &amp;lt;span
      class=&quot;w-6 h-6 rounded-full&quot;
      style={`background: oklch(0.86 0.08 ${option.hue});`}
    &amp;gt;&amp;lt;/span&amp;gt;
  &amp;lt;/button&amp;gt;
{/each}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;选中的色相会写入浏览器的 &lt;code&gt;localStorage&lt;/code&gt;，刷新页面后仍然生效。同时，对读取出的值做白名单校验，避免旧数据或异常数据让主题进入未定义状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export function setHue(hue: number): void {
  const themeHue = isThemeHue(hue) ? hue : getDefaultHue();
  localStorage.setItem(&quot;hue&quot;, String(themeHue));
  document.documentElement.style.setProperty(&quot;--hue&quot;, String(themeHue));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这次修改让我再次意识到，设置项并非越自由越好。有限、经过挑选的选项，通常能带来更稳定的视觉体验。&lt;/p&gt;
&lt;h2&gt;本地正常，不代表生产构建一定正常&lt;/h2&gt;
&lt;p&gt;开发服务器能够运行后，我原以为构建只是最后走一遍流程，实际却在 Markdown 代码块的复制按钮样式上失败了。&lt;/p&gt;
&lt;p&gt;问题来自 &lt;code&gt;@apply&lt;/code&gt; 中引用的自定义组合类。Tailwind 在生产构建时无法确认这个类一定存在，因此直接中断构建。解决方法是把组合类展开为明确的原子样式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.copy-btn {
  all: initial;
  @apply flex items-center justify-center
    bg-[oklch(0.45_0.01_var(--hue))]
    hover:bg-[oklch(0.50_0.01_var(--hue))]
    active:bg-[oklch(0.55_0.01_var(--hue))]
    dark:bg-[oklch(0.30_0.02_var(--hue))]
    opacity-0 absolute h-8 w-8 top-3 right-3
    rounded-lg transition-all cursor-pointer;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;修复后重新执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Astro 完成静态页面生成，Pagefind 随后为文章建立搜索索引。这个问题提醒我，&lt;code&gt;pnpm dev&lt;/code&gt; 只能验证开发状态；提交或部署前，必须至少完成一次与生产环境一致的构建。&lt;/p&gt;
&lt;h2&gt;让仓库成为唯一可信来源&lt;/h2&gt;
&lt;p&gt;开发过程中会产生构建目录、压缩包、临时密钥和工具缓存。如果这些内容都留在项目根目录，仓库很快就会变得难以维护。&lt;/p&gt;
&lt;p&gt;我重新整理了目录，并明确区分源码、文档和生成物：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Miike_Blog/
├─ public/                 # 静态资源
├─ src/
│  ├─ components/         # 页面组件
│  ├─ content/posts/      # 博客文章
│  ├─ layouts/            # 页面布局
│  └─ styles/             # 全局与 Markdown 样式
├─ docs/                   # 项目文档
├─ astro.config.mjs
├─ package.json
└─ pnpm-lock.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;像 &lt;code&gt;node_modules/&lt;/code&gt;、&lt;code&gt;dist/&lt;/code&gt;、部署压缩包以及私钥，都不应该提交到 GitHub。源码推送完成后，README 和 Wiki 也同步重写，明确说明项目来源、技术栈、本地运行方法以及部署方式。&lt;/p&gt;
&lt;p&gt;这样做的意义不只是让目录更好看。仓库应该能够回答三个问题：项目是什么、怎样运行、怎样部署。只要一台新机器能够仅凭仓库完成构建，项目才算真正可复现。&lt;/p&gt;
&lt;h2&gt;SSH 排障：命令必须在正确的机器上执行&lt;/h2&gt;
&lt;p&gt;部署阶段最有代表性的坑，是把 Windows PowerShell 命令粘贴到了 Linux 服务器终端。&lt;/p&gt;
&lt;p&gt;例如下面的 &lt;code&gt;$env:USERPROFILE&lt;/code&gt; 和 &lt;code&gt;Get-Content&lt;/code&gt; 都属于 PowerShell：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519 `
  -C &quot;miike-blog-deploy&quot; `
  -f &quot;$env:USERPROFILE\.ssh\miike_blog_deploy&quot;

Get-Content &quot;$env:USERPROFILE\.ssh\miike_blog_deploy.pub&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果在 Linux shell 中执行，变量不会按预期展开，甚至会生成名字奇怪的文件。正确流程是：在本地 Windows 生成密钥，把公钥追加到服务器的授权文件中。&lt;/p&gt;
&lt;p&gt;服务器端执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p /root/.ssh
chmod 700 /root/.ssh

printf &apos;%s\n&apos; &apos;这里替换为公钥内容&apos; &amp;gt;&amp;gt; /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;随后还发现服务器 SSH 配置中关闭了公钥认证：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PubkeyAuthentication no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将其改为下面的配置，并先检查语法再重载服务：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;PubkeyAuthentication yes
PermitRootLogin yes
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sshd -t
systemctl reload ssh || systemctl reload sshd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另一个现象是，部分客户端可以连接，而自动化环境中的新连接会在密钥交换阶段被服务器主动关闭。因为连接尚未进入身份认证阶段，所以此时反复更换密码或私钥没有意义。更有效的排查方向是 SSH 服务日志、连接频率限制、防火墙和安全组：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;journalctl -u ssh -u sshd --since &quot;10 minutes ago&quot;
ss -lntp | grep &apos;:22&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这次最终选择通过已经可用的终端手动部署。工具并不是目的，能够判断故障发生在网络、密钥交换还是身份认证阶段，才是排障的关键。&lt;/p&gt;
&lt;h2&gt;在服务器上构建 Astro&lt;/h2&gt;
&lt;p&gt;项目指定使用 pnpm，因此服务器安装 Node.js 后，还要通过 Corepack 启用对应版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;corepack enable
corepack prepare pnpm@9.14.4 --activate
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后从 GitHub 拉取源码并构建：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir -p /var/www
cd /var/www
git clone --branch main \
  https://github.com/cut3y1/Miikes-blogs.git miike-blog

cd /var/www/miike-blog
pnpm install --frozen-lockfile
SITE_URL=&quot;http://154.222.21.240/&quot; pnpm build
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;SITE_URL&lt;/code&gt; 很重要。Astro 会用它生成 Sitemap、RSS 等绝对地址。如果构建时仍然保留旧站点地址，页面虽然能够打开，订阅和站点地图中的链接却可能指向错误的位置。&lt;/p&gt;
&lt;p&gt;构建完成后，最终静态文件位于：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/var/www/miike-blog/dist
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;用 Nginx 提供静态站点&lt;/h2&gt;
&lt;p&gt;Astro 的默认开发服务器适合本地调试，不适合作为正式的静态文件服务。生产环境使用 Nginx，配置保持简单即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {
    listen 80;
    listen [::]:80;

    server_name 154.222.21.240;
    root /var/www/miike-blog/dist;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    error_page 404 /404.html;

    location ~* \.(css|js|jpg|jpeg|png|gif|svg|webp|ico|woff|woff2)$ {
        expires 7d;
        add_header Cache-Control &quot;public, no-transform&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启用配置前先测试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ln -sf /etc/nginx/sites-available/miike-blog \
  /etc/nginx/sites-enabled/miike-blog

nginx -t
systemctl enable nginx
systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;最后同时从服务器内部和外部浏览器检查站点。服务器内部可以使用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl -I http://127.0.0.1/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;只有返回正常状态码、页面资源能够加载、文章路由可以访问，部署才算真正完成。&lt;/p&gt;
&lt;h2&gt;以后如何更新&lt;/h2&gt;
&lt;p&gt;现在 GitHub 仓库是源码的唯一来源。以后发布文章或修改样式，只需要先把改动推送到 &lt;code&gt;main&lt;/code&gt;，再在服务器执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /var/www/miike-blog
git pull --ff-only origin main
pnpm install --frozen-lockfile
SITE_URL=&quot;http://154.222.21.240/&quot; pnpm build
nginx -t &amp;amp;&amp;amp; systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当前部署仍然使用 IP 和 HTTP。后续如果绑定域名，还需要把 &lt;code&gt;SITE_URL&lt;/code&gt; 和 Nginx 的 &lt;code&gt;server_name&lt;/code&gt; 改成正式域名，并配置 HTTPS 证书。&lt;/p&gt;
&lt;h2&gt;这次开发留下的几条经验&lt;/h2&gt;
&lt;p&gt;第一，开发服务器能运行只是起点，生产构建必须单独验证。Astro、Tailwind 和内容索引工具在构建阶段会执行更严格的检查。&lt;/p&gt;
&lt;p&gt;第二，部署问题要分层判断。连接在密钥交换阶段断开时，不应该把时间花在密码上；页面打不开时，也要分别检查构建产物、Nginx、服务器防火墙和云平台安全组。&lt;/p&gt;
&lt;p&gt;第三，命令有明确的执行环境。PowerShell、Linux shell 和远程服务器终端看起来都能输入命令，但变量语法、路径格式和内置命令完全不同。&lt;/p&gt;
&lt;p&gt;第四，部署流程应该可重复。固定 Node.js 与 pnpm 版本、保留锁文件、明确 &lt;code&gt;SITE_URL&lt;/code&gt;、让服务器从 GitHub 构建，都能减少“只在某台电脑上可以运行”的情况。&lt;/p&gt;
&lt;p&gt;最后，基于模板开发并不意味着只是换一个名字。真正属于自己的博客，来自对交互、色彩、内容结构和部署方式的一次次选择。Miike&apos;s Blog 已经上线，而这篇文章正好成为它从源码走向服务器的第一份完整记录。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;本站基于 &lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt; 模板开发，使用 &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; 与 &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind CSS&lt;/a&gt; 构建。感谢原作者和开源社区提供的优秀工具。&lt;/p&gt;
</content:encoded></item><item><title>你好，世界。这里是 Miike&apos;s Blog</title><link>https://example.com/posts/hello-world/</link><guid isPermaLink="true">https://example.com/posts/hello-world/</guid><description>欢迎来到 Miike&apos;s Blog。这里记录技术实践、学习过程，以及生活中值得保存的想法。</description><pubDate>Sat, 12 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;你好，欢迎来到 &lt;strong&gt;Miike&apos;s Blog&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这是博客的第一篇文章，也是这个小小空间真正开始生长的地方。&lt;/p&gt;
&lt;p&gt;互联网每天都会产生大量信息，但真正属于自己的思考，常常在读完、看完之后很快消失。我想留出一个安静的地方，把学习过程、开发经验和偶尔出现的灵感认真整理下来，于是有了这个博客。&lt;/p&gt;
&lt;h2&gt;为什么要写博客&lt;/h2&gt;
&lt;p&gt;很多问题在解决的那一刻看起来很简单，过一段时间再遇到，却可能又要从头查起。将过程写成文章，可以迫使自己把“好像懂了”变成能够讲清楚的知识。&lt;/p&gt;
&lt;p&gt;写作也是一种整理。当零散的命令、报错和想法被放进完整的上下文，它们才真正成为可以复用的经验。即使文章最终只帮到未来的自己，也已经很有价值。&lt;/p&gt;
&lt;h2&gt;这里会记录什么&lt;/h2&gt;
&lt;p&gt;目前，我准备在这里分享这些内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编程、建站和服务器运维中的实践记录；&lt;/li&gt;
&lt;li&gt;学习新技术时做过的实验与踩过的坑；&lt;/li&gt;
&lt;li&gt;常用工具、软件和工作流程的使用心得；&lt;/li&gt;
&lt;li&gt;偶尔出现的生活随笔与个人思考。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;内容不必追求宏大。一段有用的配置、一次排错过程，或者一个值得保存的小发现，都可以成为文章。&lt;/p&gt;
&lt;h2&gt;关于这个博客&lt;/h2&gt;
&lt;p&gt;Miike&apos;s Blog 基于开源主题 &lt;a href=&quot;https://github.com/saicaca/fuwari&quot;&gt;Fuwari&lt;/a&gt; 修改，使用 &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; 和 &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind CSS&lt;/a&gt; 构建。&lt;/p&gt;
&lt;p&gt;我为它重新整理了页面信息和项目文档，也把原来的主题色滑块改成了四个固定色板：淡粉色、粉白色、超浅紫色和奶蓝色。它们不会改变内容，却能让阅读空间多一点属于自己的气质。&lt;/p&gt;
&lt;p&gt;从主题改造、构建排错到 SSH 和 Nginx 部署，整个过程已经整理成了另一篇文章：&lt;a href=&quot;/posts/building-and-deploying-miikes-blog/&quot;&gt;从 Fuwari 到 Miike&apos;s Blog：一次 Astro 博客的开发、构建与部署记录&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;从现在开始&lt;/h2&gt;
&lt;p&gt;我希望这里能够慢慢积累，而不是在写下第一篇文章后就停住。文章可能不会按照固定频率更新，但每一次发布，都应该留下一点有用或值得回看的东西。&lt;/p&gt;
&lt;p&gt;你可以通过归档浏览文章，也可以订阅 RSS 等待更新。如果这里的某篇记录恰好解决了你的问题，或者给你带来了一点启发，那么这个博客就已经完成了它的一部分意义。&lt;/p&gt;
&lt;p&gt;感谢你的到访。故事从这里开始。&lt;/p&gt;
</content:encoded></item></channel></rss>