这篇笔记完整记录了我把一个本地 Hugo 博客部署到 VPS 的全过程,包括:
- 本地 Hugo 模板初始化与基础配置
- GitHub 仓库与 Actions 自动部署
- VPS 上的目录规划与 Nginx 配置
- 域名解析与 HTTPS 证书申请
- 常见问题排查
- 这个过程中经常使用的命令与含义
最终实现的效果是:本地写文章并提交到 GitHub 后,GitHub Actions 自动构建静态站点并发布到 VPS,网页内容自动更新。
一、目标与整体思路
我想实现的目标非常明确:
- 在本地维护 Hugo 博客内容
- 通过
git push将更新提交到 GitHub - GitHub Actions 自动构建 Hugo 站点
- 将生成后的静态文件自动同步到 VPS
- 由 Nginx 直接对外提供网页服务
- 配置 HTTPS,让
phyweicheng.com和www.phyweicheng.com都可以安全访问
整个流程可以概括为:
| |
二、本地 Hugo 模板部署
1. 准备 Hugo 博客项目
首先需要在本地准备一个 Hugo 项目。我这里使用的是 Hugo Theme Stack 模板,并保留了标准的 Hugo 目录结构,例如:
| |
其中最关键的是:
content/:文章内容config/:站点配置.github/workflows/:GitHub Actions 自动部署配置
2. 设置生产站点地址
在 Hugo 中,生产站点的域名需要通过 baseurl 指定。我在配置文件中设置为:
| |
对应文件:
这个值非常重要,因为 Hugo 在构建时会根据它生成页面中的链接、资源路径和 canonical URL。
3. 保持 public/ 不提交到仓库
Hugo 构建后的静态文件默认输出到 public/。这部分不需要提交到 GitHub,而是交给 GitHub Actions 自动构建。
因此 .gitignore 中应当忽略:
| |
这样可以避免把编译产物混入源码仓库。
三、将博客与 GitHub 仓库连接
1. 初始化 Git 仓库并提交
如果项目还没有连接 GitHub,基本流程如下:
| |
完成后,本地博客项目就与 GitHub 仓库建立了连接。
2. 为什么要用 GitHub Actions
这里没有选择“在 VPS 上直接 git pull 并构建 Hugo”,而是选择让 GitHub Actions 来完成构建,原因是:
- VPS 不需要安装 Hugo
- VPS 不需要保留完整源码仓库
- 构建过程统一由 GitHub 执行,结果更稳定
- VPS 只保存最终静态文件,更适合静态站点部署
四、配置 GitHub Actions 自动部署
1. 自动部署工作流的目标
自动部署的核心思路是:
- 当
main分支收到新的提交 - GitHub Actions 自动运行 Hugo 构建
- 将构建好的静态文件打包
- 通过 SSH 上传到 VPS
- 在 VPS 上解压并切换到最新版本
2. 工作流文件位置
自动部署工作流文件放在:
这个工作流主要做了下面几件事:
- checkout 当前仓库
- 安装 Go
- 安装 Hugo Extended
- 执行
hugo --gc --minify - 将
public/打成压缩包 - 使用
appleboy/scp-action上传到 VPS - 使用
appleboy/ssh-action在 VPS 上切换部署版本
3. 为什么要用 releases 和 current
在 VPS 上,我采用了这样的目录结构:
| |
每次发布都会:
- 生成一个新的版本目录
- 把静态文件解压进去
- 将
current软链接切换到新版本
这种方案的好处是:
- 发布过程清晰
- 方便回滚
- Nginx 永远读取固定路径
current
五、配置 GitHub Actions 所需 Secrets
在 GitHub 仓库中进入:
| |
然后新增或确认以下 Repository secrets:
1. VPS_IP
VPS 的公网 IP 地址。
2. VPS_USER
GitHub Actions 登录 VPS 时使用的 Linux 用户名。
如果直接使用 root 登录,可以写:
| |
3. VPS_PORT
SSH 登录端口。如果服务器 SSH 不是默认的 22,这里需要填实际端口,例如:
| |
4. VPS_DEPLOY_PATH
站点部署目录,例如:
| |
5. SSH_PRIVATE_KEY
GitHub Actions 用于连接 VPS 的私钥内容。通常需要把本地或服务器生成的一对 SSH 密钥中的私钥完整粘贴到这里。
六、VPS 上的目录准备
1. 创建部署目录
如果使用 root 部署,可以直接执行:
| |
如果使用普通用户,例如 deploy,则应改为:
| |
2. 检查 SSH 连通性
在正式自动部署前,最好先确认 GitHub 与 VPS 的 SSH 连通已经打通。
如果 GitHub Actions 能顺利执行远程命令,说明:
VPS_IP正确VPS_USER正确SSH_PRIVATE_KEY正确VPS_PORT正确
七、配置 Nginx 站点
1. 站点配置文件
我的 VPS 没有使用 sites-available / sites-enabled 结构,因此采用了 conf.d 的方式。
配置文件路径:
| |
2. 初始 HTTP 配置
在申请证书之前,先配置 HTTP 站点:
| |
保存后执行:
| |
只要域名已经解析到 VPS,这时就应该能通过 HTTP 访问网页。
八、域名解析配置
为了让两个域名都能访问,需要在域名服务商后台配置 DNS 解析。
推荐至少配置两条 A 记录:
| |
含义如下:
@表示裸域phyweicheng.comwww表示www.phyweicheng.com
如果只配置了 www,那么通常只有 www.phyweicheng.com 可以访问,而 phyweicheng.com 无法访问。
九、申请 HTTPS 证书
1. 安装 Certbot
我的系统是 Debian,因此安装方式如下:
| |
2. 申请两个域名的证书
执行:
| |
这个命令会完成以下工作:
- 申请 Let’s Encrypt 证书
- 自动修改 Nginx 配置
- 为
phyweicheng.com和www.phyweicheng.com绑定证书 - 可选开启 HTTP 到 HTTPS 的自动跳转
3. 证书申请后检查
申请完成后,可以执行:
| |
如果能看到:
fullchain.pemprivkey.pem
说明证书已经生成成功。
十、HTTPS 访问失败时的一个真实问题
在本次部署过程中,曾经出现过一个很典型的问题:
- 证书申请成功
- Nginx 配置正常
- 但浏览器访问
https://www.phyweicheng.com仍然失败
最后排查发现,并不是证书有问题,而是:
| |
通过以下命令可以检查是谁占用了 443:
| |
如果看到是 xray 而不是 nginx,就说明 HTTPS 请求没有交给 Nginx 处理。
解决方法是:
- 修改 xray 配置,将其监听端口从
443改到其他端口,例如8443 - 在客户端同步修改 xray 端口
- 放行新的端口,例如
8443 - 重新启动 xray 和 nginx
相关命令例如:
| |
十一、自动续期是否会生效
只要使用的是 Debian 上标准安装的 certbot,通常会自动配置续期机制。
可以通过以下命令检查:
| |
它们的作用分别是:
- 查看是否存在 Certbot 定时任务
- 查看续期定时器是否已启用
- 模拟一次证书续期,确认自动续期链路没问题
十二、首次上线后的完整发布流程
当以上步骤全部完成后,后续每次更新博客的流程就非常简单:
1. 在本地修改文章或页面
例如新建文章、修改配置、调整样式等。
2. 本地测试 Hugo
| |
或者正式构建检查:
| |
3. 提交到 GitHub
| |
4. GitHub Actions 自动执行部署
推送成功后,GitHub 会自动:
- 构建 Hugo 站点
- 上传
public/产物到 VPS - 切换
current到最新版本
5. Nginx 自动提供新内容
因为 Nginx 的 root 始终指向:
| |
所以网站内容会自动更新,不需要登录 VPS 手动 git pull 或手动复制文件。
十三、常见问题总结
1. GitHub Actions checkout 失败
可能原因:
- 主题目录存在残留 submodule 信息
- 仓库里有 gitlink,但没有
.gitmodules
解决思路:
- 不依赖错误的 submodule checkout
- 改用 Hugo module 的方式引入主题
2. phyweicheng.com 能否访问取决于 DNS
如果只有 www.phyweicheng.com 能访问,通常是因为只解析了 www,没有解析裸域 @。
3. https:// 无法访问但 http:// 正常
重点检查:
- Nginx 是否监听
443 - 443 是否被其他程序占用
- 防火墙是否放行
443 - 云厂商安全组是否放行
443
4. xray 改端口后仍然无法连接
重点检查:
- xray 是否真的监听了新端口
ufw和云安全组是否放行新端口- 客户端端口是否同步修改
十四、这个过程中常用的命令汇总
下面把整个部署过程中最常用的命令整理一下。
1. Git 相关
| |
将当前修改加入暂存区。
| |
生成一次本地提交记录。
| |
将本地提交推送到 GitHub 的 main 分支,并触发自动部署。
2. Hugo 相关
| |
在本地启动开发服务器,方便预览博客效果。
| |
执行正式构建:
--gc:清理无用缓存和资源--minify:压缩输出内容
3. Nginx 相关
| |
检查 Nginx 配置语法是否正确。
| |
平滑重载 Nginx 配置,不中断服务。
| |
重启 Nginx 服务,适合在重大配置变化后使用。
4. Certbot 相关
| |
为两个域名申请证书,并自动写入 Nginx HTTPS 配置。
| |
模拟续期,验证自动续期逻辑是否正常。
5. 端口与服务排查
| |
检查谁正在监听 443 端口。
| |
查看 Nginx 当前状态。
| |
查看 xray 当前状态。
| |
查看 xray 最近的日志,便于定位启动失败和配置错误。
6. 防火墙相关
| |
查看当前防火墙规则。
| |
分别放行 HTTP、HTTPS 和 xray 的自定义端口。
| |
重新加载防火墙规则。
7. 证书文件检查
| |
确认证书目录和文件是否存在。
十五、总结
这次部署的关键点并不只是“把网页放上去”,而是把整套链路打通:
- 本地负责内容维护
- GitHub 负责自动构建与自动发布
- VPS 负责稳定托管静态文件
- Nginx 负责网站访问
- Certbot 负责 HTTPS
当这套流程跑通以后,博客维护就会轻松很多。以后更新文章时,只需要:
| |
剩下的构建、上传、切换版本、网页更新,都会自动完成。
如果以后继续扩展,还可以在这套基础上增加:
- 评论系统
- 访问统计
- 备份与回滚脚本
- 多环境部署
- 自动化健康检查
但对于一个 Hugo 静态博客来说,这样的部署方案已经足够稳定、清晰,也非常适合长期维护。
