> ## Content Index
> Fetch the complete content index at: https://chunyangai.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Ghost 博客搭建实战：从本机部署到第一篇 Markdown 草稿
- URL: https://chunyangai.com/my-first-ghost-blog/
- Published: 2026-09-05T23:54:45.000Z
- Updated: 2026-09-05T23:55:37.000Z
- Description: Ghost 博客搭建的本机起步：从启动站点、创建 API 集成，到导入第一篇 Markdown 草稿。
- Author: 春洋
- Tags: AI 内容创作与增长, 实战教程, Ghost 博客

这篇 Ghost 博客搭建实战只完成一个目标：把只能在本机打开的站点推进到「第一篇 Markdown 已进入后台、状态仍是草稿」的可验收阶段。你会依次确认网站和数据库正常运行、创建供自动化使用的专用接口，再把本地文章写入 Ghost；本文不会完成公网域名、HTTPS 或正式发布。

先看 2026 年 9 月 2 日的本机复核结果：

- **运行环境**：Ghost 6.61.0 与 MySQL 8.0.46 正常运行；数据库处于健康状态。
- **访问边界**：Ghost 只绑定在 `127.0.0.1:2369`。
- **页面结果**：首页返回 200；5 个主题标签页返回 404，因为标签尚未关联已发布文章。

**我的判断是：本课的成功标准**不是「公开文章已经可见」，而是四项草稿状态成立：本地正本与 Ghost 指向同一篇文章；Ghost 保持 Draft；5 个空标签页的 404 已登记为首篇发布后的复查项；发布和排期仍被闸门阻断。

> 💡 **通俗讲**：`127.0.0.1` 是只供本机访问的回环地址；在没有公网隧道或代理的前提下，外部访客无法直接打开。HTTP `200` 表示页面正常返回，`404` 表示该地址目前没有公开页面。此阶段应看到「后台有草稿、公开文章地址仍是 404」。

## 要点速览

- **你会得到什么**：Ghost 后台里一篇可编辑、尚未公开的 Markdown 草稿。
- **先做什么**：确认首页、后台和数据库正常，再创建专用集成，最后写入并回查草稿。
- **现在不要做什么**：不要配置成公开发布或排期；公网域名、HTTPS 和生产迁移不在本课完成。
- **权限怎么分**：管理员账号供人使用，自定义集成（Custom Integration）供自动化工具使用；两者不应混用。

### 按你的起点选择阅读路径

- **零基础建站学员**：先读「为什么不直接放到公网」和「三个组件的职责」，确认本机首页与后台都能打开，再继续创建集成。
- **Ghost 自托管实践者**：重点检查端口暴露、数据持久化、备份恢复与生产迁移条件，不要把本机可用当成上线完成。
- **Markdown 内容创作者**：从「如何把第一篇 Markdown 变成 Ghost 草稿」开始，重点核对正本字段、草稿身份和回写规则。
- **内容自动化入门者**：从「管理员和自动化程序为什么分开授权」开始，先跑通只写 Draft 的最小链路，再考虑质检、发布或排期。

## 为什么第一篇 Ghost 博客不直接放到公网？

把「网站能打开」直接等同于「内容系统已经可用」，是这套流程要避免的反模式。对本文这条内容运维路径而言，文章导入、权限管理、草稿审核、发布设置和故障恢复也需要分别验收。只有在 Ghost 绑定回环地址且没有公网隧道、端口转发或反向代理时，`localhost` 测试才与公网隔离。若另行配置了公网入口，就应按公开环境重新检查访问控制与搜索索引风险。

本文采用 Docker Compose（容器编排工具）搭建自托管环境。以 Ghost 6 的官方 Docker 工具为例，基础安装会协调 Ghost、MySQL 与反向代理 Caddy。其他自托管方案的组件和重建步骤可能不同。若要正式自托管，仍需准备 Linux 服务器或等价托管环境、正确的域名解析与邮件服务。[Ghost Docker 部署文档](https://docs.ghost.org/install/docker?ref=chunyangai.com)

如果你是从零开始，而且本机 Ghost 首页或 `/ghost/` 后台还打不开，先不要继续创建集成。请先按上面的官方 Docker 文档完成本机启动；只有「首页能打开、后台能登录、数据库状态正常」三项同时成立，才进入本文后续的草稿导入流程。若其中一项不成立，就停在部署排错，不要用后面的导入命令掩盖基础环境问题。

这里不展开空服务器安装，而是给出进入内容流程前的最小验收。在 `ghost-blog-lab` 项目根目录运行：

```bash
docker compose -f module-1-ghost-deploy/docker-compose.yml ps
curl -I http://127.0.0.1:2369/

```

预期结果是 `db` 显示 `healthy`、`ghost` 显示 `running`，且首页返回 `HTTP/1.1 200 OK`。如果容器未运行或数据库不健康，先运行 `docker compose -f module-1-ghost-deploy/docker-compose.yml logs --tail=100 ghost` 检查 Ghost 日志；不进入集成和导入步骤。

> 💡 **通俗讲**：本机站点像排练室。先解决「文章写完后会去哪儿、谁有权限修改、发布前能否拦住错误」这些问题，再搬到真正的舞台。

## 什么是 Ghost、数据库和反向代理的职责边界？

第一次搭建时，先理解它们分别存什么、处理什么请求。Ghost 负责写作后台和网站页面，MySQL 保存文章、标签与成员。反向代理（reverse proxy）在正式上线时把访客请求安全地转给 Ghost。分清三者职责，升级、排错和备份才有明确边界。

![浏览器请求经 Caddy 反向代理进入 Ghost，Ghost 再读写 MySQL 的博客部署架构图](https://pub-6611d907480747408f61edaf01b5e2c9.r2.dev/articles/my-first-ghost-blog/2026-09-04/architecture-v02.webp)

*图 1：请求入口、内容服务和数据存储各自承担不同职责。*

> 💡 **通俗讲**：把网站想成一家店：Ghost 是处理内容和展示页面的前台，MySQL 是保存文章等记录的仓库，Caddy 是门口接待，先接住公网请求，再把请求交给 Ghost。出了问题时，先分清是入口、Ghost 还是数据保存出了问题。

本机部署应将 Ghost 端口绑定到回环地址，而不是直接暴露给公网。启动后可检查 Docker 的端口映射是否以 `127.0.0.1` 开头；只有确认没有公网隧道或代理时，才可认为该实验站不会被外部访问。正式环境应让 Caddy 或同类代理处理公网的 80/443 端口，而不是将 Ghost 的内部端口直接开放。

> ⚠️ **常见踩坑**：修改正式域名后忘记重建 Ghost 容器，后台链接、邮件链接和规范网址（Canonical URL）都可能仍指向旧地址。Ghost 官方 Docker 文档说明，改变域名相关配置后需要重新创建相应容器。[配置更新说明](https://docs.ghost.org/install/docker?ref=chunyangai.com)

> ⚠️ **常见踩坑**：数据库凭据不能只靠「改 `.env` 后重建」来轮换。Ghost 官方 Docker 文档明确说明：MySQL 初始化完成后，只修改 `DATABASE_*` 环境变量不会同步改变数据库内已存的账号和密码，反而会导致连接失败。需要轮换数据库凭据时，应先做好可恢复备份，再按 MySQL 的账号变更流程同步数据库和 Ghost 配置，不要只改环境变量。[Ghost Docker 配置更新说明](https://docs.ghost.org/install/docker?ref=chunyangai.com)

## 为什么建议把管理员和自动化程序分开授权？

管理员账号用于设计站点、管理成员和人工编辑。自定义集成则以「集成」身份调用管理员接口（Admin API）；它拥有 Ghost 预设的固定权限集，可执行常见发布工作流，但不等于用 Owner 或 Admin 账号取得全部用户权限。Admin API Key 不是每次请求直接使用的公开口令；服务端会用它生成最长有效 5 分钟的 JSON Web Token（JWT，签名请求令牌）。密钥只能保存在受限的服务端位置；疑似泄露时，应在 Ghost 中重新生成密钥，并同步更新使用它的工具。[Ghost Admin API 认证说明](https://docs.ghost.org/admin-api?ref=chunyangai.com)

![Ghost 后台 Settings 的 Integrations 页面，Custom 标签中显示专供自动化使用的 ghost-blog-lab-cli 集成](https://pub-6611d907480747408f61edaf01b5e2c9.r2.dev/articles/my-first-ghost-blog/2026-09-04/ghost-custom-integration-v01.webp)

*图 2：真实 Ghost 后台中的自定义集成入口；截图未包含 Admin API Key。*

第一次配置时，打开 Ghost 后台的 Settings → Integrations，新增一个只供内容导入使用的自定义集成。创建后，按本机工具的要求保存管理员接口地址和 Admin API Key；它们只应进入受限的本机凭据文件，不要写进 Markdown、Git 等版本控制、公开目录或聊天记录。这一步先只验收两项：后台能看到该集成；本机工具能通过下一段的只读命令读取正确站点信息。此时尚未验证文章写入，不能据此判定草稿导入已完成。

继续导入前，先在 `ghost-blog-lab` 项目根目录用只读命令确认当前 profile 能连接到目标站：

```bash
python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  site-info --profile ghost-blog-lab

```

返回结果中应有 `"code": 200`，并且 `title`、`url` 指向你准备写入的站点。若提示凭据不存在、密钥格式错误或认证失败，就停在这里修正配置，不要继续运行文章写入命令。

> 🔍 **深入一步**：内容接口（Content API）适合公开读取文章，管理员接口（Admin API）才能创建和修改内容。把两者混用会扩大泄露后的影响范围。

## 如何把第一篇 Markdown 变成 Ghost 草稿？

![Markdown 转换为 Lexical 后经 Admin API 写入 Draft，再执行机器回读与人工确认的内容自动化流程](https://pub-6611d907480747408f61edaf01b5e2c9.r2.dev/articles/my-first-ghost-blog/2026-09-04/content-pipeline-v02.webp)

*图 3：写入没有报错只是中间状态，机器回读和人工检查完成后才算草稿交付。*

### 写入前先验收环境与连接

开始前先确认三件事：Ghost 已通过 Docker 正常启动、你能进入 `/ghost/` 后台、终端可以访问本机项目目录。第一篇文章使用 Markdown 作为本地正本，至少包含标题、网址路径标识（slug）、摘要和标签。之后按三个可核验节点操作：

1. 保存 Markdown 正本；这表示文章内容已在本地可管理。
2. 用本项目的命令行工具把 Markdown 转成 Ghost 编辑器使用的 Lexical 文档数据，再通过 Admin API 创建草稿（Draft）；这表示文章已进入 Ghost 的内容库。
3. 在后台打开该文章，确认状态为 Draft，并核对标题、标签、摘要和封面图。

下面的 `ghost.py` 是本项目仓库内的自动化工具，不是 Ghost 官方自带命令。

💡 **根据你的使用环境选择路径**

- **正在使用本项目**：可以继续执行下面的 `ghost.py` 命令，它已经封装 Markdown 转换、Ghost 鉴权、草稿写入和回查。
- **使用其他 Ghost 项目**：不要照抄命令和路径。请按 [Ghost 创建文章接口](https://docs.ghost.org/admin-api/posts/creating-a-post?ref=chunyangai.com) 调用 Admin API，完成同样的四步：确认身份 → 转换内容 → 写入 Draft → 读取结果并验收。

### 选择新建还是更新

本项目把「新建草稿」与「更新已有草稿」拆成两个写入分支。不要凭印象选择：先在 `ghost-blog-lab` 项目根目录运行下面的只读命令，查询目标 slug；这一步不会修改文章。

```bash
python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  posts-get my-first-ghost-blog --profile ghost-blog-lab

```

2026 年 9 月 3 日已用当前项目 CLI 实测两类正常分流：不存在的 slug 返回 `code: 404`、`error_type: not_found`，退出码为 3；现有草稿返回 `code: 200`，并在 `data` 中给出 `id`、`uuid`、`slug`、`status` 和 `published_at`。按下面的结果选择分支：

| 只读查询结果                              | 应执行的动作                                  |
| ----------------------------------- | --------------------------------------- |
| code: 404 且 error\_type: not\_found | 走分支 A；先确认本地 Markdown 字段完整，再新建草稿         |
| code: 200，并返回目标文章的 id、uuid          | 走分支 B；身份一致后，才按已确认的 id 更新                |
| code: 401/403 或 error\_type: auth   | 停止；检查 Admin API Key 与 profile，不得当成文章不存在 |
| error\_type: network 或连接错误          | 停止；检查 Ghost、接口地址和容器状态                   |

两个写入分支都显式带上 `--status draft`。任何不属于前两行的结果都不执行写入。

#### 分支 A：Ghost 中还没有这个 slug

只执行新建命令；如果同名 slug 已存在，`--on-exists error` 会让流程停止，不会猜测或覆盖。

```bash
python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  posts-create content/ai-content-growth/20260831-my-first-ghost-blog/my-first-ghost-blog.md \
  --status draft \
  --on-exists error \
  --profile ghost-blog-lab

```

新建成功后立即按 slug 只读回查，不以“创建命令没有报错”代替状态验收：

```bash
python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  posts-get my-first-ghost-blog --profile ghost-blog-lab

```

只有回查同时返回新的 `id`、`uuid`、目标 `slug`、`status: draft` 和 `published_at: null`，分支 A 才算完成。

#### 分支 B：Ghost 中已经有这个 slug

使用分流检查中 `code: 200` 的结果，核对返回的 `id`、`uuid` 和本地 frontmatter 是否一致。

> ⚠️ **写入提醒**：下面的 `posts-update` 会修改现有 Ghost 草稿。只有分流检查返回的 `id`、`uuid` 与本地 frontmatter 一致时，才能把占位值换成已确认的 id 并执行。

```bash
CONFIRMED_POST_ID='REPLACE_WITH_CONFIRMED_POST_ID'

python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  posts-update "$CONFIRMED_POST_ID" \
  --from-file content/ai-content-growth/20260831-my-first-ghost-blog/my-first-ghost-blog.md \
  --status draft \
  --profile ghost-blog-lab

```

更新完成后，再用只读命令回查同一个 id：

```bash
python3.12 module-2-xiangyu-cms-ghost-cli/providers/ghost/ghost.py \
  posts-get "$CONFIRMED_POST_ID" --profile ghost-blog-lab

```

### 写入后核对身份与草稿状态

下面是 2026 年 9 月 3 日对本机 Ghost 执行上述只读回查得到的关键回执（其他站点的 `id` 和 `uuid` 会不同）：

```text
id: 6a963a838ff59100016037ec
uuid: c47c3232-8a25-4657-8aa5-073b37d59bf7
slug: my-first-ghost-blog
status: draft
published_at: null
未登录访问 /my-first-ghost-blog/: HTTP 404

```

这组结果只证明「身份是同一篇、Ghost 仍为草稿、公开地址不可见」；它不代替后面的标题、标签、摘要、封面和正文字段对照。

执行命令时，按下面五条验收：

- **新建遇到冲突就停**：`--on-exists error` 不会生成 `-2` 或直接覆盖。
- **更新先核对身份**：先用 `posts-get` 核对 slug、id 和 uuid，再按已确认的 id 写入。
- **让工具处理版本冲突**：Ghost 更新要求最新 `updated_at`；本项目 CLI 会在 PUT 前自动 GET 并附上该字段。
- **写入前给全标签**：Ghost 更新会替换而不是合并标签关系，因此 Markdown frontmatter 必须包含完整标签列表。
- **写入后只读回查**：`id` 和 `uuid` 与本地一致、`status` 为 `draft`、`published_at` 为 `null`，四项要同时成立。

如果提示文件不存在，先检查当前目录和 Markdown 路径；如果认证失败，回到 Integrations 检查接口地址、密钥与 profile。不要把密钥直接粘进命令。

如果你要把这一步接入自动化，第一版只串联五个关卡：读取 Markdown → 运行本地质检 → 核对文章身份后以 `draft` 写入 → 只读查询确认仍为 `draft` → 人工打开后台核对。前两项是读取与检查，中间两项是写入与机器验收，最后一项是人工验收；它们不是 Ghost 的五种文章状态。任一关失败就停止，不继续触发发布或排期。这种设计能降低误发布风险，但不是「所有错误都只会停在草稿」的保证：文章身份核对、密钥保护和人工复查仍需分别成立。

### 回到后台做人工字段对照

草稿创建后，仍要在 Ghost 后台检查三个地方：标题是否符合读者预期；标签是否归入正确栏目；摘要和首段是否能独立说明文章价值。Ghost 的发布设置支持为文章调整 slug、标签、访问级别、摘要和发布时间。[Ghost 文章设置指南](https://ghost.org/help/post-settings/?ref=chunyangai.com)

如果标签、摘要或图片不正确，应优先修改 Markdown 正本后再回写草稿；只有后台排版问题才在 Ghost 中局部调整。这样本地文件仍是可追溯的内容来源。

对 Markdown 内容创作者，回写前后固定比较同一组字段：`title`、`slug`、`custom_excerpt`、`tags`、封面替代文字和正文。首次创建后还要记录并复查 `ghost_id`、`ghost_uuid`；后续更新时，这两个身份字段应继续指向同一篇文章，且 `status` 仍为 `draft`。任一项不一致，先回到 Markdown 修正并重新写入，不要同时在本地和后台各改一份。

## 发布前要检查哪些事项？

![Ghost 草稿依次经过自动检查和人工批准，发布闸门才允许进入公开发布状态的流程图](https://pub-6611d907480747408f61edaf01b5e2c9.r2.dev/articles/my-first-ghost-blog/2026-09-04/publish-gate-v02.webp)

*图 4：自动化可以把文章推进到草稿并完成检查，但公开发布仍由人工闸门控制。*

- 标题是否同时包含主题（Ghost 博客搭建）与当前进度（本机到草稿），而不是只写「我的第一篇文章」。
- slug 是否短、稳定，并且与主题一致。
- 一级标签是否准确；不要因为名称不一致而制造重复标签。
- 是否已经添加合适的封面图、替代文字和摘要。
- 文章是否仍是草稿；本机测试文不应误发到正式站。
- 所有外部链接是否来自可信来源，且没有泄露密钥、密码或本地文件路径。
- **生产占位是否清零**：确定正式域名后，将 `feature_image`、`og_image`、`twitter_image` 和三件套 Schema 中的 `localhost` 地址全部替换，并由发布流程写入真实日期；只要仍有 `localhost` 或 `PUBLISH_DATE_PLACEHOLDER`，就不得发布。

## 从本机迁移到正式网站还缺什么？

内容流程稳定后，再按优先级迁移到生产环境。先验证数据库与 Ghost 内容卷能够备份和恢复；再确定启用 HTTPS 加密的正式域名，并完成域名解析（DNS）；随后配置反向代理 Caddy、邮件投递服务（SMTP）和防火墙。切换后逐项检查后台链接、文章链接和邮件链接。Ghost 官方将域名、服务器与邮件服务列为自托管的前置条件。[Ghost 自托管安装概览](https://docs.ghost.org/install?ref=chunyangai.com)

不要把本地 `localhost` 地址写进正式文章或元数据。生产地址一旦确定，应统一更新 Ghost 配置、命令行工具（CLI）凭据和工作流站点设置，再重新验证后台、文章链接和邮件链接。

对 Ghost 自托管实践者，迁移完成的判断不是「新域名能打开」，而是下面四项都通过：数据库与 `content` 目录已经从备份恢复验证；域名解析与 HTTPS 正常；测试邮件能够送达；使用未登录浏览器检查首页、文章地址和后台入口后，公开范围与预期一致。任一项未通过，就继续保持草稿，不进入发布。

## FAQ

### 导航已经配置，为什么 Ghost 标签页仍然返回 404？

Ghost 只有在标签关联了已发布文章后，才会生成可访问的标签归档页。草稿不会让标签页公开，所以新站可能出现首页导航正常显示、标签入口却返回 404 的情况。第一篇文章发布后，应逐个复查这些入口。

### 怎样确认 Ghost 草稿没有公开？

先在 Ghost 后台或 Admin API 中确认文章状态为 Draft，并确认 `published_at`（发布时间字段）为空；再用未登录浏览器访问正式文章 slug（网址路径标识）。公开地址应返回 404，表示普通访客找不到该页面。后台预览能打开，只说明管理员可以检查草稿，并不表示文章已经公开。

### Admin API Key 可以放在浏览器前端吗？

不可以。Admin API Key 能生成管理接口令牌，只适合受保护的服务端环境。浏览器里只应使用用于读取公开内容的 Content API Key；管理密钥应保存在受限凭据文件、密钥服务或受保护的环境变量中。

### 迁移或重建 Ghost 前应该备份什么？

至少要分别备份 MySQL 数据库和 Ghost `content` 目录。数据库保存文章、标签和成员等结构化数据，`content` 目录保存图片、主题与其他文件。Docker 命名卷能跨容器重建保留数据，但不能替代可恢复验证过的备份。

### 本机测试 Ghost 必须配置 HTTPS 吗？

仅绑定 `127.0.0.1` 且没有公网隧道时，本机学习环境可以先使用 HTTP。正式网站必须使用真实域名和 HTTPS，并由 Caddy 或同类反向代理处理公网流量；上线前还要检查防火墙、邮件和备份。

### 第一篇文章之后优先自动化什么？

先自动化 Markdown 导入，再加入元数据（标题、摘要、标签等）、结构化数据（Schema，供搜索引擎识别文章类型）、事实和链接质检，最后逐项比较本地正本与 Ghost 草稿是否一致。发布和排期应保留明确的人工确认步骤，避免把流程错误直接放大到公网。

## 参考来源

- [Ghost Docker 部署文档](https://docs.ghost.org/install/docker?ref=chunyangai.com)
- [Ghost Admin API 文档](https://docs.ghost.org/admin-api?ref=chunyangai.com)
- [Ghost 发布设置指南](https://ghost.org/help/post-settings/?ref=chunyangai.com)