VitePress 博客自动部署到 ECS:GitHub Actions + Nginx 完整实践
更新: 5/26/2026字数: 0 字 时长: 0 分钟
项目背景
我的博客项目是基于 VitePress 搭建的静态站点。项目构建后会生成纯静态文件,最终产物目录是:
docs/.vitepress/dist之前站点可以部署到 GitHub Pages、EdgeOne Pages 这类平台,但如果想拥有更高的可控性,比如自定义 Nginx 配置、部署多个项目、统一管理服务器资源,那么部署到 ECS 是一个比较合适的选择。
本次目标是:
代码 push 到 GitHub
→ GitHub Actions 自动构建
→ 上传静态产物到 ECS
→ Nginx 通过 blog.xxx.com 提供访问整体架构
一、ECS 准备目录
先在 ECS 上创建博客部署目录:
sudo mkdir -p /var/www/blog如果 GitHub Actions 使用 root 用户 SSH 登录,可以保持默认权限。 如果使用普通用户,比如 deploy,需要授权:
sudo chown -R deploy:deploy /var/www/blog本次使用的部署目录是:
/var/www/blog二、安装 rsync
GitHub Actions 后面会通过 rsync 把构建产物同步到 ECS。
检查是否安装:
rsync --version如果提示:
rsync: command not found说明没有安装。
CentOS / Alibaba Cloud Linux / RHEL 系统使用:
sudo yum install rsync -y安装完成后再次确认:
rsync --version三、配置 Nginx
当前项目使用独立子域名:
blog.xxx.comVitePress 配置里的 base: "/" 不需要修改,因为它适合部署在独立域名或子域名根路径下。
在 /etc/nginx/nginx.conf 的 http {} 中添加博客站点配置:
server {
listen 80;
listen [::]:80;
server_name blog.xxx.com;
root /var/www/blog;
index index.html;
location / {
try_files $uri $uri.html $uri/ /404.html;
}
location /assets/ {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, immutable";
}
location = /index.html {
add_header Cache-Control "no-cache";
}
error_page 404 /404.html;
}这里最关键的是:
try_files $uri $uri.html $uri/ /404.html;因为 VitePress 开启了 cleanUrls: true 后,访问路径可能是:
/column/React/index但真实文件是:
/column/React/index.html所以 Nginx 需要尝试匹配 .html 文件,否则文章页刷新可能 404。
检查配置:
sudo nginx -t重载 Nginx:
sudo systemctl reload nginx四、配置 DNS
在域名控制台添加一条 A 记录:
类型:A
主机记录:blog
记录值:ECS 公网 IP配置后访问:
http://blog.xxx.com如果 ECS 安全组没有开放 80 端口,也需要在云服务器控制台放行:
80
22
443五、准备 SSH Key
GitHub Actions 需要通过 SSH 登录 ECS。建议单独生成一把部署专用密钥,不要使用个人常用私钥。
生成密钥的本质是:GitHub Actions 拿到私钥,ECS 存入公钥。因此,在哪台机器上生成都可以,这里提供两种常见方式,任选其一即可:
方式一:在 ECS 服务器上生成(推荐,操作最连贯)
因为你现在可能正好连着 ECS,直接在服务器上生成会更顺手。
在 ECS 终端执行:
ssh-keygen -t ed25519 -C "github-actions-ecs-deploy" -f ~/.ssh/ecs_deploy直接将公钥追加到授权列表:
cat ~/.ssh/ecs_deploy.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys查看私钥内容(准备下一步复制给 GitHub):
cat ~/.ssh/ecs_deploy(可选安全建议:把私钥复制到 GitHub Secrets 后,可以执行 rm ~/.ssh/ecs_deploy 将其从 ECS 上删除,更符合安全规范)
方式二:在本地电脑生成(最符合安全规范)
在本地生成,私钥永远不会出现在 ECS 上。以 Windows PowerShell 为例:
ssh-keygen -t ed25519 -C "github-actions-ecs-deploy" -f "$env:USERPROFILE\.ssh\ecs_deploy"生成两个文件:ecs_deploy(私钥)和 ecs_deploy.pub(公钥)。
查看公钥内容:
Get-Content "$env:USERPROFILE\.ssh\ecs_deploy.pub"把复制的公钥追加到 ECS 中:
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "这里粘贴刚才复制的公钥内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys查看私钥内容(准备下一步复制给 GitHub):
Get-Content "$env:USERPROFILE\.ssh\ecs_deploy" -Raw本机测试 SSH 是否能登录 ECS:
ssh -i "$env:USERPROFILE\.ssh\ecs_deploy" root@你的ECS公网IP能登录说明密钥配置成功。
六、配置 GitHub Secrets
进入 GitHub 仓库:
Settings
→ Secrets and variables
→ Actions
→ New repository secret添加以下变量:
ECS_HOST ECS 公网 IP
ECS_USER root 或 deploy
ECS_PORT 22
ECS_PATH /var/www/blog
ECS_SSH_KEY 上一步获取的私钥完整内容复制私钥时必须包含:
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----七、编写 GitHub Actions
新增文件:
.github/workflows/deploy-ecs.yml内容如下:
name: Deploy VitePress to ECS
on:
push:
branches: ["main"]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ecs
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
env:
ECS_HOST: ${{ secrets.ECS_HOST }}
ECS_USER: ${{ secrets.ECS_USER }}
ECS_PORT: ${{ secrets.ECS_PORT }}
ECS_PATH: ${{ secrets.ECS_PATH }}
ECS_SSH_KEY: ${{ secrets.ECS_SSH_KEY }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build VitePress site
run: pnpm run build
- name: Setup SSH
run: |
mkdir -p ~/.ssh
printf '%s\n' "$ECS_SSH_KEY" > ~/.ssh/ecs_key
chmod 600 ~/.ssh/ecs_key
ssh-keyscan -p "$ECS_PORT" "$ECS_HOST" >> ~/.ssh/known_hosts
- name: Ensure remote directory
run: |
ssh -i ~/.ssh/ecs_key -p "$ECS_PORT" "$ECS_USER@$ECS_HOST" "mkdir -p '$ECS_PATH'"
- name: Deploy to ECS
run: |
rsync -az --delete \
-e "ssh -i ~/.ssh/ecs_key -p $ECS_PORT" \
docs/.vitepress/dist/ \
"$ECS_USER@$ECS_HOST:$ECS_PATH/"八、提交并触发部署
提交 workflow:
git add .github/workflows/deploy-ecs.yml
git commit -m "ci: deploy vitepress to ecs"
git pushpush 到 main 后,GitHub Actions 会自动执行部署。
也可以手动触发:
GitHub → Actions → Deploy VitePress to ECS → Run workflow九、验证部署结果
ECS 上查看:
ls /var/www/blog应该看到:
index.html
404.html
assets
column
sitemap.xml访问:
http://blog.xxx.com再测试文章页刷新是否正常:
http://blog.xxx.com/column/xxx/xxx如果刷新不 404,说明 Nginx 配置正确。
优点
这种方案的优点很明显:
1. ECS 不需要安装 Node
2. ECS 只负责 Nginx 静态托管
3. GitHub Actions 自动构建,环境稳定
4. 每次 git push 自动发布
5. rsync --delete 会清理旧文件
6. 多项目可以通过不同子域名统一部署到同一台 ECS缺点
也有一些缺点:
1. 需要自己维护 ECS 和 Nginx
2. 需要管理 SSH Key
3. HTTPS 需要额外配置
4. 服务器安全、备份、监控都要自己负责
5. 如果部署多个项目,Nginx 配置需要保持清晰更好的方案有哪些
如果只是个人博客,最省心的是:
Vercel
GitHub Pages
Cloudflare Pages
EdgeOne Pages这些平台不需要自己维护服务器。
如果追求国内访问速度,可以考虑:
对象存储 OSS/COS + CDN这种方式更适合纯静态网站,成本低,访问快,也不需要维护 Nginx。
如果项目后续变多,推荐升级为:
Docker + GitHub Actions + Nginx每个项目独立容器,部署和回滚更规范。
如果团队协作更复杂,可以进一步升级为:
CI/CD 平台 + 制品管理 + 灰度发布但对个人博客来说,当前的:
GitHub Actions + rsync + Nginx已经足够简单、稳定、可控。
常见问题
1. 页面打开 404
检查:
ECS_PATH 是否等于 Nginx root
/var/www/blog 是否有 index.html
Nginx 是否 reload
DNS 是否解析到 ECS2. 文章页刷新 404
检查 Nginx 是否有:
try_files $uri $uri.html $uri/ /404.html;3. GitHub Actions SSH 失败
检查:
ECS_SSH_KEY 是否复制完整
公钥是否写入 ~/.ssh/authorized_keys
ECS_PORT 是否正确
安全组是否开放 224. rsync 失败
检查 ECS 是否安装:
rsync --version总结
这次部署的核心是把构建和运行分离:
GitHub Actions 负责构建
ECS 负责托管
Nginx 负责访问最终链路是:
git push
→ GitHub Actions
→ pnpm run build
→ rsync 到 /var/www/blog
→ Nginx 提供 blog.xxx.com 访问对于 VitePress 这类静态博客,这是一种成本低、可控性强、后期也容易扩展的部署方式。