作为一个写了两年博客的 “半吊子技术人”,我之前一直把 Hexo 搭在 Ubuntu Server 上 —— 虽然能跑,但每次更新主题、升级插件都要 ssh 连服务器,改配置怕崩,备份怕漏文件,久而久之成了 “不敢动的遗产项目”。直到朋友说 “试试 Docker 吧,容器化后维护能省一半心”,我才咬咬牙开启了这场 “痛并快乐着” 的迁移之旅。​

一、迁移前的小忐忑:先理清楚 “要带什么走”​

迁移的第一步,我就犯了 “选择困难症”:Hexo 目录里那么多文件,哪些是必须带走的?总不能把整个文件夹一股脑复制吧?​
翻了半天教程,才确定核心要备份的是这几样(后来证明少一个都不行):​
source/:所有 markdown 博客文章,这是 “命根子”;​
themes/:我折腾了好久的 Butterfly 主题配置,丢了要哭;​
_config.yml 和主题目录下的 _config.next.yml:所有个性化设置;​
package.json 和 package-lock.json:依赖清单,没这个后续装插件会崩。​
于是在原服务器上执行备份命令时,我手都是抖的(怕漏文件):​
​

进入原Hexo目录​

1
cd /home/hexo/my-blog​

打包核心文件(特意排除了node_modules,体积太大)​

1
tar -zcvf hexo-backup.tar.gz source/ themes/ _config.yml _config.next.yml package*.json​

接着用 scp 把压缩包传到新主机,看着进度条走满 100%,才松了第一口气 —— 但没想到,真正的坑还在后面。​

二、Docker 配置:从 “照抄教程” 到 “报错连连”​

新主机上我先按教程装了 Docker 和 Docker Compose,一切顺利。然后想把 Hexo 文件整理得整齐点,就建了个blog/二级目录,把备份文件解压进去,目录结构变成这样:​

hexo-docker/​
├── docker-compose.yml # 待写​
├── Dockerfile # 待写​
├── .dockerignore # 待写​
└── blog/ # Hexo核心文件​
├── source/​
├── themes/​
└── 其他配置文件​

坑 1:镜像拉取时的 “401 Unauthorized”​
按照之前的教程写了 Dockerfile(基础镜像用node:lts-alpine)和 docker-compose.yml,第一次执行docker-compose up -d --build时,终端突然跳红:
​
​ ERROR: pull access denied for node:lts-alpine, repository does not exist or may require 'docker login': denied: requested access to the resource is denied​ ​

我当时懵了:Docker Hub 的镜像怎么会 “未授权”?难道是我没登录?赶紧执行docker login输了账号密码,结果还是报错。查了半小时才发现,原来新主机的网络默认走公司代理,Docker 没配置代理导致拉取失败。​
解决办法也简单:给 Docker 加代理配置(如果是国内网络,换国内镜像源更方便):​
​

编辑Docker配置文件​

1
sudo nano /etc/docker/daemon.json​

加入代理地址(换成自己的):​
​
{​
“proxies”: {​
“default”: {​
“httpProxy”: “http://192.168.1.100:8080",​
“httpsProxy”: “http://192.168.1.100:8080"​
}​
}​
}​
​
重启 Docker 后再拉取,终于看到了熟悉的 “Pull complete”。​
坑 2:npm install 的 “enoent”错误,差点以为文件丢了​
镜像拉取成功,以为接下来会顺利,结果又卡在npm install步骤,报错:​
​ npm ERR! enoent ENOENT: no such file or directory, open '/app/package.json'​ ​
我当时冷汗都下来了:难道备份时漏了 package.json?赶紧去blog/目录下看 —— 文件明明在啊!再仔细看 docker-compose.yml 的 volumes 映射,才发现自己犯了低级错误:把./blog/package.json:/app/package.json写成了./blog/package.json:/app/package-lock.json,路径对应错了!​
改对 volumes 配置后,npm install还是报错,这次是 “权限不足”。原来宿主机的blog/目录权限是700,容器内无法读取。执行chmod -R 755 ./blog后再试,终于看到“added 1234 packages”的提示,我差点拍桌子欢呼。​
坑 3:“hexo: not found”—— 最让人崩溃的 “命令失踪案”​
解决了依赖问题,新的报错又来了:​
​
RUN hexo generate: /bin/sh: 1: hexo: not found​ ​

Hexo 命令怎么会找不到?我明明在 Dockerfile 里写了npm install -g hexo-cli啊!反复检查 Dockerfile,没发现问题;进入容器执行hexo -v,果然提示 “command not found”。​
后来在论坛看到有人说 “宿主机的 node_modules 会覆盖容器内的依赖”,我才想起:备份时虽然没打包 node_modules,但之前解压后手动复制过旧的 node_modules 到blog/目录!容器启动时,./blog/node_modules:/app/node_modules的映射把容器内新安装的 hexo-cli 覆盖了。​
赶紧删除宿主机blog/目录下的 node_modules:​
​

1
rm -rf ./blog/node_modules​

重新构建容器,这次hexo generate终于成功执行,看到 “Start processing” 的日志时,我长舒一口气 —— 折腾了 3 小时,终于看到希望了。​

三、成功启动:当浏览器加载出博客的那一刻​

最后执行docker-compose up -d,用docker ps看到hexo-blog容器状态是 “Up”,赶紧在浏览器输入http://新主机IP:4000—— 熟悉的博客首页慢慢加载出来,标题栏还是我去年改的 “小站”,侧边栏的阅读统计也还在。​
那一刻突然觉得之前的折腾都值了:现在要更新博客,只需在宿主机blog/source/_posts/里写文章,执行docker exec -it hexo-blog hexo generate就能生效;要备份,直接打包hexo-docker/目录就行,再也不怕漏文件;甚至想换服务器,把整个目录复制过去,docker-compose up -d就能一键启动。​

四、迁移后的小感悟:技术成长就是 “踩坑填坑”​

这次迁移让我明白,“容器化” 不是 “高大上的名词”,而是真真切切能解决问题的工具。过程中虽然踩了不少坑 —— 镜像拉取失败、文件映射错误、命令失踪,但每解决一个问题,都对 Docker 的 “文件映射”“镜像构建” 理解更深一层。​
如果你也想把 Hexo 迁到 Docker,别害怕报错:遇到问题时,先看日志(docker-compose logs -f是神器),再搜关键词,大部分坑前人都踩过。当你终于看到博客在容器里跑起来的那一刻,那种成就感,比写一篇博客还让人开心。​
最后放一张容器成功运行的截图,纪念这次 “历险记”:​
(此处可插入 docker ps 或博客首页截图)​
未来,我还想试试给博客加 HTTPS、用 Nginx 反向代理,技术之路漫漫,慢慢折腾吧~