Hexo博客迁移及自动化部署指南:从踩坑到成功
Hexo博客迁移及自动化部署指南:从踩坑到成功
Lasuy最近将我的 Hexo 博客迁移到了一台新服务器上。在这个过程中,虽然基本流程都懂,但在权限配置、SSH 端口等方面还是踩了一些小坑。特此记录下完整的迁移与自动化部署过程,希望能帮到有同样需求的朋友。
1. 迁移背景
- 旧服务器环境:常规配置,使用 Git 钩子自动部署。
- 新服务器环境:安装了宝塔面板 (BT-Panel),修改了默认 SSH 端口,网站目录托管在宝塔的
wwwroot下。 - 目标:实现本地在 VS Code 中写完文章后,执行
hexo d即可一键推送到新服务器,并自动更新网站目录。
2. 服务器端配置
部署的核心思想是利用 Git 的裸仓库(Bare Repository)接收本地推送的代码,然后通过 post-receive 钩子脚本将代码自动检出(checkout)到 Nginx/宝塔 的网站根目录。
2.1 创建 Git 用户及 SSH 密钥
为了安全,最好不要直接用 root 用户接收 Git 推送,我们创建一个专门的 git 用户。
1 | # 使用 root 登录服务器 |
2.2 创建裸仓库
在 git 用户的家目录下创建一个裸仓库,用来接收代码。
1 | mkdir -p ~/repos |
2.3 编写 Git 钩子 (Hook)
进入刚刚创建的裸仓库的 hooks 目录,编写自动化脚本。
1 | cd ~/repos/taiblog.git/hooks |
在文件中填入以下内容。注意:--work-tree 的路径必须是你的实际网站根目录。
1 |
|
赋予脚本执行权限:
1 | chmod +x post-receive |
2.4 【踩坑点】目录权限与路径大小写
这是迁移过程中最容易出错的地方。
坑点 1:路径大小写严格区分
Linux 系统对路径大小写是敏感的。如果在配置 Git 钩子时,将 /www/wwwroot/blog.Lasuy.cn 错写成全小写的 blog.lasuy.cn,会导致 git checkout 失败或检出到错误的目录,表现为本地提示 Deploy done,但服务器页面死活不更新。
坑点 2:目录权限问题
如果在本地执行 hexo d 时遇到类似 remote: error: unable to unlink old '...': Permission denied 的报错,100% 是权限问题。
因为网站目录通常是由 root 或 www 创建的,而我们推送代码使用的是 git 用户,导致 git 用户没有权限向该目录写入或删除文件。
解决方法:切换回 root 用户,强制修改网站目录的所有权,并确保路径拼写完全正确。
1 | # 切换回 root |
3. 本地 Hexo 配置
服务器端配置好后,回到本地项目,修改 _config.yml 文件中的 deploy 字段。
3.1 【踩坑点】非标准 SSH 端口
因为我的新服务器修改了 SSH 端口为 996(为了防爆破),所以不能使用默认的 git@IP:/path 格式,否则会报 Connection timed out。
必须改用 ssh:// 协议,并在 IP 后加上端口号:
1 | deploy: |
4. 部署测试
一切配置妥当后,在本地终端执行:
1 | hexo clean |
当你看到类似下面的输出时,说明部署大功告成:
1 | Enumerating objects: 229, done. |
现在,刷新你的浏览器,就能看到最新的博客内容了!
5. 进阶:配置 SSH 免密推送
每次部署都需要输入密码非常繁琐,配置 SSH 免密推送可以实现真正的“一键部署”。
5.1 获取本地公钥
在本地电脑终端执行以下命令,查看你的 SSH 公钥(通常是 id_rsa.pub 或 id_ed25519.pub):
1 | # Windows 环境下查看公钥 |
复制输出的那一大串以 ssh-ed25519 或 ssh-rsa 开头的字符串。
5.2 将公钥配置到服务器
登录服务器,切换到 git 用户,将公钥写入到授权文件中:
1 | # 切换到 git 用户 |
保存退出后,在本地再次执行 hexo deploy,就不会再提示你输入密码了,丝滑推送!
总结
Hexo 的 Git 部署本质上就是一次 SSH 推送 + 服务器本地文件复制。遇到报错时,重点排查三点:
- 网络/端口连通性(Connection timed out):检查安全组、防火墙和 SSH 端口配置。
- 文件权限(Permission denied):检查
git用户对目标work-tree目录是否有读写权限。 - 路径大小写(部署成功但页面不更新):Linux 严格区分大小写,检查宝塔面板中的目录名与 Git 钩子脚本中的
--work-tree路径是否完全一致。
希望这篇文章能帮你避开这些坑,享受丝滑的写作体验。








