news 2026/10/22 5:25:21

Hexo部署到GitHub Pages避坑指南:SSH配置、分支管理与样式修复

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hexo部署到GitHub Pages避坑指南:SSH配置、分支管理与样式修复

接上一篇:本地博客已经能在localhost:4000跑起来了,但那是你自己电脑上的服务,别人访问不了。这一篇要解决的,就是把本地Hexo生成的静态页面推到GitHub,用GitHub Pages把博客公开到互联网上。所有工作围绕三个核心动作展开:配好SSH访问、创建一个公开仓库、在配置文件里写好部署目标。整个过程不算复杂,但里面有几个细节一旦写错,后果就是页面404或者样式全丢,而且报错信息还不太直观,排查起来很费时间。

我是在做这个步骤时踩过不少坑的,所以这篇会写得细一点,把操作步骤、配置文件里的每个字段、以及我当时排错的经验都写清楚。看完这篇,你就能顺利走通hexo clean && hexo g -d这条命令,把博客从本地搬到线上。

1. 部署前的准备工作:环境检查和SSH密钥配置

1.1 三条命令确认本地环境

我见过不少人在部署阶段卡住,最后发现是最基础的东西没装齐。所以第一步别急着建仓库,先在命令行里敲三条命令,确认环境没问题:

node -v git --version hexo version

三条命令分别看的是Node.js、Git、Hexo的版本。正常情况下都会有版本号输出,比如v20.11.0、git version 2.43.0这样的内容。如果哪条提示command not found,那就先补装对应的工具,别往下走。

检查完版本,还要确认两件事。

第一,你的Hexo项目目录结构是完整的。所谓“完整”,就是目录下能看到_config.yml、package.json、source、themes这几个关键文件或文件夹。这是Hexo项目的基本盘,缺一不可。

第二,确认主题已经生效。打开项目根目录下的_config.yml,找到theme:这一行,确认它写的是theme: fan,不是别的主题名。检查方法很简单:在项目目录跑hexo s,然后本地访问localhost:4000,如果页面显示的是你选定的主题样式,说明本地环境正常。这一步多花两分钟,能帮你把“部署后才暴露的样式问题”提前暴露在本地。

1.2 SSH密钥:一次配置长期受益

部署Hexo到GitHub,需要在本地和GitHub之间建立安全连接。我强烈建议直接用SSH协议,而不是HTTPS。原因有两个:

  • 用SSH推送时不需要每次输入用户名和密码,一条hexo d直接推完;
  • 用HTTPS方式推送,如果开了双重验证,GitHub密码就不好使了,还得额外生成personal access token,麻烦。

检查本地是否已经有SSH密钥,执行:

ls -al ~/.ssh

如果看到id_ed25519或id_rsa以及对应的.pub文件,说明之前生成过密钥。如果没看到,就执行下面的命令生成一对新的:

ssh-keygen -t ed25519 -C "你的邮箱"

执行过程中会问你保存路径和密码短语,直接一路回车即可。密码短语那一步不用填,填了的话以后推送还要输密码,反而违背了我们用SSH的初衷。

生成完成后,把公钥内容复制到剪贴板。在macOS上可以用pbcopy < ~/.ssh/id_ed25519.pub,Windows的话用type C:\Users\你的用户名\.ssh\id_ed25519.pub或者直接用文本编辑器打开复制。

然后登录GitHub,进入Settings→SSH and GPG keys→New SSH key,把公钥粘贴进去,Title随意,保存后执行验证:

ssh -T git@github.com

看到Hi 你的用户名! You've successfully authenticated, but GitHub does not provide shell access.就说明连接成功了。这一步是整个部署流程的“地基”,地基没打好,后面所有推送都会报权限错误。我见过有人把公钥和私钥搞混,也见过有人把私钥贴到GitHub上导致验证失败,注意.pub才是公钥,私钥(不带后缀的那个)永远不要给任何人。

2. 在GitHub上创建仓库与确定部署分支

2.1 仓库命名规则:用户页和项目页的区别

GitHub Pages提供了两种托管模式,理解这两种模式的区别,对你的仓库命名至关重要。

第一种叫用户页(User Page),仓库名必须是你的用户名.github.io。这是GitHub Pages的“特权仓库”,整个账号只能建一个,建好之后博客访问地址就是https://你的用户名.github.io,不需要加额外的路径,干净利落。我个人推荐用这种方式,因为博客地址最短,分享给别人时也不容易打错。

第二种叫项目页(Project Page),仓库名可以随便起,比如my-blog、hexo-blog,访问地址是https://你的用户名.github.io/仓库名/。如果你的GitHub账号下面还有别的项目要展示,或者你想把博客源码和别的repo区分开,可以选这种方式。不过要注意,使用项目页时,站点根路径会带上仓库名,后面配置root字段时稍不注意就会踩坑。

注意:仓库可见性必须设为Public。免费版账号的GitHub Pages不支持Private仓库,如果你选了Private,后面在Pages设置里根本找不到开启的选项。

创建仓库的时候,还有一个细节很多人忽略:GitHub会让你选择是否初始化README文件。这一步一定不要勾选,保持“空仓库”状态。原因很简单,如果GitHub帮你生成了一个带README的初始提交,你本地Hexo项目在推送时就会和远程仓库产生冲突,推送时还需要先git pull合并,白白增加操作复杂度。

2.2 分支选择:main还是master

这个问题看起来很小,但恰恰是初学者最容易搞混的地方。GitHub新建仓库时默认分支名是main,但在2020年之前创建的仓库默认分支是master,很多老教程里写的都是推到master分支。如果照抄老教程,你很可能把博客推送到了main分支上,但Pages配置里选的是master,最后页面直接404。

我的建议是在_config.yml的部署配置里明确写清楚分支名,统一用main。原因有两个:一是新仓库默认就是main,顺水推舟;二是以后不管谁接手你的博客,看配置就知道该去哪个分支看部署产物。

仓库建好之后,顺便打开仓库的Settings→Pages,在Branch区域选择main分支,根目录保持/(root)不变,然后保存。这一步不是必须提前做,但提前把页面托管的分支定下来,后续部署完就不会有“部署成功但无法访问”的困惑。更新的GitHub界面把部署分支选择放在了Pages设置页的Build and deployment区域,ensuring选择Deploy from a branch模式即可。

3. 修改配置文件:部署的核心三行

3.1 安装hexo-deployer-git插件

直接执行hexo d是不能把站点推送上去的,因为Hexo默认不带Git部署功能。需要在项目根目录下安装部署插件:

npm install hexo-deployer-git --save

这一步会下载部署插件并自动写入package.json依赖。建议安装命令带上--save参数,这样以后换电脑重新部署时,执行npm install就能一键恢复所有依赖。

安装完成后,可以用npm ls hexo-deployer-git确认插件是否正常安装。输出里能看到版本号说明安装成功。这里提醒一句:如果你用了某个“全家桶”主题或博客框架,主题文档里可能已经指定了你需要用的部署插件版本,以官方文档为准,避免版本冲突。

3.2 根目录_config.yml中的deploy配置

打开项目根目录下的_config.yml,找到deploy配置项。如果没有,就在文件末尾追加。核心配置如下:

deploy: type: git repo: git@github.com:你的用户名/你的用户名.github.io.git branch: main

逐行解释一下:

  • type: git告诉Hexo,部署方式使用Git;
  • repo是远程仓库的SSH地址,注意是git@github.com:开头的SSH格式,不是https://github.com/开头的HTTPS地址。如果用了HTTPS地址配合SSH密钥,Git依然会在推送时要求输入密码,等于白配了密钥;
  • branch: main指定推送目标分支,必须和你在GitHub Pages设置里选择的分支一致。

写完之后,建议用支持YAML语法检查的编辑器看一眼格式。YAML对缩进极其敏感,deploy:下面的子项目必须保持相同的缩进级别,混用Tab和空格也会导致解析失败。我见过最典型的错误是repo:前面多写了一个空格,结果Hexo启动时直接报“YAMLException”,半天找不到原因。

另外,_config.yml文件里还有一个url字段也特别重要,它默认是一串注释掉的示例,形如url: http://example.com。部署到GitHub Pages后,需要把它改成你的真实访问地址:

url: https://你的用户名.github.io

这个字段影响的不只是浏览器地址栏显示,更关键的是RSS订阅、sitemap插件、以及部分主题里的分享功能都会调用它生成绝对链接。如果不改,很可能会出现“文章内站内链接指向localhost”这种诡异问题,复制给别人的链接打不开,自己浏览器却显示正常。

3.3 主题与站点URL配置:确保页面样式不崩

接下来是部署环节最容易被忽略的一步:root路径配置。

root字段位于根目录_config.yml里,它的值取决于你在2.1节选择的仓库类型。

  • 如果仓库名是你的用户名.github.io(用户页),root直接写成/;
  • 如果仓库名是普通仓库名(项目页),root要写成/仓库名/。

这个字段的作用是告诉Hexo,站点资源(CSS、JS、图片)放在什么路径下面。HTML里加载CSS的路径就是由root拼接出来的。如果root配错,典型症状就是:页面文字和结构在,但所有样式全部丢失,纯文本裸奔在页面上。浏览器地址是https://你的用户名.github.io/repo-name/,CSS却指向了https://你的用户名.github.io/css/style.css,自然404。

这里再多说一句关于主题的配置。Fan主题(及其他绝大多数Hexo主题)自己也有一个_config.yml,位于themes/fan/_config.yml下。和部署直接相关的其实不多,但有几个地方值得检查:

  • 主题文件里的菜单链接、社交链接,如果写的是绝对路径,要确认引用了正确的url;
  • 主题内部如果有favicon、logo、avatar等图片设置,建议填写相对于root的路径,不要写成以盘符开头的本地路径;
  • 如果主题支持文章阅读量统计、评论系统等第三方服务,这些服务的站点地址也需要和线上域名一致。

有些主题在本地预览和线上部署后表现不一样,根本原因是本地预览时localhost:4000下页面路径和线上的平台路径不同。一个简单验证方法:在本地跑hexo s,按Ctrl+Shift+I打开开发者工具,看Console里有没有红色的404报错。如果本地没有报错但部署后样式崩了,九成是root的问题。

4. 执行部署:三行命令搞定

4.1 clean、generate、deploy的前后顺序

配置全部完成后,正式的部署命令非常简单,就三步:

hexo clean hexo generate hexo deploy

也可以连写:

hexo clean && hexo generate && hexo deploy

解释一下这三条命令分别做了什么,以及为什么顺序不能乱。

hexo clean会清除之前生成的静态文件缓存,具体来说是删除public目录和.db.json缓存文件。我在实际操作中强烈建议每次部署前都执行一次clean,因为如果你改过文章、换过主题、调整过配置文件,旧缓存可能导致线上出现“文章列表还是旧的”“分类页和标签页对不上”这类说不清的问题。clean之后一切从零开始,干净。

hexo generate是核心构建命令,它会读取source目录下的Markdown文章、主题模板、配置文件,最终生成完整的静态网站到public目录。你可以打开public目录看一下,里面就是纯粹的HTML/CSS/JS/图片文件,没有任何依赖Node.js的运行时逻辑,这正是静态博客的优势——部署到哪里都能跑,不需要服务器端动态执行。

hexo deploy则调用我们前面安装的hexo-deployer-git插件,把public目录里的所有文件推送到GitHub仓库的main分支。注意,它不是把整个Hexo项目推上去,只推public构建产物。所以你不用担心博客源码泄露出去,或者说,如果你希望源码也保存在GitHub上,需要另外单独处理,通常做法是给源码建一个独立仓库或独立分支。

部署命令执行后,终端会出现类似下面的输出:

INFO Deployed: https://你的用户名.github.io/

看到这行信息,说明推送成功。这时打开浏览器,访问你的GitHub Pages地址,如果一切正常,看到和本地一样的博客页面就大功告成了。我第一次部署成功后,终端提示Deployed,但浏览器打开却显示404,当时一头雾水,后来才意识到是GitHub Pages的构建和发布并非即时生效,需要等待一两分钟。

4.2 首次访问与日常更新流程

GitHub Pages的更新有个特点:部署不是秒级生效。即使hexo deploy已经成功推送,页面要过一两分钟才能刷新出最新内容。这是因为GitHub收到推送后需要重新构建并发布静态站点,首次部署等待时间尤其明显,有时候要等3到5分钟。我建议你部署完成后不要频繁刷新,去做点别的事,过几分钟再看。

日常更新的操作流程非常简单,每次写完新文章,只需要执行:

hexo clean && hexo generate && hexo deploy

也就是“清理一遍、重新生成、推到远程、等待生效”。这就是整套博客维护的全部日常操作。

我自己还有一个习惯:部署前先用hexo s本地预览一遍,确认新文章排版正确、分类标签没写错,再执行部署。虽然每次多花30秒,但能帮你把绝大多数问题拦截在本地。毕竟线上出了问题,要经历“发现问题→修改→重新部署→等生效”这个完整循环,至少5分钟,远不如本地预览来得快。

还有一个小细节:修改了配置文件或主题文件之后,很多人喜欢只执行hexo d或者只执行hexo g -d,不先clean。这种做法偶尔能成功,但一旦遇到“页面样式还是旧的”“新增的菜单没出现”这类现象,基本就是缓存惹的祸。与其花时间排查,不如老老实实全套三步走。你可以把命令定义成别名,比如在shell里写alias hd='hexo clean && hexo g -d',省得每次敲三遍。

5. 常见问题排查与避坑经验

5.1 权限报错与SSH调试

部署时最常见的报错是:

Permission denied (publickey). fatal: Could not read from remote repository.

看到这个提示,优先检查三处。

第一,确认SSH密钥是否在本地生效。执行ssh -T git@github.com,如果显示的是“Permission denied”而不是“You've successfully authenticated”,说明密钥没有被Git使用。Windows用户常遇到这个问题,因为系统自带的ssh-agent服务没有启动,或者没有把私钥添加进去:

eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519

macOS用户如果在钥匙串访问里找不到SSH密钥,也可以执行同样的命令手动注册。

第二,确认密钥文件权限没问题。我自己有一次在Linux服务器上部署时,发现私钥文件权限太开放,Git直接拒绝使用。需要把私钥权限收紧:

chmod 600 ~/.ssh/id_ed25519

这个操作在macOS和Linux上尤其重要,Windows用户通常通过界面勾选的路径不容易出现权限问题。

第三,确认GitHub账户里添加的是公钥,不是私钥。公钥以.pub结尾,内容是一长串字符,开头一般是ssh-ed25519或ssh-rsa。私钥的内容看起来类似,但没有.pub后缀,而且在创建时可能还包含类似“BEGIN OPENSSH PRIVATE KEY”的字样。两者长得很像,但功能和保密级别完全不同。

5.2 页面404或样式丢失的排查

部署成功但页面打不开,这是第二类高频问题。整理成表格方便对照排查。

现象原因解决办法
访问主页404Pages设置里的分支不对确认Settings→Pages里的分支是main
首次部署后短时间404GitHub Pages构建有延迟等待3~5分钟再刷新
文章页能开,但CSS/JS全部失效root路径配置错误按仓库类型设置root: /或/仓库名/
页面能显示,但图片裂开图片路径用了盘符或相对路径在文章中使用/图片名.jpg或![](图片名)的相对格式
页面文字正常,菜单点击后404分类/标签页路由路径和主题不匹配检查主题文档,确认menu路径配置正确

样式丢失这个问题值得展开说一下。它的本质是浏览器按root拼接出的静态资源URL和实际部署位置对不上。排查方法是:打开浏览器开发者工具,切到Network或Console,找到加载失败的CSS请求,看看它请求的完整URL,再对比真实的CSS文件地址。只要这一步能定位到URL差异,解决起来就很直接——改root配置,重新clean && g -d。

很多人会忽略的另一个点:浏览器缓存。部署完成后,即使线上页面已经更新,浏览器可能还在用本地缓存的旧CSS和旧HTML。尤其是那些“我在线上一看明明一切正常,但手机上就是旧页面”的情况,几乎都是这个原因。解决办法有两个:强制刷新(Ctrl+F5或Cmd+Shift+R),或用无痕模式打开验证。记住判断原则:如果无痕窗口能看到新页面,问题就在浏览器缓存,不是部署问题。

5.3 部署流程中的其他坑

再分享几个我实际遇到过、且不太容易搜到答案的问题。

第一个坑:fatal: repository not found。仓库名和用户名拼错、仓库还没创建、或者用了不存在的仓库地址,都会报这个错。解决办法很简单,检查_config.yml中repo的SSH地址和实际仓库名是否一致。注意GitHub用户名的大小写并不影响SSH地址,但仓库名的大小写是敏感的,最好直接复制仓库页面的SSH地址,不要手打。

第二个坑:部署完成后,GitHub仓库里能看到提交,但提交人是“noreply”地址。这是因为GitHub把用户的邮箱地址用隐私代理代替了。如果介意,可以在本地设置Git的用户信息:

git config --global user.name "你的用户名" git config --global user.email "你的邮箱"

或者单独在Hexo项目目录里设置局部用户信息,避免影响全局配置。

第三个坑,也很隐蔽:public目录被提交到了源码仓库。有些刚开始玩Git的读者,喜欢把整个博客目录都git add并推送到GitHub,结果public目录也被一起提交了。由于部署插件每次部署都会重新生成public内容并强制推送,在源码仓库里出现public目录会造成不必要的混乱。解决方法是回到项目根目录,编辑.gitignore文件,确认里面包含public/这一行。这样源码仓库就不会跟踪构建产物了。

第四个坑:个别主题需要额外的部署后操作。比如有些主题依赖搜索索引文件或JSON数据文件,需要在部署前先执行对应的生成命令。Fan主题在这类需求上比较常规,但如果你日后换用其他主题,记得看主题文档的“部署前需要做什么”章节,别只盯着通用部署流程。

还有一个我折腾过很久的点:CNAME自定义域名。如果你手里有自定义域名,比如blog.example.com,需要在仓库的设置里配置自定义域名,并且在source目录下放一个名为CNAME的文件,内容只写你的域名。这样每次部署时,CNAME文件都会被自动带进public目录,推送到线上,自定义域名才不会因为部署更新而丢失。这个文件放在source/CNAME下,不要手动放到public里,因为public每次生成都会被清空重来。

到这儿,Hexo加GitHub Pages的部署流程就算完整走通了。整个过程核心就一句话:把本地生成的静态页面推到GitHub指定仓库的指定分支,再让GitHub Pages把这个分支托管为网站。SSH密钥、仓库分支、_config.yml里的deploy和root配置是四个关键控制点,只要这四个点没有搞混,部署基本不会出大问题。

我在实际部署中最大的体会是:不要急着追求自动化部署那些“高级操作”,先把最基础的手动流程跑通。手动流程能稳定复现之后,你再去做“在服务器上自动构建、利用Webhook触发部署”这些进阶操作,会顺手很多。手动部署是地基,自动化是锦上添花。下一篇我打算写一些进阶的玩法,比如如何用GitHub Actions实现“推文章自动部署”,以及多设备之间如何同步博客源码,这些都是基于你已经手动部署成功、并且理解了这套机制之后才能顺畅上手的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 5:25:17

AI驱动接口自动化测试:用例生成、智能断言与失败排查落地实践

最近总有人问我&#xff0c;能不能用AI把接口自动化测试的活儿给干了。我试了半年&#xff0c;结论是可以的&#xff0c;但前提是你要先搞清楚AI在这条流水线里到底该站在哪个位置。不讲那些听上去很玄的Agent&#xff0c;就聊怎么用AI来实现API接口自动化测试——从用例生成、…

作者头像 李华
网站建设 2026/10/22 5:25:04

人工智能期末作业从选型到交付的完整避坑指南

简介&#xff1a;面向人工智能课程期末综合大作业与课程作业场景&#xff0c;这份资料包整合了深度学习、经典智能优化算法&#xff08;BP、CNN、PSO、ACO、GA&#xff09;以及搜索算法&#xff08;BFS、DFS、A*&#xff09;的完整源码与说明文档&#xff0c;适合计算机相关专业…

作者头像 李华
网站建设 2026/10/22 5:25:00

AI审计管线处理908K tokens仓库的崩溃与分块改造实践

1. 一次意料之外的管线崩溃那天下午&#xff0c;我像往常一样把刚跑通的 AI 审计管线指向了一个真实开源仓库。在此之前&#xff0c;它已经在十几个中小型项目上表现稳定&#xff0c;单次分析耗时控制在几分钟以内&#xff0c;输出报告的质量也让我比较满意。然而这一次&#x…

作者头像 李华
网站建设 2026/10/22 5:24:49

从单体Agent到多智能体协作:架构演进与设计实践

1. 从单体机器人到协作生态&#xff1a;先聊聊这轮演进的背景先说结论&#xff1a;Clawdbot和Moltbook并不是什么商业产品&#xff0c;而是我自己在一系列模拟项目里逐步迭代出来的两代智能体系统代号。Clawdbot代表的是最早期的、单打独斗的机器人形态&#xff0c;Moltbook则是…

作者头像 李华
网站建设 2026/10/22 5:24:38

Redis GEO底层原理与自定义数据类型:从附近门店实战到Modules扩展

前阵子帮某本地生活平台排查一个“附近门店”功能的性能问题&#xff0c;当年几百万个门店坐标放在关系型数据库里&#xff0c;每次按距离排序都要扫一遍全表&#xff0c;接口响应直接飙到 3 秒开外。最终方案落到了 Redis 的 GEO 类型上——这也是我第二次在真实项目里大规模用…

作者头像 李华
网站建设 2026/10/22 5:23:33

运维测试开发内卷严重,网络安全人才缺口大:如何转型入行

你还在卷运维测试开发&#xff1f;网络安全连卷的人都没有&#xff01;最近跟几个在不同公司做技术的朋友聊天&#xff0c;聊来聊去都绕不开同一个话题&#xff1a;现在搞运维和测试开发&#xff0c;怎么就这么卷&#xff1f;岗位要求一年比一年高&#xff0c;简历投出去石沉大…

作者头像 李华