← 返回工作日志

WORK LOG #001 · 2026-09-18

从 ChatGPT Sites 到公网个人技术网站

这不是一篇“我今天点了哪些按钮”的流水账,而是一篇小型工程复盘:一个静态网站如何从 AI 辅助创作进入本地工程、版本控制、持续验证、边缘部署、DNS 与 HTTPS,最后成为稳定的公网入口。

站点形态Static Site
HTML · CSS · JavaScript
源码系统Git + GitHub
private repository
交付平台Cloudflare Pages
Git integration
正式入口tech.bestlonger.top
HTTPS · Cloudflare Edge
Site TypeStatic Site
HTML · CSS · JavaScript
Source ControlGit + GitHub
private repository
DeliveryCloudflare Pages
Git integration
Production URLtech.bestlonger.top
HTTPS · Cloudflare Edge
01 / 分层

域名不是服务器

域名负责“找到谁”,Pages 负责“提供内容”,GitHub 负责“保存版本”,CI 负责“证明改动没有明显破坏网站”。

02 / 自动化

CI 与 CD 不是一回事

我们目前的 CI 与 Cloudflare 部署是并行触发;CI 会报警,但还不是阻止生产部署的质量闸门。

03 / 工程化

最小技术栈也能很正式

没有 React、数据库和服务器,同样可以拥有版本管理、自动测试、自动部署、HTTPS 与自定义域名。

01 / Layers

A domain is not a server

DNS tells clients where to go. Pages serves content. GitHub preserves versions. CI provides evidence that a change did not obviously break the site.

02 / Automation

CI and CD are different

Today our CI and Cloudflare deployment are triggered in parallel. CI reports failures, but it is not yet a blocking production gate.

03 / Engineering

A small stack can still be production-grade

No React, database or server is required to gain version control, automated checks, continuous deployment, HTTPS and a custom domain.

真正的交付链路

这张图由 Archify 生成。注意 GitHub 之后分成两条线:一条进入 CI,一条进入 Cloudflare Pages——这正是我们当前架构的真实状态。

在独立窗口打开交互式架构图 →

01. 先看清每一层负责什么

这次最值得保留下来的不是某条命令,而是职责分层。当一个网站出了问题,如果不知道是哪一层负责什么,就会在 DNS、GitHub、Cloudflare、本机代码之间来回猜。

我们使用的东西核心职责典型故障
创作 / 执行ChatGPT + DevSpace MCP生成内容、修改文件、运行检查代码写错、路径错误、工具链错误
本地源码F:\Personal-Tech-Site当前可编辑工作副本文件缺失、语法错误、资源断链
版本控制Git + GitHub版本历史、远端备份、触发自动化未提交、未 push、分支不一致
持续验证GitHub Actions对每次改动给出自动质量证据测试失败、Runner 环境差异
托管 / CDNCloudflare Pages构建或发布静态文件并从边缘网络提供访问部署失败、项目关联错误
访问入口DNS + tech.bestlonger.top把人类可读域名映射到站点服务NXDOMAIN、记录冲突、证书未就绪
判断问题的第一原则:

“Pages 地址能打开,但自定义域名打不开”,优先看 DNS / Custom Domain;“本机正常但 GitHub CI 失败”,优先看 Runner 环境和测试脚本;“CI 和 Pages 都成功但页面内容不对”,再回到源码版本与缓存。

02. 为什么第一版坚持静态站

第一版只有 index.htmlstyles.cssapp.js。这不是“技术简单”,而是有意识地减少运行时依赖。当前需求本质上是内容展示 + 轻量交互,没有登录、交易、实时数据库或服务端计算。

静态站的一个关键优势是:生产环境几乎没有“应用服务器状态”。浏览器请求 HTML/CSS/JS,Cloudflare Edge 直接返回文件。没有数据库连接池、没有长期运行的 Node/Python 服务,也没有服务器进程需要自己维护。

问题静态站全栈应用
部署复杂度低,文件即可发布需要构建、运行时、环境变量甚至数据库
攻击面较小,无自建后端接口需要保护 API、认证、依赖与服务器
扩展内容适合文章、项目页、文档适合动态用户数据和复杂业务
我们现在是否需要暂时没有必要

真正需要 React/Vite、数据库或后端的时候再升级。工程设计里一个很重要的原则是:不要为了“看起来先进”提前购买复杂度。

03. GitHub 为什么成为整个链路的中枢

本机目录是编辑现场,但 GitHub 才是自动化系统共同能看到的“稳定交接点”。本地执行:

git add .
git commit -m "..."
git push

其中最关键的不是 push 把文件“上传”了,而是它产生了一个确定的 commit SHA。CI 和 Cloudflare Pages 都可以围绕同一个 SHA 工作,因此我们能回答:

  • 哪个版本通过了 CI?
  • 哪个版本被 Cloudflare 部署?
  • 线上出问题时要回滚到哪个已知良好版本?

这就是 Git 从“备份工具”升级成“交付协议”的地方。

04. Cloudflare Pages 如何接住一次 Git push

1

GitHub 收到新 commit

仓库更新后,Cloudflare 的 Git integration 能看到对应分支的新版本。

2

Pages 创建 deployment

我们的站点没有构建步骤,所以部署的核心动作就是取得仓库内容并发布静态资源。

3

先落到 pages.dev

personal-tech-site.pages.dev 是 Cloudflare Pages 原生提供的项目地址。它是排障时非常重要的“基线地址”。

4

Custom Domain 映射正式入口

tech.bestlonger.top 成为面向读者的稳定地址,而底层仍由 Pages 托管。

这里有一个很实用的排障策略:先测试 pages.dev,再测试自定义域名。 如果前者 200、后者失败,问题通常就不在 HTML/CSS/JS,而在域名绑定、DNS 或证书链路。

05. 域名、DNS 与 HTTPS 到底做了什么

我们一开始讨论“要不要买域名”时,最容易混淆的概念是:域名不是网站本身,也不是托管空间。 它只是一个稳定、可读的名字。

这次的职责关系可以抽象成:

tech.bestlonger.top
        │
        │ DNS / Custom Domain
        ▼
Cloudflare Pages
        │
        ▼
static assets

实际配置时,我们没有先随便手工造一条 CNAME,而是先在 Pages 项目的 Custom Domains 中声明 tech.bestlonger.top 属于这个项目。这样 Cloudflare 同时知道“DNS 指向哪里”和“这个 Hostname 应由哪个 Pages 项目回答”。

随后 HTTPS 证书由 Cloudflare 侧签发和托管。浏览器最终访问的是 https://tech.bestlonger.top,TLS 握手、边缘节点和内容分发都在 Cloudflare 的网络中完成。

06. CI/CD 的真实边界:现在还不是“CI 通过才发布”

这是今天最值得讲清楚的一点。很多文章会把 CI/CD 写成一根直线:

commit → CI → deploy

但我们当前真实架构并不是这样。GitHub 收到 push 后,GitHub Actions CI 和 Cloudflare Pages Deployment 是两个独立消费者

             ┌─ GitHub Actions CI
git push ────┤
             └─ Cloudflare Pages Deploy

因此 CI 失败并不自动阻止 Pages 发布。它现在的价值是:快速告诉我们“这个 commit 的质量检查失败了”。这已经很有用,但它仍然不是 blocking gate。

模式触发方式CI 失败时适合阶段
当前模式CI 与 Pages 并行报警,但 Pages 可能已经部署当前静态个人站,简单可靠
严格门控CI PASS 后由 Actions 部署生产部署不会发生有构建、测试、多人协作或高风险变更时

所以我们没有急着把系统复杂化。等网站发展到 Markdown 构建、搜索索引、更多脚本或多人协作时,再把 Cloudflare 部署迁入 GitHub Actions,形成真正的质量闸门

07. 一次真实 CI 故障:不是网站坏了,而是测试脚本太乐观

把 Work Log #001 做成网页后,我们的 CI 真正失败过一次。Cloudflare Pages 已经部署成功,但 GitHub Actions 的 HTTP smoke test 报:

curl: (7) Failed to connect to 127.0.0.1 port 4173

最初脚本启动 Python HTTP Server 后只固定等待 1 秒:

python -m http.server 4173 --bind 127.0.0.1 &
sleep 1
curl http://127.0.0.1:4173/

问题在于 CI Runner 的调度和进程启动速度不是确定值。sleep 1 只是“希望一秒够用”,并没有证明服务已经 ready。这是一类典型的 race condition / readiness problem

我们把它改成有上限的重试:

for attempt in {1..10}; do
  if curl --fail --silent http://127.0.0.1:4173/; then
    break
  fi
  sleep 1
done
真正的经验:

测试外部进程时,不要把“等待固定时间”当成“服务已经就绪”。优先检测真实 readiness 条件,并设置明确的最大等待时间和失败日志。

修复后,同一套 CI 同时验证首页和 Work Log #001 页面,最终 GitHub Actions 与 Cloudflare Pages 两项都恢复为 green。

08. 这次可以复用到其他项目的工程经验

  1. 先建立最小闭环,再增加复杂度。 本机能打开 → Git 可追踪 → GitHub 可恢复 → Pages 可部署 → 域名可访问 → CI 可验证。
  2. 保留一个基础访问入口。 pages.dev 是判断“应用问题还是域名问题”的重要对照组。
  3. 自动化必须检查真实结果。 只做语法检查不够,所以 CI 最后真的启动 HTTP Server 并用 curl 访问页面。
  4. 把失败也写进日志。 “CI 曾经失败一次”比“全部顺利完成”更有学习价值,因为它揭示了 readiness 与并发触发的真实边界。
  5. 架构图必须表达真实系统,而不是理想系统。 所以 Archify 图里 CI 与 Pages 是分叉,而不是假装 CI 是部署前置条件。

下一阶段,网站会继续增加独立专题页、Markdown 文章构建、搜索与标签。但基础原则不变:每新增一层能力,都要知道它解决什么问题,也要知道它新增什么维护成本。

查看 Markdown 源记录 返回工作日志

01. Start with clear responsibilities

The most reusable result of this work is not a command. It is the separation of responsibilities. Without that map, debugging quickly turns into guessing between DNS, GitHub, Cloudflare and local code.

LayerTechnologyResponsibilityTypical failure
AuthoringChatGPT + DevSpace MCPCreate content, edit files, run checksBad code, wrong path, tooling failure
Local sourceF:\Personal-Tech-SiteEditable working copyMissing file, syntax error, broken asset
Version controlGit + GitHubHistory, remote backup, automation triggerUncommitted or unpushed changes
Continuous integrationGitHub ActionsAutomated evidence for each changeFailed checks or runner differences
Hosting / CDNCloudflare PagesPublish static assets at the edgeDeployment or project integration failure
Public entry pointDNS + custom domainMap a stable human-readable hostname to the siteNXDOMAIN, record conflict, certificate pending
Debug by layer:

If the pages.dev URL works but the custom domain does not, start with DNS and Custom Domains. If local checks pass but CI fails, inspect runner behavior and test assumptions. If CI and Pages are green but content is wrong, compare the deployed commit and cache state.

02. Why the first version stays static

The first version began with only index.html, styles.css and app.js. That is not a lack of sophistication; it is a deliberate decision to avoid runtime complexity before the product needs it.

The current problem is content publishing plus light interaction. There is no login, transaction processing, live database or server-side computation. A static site therefore removes application-server state, reduces the attack surface and makes deployment almost trivial.

QuestionStatic siteFull-stack app
DeploymentPublish filesBuild + runtime + secrets + possibly a database
Attack surfaceSmallAPIs, auth, dependencies and servers
Best fitArticles, projects, documentationDynamic user data and complex business logic
Needed today?YesNot yet

A useful engineering rule is: do not buy complexity before a requirement can pay for it.

03. Why GitHub becomes the hub

The local directory is where editing happens, but GitHub is the stable hand-off point visible to automation. A push does more than “upload files”; it creates a specific commit SHA that CI and deployment systems can both reference.

git add .
git commit -m "..."
git push

This lets us answer operational questions precisely: Which commit passed CI? Which commit was deployed? Which known-good version should we roll back to? That is the moment Git becomes part of the delivery protocol rather than just a backup tool.

04. How Cloudflare Pages consumes a Git push

1

GitHub receives a new commit

The connected branch changes and becomes visible to Cloudflare's Git integration.

2

Pages creates a deployment

Because this site has no build step, deployment mainly means retrieving and publishing static assets.

3

The project is available on pages.dev

personal-tech-site.pages.dev is more than a fallback URL; it is a valuable diagnostic baseline.

4

The custom domain becomes the public contract

tech.bestlonger.top is stable for readers while Pages remains the underlying hosting layer.

A useful debugging rule follows: test pages.dev first, then test the custom domain. If the first returns 200 and the second fails, the application files are probably not the problem.

05. What the domain, DNS and HTTPS actually do

A domain is not the website and it is not the hosting environment. It is a stable name that participates in routing a browser request to the service that owns the hostname.

tech.bestlonger.top
        │
        │ DNS / Custom Domain
        ▼
Cloudflare Pages
        │
        ▼
static assets

We registered the hostname through the Pages project's Custom Domains flow instead of blindly creating a CNAME first. That gives Cloudflare both pieces of information: where DNS should point and which Pages project is authorized to answer for that Host header.

Cloudflare then manages the TLS certificate and edge delivery. The browser sees https://tech.bestlonger.top; certificate handling and content delivery happen inside Cloudflare's network.

06. The real CI/CD boundary: CI does not block production yet

A common simplified diagram says:

commit → CI → deploy

That is not our current architecture. After a GitHub push, GitHub Actions and Cloudflare Pages are independent consumers:

             ┌─ GitHub Actions CI
git push ────┤
             └─ Cloudflare Pages Deploy

So a failed CI run can report a problem even after Pages has started or completed a deployment. CI currently provides a quality signal, not a blocking production gate.

ModeTriggerIf CI failsBest fit
CurrentCI and Pages run in parallelWe get an alert; deployment may already existSimple personal static site
Strict gateActions deploys only after CI passesNo production deploymentBuild pipelines, larger teams, higher-risk changes

We deliberately keep the simpler model for now. Once the site gains Markdown builds, search indexing, more scripts or multiple contributors, moving deployment into GitHub Actions will make a blocking gate worthwhile.

07. A real CI failure: the site was fine, the test was too optimistic

When Work Log #001 first became a web page, CI failed even though Cloudflare Pages successfully deployed the site. The smoke test reported:

curl: (7) Failed to connect to 127.0.0.1 port 4173

The original test started Python's HTTP server and waited for a fixed second:

python -m http.server 4173 --bind 127.0.0.1 &
sleep 1
curl http://127.0.0.1:4173/

The flaw is subtle: runner scheduling and process startup time are not deterministic. sleep 1 expresses hope, not readiness. This is a classic race condition / readiness problem.

We changed the test to a bounded retry loop:

for attempt in {1..10}; do
  if curl --fail --silent http://127.0.0.1:4173/; then
    break
  fi
  sleep 1
done
General lesson:

When testing another process, do not confuse “waited for some time” with “the dependency is ready.” Probe the real readiness condition, set a maximum wait, and preserve failure logs.

08. Reusable engineering lessons

  1. Build the smallest complete loop first. Local → Git → GitHub → Pages → domain → CI.
  2. Keep a baseline endpoint. The pages.dev URL helps separate application failures from domain failures.
  3. Automation should test real outcomes. Syntax checks are useful, but our CI also starts an HTTP server and performs real requests.
  4. Document failures, not only successes. The failed CI run teaches more about readiness and parallel automation than a perfect happy-path story.
  5. Architecture diagrams must describe reality. That is why the Archify diagram branches from GitHub into CI and Pages instead of pretending CI already gates deployment.

The next phase will add topic pages, Markdown publishing, search and tags. The rule remains the same: every new layer must solve a concrete problem worth its maintenance cost.

Open Markdown source record Back to Work Log