把 ShuFeiCat 这个 Typecho 主题折腾上线的过程记录

最近搭了个博客,用的是 Typecho,主题挑了个叫 ShuFeiCat 的。功能宣传得挺全——AI 写作、AI 审核、评论点赞投票、图床直传,看起来像把十几个插件全塞进去了。

我这个人有点轴,没直接装上就开写,而是先把它拉下来翻了遍源码,再一步步部署、加固、上线。这篇就是把这一路的经过记下来,尤其是几个踩过的坑。不一定对你有多大用,但如果正好你也要用这个主题,或者要搭个类似的博客,应该能少走点弯路。


先翻了遍源码

拉下来一看,第一个感觉是:这不只是"主题",更像是一套打包成主题的博客系统。

  • 65 个 PHP 文件,三万多行
  • core/ 下面塞了 43 个模块
  • 光一个 functions.php 就 195KB,后台配置项 168 个

Typecho 生态里通常要靠十几个插件才能凑齐的东西(AI、图床、邮件、验证码、统计、SEO),它全自己做了。完成度是比一般国产主题高,但换来的是整体很重,而且是一个人维护的(当时 61 个 star、2 个 fork)。

安全上扫了一遍,好坏都有。

好的地方:没有后门,eval、混淆代码、shell 调用一概没有;SQL 全是参数化或者强转;图片代理的 SSRF 防护做得挺细;上传有扩展名白名单。

要留意的几个:

  1. 后台的 CSRF 只校验 Origin/Referer,没有 token,两个都缺的时候直接放行,还允许子域后缀匹配。前台那些接口(点赞、投票、搜索)倒是用了 session token,是强的。
  2. core/cache/ 存的是正文的渲染缓存,包括编辑器"免保存预览"生成的草稿。文件名能猜出来(content_文章id.html),等于草稿可能被人直接读走。
  3. install.php 装完不会自己删,哪天数据库配置一出问题,这个入口能重置整个站。

这三个问题后来上线的时候一个一个都应验了。


SEO 看了下,84 分,有两处我补了下

单独把 core/seo.php(549 行)和 header 的输出读了一遍,给个 84 分吧,在 Typecho 主题里算不错的。

好的地方:分页的 canonical 各自指向自己,没犯那个最常见的错;三套结构化数据都齐;sitemap 是全站的。

但有两个明显的短板,而且都能自己修:

  1. description 会混进 Markdown 源码。shufei_seo_trim() 只做了 strip_tags,没把 ##、**、链接语法剥掉,所以摘要里可能出现 ## 前言 这种。
  2. 首页和列表页没有 H1,只有文章页和独立页有。

我就自己改了两处:给 description 加一段 Markdown 清理,首页补一个 sr-only 的 H1(视觉上看不出来,但对 SEO 有用)。后来直接打进部署包里了,上线后验证过是生效的。


打包:做成解压就能用

我的需求是解压到服务器直接装,所以把三样东西拼成了一个 zip:

typecho-1.3.0-shufeicat.zip
├── Typecho 1.3.0 官方版
├── usr/themes/ShuFeiCat/   ← 主题装好了,两处 SEO 补丁也打了
├── robots.txt
└── 安装说明.md

有个细节得说下:主题必须放在 usr/themes/ShuFeiCat/ 这一层,错一层的话所有 AJAX 接口直接报错。这个坑太容易踩了。


上线实测,curl 揪出三个问题

部署到服务器之后,我没信"看起来正常",而是用 curl 一条条测。结果真测出三个问题:

install.php 还在。 访问返回 302 而不是 404,响应头里还有 X-Powered-By: PHP/8.5.12,说明是真文件没删。这个最该删,虽然现在有安装锁挡着,但保不齐哪天数据库配置出问题。

robots.txt 域名没改。 我把模板原样传上去了,里面的 Sitemap 还是 example.com,等于提交给搜索引擎的地址是错的。

安全加固没生效。 安全响应头一个都没有,readme.md 能直接访问(返回 200),缓存目录也没封。


补了一段 Nginx 配置

针对第三个问题,给站点配置加了一段。核心是四个 location 加四条安全头,关键在位置——必须放在 location ~ [^/]\.php(/|$) 之前。Nginx 里正则 location 的优先级更高,放后面的话请求就被 .php 那段抢走了,封禁等于没写。

# 屏蔽主题缓存目录(含草稿缓存)
location ~ ^/usr/themes/ShuFeiCat/(core/)?cache/ {
    return 403;
}

# 上传目录禁止执行 PHP
location ~ ^/usr/uploads/.*\.php$ {
    return 403;
}

# 屏蔽深层敏感文件和备份文件
location ~ ^/(\.user\.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README\.md|\.gitignore|\.DS_Store) {
    return 404;
}
location ~ \.(sql|bak|tar\.gz|zip|rar|7z)$ {
    return 403;
}

# 安全响应头
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-XSS-Protection "1; mode=block" always;

重载之后再测,五条全绿了:

检查项之前之后
install.php302404
readme.md200404
上传目录 PHP404403
缓存目录404403
安全响应头缺4 条

上传目录那个 PHP 从 404 变成 403 是个挺直观的信号,说明正则 location 真的抢在 .php 前面命中了,整段配置不是白写的。


几个坑,单独记一下

PHP 执行时间得提到 120 秒以上。 AI 写作那个端点里没有 set_time_limit(),但它请求 AI 的 curl 超时写的是 60 秒。容器里 PHP 默认 max_execution_time 是 30 秒,模型还没返回,fpm 就先把进程杀了。表现就是点 AI 写作转圈半天然后 502,特别容易误判成接口配错。

SMTP 发信失败是没提示的。 主题内置了 PHPMailer 和测试按钮,但发送失败只写 error_log,前端永远显示成功。所以配完邮箱一定要点测试按钮,真收到邮件才算数。另外云服务器默认封 25 端口,得走 465,密码填的是授权码不是登录密码。

PHP 8.5 反而最省心。 我一开始担心主题声明的 8.3 和实际跑的 8.5 有差异,就把 65 个文件对着 PHP 8.0 到 8.5 的废弃清单扫了一遍,结论是没风险:没有已移除的函数,动态属性都有声明,依赖的扩展都在。主题代码写得很保守,能兼容到 7.2。

面板类型别想当然。 我一度以为是 1Panel,实际是 qpanel。这俩配置路径和操作方式不一样,改错文件就白忙。拿到服务器先确认环境,别急着套模板。


最后

整个过程走下来,其实就几个点:源码先审一遍再部署;搞清楚它把敏感数据存在哪(缓存目录、上传目录);上线后别信"看着正常",拿 curl 逐条验;加固配置要明白 Nginx 的 location 优先级。

主题这东西,管的是页面上那点 on-page 的事,真正能不能被搜到、有没有人看,还是得靠一篇篇写下去。


项目地址:smcloudcat/shufeicat-typecho

添加新评论

文章目录