MySQL

下线 WordPress,躲过 PHP 漏洞,瘦身 Hugo 输出

八月底把博客迁移到 Hugo,九月初又把历史文章都按 Markdown 整理了一遍,之后正常写了几篇新文章。按迁移时的规划,把旧 WordPress 留在 VPS 上空跑一段时间,以备还有啥需要迁移的

这几天趁着 Tibo 不停重置 Codex 的使用额度,再让 AI 验证迁移确实没有遗漏,把旧系统下线并卸载依赖,顺便把之前模板在每个页面里完整输出的侧边栏做了下优化瘦身

下线旧 WordPress

从八月底切换到 Hugo 开始,访问就已经全部走 Hugo 生成的静态文件,nginx 配置里也没有再把请求转发给 PHP

这次让 AI 先帮忙核查了一遍,确认现在的文章、图片、RSS、搜索和评论标识都不需要 WordPress,旧站里的图片也都已经在新站找到对应文件,已有的文件和数据库备份继续保留,才开始动手

10 月 20 日先停掉 MySQL 和 PHP-FPM,释放空跑占用的 VPS 内存,禁用开机启动,顺带把之前人肉维护的每日备份到 Dropbox 和 Google Drive 的脚本也停了。同时让 AI 修了一个 RSS 的小问题,原来 /blog/feed/ 可以正常访问,但少了最后那个斜杠的 /blog/feed 会返回 404,现在加了跳转

停掉后又观察了一天,确认正常访问没受影响,21 日把 PHP、MySQL 相关的软件包卸载,再清掉旧 WordPress 目录和数据库文件,也省得每次 apt upgrade 还要更新一堆没用的包

非常巧,PHP 官方在 10 月 21 日发布紧急安全更新,修复两个可能导致未认证远程代码执行的严重漏洞(CVE-2026-109618 和 CVE-2026-109619)。我这边下午刚把 PHP 卸载完,当天就赶上了紧急补丁发布。八月底公开访问就已经不经过 PHP,这次连运行环境也收掉了,刚好省了追着看影响范围和打补丁的事,庆幸有时候抠门省事也能少操一点心

这也符合之前迁移到 Hugo 的目标之一,减少对 WordPress、PHP 等的依赖,只放静态文件在 VPS 上,未来再要迁移也容易很多

同步 whusnoopy.github.io

GitHub 很早就有这个用自己用户名开头、以 github.io 结尾的 GitHub Pages 托管服务,早先打算折腾 Hugo,也是从考虑 GitHub Pages 默认支持的 Jekyll 看起,后面发现还是用 Hugo 更符合自己的需求

这次顺带让 Codex 完成了对 whusnoopy.github.io 的镜像流程,未来如果懒得自己维护 VPS 了,再配好自定义域名和 DNS,把它改成主站应该也可以的

瘦身 Hugo 输出

往 github.io 做镜像同步时,发现 Hugo 的输出目录到了 600 MiB+,这个空间占用明显超出预期,原来的 WordPress 站点目录在清理前核查时约 264 MiB。Codex 在分析能否将 github.io 做镜像时还提到,GitHub Pages 已发布站点的大小不能超过 1 GB,这一下就用掉了大半

自己人肉简单看了下是不是附件图片什么的太大了,用 gdu 扫了下也还好,就是旧文章里的图片链接还在 wp-content/uploads,新文章的图片放在 media/posts 下。这些旧地址继续保留,毕竟二十多年的各种历史包袱,能不动就不动,省得哪天又冒出来一个旧链接打不开

继续看,是最终生成的各种 HTML 文件累积起来太大了,一开始还怀疑是 Tag 和分类太多,导致输出的文件数量过多,后来让 AI 一查,是每个页面重复输出了完整侧边栏导致的

迁移到 Hugo 时为了保留原来的使用习惯,把右侧按年、月展开的文章归档也搬了过来。这东西在 WordPress 时代用的是 Collapsing Archives,之前还为兼容 PHP 8 修过插件,自己用习惯了这一套,希望能继续按年月翻旧文章

不过之前本站的模板实现就是把二十多年的年月、八百多篇文章的标题和链接,以及折叠用的按钮、列表结构,全部生成到每一个页面里,哪怕后来加了默认收起来等 JS 行为,实际上每页光侧边栏就有大约 216 KiB 的 HTML

算上文章分类、标签、年月归档和各种分页,整站的两千多个页面,把这部分内容原封不动输出了两千多遍。难怪文章和图片都没怎么变化,生成出来的整站文件却有 600 MiB+

找到问题就改呗,现在虽然不用 WordPress 动态输出,但可以把侧边栏依赖的文章归档数据提取到一个共用的 archive-index.json,页面里只留容器,由浏览器读取数据来生成年月列表,展开某个月时再创建里面的文章链接。这样同一份数据不用在每个 HTML 里塞一份,也可以利用浏览器缓存,跨页面访问时不必每次都重新传输整份数据,原来按年月展开、记住展开状态的功能都还在

这一波整完,单页侧边栏从 216 KiB 降到 8.3 KiB,整站从 632 MiB 降到 141 MiB

后面继续把文章分类和常用标签也用类似的方式处理,两块共用一份 sidebar-index.json,再把分页模板输出里那些没必要的缩进和换行裁掉。最后结果是

构建状态 单页侧边栏大小 整站文件大小
优化前 约 216 KiB 约 632 MiB
年月归档改用共享 JSON 约 8.3 KiB 约 141 MiB
分类、标签及分页继续优化 约 1.9 KiB 约 125 MiB

后面的优化收益没那么大,不过现在整个输出约 125 MiB,已经比之前含 WP 系统的旧站目录小了,每次发布和同步 github.io 镜像需要处理的数据也少了很多,离 GitHub Pages 的容量上限也还远,满意

随记

八月底迁移时想着后面就安心写东西吧,结果这两个月又断断续续折腾了不少。现在旧系统退役,生成文件也瘦了一大圈,希望接下来能多写几篇文章,少折腾点博客本身吧

现在我也变成用 AI 来输出内容的懒人了,上面引用这部分是 AI 输出的原文,更前面的内容是让 AI 用我的文风出的草稿,我改了一遍后的结果。有好有坏吧,先保持自己的想法记录输出,再继续平衡内容中的机械味和活人感

BuyVM VPS 安装优化记

BuyVM 的 VPS

早两周忘了是谁提醒了下, 说 buyvm 家 15$/yr 的 VPS 有货, 非常值得去抢, 当时估算了下这个价格确实算良心价, 虽然只有 128M 内存, 但作为一台自己的 vps 折腾点东西完全都够了的, 果断下手一台

这台机器打算拿来放一些自己玩的小程序, 同时把个人的空间和 blog 迁过来, 本还想拿这个机器做自己私有的翻墙中继, 不过试了下到本地的速度最高也没超过 30KB/s 过, 遂放弃, 等啥时候有烧包需要时去买 linode 在日本的节点好了

系统选择和基本设置

之前自己用 debian-server 做纯服务端的东西感觉很爽, 占资源少文档丰富, 出点问题也能很容易在 Google 帮助下搞定, 所以系统也选的 debian, 然后因为只有 128M 内存, 上 64bit 没意义, 而且会更耗内存一点, 所以选了 32bit 的版本

debian 有几个比较坑爹的地方, 首先就是新建用户默认不建 home 目录, 非要在 useradd 的时候强加 -m 参数指定, 不然还要人肉新建 home 目录兵把 /etc/skel/ 下的几个隐藏文件拷过来做初始化

然后就是如果不是 root 用户, /sbin 和 /usr/sbin 默认是不在 PATH 里的, 需要手动将这些路径打开, 不然连 ifconfig 什么的都用不了. 修改 /etc/profile 里, 将 PATH 设成全用户一致 (此处参考: http://techpoet.blogspot.jp/2010/01/add-sbin-to-user-path-in-debian.html)

自己有一堆常用的配置库放在 github 上, 直接 git 取下来放到 home 目录, 把一堆 rc 结尾的文件前面加点让对应的程序能读到. 特别的是 vimrc, 最好还是放到 /etc/vim/vimrc.local 下, 不然 sudo 的时候碰上的还是没配过的 vim, 挺不爽的

系统自带应用内存优化

因为只有 128M 的内存, 要做很多勒紧腰带过日子的准备, 先就是卸载一堆自带的服务, 释放宝贵的内存, 此处参考了 http://www.yyphs.com/post/475.html, 不过我只去掉了会启动的组件, 即如下操作

# 系统升级
apt-get update && apt-get upgrade

# 去除多余软件
apt-get -y purge apache2-* bind9-* xinetd samba-* nscd-* portmap sendmail-* sasl2-bin

# 清理软件包
apt-get autoremove && apt-get clean

LEMP 环境安装

Web 应用从早两年的 LAMP 现在都在转 LEMP, 主要还是把 Apache 这个巨无霸换成了相对小巧又耐操的 nginx, 自己之前用 nginx 感觉也相当好, 这次也把系统默认的 Apache 干掉换这个

一开始参考的 http://www.howtoforge.com/installing-nginx-with-php5-and-mysql-support-on-debian-squeeze, 安装 mysql, nginx, php 都很正常, 但是这里面提到 debian 没有 php-fpm, 所以用 lighttpd, 不过我装 lighttpd 后内存爆掉, 随便搜了下优化方案都搞不定, 卸掉, 还是用习惯的 php-fpm 方式跑 fastcgi

按 http://www.webhostingtalk.com/showthread.php?t=1025286 这个提示装上 php5-fpm, 从装 nginx 开始就用不上了, 后面的优化也先不用管, 一会一起处理 (wordpress 似乎还依赖一个叫 php5-apc 的包, 装的时候一起带上)

内存优化

上面那一堆装好后如果不做优化, 坨坨的爆内存, 所以该关的功能要关, 该调的参要调. mysql 的一个优化关键是要关 innodb, 然后 nginx/php-fpm/mysql 都要做的事就是降低同时运行的实例数, 减少连接数, 同时严格控制各处内存大小. 具体怎么配的也忘了, 主要参考的是搜到的这两篇里关于参数的配置

http://blog.log4d.com/2011/11/vps-lnmp-setup-config/ (主要参考其参数配置)

http://keithscode.com/blog/23-running-mysql-on-a-small-128mb-vps.html (主要参考其参数配置)

最后的内存占用如下 (目前运行状态, 装了 wordpress)

$ free
             total       used       free     shared    buffers     cached
Mem:        262144      88972     173172          0          0          0
-/+ buffers/cache:      88972     173172
Swap:            0          0          0

安装迁移 wordpress

先在 mysql 里建对应的数据库, 这个随便都能搜到, 自己碰到个坑是 mysql 分配数据库权限时用已有用户无法登陆, 最后还是删掉用户在分配权限时再新建用户, 用 identify 来设置密码

mysql> create database wp;
mysql> grant all privileges on wp.* to wp_user@localhost identified by 'wp_pass';

装 wordpress, 一切正常, 用老的文件, 改名备份 wp-config.php 直接访问 wp-admin/install.php
用导出的文件再导入 (大于 2M 的话需要修改 php 的上传限制: 修改 /etc/php5/fpm/php.ini 文件修改 upload_max_filesize 项)

之前用的是多说的评论系统, 把插件重新启用, 并绑定原来注册过的站点就能将评论恢复, 一切搞定

奇怪的问题

上面写的好像很容易, 实际上对一个新手 OP 来说还是非常磕磕碰碰的, 最后在 OP 之外还有些奇怪的问题

先是多说, 绑定站点时临时性卡死, 然后再导数据时有延迟, 再后面就有重复的评论出现, 但是又不是所有的评论都被重复一遍, 研究了半天没弄明白, 自己手动删掉了重复的

然后删重复数据时发现有一条奇葩的回复显示在了另一篇文章下, 还是一条二级评论, 但是在后台看对应的又是正确的文章, 而且文章下的评论数是对的, 就是不显示, 自己折腾半天都没弄好, 无奈去联系多说的技术客服, 周末不在线, 留言后觉得不放心, 又去 dev.duoshuo.com/wordpress-plugin 报了一遍才安心

今天终于找上人, 帮着看了下, 先让我把评论模式从嵌套改成盖楼, 发现果然显示在正确的文章下了, 但是错误的引用了一条另一篇文章下的评论, 而且引用的那条评论还在此评论后好几个月才发出来, 顺手看了下 HTML 源码, 发现多说也是按 评论(post-id), 文章(thread-id), 引用(root-id) 来组织的数据 (这跟 BBS 上的 pid, gid, rid 一样一样啊), 然后这条出错的评论应该是两边哪里没同步好, 导致其 root-id 出错, 而 root-id 对应的评论在另一篇文章下, 所以嵌套模式时就显示到那边去了, 而正确的文章下因为找不到对应的父评论所以也没显示, 而盖楼模式下不判断父评论所以能显示, 但是存在错误引用关系, 最后让帮忙手动将出错评论的 root-id 置零, 总算搞定

第二件事是一个陈年老问题还在, 一年多前就写过一篇爆流量记, 里面提到有人抓 win7.iso, 但是当时找不到证据说是谁, 迁到新站后还在被抓, 期间 404/302/416 轮着报了一年多错居然还抓, 怒了去看看到底都哪来的请求, 意外发现有很多标识 QQDownload 的请求, 从 momodi 那联系上 QQ 旋风的人, 跟他们 blabla 说了一堆, 结果估计他们也从来没碰到过这样的事, 说要不你先自己屏蔽掉? 我哭笑不得说现在对我倒没啥影响了, 反正就算屏蔽也耗系统资源, 而且现在每次给个 416 也费不了我多少流量, 只是觉得很不爽而已. 不过后来自己去找了下迅雷和旋风离线下载的 IP 段, 这几个好像又都不在里面, 贴下原始日志, 大家看看有啥想法没:

$ awk '/QQDownload/{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}' access.log
101.226.68.137 196
140.207.54.139 195
183.195.232.138 196
$ awk '/cn_windows_7/{cnt[$1]++};END{for(ip in cnt){print ip, cnt[ip]}}' access.log
122.141.67.50 329
123.185.52.73 54
14.114.226.18 150
14.114.226.194 14677
14.115.129.55 4040
180.117.68.185 361
59.33.63.137 1476

抽几条完整日志如下:

101.226.68.137 - - [21/Apr/2013:19:44:18 +0800] "HEAD / HTTP/1.1" 200 0 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; QQDownload 713; .NET CLR 2.0.50727; InfoPath.2)"
14.115.129.55 - - [21/Apr/2013:19:44:18 +0800] "GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1" 416 615 "http://yewen.us/" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)" 
14.115.129.55 - - [21/Apr/2013:19:44:22 +0800] "GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1" 416 615 "http://yewen.us/" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)" 
14.115.129.55 - - [21/Apr/2013:19:44:25 +0800] "GET /ftp/Win7_rtm_with_loader/cn_windows_7_professional_x86_dvd_x15-65790.iso HTTP/1.1" 416 615 "http://yewen.us/" "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729)"

终于搞定 Java 和 MySQL 连接问题

计划就是在元旦假期搞定数据库的大作业, 用 MySQL, 先用 Java 写个能用的界面出来, 如果有时间就去看看能不能把服务器上的首页弄成动态 JSP 的. 加油加油啦.

自己遇见的问题:
在 Java 下从数据库内读出中文显示有乱码, 最后调整一下编码格式就好了.

// String sname = rs.getString("sname");
String sname=new String(rs.getString("sname").getBytes("ISO-8859-1"),"GBK");

就是这里有问题, 从数据库内读出的东西要改变编码格式才能正确显示, 亏我弄了差不多一天来搞这个问题. 谢谢飞飞帮忙搞定 :)

还有一天多的时间, 有空就看看 JSP 然后看能不能搞定 MySQL 和 JSP 的连接, 反正 KO 他们都有做过, 估计能找到源码吧.