2026 年初我做了一个决定:建一个自己的 AI 内容站,而不是在别人的平台上发内容。原因很简单——平台的内容分发规则随时会变,而独立站的数据和流量是自己的。这篇文章记录从零搭建的全过程,包括技术选型的考量和掉过的坑。

为什么选 Express + SQLite 而不是 Next.js + PostgreSQL

建站之前我认真对比了几种方案。

Next.js + Vercel。最流行的方案,SSR 对 SEO 友好,部署简单。但 Vercel 在国内访问不稳定,而且 Serverless 函数有冷启动问题。我的站面向的是中英文用户,国内访问占比不低。

WordPress。功能最全,插件生态丰富。但 PHP+MySQL 的运维成本和安全隐患对于一个人的项目来说太重了。半个月不更新就可能被扫到漏洞。

Express + sql.js(实际选型)。选这个方案的原因有三个:第一,JavaScript 全栈,一个人维护成本最低。第二,sql.js 把 SQLite 编译成 WebAssembly,不需要安装维护数据库服务。第三,部署简单——一个 Node.js 进程 + Caddy 就是全部。

当然有取舍。sql.js 不支持并发写,所以所有写操作都是串行的。对于日活几百的站来说完全够用,但如果做到日均上万访问就得换方案了。

Caddy:比 Nginx 更适合一人项目

一开始用的 Nginx,但很快就后悔了。Nginx 的配置语法繁琐,SSL 证书要手动续期,反向代理规则写错一行整个站就挂了。

换成 Caddy 之后体验完全不同:

自动 HTTPS。Caddy 内置 Let's Encrypt 自动申请和续期证书。不需要 certbot,不需要 cron 脚本。配置里写一句 tls your@email.com 就行。

配置文件简洁。反向代理、静态文件服务、安全头设置全部在一页配置里搞定。对比 Nginx 动辄上百行的配置,Caddy 的配置大概只有三分之一。

安全头开箱即用。X-Frame-Options、HSTS、Content-Security-Policy 这些安全头直接在 Caddy 配置里声明,不需要中间件。

对一人项目来说,运维复杂度下降一个档次就是实打实的时间节省。

内容结构的演变:从 PC 站到移动优先

最初的设计方案参考了传统论坛——左侧导航、右侧内容、顶部有复杂的分类标签。上线后实测移动端体验一塌糊涂。按钮太小、布局错位、加载时间太长。

后来做了一次彻底的移动端重构:

  • 导航栏改成汉堡菜单,收起非核心链接
  • 排行榜卡片用 grid 布局自适应列数
  • 论坛帖子列表去掉多余信息,只保留标题和分类
  • 所有 padding 和 font-size 用 clamp() 做响应式
  • Canvas 星空特效加 pointer-events: none 防止干扰点击

重构完移动端体验明显改善,但有一个新问题:Canvas 星空粒子在低端手机上掉帧。最后加了 screen.width 判断——视野宽度小于 768px 时减少粒子数量一半。

SEO 的技术债:早该做的事

这个站最大的技术债是 SEO。因为做的是 SPA(Single Page Application),内容通过 JavaScript 加载,Google 抓到的页面是空的。

最初的方案是给每个页面做动态 meta 注入——JS 加载内容后更新 title、description、canonical、结构化数据。这个方法对已经通过 JS 渲染的页面有效,但对 Googlebot 不够友好——Google 虽然能执行 JS,但执行成本高,优先级低,抓取频率远低于静态页面。

后来的方案是 prerender(预渲染):发布文章时,同时生成一个静态 HTML 文件。sitemap 指向静态文件而不是动态 URL。这样无论 Googlebot 执不执行 JS,都能拿到完整的文章内容。

prerender 的流程:

发布文章 → POST /api/blog
       ↓
prerender 读取 DB → 生成 blog/post-{id}.html
       ↓
gen-sitemap 重新生成 → 包含新静态 URL
       ↓
新文章在 5 分钟内可被 Google 抓取

这个流程跑通之后,Google 的收录速度从"几周"变成"几个小时"。

持久化和备份

对于一个 sql.js 的站点,整个数据库就是一个文件。备份策略简单到令人感动:每天 cron 把 data.db cp 到备份目录,保留最近 7 天。脚本大概 5 行:

#!/bin/bash
BACKUP=/var/backups/playje
mkdir -p $BACKUP
cp /var/www/playje/server/data.db $BACKUP/data-$(date +%Y%m%d).db
find $BACKUP -name '*.db' -mtime +7 -delete

恢复也简单:把备份文件 cp 回去,重启 PM2 进程。整个过程不超过 30 秒。

对于一人项目来说,简单可靠的备份方案比复杂漂亮的高可用方案重要得多。太复杂的方案你根本不会去执行。

关于成本

这个站每月的运营成本:

  • 阿里云日本轻量服务器:约 ¥34/月
  • 域名 Namesilo 续费:约 ¥60/年
  • Caddy(免费)
  • sql.js(免费)
  • Cloudflare(免费,已不用)

算下来每月运营成本不到 ¥40。加上 AI API 的费用(约 $50/月),一个独立站的月度支出在 ¥400 左右。这个成本一个人完全承担得起,也是支撑我持续做下去的重要原因。

给想搭站的人的建议

如果你也想建一个独立的内容站,我的建议是:不要等到万事俱备再上线。第一版可以简陋,甚至可以没有后台、没有评论区、没有好看的 UI。只要内容在、能访问,就可以上线了。

后续的功能根据用户反馈和数据来决定优先级。不要猜用户想要什么——问他们。一个简单的反馈按钮比三个月的功能开发更有价值。

最后,关注技术债务。做技术选型时选简单方案没错,但要清楚每个简单方案的局限性,知道它什么时候该换成更成熟的方案。超前的架构决定是无意义的,滞后的重构压力是有代价的。