Ghost 建站最佳实践:一人公司从零到有订阅者的完整手册
基于两个 Ghost 站(中文站 + 英文站)18 个月的完整运营经验,覆盖选型决策、VPS 部署、域名配置、主题开发、Newsletter 增长、SEO 优化、多站管理和 API 自动化发布全链路。
基于两个 Ghost 站(中文站 + 英文站)18 个月的完整运营经验,覆盖选型决策、VPS 部署、域名配置、主题开发、Newsletter 增长、SEO 优化、多站管理和 API 自动化发布全链路。
Ghost 是目前最适合独立创作者和一人公司的开源内容管理系统(CMS):内置会员系统、邮件通讯(Newsletter)发送、付费墙,同时对搜索引擎高度友好。比起需要堆插件才能实现类似功能的 WordPress,Ghost 用更少的组件做到了更专注的事情。
这篇文章基于我同时运营中文站和英文站共 18 个月的实战经验,按八个核心模块逐个拆解:为什么选 Ghost、虚拟专用服务器(VPS)部署、域名配置、主题开发、邮件通讯增长、搜索引擎优化(SEO)、多站管理、API 自动化。每个模块都讲清"为什么这么做→具体怎么操作→哪些坑要避开"。
如果你正在考虑建站但还没确定用什么工具,先看完第一章的对比表。如果你已经决定用 Ghost,可以直接跳到你需要的章节。对 AI 编程工具链感兴趣的,建议先看 Claude Code 最佳实践 了解 AI 工具如何加速整个建站和内容生产过程。

在决定用什么建站之前,先明确需求:一人公司需要的是拥有内容的所有权、无平台抽成的变现能力、对搜索引擎友好、以及低维护成本。
| 维度 | Ghost | WordPress |
|---|---|---|
| 内容所有权 | 完全自有,数据在你的服务器 | 完全自有(自托管版本) |
| 变现能力 | 内置 Stripe 付费墙 + 会员分级,零抽成 | 需要 WooCommerce / MemberPress 插件 |
| SEO 支持 | 内置站点地图(sitemap)、元标签(meta tag)、结构化数据标记(Schema)、规范链接(canonical URL) | 依赖 Yoast / Rank Math 插件 |
| 部署复杂度 | 容器化工具(Docker)一键拉起,升级改版本号 | 插件与主题兼容性频繁冲突 |
| 性能 | Node.js 轻量运行,约 300MB 内存 | PHP + 插件堆叠,内存消耗大 |
| 邮件通讯 | 内置 Mailgun 集成,发布即推送 | 需要额外插件或第三方服务 |
| API | 完整的 Admin API / Content API | REST API 可用但接口臃肿 |
WordPress 的优势在于生态——几万个插件和主题。但对于以内容和订阅为核心的一人公司,Ghost 用更少的组件做到了更专注的功能。
| 维度 | Ghost(自托管) | Substack |
|---|---|---|
| 内容所有权 | 完全自有 | 平台托管,导出受限 |
| 变现抽成 | 0%(Stripe 标准手续费除外) | 10% 平台抽成 |
| 域名 | 自定义域名 | yourname.substack.com 或自定义域名 |
| SEO 控制 | 完全控制元标签、结构化数据、站点地图 | 几乎无法自定义 |
| 主题定制 | 完全自由 | 极度受限 |
| 年成本 | 约 $200(VPS + 域名) | 免费开始,但收入 10% 归平台 |
Substack 的优势在于零门槛和社区推荐算法。但当你的年收入超过 $2000,10% 的平台抽成就开始让人心疼。更关键的是,你不完全拥有订阅者列表——一旦平台政策变化,你的一切都建立在别人的地基上。
theStacc 的 WordPress 与 Ghost 对比分析指出,约三成 Ghost 用户是从 Substack 或 Medium 迁移而来。迁移的核心驱动力就是内容所有权和抽成问题——当收入规模上去之后,10% 的平台税变成一笔不可忽视的成本。
Medium 是纯读者平台,不适合建立自己的品牌:你的文章在别人的域名下,读者认的是 Medium 而不是你。Ghost 让每一篇文章都积累在你自己的域名权重上。
第一个问题:你需要长期拥有内容吗? 如果不需要,Substack 或 Medium 零成本即可起步。如果需要,进入第二个问题。
第二个问题:你的年内容收入预期超过 $2000 吗? 如果不超过,先用 Substack 零成本开始,未来再迁移。如果超过,进入第三个问题。
第三个问题:你能接受每月 $20 左右的服务器成本吗? 如果不能,选择 Ghost(Pro) 托管版(低档起步价具体以 ghost.org/pricing 为准)。如果能接受,Ghost 自托管就是本文介绍的方案。

Ghost 自托管需要一台虚拟专用服务器(VPS)。以下是经过实战验证的完整部署流程。
Ghost(Pro) 是官方托管版,每月十几到二十几美元起步,省去了服务器维护的麻烦。但它有三个限制:最低档只支持 500 个会员、不支持自定义代码注入的深度定制、无法用反向代理服务器(Caddy)做细粒度的安全响应头配置。对于技术能力足够的一人公司来说,自托管月均 $5-20 的 VPS 成本更低,控制权更高。
| 面向受众 | 推荐方案 | 理由 |
|---|---|---|
| 国内中文读者 | 香港 VPS | 延迟约 50ms,无需 ICP 备案 |
| 海外英文读者 | 美国 VPS | 延迟低,Cloudflare 内容分发网络(CDN)加速全球 |
| 全球双语 | 一站一机,各自就近 | 避免单点故障,各自优化 |
硬件要求:2 核 CPU、2GB 以上内存、20GB 以上 NVMe 存储。Ghost + MySQL + Caddy 三个容器日常内存占用约 800MB,留足冗余应对流量峰值。
成本参考:香港 VPS 约 $19/月,美国 VPS 低至每月几美元。
通过 SSH 登录服务器后,安装 Docker 引擎、Docker Compose V2 插件、Git 和 curl。安装完成后启用 Docker 服务并设为开机自启。验证安装是否成功:Docker 引擎版本应为 25.x 以上,Docker Compose 版本应为 v2.x。
在 /opt/ghost/ 目录下创建 docker-compose.yml,定义两个服务:
Ghost 服务(使用 ghost 官方 alpine 镜像,建议指定 Ghost 最新稳定版标签):Ghost 依赖 MySQL 服务的健康检查通过后才启动。环境变量配置的要点包括——url 设为你的正式域名(含 https),数据库连接指向同一 Compose 网络内的 mysql 服务,SMTP 邮件指向 Resend(host 为 smtp.resend.com,端口 587)。卷挂载方面,将本地 ./data/ghost 目录映射到容器内 /var/lib/ghost/content,持久化所有主题、图片和配置。端口绑定仅监听 127.0.0.1:2368(只允许本机访问,由 Caddy 反向代理对外暴露)。日志轮转使用 json-file 驱动,单文件上限 10MB,最多保留 3 个文件。
MySQL 服务(使用 MySQL 官方镜像):通过环境变量注入 root 密码、ghost 用户密码和数据库名,所有敏感值从 .env 文件读取。卷挂载将 ./data/mysql 映射到 /var/lib/mysql,持久化数据库文件。健康检查每 10 秒执行 mysqladmin ping,超时 5 秒,重试 5 次。
💡 通俗讲:docker-compose.yml 就像一份"服务编排清单"——告诉 Docker 拉起哪些容器、它们之间怎么连接、数据存到哪里。写好这一份文件,一条命令就能把整个 Ghost 站跑起来。
注意 SMTP 配置指向 Resend——这是事务邮件(登录验证码、密码重置)的发送通道。邮件通讯群发通过 Mailgun API 走独立通道,配置方式见后文"邮件通讯从零到增长"章节。Ghost 的邮件架构刻意分离这两种邮件:事务邮件走 SMTP 保证实时性,邮件通讯走 Mailgun HTTP API 保证大批量投递的送达率。
在同一目录创建 .env 文件,写入数据库 root 密码、Ghost 数据库用户密码、Resend API 密钥三个变量。文件权限设为 600(仅 root 可读),防止其他用户读取敏感凭据。
Ghost 已不再支持 SQLite。MySQL 是唯一官方支持的数据库引擎,支持 JSON 存储和并发写入。MariaDB 虽然兼容,但官方建议迁离。具体的最低版本要求以 Ghost 官方文档 为准。
Caddy 会自动通过 Let's Encrypt 签发安全证书(SSL),无需手动配置 HTTPS。
Caddyfile 配置的要点(文件位于 /etc/caddy/caddyfile):主域名块用 reverse_proxy 指向 Ghost 的 127.0.0.1:2368,开启 gzip 压缩,注入四个安全响应头(X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Strict-Transport-Security)。www 域名块永久重定向到主域名(301),保留原始路径。
进入 /opt/ghost 目录,执行 docker compose up -d 后台启动 Ghost 和 MySQL 两个容器,再 reload Caddy 使反向代理配置生效。等待 30 秒让 Caddy 完成证书签发,然后访问 https://你的域名/ghost/ 设置管理员账号。
让 Claude Code 帮你生成完整部署配置:
帮我生成一套 Ghost 自托管的完整部署文件。需要:(1)docker-compose.yml 包含 Ghost 最新稳定版 alpine + MySQL 双容器,Ghost 只监听 127.0.0.1:2368,MySQL 有健康检查,所有密码从 .env 读取;(2)Caddyfile 把我的域名反代到 Ghost 的 2368 端口,www 永久重定向到主域名,注入 HSTS/X-Frame-Options/Referrer-Policy/X-Content-Type-Options 四个安全头;(3).env 模板包含数据库密码、Resend SMTP、Mailgun API Key 三组变量;(4)一个启动脚本依次拉起 Docker 和 Caddy。所有文件放到 /opt/ghost/ 目录下,.env 权限设 600。

即使域名在其他注册商购买,也建议把 DNS 托管迁移到 Cloudflare。三个理由:秒级 DNS 切换(其他平台需要 2-48 小时传播)、免费 CDN 和分布式拒绝服务(DDoS)防护、完善的 API 支持自动化操作。
迁移步骤很简单:在 Cloudflare 添加域名,选 Free 计划 → Cloudflare 自动扫描现有 DNS 记录 → 到原注册商修改 Nameserver 为 Cloudflare 分配的地址 → 等待 1-2 小时 NS 传播完成。
这里有一个容易踩的坑:先用灰色云朵(DNS only)让 Caddy 签到 Let's Encrypt 证书,再开橙色云朵(Proxied)启用 CDN。
顺序不能反。Caddy 通过 HTTP-01 验证来签发证书,这个验证需要 Let's Encrypt 的服务器直接访问到你的 VPS。如果一上来就开橙色云朵,Let's Encrypt 的请求被 Cloudflare 拦截,Caddy 就永远签不到证书。
操作顺序:Cloudflare DNS 添加 A 记录,保持灰色云朵 → 等 Caddy 自动签发证书 → 确认 HTTPS 可正常访问 → 切换为橙色云朵启用 CDN → Cloudflare SSL/TLS 设置选 "Full"。
为什么选 "Full" 而不是 "Full Strict"?因为 Caddy 签的是 Let's Encrypt 证书,Cloudflare 信任它,但某些边缘情况下 "Full Strict" 可能误判证书链。
对内容站来说,AI 搜索的曝光越来越重要。开启 Cloudflare 橙云代理后,Cloudflare 默认会注入一个托管的 robots.txt 文件,屏蔽所有 AI 爬虫。
关闭方法:通过 Cloudflare API 的 bot_management 端点,将 is_robots_txt_managed 设为 false,然后清除 robots.txt 的 CDN 缓存。这样 GPTBot、ClaudeBot、PerplexityBot 等 AI 爬虫都能正常访问你的内容。
让 Claude Code 帮你配置 Cloudflare:
帮我为 Ghost 站点配置 Cloudflare。需要:(1)检查当前 DNS 记录是否正确指向我的 VPS IP;(2)确认 SSL/TLS 模式是 Full;(3)通过 Cloudflare API 关闭托管的 robots.txt,让 AI 爬虫能正常访问;(4)创建一条 Page Rule 让 /ghost/* 路径 bypass 缓存(管理后台不该被缓存)。给出每一步的操作说明。

Ghost 主题基于 Handlebars 模板引擎(一种服务端模板语言,类似于给 HTML 套数据的占位符系统)。选主题时关注五个维度:Ghost 版本兼容性(确认支持当前 Ghost 最新稳定版)、Portal UI 支持(会员注册/登录弹窗是否原生集成)、暗色模式(是否内置系统/亮/暗三档)、目录组件(Table of Contents,长文章必备)、代码高亮(技术博客必备)。
核心原则:Ghost 保持可升级,主题自由修改。Ghost 和主题是两个独立的升级单元——Ghost 需要跟安全补丁,主题一旦定制到位就很少需要升级。
| 层级 | 方式 | 适用场景 |
|---|---|---|
| 1 | Ghost 后台 UI | CTA(行动号召)文案、导航、社交账号、品牌色 |
| 2 | 主题模板直改 | 日期格式、图标、社交链接、底部栏——服务端渲染,零闪烁 |
| 3 | locales 翻译文件 | 界面中文化 |
| 4 | 代码注入(Code Injection)CSS | Ghost 核心注入的元素、全局排版微调 |
能用模板直接改的,不要用 JavaScript 动态注入。 模板修改是服务端渲染,搜索引擎友好且无闪烁。JavaScript 注入是客户端渲染,页面加载时会先闪一下原始内容再变成修改后的样子,对用户体验和 SEO 都不好。
Ghost 的 {{t}} 翻译助手是精确字符串匹配,不存在语言回退机制:@site.locale 设为 zh-Hans 就只读 locales/zh-Hans.json,找不到对应文件就直接显示英文原文。
踩坑教训:曾因 locale 设置为 zh-Hans 但翻译文件命名为 zh.json 导致整站界面回退英文。locale 设置必须与翻译文件名严格一一对应——这种细微的命名不匹配排查起来很费时间,因为 Ghost 不报错、只是静默回退。
关键翻译示例:Menu → 菜单、Search → 搜索、Subscribe → 订阅、Table of contents → 目录、min read → 分钟阅读、Load more → 加载更多。
Ghost 主题通常需要上传 routes.yaml 才能正常工作。路由文件定义三个部分:routes 段注册静态路由并指定模板;collections 段设置根集合的永久链接格式为 /{slug}/;taxonomies 段定义标签页和作者页路径。
上传位置:Ghost 后台 → Settings → Labs → Routes → Upload routes file。上传后必须重启 Ghost 容器才生效。
所有主题修改走 Git 版本控制,禁止直接在服务器上改文件或通过 Ghost 后台上传 zip 覆盖。标准流程:本地修改主题文件后 git commit,再执行 make deploy 一键完成推送 GitHub、SSH 上传到服务器、重启 Ghost 三个步骤。
这样做的好处:所有改动有版本记录、多人协作不冲突、回滚只需一条命令、主题升级时可以选择性合并需要的改动。
让 Claude Code 帮你定制主题:
我的 Ghost 站使用 Maali 主题。帮我做以下定制:(1)创建 locales/zh-Hans.json 翻译文件,覆盖所有 {{t}} 调用点,重点翻译导航、按钮、日期相关的界面文字;(2)修改 footer 的品牌信息和社交链接;(3)把日期格式从英文月份改成中文格式(用 Handlebars 的 date 格式化,不要用 JavaScript 注入)。所有修改走 Git 版本控制。
→ 深入阅读:CLAUDE.md 最佳实践——了解如何用 CLAUDE.md 管理项目指令,让 AI 工具准确执行你的主题定制要求

Ghost 内置邮件通讯(Newsletter)功能,但需要配置外部邮件服务才能实际发送。这是很多人初次部署 Ghost 时最困惑的地方——"配了 SMTP 为什么邮件通讯还是发不了?"答案是:Ghost 的邮件通讯不走 SMTP,它走 Mailgun API。
Ghost 的邮件有两种,走完全不同的通道:
事务邮件(Transactional)——登录验证码、密码重置、会员确认——走 SMTP 协议。发送量小(每天几封到几十封),对实时性要求高。配置在 docker-compose.yml 的 SMTP 环境变量里。
批量邮件(Bulk / Newsletter)——文章推送给所有订阅者——走 Mailgun HTTP API。发送量大(可能一次推送几千封),对送达率要求高。配置在 .env 文件的 bulkEmail__mailgun__ 前缀变量里。
💡 通俗讲:事务邮件像打电话——一对一、即时、用固定电话线(SMTP)。邮件通讯群发像群发短信——一对多、批量、用专门的短信平台(Mailgun API)。两者用不同的基础设施,是因为它们的需求完全不同。
| 用途 | 服务 | 协议 | 免费额度 |
|---|---|---|---|
| 邮件通讯群发 | Mailgun | HTTP API | 100 封/天(免费计划) |
| 事务邮件 | Resend | SMTP | 100 封/天 |
两者用不同的子域名互不干扰:Mailgun 用 mg.你的域名,Resend 用主域名。即使邮件通讯被大量退订,事务邮件的登录验证码仍然能稳定送达。
注册 Mailgun 账号(Free 计划)→ 添加发件域名(建议子域名 mg.你的域名)→ 在 Cloudflare 添加 5 条 DNS 记录(SPF、DKIM、两条 MX、一条 CNAME)→ 生成 Sending API Key → 在 .env 文件中追加 Mailgun API Key、发件域名和 API Base URL → 在 docker-compose.yml 的 ghost 服务中通过 bulkEmail__mailgun__ 前缀引用这三个变量。
关键坑点:配置完成后必须用 docker compose up -d ghost 重建容器才能生效。很多人用 docker compose restart 发现邮件通讯还是不工作——因为 restart 不会重新读取 .env 文件,只有重建容器才会。这是 18 个月运营中最常见的配置问题。
Resend 负责 Ghost 的事务邮件。注册 Resend 账号(免费计划 100 封/天)→ 添加发件域名,获取 DKIM / SPF / Return-Path 三条 DNS 记录 → 在 Cloudflare 添加并等待验证通过 → 获取 Resend API Key(SMTP 用户名固定为 resend,密码即 API Key)。
注意 mail__options__port 必须是 587(STARTTLS),不是 465(隐式 TLS)——Ghost 的邮件库 Nodemailer 在 465 端口下可能无法正确握手。
验证方式:Ghost 后台 → Settings → Labs → Test email,输入你自己的邮箱地址,检查收件箱和垃圾箱是否收到测试邮件。
经过 18 个月测试,转化率最高的订阅入口位置是:
文章末尾 CTA(转化率最高):读完一篇有价值的文章后,读者的信任度最高,此时引导订阅最自然。
首页 Hero 区域:新访客第一眼看到价值主张 + 订阅入口。
侧边栏固定组件(桌面端):不打断阅读,但始终可见。
退出意图弹窗(Exit Intent):Ghost 的 Portal 组件不原生支持,需要通过代码注入用 JavaScript 监听鼠标离开事件来触发。
Ghost 的邮件通讯模板在后台 Settings → Email newsletter 中配置。建议开启站点名称和图标显示,正文字体选无衬线(Sans-serif,中文兼容性更好),底部自定义文字写上社交账号链接和退订说明。Ghost 默认的邮件模板已经做了主流邮件客户端适配(Gmail、Outlook、Apple Mail),大多数情况下无需额外调整。
健康指标参考:打开率 40-60%(低于 20% 需警惕)、点击率 5-15%(低于 2% 需警惕)、退订率 0.1-0.5%(超过 1% 需排查原因)。
退订率超过 1% 时检查三件事:发送频率是否过高(每天推送很容易引发退订)、内容是否偏离了订阅者预期(承诺写 AI 编程但频繁发非技术内容)、邮件标题是否过度标题党。
建议策略:重要教程推送邮件通讯,日常更新只发布不推送。控制频率在每周 1-2 封。
让 Claude Code 帮你配置 Ghost 邮件系统:
帮我为 Ghost 站点配置完整的邮件系统。需要两个服务:(1)Mailgun 用于 Newsletter 群发——在 .env 中配置 API Key、发件域名 mg.我的域名 和 API Base URL,在 docker-compose.yml 中通过 bulkEmail__mailgun__ 前缀引用;(2)Resend 用于事务邮件——在 docker-compose.yml 中配置 SMTP host smtp.resend.com、端口 587、用户名 resend、密码从 .env 读取。帮我列出需要在 Cloudflare 添加的所有 DNS 记录(Mailgun 的 SPF/DKIM/MX/CNAME + Resend 的 DKIM/SPF/Return-Path)。最后用 docker compose up -d ghost 重建容器使配置生效。

Ghost 内置了站点地图(sitemap)、元标签(meta tag)、规范链接(canonical URL)等搜索引擎优化基础设施,比大多数内容管理系统的默认配置完善。但要真正在搜索结果中获得排名,还需要手动配置几个关键环节。
Ghost 自动生成 /sitemap.xml,包含四个子索引:独立页面、所有已发布文章、作者页和标签页。
提交到 Google 搜索控制台(Search Console,简称 GSC):进入 GSC → Sitemaps → 输入 sitemap.xml → 提交 → 等待 1-3 天完成首次抓取。
提交后每周检查 GSC 的索引报告,关注两种状态:"Discovered - currently not indexed"(Google 发现了页面但尚未编入索引,通常是新页面或内容质量不足)和 "Crawled - currently not indexed"(Google 抓取了但认为不值得索引——需要检查内容是否太薄或与已有页面重复)。
结构化数据标记通过 JSON-LD 格式注入到页面头部,帮助搜索引擎理解内容类型,有机会触发富文本搜索结果(Rich Results)展示。
Ghost 的注入方式有两种:全局注入通过后台代码注入(Code Injection)设置,适用于所有页面共享的 Schema,如 Organization 类型。文章级注入通过 frontmatter 的 codeinjection_head 字段,每篇文章独立配置。
推荐为技术文章配置三套结构化数据:TechArticle(文章基础信息,Google 据此生成搜索结果摘要)、HowTo(步骤分解,Google 可能展示带步骤的富文本结果)、FAQPage(常见问题,Google 可能在搜索结果下方展示可展开的问答卡片)。
验证工具:Google 的 Rich Results Test 粘贴文章 URL 即可检测是否被正确识别。
Ghost 为每篇文章支持独立的 SEO 字段:meta_title(搜索结果标题,控制在 60 字符以内)、meta_description(搜索结果描述,155 字符以内)、og_title / og_description(社交平台分享卡片)、twitter_title / twitter_description(X 平台分享卡片)、canonical_url(规范链接,防止重复内容)。
中文字符占位:中文字符在 Google 搜索结果中大约占 2 个英文字符的显示宽度,因此 meta_title 建议控制在 30 个中文字符以内,meta_description 控制在 75 个中文字符以内。
内链对 SEO 的价值经常被低估。Ghost 按标签(Tag)组织内容,天然形成内容集群(Content Cluster)。标签页作为支柱页(Pillar),下挂的各篇文章互相链接,形成紧密的内链网络。Google 会把这些相互链接的页面理解为同一主题的权威内容集群。
内链操作规范:每篇文章 3-5 条站内链接——太少起不到传递权重的效果,太多会稀释单条链接的价值。锚文本用描述性短语——"查看 Claude Code 最佳实践" 优于 "查看这篇文章"。新文章发布后回补旧文章的链接——在相关旧文章中添加指向新文章的链接,否则新文章成为孤岛。
铁律:内链目标页面必须已存在且已发布。 推测地址写链接会导致 404,损害站点权重。发布前必须检查每一条内链。
IndexNow 让搜索引擎在文章发布后几分钟内发现新内容,而不是等待爬虫下一次来访(可能需要数天甚至数周)。
部署步骤:在 indexnow.org 生成 API 密钥 → 将密钥文件放到网站根目录 → 创建推送脚本 → Ghost 发布文章后通过 Webhook 触发推送。验证方式:推送后 1-2 天在 GSC 的 URL Inspection 中查看目标 URL,应显示 "URL is on Google"。
Ghost 站点上线后的完整 GSC 配置流程:通过 DNS TXT 记录验证站点所有权 → 提交站点地图 → 对重要文章使用 URL Inspection 请求索引 → 每周监控覆盖率 → 检查移动端可用性确保零错误。
让 Claude Code 帮你做 Ghost SEO 配置:
帮我为 Ghost 站点做完整的 SEO 配置。需要:(1)检查 sitemap.xml 是否可访问,列出包含的文章数量;(2)为我最近发布的 5 篇文章生成 Schema 三件套(TechArticle + HowTo + FAQPage),格式为 JSON-LD,写入每篇文章的 codeinjection_head;(3)审计所有文章的 meta_title 和 meta_description 长度,标注超限的;(4)检查内链健康度——找出孤岛文章(零站内链接指向它)和断链(指向 404 的内链);(5)生成一个 IndexNow 推送脚本,接收文章 URL 列表并批量推送。
→ 深入阅读:MCP 最佳实践——了解如何用 MCP 工具自动化 SEO 检查和内容分析

同时运营中文站和英文站是很多一人公司的选择——不同语言触达不同市场。以下是并行运营两个 Ghost 站的实战经验。
| 方案 | 优点 | 缺点 |
|---|---|---|
| 同一台 VPS 跑两个 Ghost | 成本低,维护集中 | 资源竞争,故障互相影响 |
| 各自独立 VPS | 完全隔离,各自优化 | 成本翻倍 |
我的选择是各自独立:中文站在香港 VPS(面向国内用户低延迟),英文站在美国 VPS(面向海外市场)。两站共用同一套主题和 CLI 工具,但部署完全独立。
两站必须在以下维度完全隔离:Stripe 支付账号(绝对不能共用,否则财务混乱)、GA4 分析属性(各自独立衡量,数据不混)、Mailgun 发件域名(各自子域名)、Ghost 集成密钥(Integration Key,各自创建)。
| 维度 | 中文站 | 英文站 |
|---|---|---|
| 分类方式 | 按主题(ai-coding / ai-automation / ai-beginner) | 按形态(tutorials / hands-on / research) |
| 文章长度 | 6000-15000 字(深度实战) | 3000-8000 词(简明实操) |
| 发布频率 | 每周 2-3 篇 | 每周 1-2 篇 |
| 变现模式 | 付费会员 + 课程 | 年付订阅 |
两个站的所有已发布文章在本地有一一映射的正本,按 {标签}/{slug}/{slug}.md 结构分目录存放。编辑流程统一为:拉云端最新 → 本地修改 → 推回 Ghost。
这一步绝不能跳过"拉云端"环节——因为你可能在 Ghost 后台做过手动编辑(加样式、改正文、调元标签),本地正本是过时的。直接改本地再推,会覆盖掉云端的真实改动。判断标准:比对 frontmatter 中的 updated_at 时间戳,云端大于本地时,必须先拉取再修改。

Ghost 提供两套 API:Content API(只读,用于前端展示)和 Admin API(读写,用于文章管理)。自动化发布的核心是 Admin API。
Ghost Admin API 使用 JWT(JSON Web Token)认证。流程分三步:在 Ghost 后台创建 Integration 获取 Admin API Key(格式为 {id}:{secret})→ 用密钥构造 JWT Token(有效期 5 分钟,建议每次调用前重新生成)→ 请求头中用 Ghost {token} 格式携带(注意前缀是 Ghost 而不是 Bearer)。
创建文章通过 POST 请求发送,请求体包含标题、slug(URL 路径标识)、HTML 正文、标签数组、状态和元标签等字段。
更新文章的关键机制是乐观锁:请求体必须携带 updated_at 字段,值为当前文章的最新时间戳。如果服务端的时间戳与请求不匹配(说明有人在你读取后做了修改),API 返回 409 冲突错误。正确的更新流程:先 GET 获取文章最新版本 → 取出 id 和 updated_at → 连同要修改的字段一起发送 PUT 请求。
将 status 设为 scheduled 并指定 published_at 时间(UTC 格式)。Ghost 在指定时间到达后自动发布,无需额外触发。
Ghost 的 Webhook 功能允许在文章发布、更新、删除或新会员注册等事件发生时,向外部 URL 发送 HTTP POST 请求。典型用途包括:发布后触发 IndexNow 推送搜索引擎、清除 CDN 缓存、通知到 Slack 或 Telegram。
注意事项:Webhook 目标 URL 必须是 HTTPS 公网可达的地址,Ghost 发送后不会等待响应也不会重试失败的请求。如果需要可靠的事件处理,接收端需要实现幂等逻辑。
我的文章发布完全由 CLI 工具驱动:本地 Markdown(含 frontmatter 和正文)→ CLI 读取 frontmatter 字段 → 自动转换正文为 Ghost Lexical 格式 → 注入结构化数据到 codeinjection_head → 调用 Ghost Admin API 创建或更新文章 → 调用 Cloudflare API 清除对应 URL 的 CDN 缓存 → 调用 IndexNow API 推送搜索引擎 → 验证线上版本已生效。
这条链路把一篇文章从编辑到上线压缩为一条命令,消除了所有手动操作环节。
| 限制 | 说明 | 解决方案 |
|---|---|---|
| 无法修改 Settings | Integration Token 无 settings 写权限 | 通过 Ghost 后台 UI 修改 |
| 并发写入冲突 | updated_at 不匹配时返回 409 |
先 GET 获取最新时间戳,再 PUT 更新 |
| 速率限制 | 大量并发请求可能被限流 | 批量操作间隔 200ms,或串行执行 |
让 Claude Code 帮你做 Ghost API 自动化:
帮我写一个 Ghost 文章发布自动化脚本。功能:(1)读取本地 Markdown 文件的 frontmatter(title、slug、tags、meta_title、meta_description、feature_image);(2)将 Markdown 正文转换为 Ghost 兼容的 HTML;(3)通过 Ghost Admin API 创建或更新文章(根据 slug 判断是否已存在);(4)发布后调用 Cloudflare API 清除该文章 URL 的 CDN 缓存;(5)调用 IndexNow API 推送搜索引擎。Ghost Admin API Key 和 Cloudflare API Token 从环境变量读取,不硬编码。
→ 深入阅读:Claude Code 最佳实践——了解如何用 Claude Code 的 Hooks 和 Skills 将 Ghost API 操作封装成可复用的自动化工作流

每周定时备份三项:数据库一致性快照(通过 MySQL 的 --single-transaction 保证写入时的一致性,--default-character-set=utf8mb4 确保中文不乱码)、Ghost content 目录打包(包含图片、主题、路由配置)、配置文件归档(.env、docker-compose.yml、Caddyfile)。通过定时任务(cron)每周自动执行,滚动删除 30 天前的备份。
Ghost 升级极其简单——修改 docker-compose.yml 中 ghost 服务的镜像标签为目标版本号,然后拉取新镜像、重建容器。Ghost 容器启动时会自动检测数据库版本并执行迁移。
升级后检查三项:容器运行状态正常、后台能正常登录、主题仍然生效。
回滚注意:Ghost 的大版本数据库变更不向后兼容。一旦升级并完成迁移,只能通过恢复备份来回退到旧版本。所以升级前的备份是必须的。
| 措施 | 配置 |
|---|---|
| SSH 密钥认证 | ed25519 密钥,禁止密码登录 |
| UFW 防火墙 | 仅开放 22/80/443 |
| fail2ban | SSH 暴力破解防护(10 次失败锁 10 分钟) |
| Docker 日志轮转 | 10MB × 3 个文件,防磁盘撑满 |
| .env 权限 | 仅 root 可读(chmod 600) |
| 自动安全更新 | unattended-upgrades 开启 |
Ghost 站开启 Cloudflare 橙云代理后,CDN 缓存既是加速利器也是运维隐患。文章发布或修改后,读者在几小时内可能看到旧版本。
解决方案:每次通过 API 发布或更新文章后,立即调 Cloudflare API 清除对应 URL 的缓存。还有一个更隐蔽的坑——文章在草稿(draft)状态时如果有人访问了 URL(比如内链指过来),Cloudflare 会缓存 404 响应。文章正式发布后,读者仍然看到 404。发布后必须主动清除该 URL 的缓存。
推荐的 Cloudflare 缓存策略:/ghost/* 路径 bypass 缓存(管理后台不应缓存)、/content/images/* 长期缓存 30 天(图片不会变)、/rss/ 缓存 1 小时(RSS 更新不急)、其他路径按默认策略。
Ghost 近年的大版本带来了几个重要更新。
启用后你的 Ghost 站点获得一个 ActivityPub 端点,Mastodon、Threads 等联邦宇宙客户端可以直接"关注"你的博客。每篇新文章自动作为 ActivityPub 对象分发到所有关注者的信息流。这意味着无需额外运营社交媒体账号,文章发布即分发。
Ghost 内置了实时流量分析面板:实时访客数、热门内容排行、流量来源分析、邮件打开率、会员增长趋势。无需 Google Analytics 也能获得基础数据。但如果需要更细粒度的转化追踪,GA4 仍然是必要的补充。
通过支持此功能的主题(如 ghostFam / TanaFlows)或自定义 routes.yaml,可以在 Ghost 上配置 llms.txt 文件——一种面向大语言模型的站点内容清单。AI 搜索引擎(如 Perplexity、ChatGPT Browse、Google AI Overviews)可以通过这个文件了解站点结构和内容概要,提升内容在 AI 搜索结果中的引用概率。配置方式是在后台 Settings → Labs → Routes 中上传包含 llms.txt 路由的 routes.yaml 文件。注意这不是 Ghost 核心的原生功能,而是通过路由系统和主题模板实现的。
如果你已有 WordPress 站点,迁移到 Ghost 是 SEO 风险最低的 CMS 切换类型——同域名迁移不需要 Google 重新评估域名权威。
三件事:审计现有内容(区分要保留的核心文章、可淘汰的低质量内容、需要更新的过时文章)→ 确认 URL 结构一致(WordPress 的 /{slug}/ 必须与 Ghost 的 /{slug}/ 对应,零重定向成本)→ 配置 redirects.json 处理分类路径变更(WordPress 的 category 在 Ghost 中变成 tag,用正则匹配做 301 重定向)。
准备阶段(DNS 切换前):在 Ghost 完成文章导入并验证、确认所有 slug 一致。切换阶段(5 分钟):修改 Ghost 环境变量中的 URL → Caddy 添加新域名配置 → Cloudflare A 记录指向新 VPS → 验证 HTTPS 和文章可访问。切换后:提交新站点地图 → 旧临时域名全站 301 到主域名 → 监控 GSC 覆盖率 2-4 周。
Ghost 内置 Stripe 集成,无需任何插件即可实现付费会员功能。
在 Ghost 后台 Settings → Tiers → Connect with Stripe 关联支付账号 → 设置会员等级和价格 → Portal Settings 中控制前端展示(可选展示 Free + Paid 两档,可隐藏月付只显示年付,注册弹窗样式自动匹配品牌色)。
合规页面(Stripe 硬性要求):付费订阅站点必须有 /privacy/(隐私政策)和 /terms/(服务条款)两个页面。面向欧盟/英国用户的数字内容订阅,还必须加入放弃条款(Waiver of Withdrawal Right),否则用户有权无理由退款。
分享一下翔宇中文站建站以来,用 15 个月积累到 162 篇已发布文章的实际节奏和关键决策。
从 WordPress 迁移时,原站有 199 篇文章。审计后决定只迁移 96 篇——淘汰了大量 AI 批量生成的低质量内容(同一天发布 5 篇以上万字文是明确的淘汰信号)。这个阶段的重点是 Docker 部署 + Caddy 反代 + Cloudflare CDN 全部跑通,确认所有 URL 结构与 WordPress 一致。
购买主题后花了两周完成定制:全套 110 个翻译键覆盖、底部栏品牌信息替换、社交图标添加、代码注入 CSS 微调、代码高亮全局启用。
关键教训:一开始用 JavaScript 注入做日期中文化(Ghost 默认英文月份),后来发现直接改模板文件用 Handlebars 的日期格式化更好——服务端渲染,零闪烁,搜索引擎友好。
建立了完整的 CLI 工具链:本地 Markdown 直接创建/更新 Ghost 文章的 CLI、图片上传到 Cloudflare R2 的 CLI、AI 配图工具。有了这套工具,发布一篇文章的操作变成:写 Markdown → 配图 → 一条命令发布 → 自动清 CDN 缓存。整个过程不需要打开 Ghost 后台。
当文章积累到 80 篇以上时,开始系统性做 SEO:建立 Pillar-Cluster 内容结构、为每篇文章补充结构化数据三件套、内链补全将孤立文章从 18 篇降到 2 篇、提交 IndexNow 让新文章发布后几分钟被搜索引擎发现。
当前节奏:每周 2-3 篇新文章,重要教程(如系统性指南)发布时推送邮件通讯,日常更新类文章只发布不推送。
| 指标 | 值 | 说明 |
|---|---|---|
| 总文章数 | 162 篇 | 横跨 6 个一级标签 |
| 月均新增 | 8-12 篇 | 含新写 + 旧文更新 |
| 平均文章长度 | 5000-8000 字 | 深度实战定位 |
| 封面图覆盖率 | 95%+ | AI 生成 + R2 托管 |
| 内链密度 | 平均每篇 3-5 条 | Pillar-Cluster 结构 |
| 项目 | 费用 | 说明 |
|---|---|---|
| VPS(香港) | $19/月 | 4 核 4GB NVMe |
| 域名 | $1.2/月 | 年付 $14 均摊 |
| Mailgun | $0 | 免费计划足够 |
| Cloudflare | $0 | Free 计划 |
| R2 存储 | $0.5/月 | 10GB 以内免费 |
| AI 配图 | $3-5/月 | 按篇计费 |
| 合计 | 约 $25/月 |
对比 Substack 10% 抽成——当年收入达到 $2000,自托管就已经回本。年收入 $10000 时,省下的平台抽成就是 $1000。收入越高,自建站的成本优势越明显。
18 个月运营两个 Ghost 站踩过的坑,按影响程度排序:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 文章发布后前台仍显示旧版本 | Cloudflare CDN 缓存了 HTML 响应 | 发布后自动调 Cloudflare API 清除缓存 |
docker compose restart 后配置不生效 |
restart 不重新读取 .env 文件 | 必须用 docker compose up -d 重建容器 |
| 邮件通讯配置后仍提示未设置 | Ghost 只读环境变量,不读后台设置 | 必须在 .env 中配置,不能通过后台设置 |
| Caddy 签安全证书失败 | DNS 记录指向了 Cloudflare CDN 而非 VPS 直连 | 先关橙云(灰云直连),签完证书再开 |
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 中文化界面回退英文 | locale 设置与翻译文件名不匹配 | 翻译文件名必须与 locale 设置严格一致 |
| 新增主题 partial 后重启不生效 | Ghost 启动时一次性扫描 partials 目录 | 必须强制重建容器 |
| MySQL 备份中文乱码 | 默认 latin1 连接编码 | 所有 mysqldump 命令加 utf8mb4 字符集参数 |
以下是完整的实施检查清单:
基础设施:VPS 初始化(Ubuntu 24.04 LTS)→ Docker + Docker Compose 安装 → Ghost + MySQL + Caddy 三容器部署 → 域名 DNS 迁移到 Cloudflare → 安全证书签发 → CDN 开启 → 防火墙配置 → SSH 防暴力破解 → 自动备份定时任务。
内容基础:Ghost 管理员账号创建 → 主题上传并激活 → 路由文件上传 → 导航菜单配置 → 品牌色和 Logo 设置 → About 页面创建 → 社交账号链接配置。
SEO 配置:搜索控制台验证 → 站点地图提交 → GA4 统计代码注入 → 结构化数据模板准备 → robots.txt 确认 AI 爬虫未被屏蔽 → IndexNow 密钥部署。
邮件系统:Resend 域名验证(事务邮件)→ Mailgun 域名验证(邮件通讯)→ Ghost 环境变量配置 → 测试邮件发送成功 → 订阅 CTA 文案设置。
变现(可选):Stripe 账号注册 → Ghost Connect with Stripe → 会员等级和价格设置 → Portal 前端展示调整 → 隐私政策 + 服务条款合规页面 → 测试支付流程。
本文介绍的所有建站实操——Docker Compose 完整配置、Caddy 反向代理模板、Ghost Admin API 自动化脚本、邮件通讯配置、结构化数据注入方案——都有可直接部署的完整文件,收录在翔宇的 AI 编程实操课中。
每周精选 AI 编程与自动化实战内容,直达你的邮箱