Appearance
目标:当你
git push到main,自动构建 VitePress,并同时: 1)发布到 GitHub Pages;2)发布到你云服务器(国内访问更稳)。
思路
- 本地正常开发,添加 md 文章等;仓库放 github 上,一来免费稳定,二来可以使用 github actions 自动构建和部署;
- 创建部署配置文件,使用 github 工作流,当提交代码时到特定分支时,先构建打包,然后通过 ssh 将打包后的静态资源同步到云服务器;同时将打包后的静态资源发布到 github pages;
- 云服务器上安装 nginx,为 viterpress 构建后的静态资源创建一个目录,将 nginx 的配置文件指向这个目录;
- 创建一个 deploy 用户,这个用户只用于发布静态资源,没有 sudo 权限;用这个账户创建一对密钥对,并对相关目录进行权限设置;
- 将密钥放到 github 的 secrets 中,这样 github actions 就可以使用这个密钥通过 ssh 来同步静态资源到云服务器;
一、云服务器上的一次性操作
1)创建部署用户与站点目录
bash
# 复杂逻辑:创建仅用于发布的低权限用户,便于最小权限控制
sudo useradd -m -s /bin/bash deploy
sudo mkdir -p /var/www/vitepress-site
sudo chown -R deploy:deploy /var/www/vitepress-site2)把 GitHub Actions 专用公钥 加到服务器
在你本地临时生成一对“部署专用密钥”,公钥放服务器,私钥放到 GitHub Secrets。
bash
# 本地生成密钥(无口令,CI 用;如要口令请配置 ssh-agent)
ssh-keygen -t ed25519 -C "github-actions" -f ./gh-actions-deploy-key -N ""
# 复杂逻辑:把公钥内容追加到服务器 deploy 用户的授权列表
cat gh-actions-deploy-key.pub
# 复制输出,在服务器上执行:这是在这个deploy 用户下的创建了密钥对存储空间,和root用户下是分开的
sudo -u deploy bash -c 'mkdir -p ~/.ssh && chmod 700 ~/.ssh'
sudo -u deploy bash -c 'echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIfXhL85pb6cKv+Jjwc1XR5RthnknqxZIA9uQ+bx9uyV github-actions" >> ~/.ssh/authorized_keys'
sudo -u deploy bash -c 'chmod 600 ~/.ssh/authorized_keys'deploy 的 ~/.ssh 属于 deploy 用户家目录(/home/deploy/.ssh),root 的 ~/.ssh 属于 root 家目录(/root/.ssh)。 SSH 认证时,你用哪个用户名登录,sshd 就去那个用户的 authorized_keys 里找公钥。
然后把私钥文件
gh-actions-deploy-key内容,添加到 GitHub 仓库 → Settings → Secrets and variables → Actions:
SSH_KEY:粘贴 私钥 全文SSH_HOST:你的服务器公网 IP/域名SSH_PORT:22(或你的自定义端口)SSH_USER:deploy(上面创建的用户)
3)安装 Nginx 并配置站点
bash
# 复杂逻辑:安装并启动 Nginx
sudo apt update && sudo apt -y install nginx
sudo systemctl enable --now nginxnginx
# 复杂逻辑:最小静态站配置(/etc/nginx/sites-available/vitepress)
server {
listen 80;
server_name your.domain.com; # ← 替换为你的域名或服务器IP
root /var/www/vitepress-site; # ← GitHub Actions 会把 dist 同步到这里
index index.html;
# 复杂逻辑:VitePress SPA 路由,所有未命中回退到 index.html
location / {
try_files $uri $uri/ /index.html;
}
# 复杂逻辑:静态资源缓存
location ~* \.(png|jpg|jpeg|gif|svg|css|js|woff2?)$ {
expires 7d;
access_log off;
}
}安装/启动 Nginx 属于系统级操作,必须用 root 或具备 sudo 权限的用户执行;deploy 用户只是用来发布静态文件(rsync 到 /var/www/vitepress-site),不负责装软件或管服务。
如果你已经是 root,原命令照跑即可; 如果你打算用 deploy 来执行安装,请先给它 sudo 权限,然后用 sudo 跑同样的命令。
bash
# 复杂逻辑:把 deploy 加入 sudo 组(在 root 下执行一次)
usermod -aG sudo deploybash
# 复杂逻辑:切换到 deploy 后,用 sudo 安装与启用 Nginx
sudo apt update && sudo apt -y install nginx
sudo systemctl enable --now nginx补充说明:
- Nginx 运行时的默认用户通常是
www-data,与deploy无关; - 你只需确保 站点目录(如
/var/www/vitepress-site)对deploy可写,用于部署发布:
bash
# 复杂逻辑:把站点目录的属主设为 deploy,便于 rsync 写入
chown -R deploy:deploy /var/www/vitepress-sitebash
# 复杂逻辑:启用站点并重载 Nginx
sudo ln -s /etc/nginx/sites-available/vitepress /etc/nginx/sites-enabled/vitepress
sudo nginx -t && sudo systemctl reload nginx确保安全组放行 80/443(HTTPS 可后续加证书:Certbot/反代等)。
二、GitHub 仓库里的设置(一次性)
1)新增 GitHub Secrets(前面已说明)
SSH_KEY、SSH_HOST、SSH_PORT、SSH_USER
可选:如果你要自定义远端目录,也可加
REMOTE_DIR=/var/www/vitepress-site/(也可直接写在 workflow)。
2)创建(或合并进现有)工作流:.github/workflows/deploy.yml
yaml
# 复杂逻辑:同一触发同时部署 Pages 与 VPS
name: build-and-deploy
on:
push:
branches: [main] # ← 推送 main 分支触发
permissions:
contents: read
pages: write # ← 部署 GitHub Pages 需要
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install deps
run: npm ci
- name: Build VitePress
run: npm run docs:build # ← 按你的脚本替换,如:npm run build
- name: Upload Pages artifact
# 复杂逻辑:把 dist 打包为 Pages 工件,供后续两个部署 job 复用
uses: actions/upload-pages-artifact@v3
with:
path: ./.vitepress/dist # ← VitePress 默认产物目录
deploy-pages:
needs: build
environment:
name: github-pages
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
# 复杂逻辑:官方 Action,一键发布到 Pages
uses: actions/deploy-pages@v4
deploy-vps:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download artifact
# 复杂逻辑:把 build 产生的工件下载到当前工作目录
uses: actions/download-artifact@v4
with:
name: github-pages
path: dist
- name: Rsync to VPS over SSH
# 复杂逻辑:通过 SSH/rsync 同步到云服务器
uses: easingthemes/ssh-deploy@v5
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
REMOTE_HOST: ${{ secrets.SSH_HOST }}
REMOTE_PORT: ${{ secrets.SSH_PORT }}
REMOTE_USER: ${{ secrets.SSH_USER }}
ARGS: "-avzr --delete" # ← 同步并删除远端多余文件
SOURCE: "dist/" # ← 工件目录
TARGET: "/var/www/vitepress-site/" # ← 服务器目标目录(与上一步Nginx一致)说明:
- 复杂逻辑行我已在上一行注释说明原因与作用;
- 如果你的构建命令不是
npm run docs:build,只需要改这一行即可;- 如需
pnpm,把setup-node后换成安装 pnpm 并pnpm i && pnpm build即可。
三、你需要改的最少几处(按你偏好仅列修改点)
Nginx 配置:把
server_name改成你的域名或 IP。GitHub Secrets:填入
SSH_KEY/SSH_HOST/SSH_PORT/SSH_USER。工作流中的两处路径:
path: ./.vitepress/dist(如果你的产物不在这里,改成你的 dist 路径)TARGET: "/var/www/vitepress-site/"(如果你想换目录,这里和 Nginx 的root要一致)
构建命令:
npm run docs:build↔ 改成你实际的构建脚本。
四、常见问题速查
- SSH 权限问题:服务器
deploy家目录与~/.ssh/authorized_keys权限需为700/600;sshd_config开启PubkeyAuthentication yes。 - Rsync 权限不足:
deploy用户需对目标目录有写权限(已将/var/www/vitepress-site设为deploy:deploy)。 - Pages 没更新:确保仓库
Settings → Pages → Build and deployment选择 GitHub Actions。 - 国内访问慢:考虑把服务器放在国内/香港并接入 CDN;或仅用服务器端点对国内读者做加速访问。
五、一句话收尾
服务器:
deploy用户 +authorized_keys+ Nginx 指向/var/www/vitepress-site。 仓库:SSH_*Secrets + 一个 workflow,build后同时跑deploy-pages与deploy-vps。 从此一推代码,GitHub Pages 与你的云服务器同步上线。
如果你把你的构建命令和想要的目标目录发我,我只给你需要修改的几行(不整段贴出),直接可用。
- VitePress 的
outDir是以docs/为基准解析的。 你在 CI 里把OUT_DIR写成了docs/.vitepress/dist-vps,结果真实路径变成docs/docs/.vitepress/dist-vps,rsync 自然找不到。把OUT_DIR改成.vitepress/dist-vps(以及.vitepress/dist-gh)就对了。
给你一份「不再踩坑」清单(超短):
CI 里传
OUT_DIR:写相对docs/的路径(不加docs/前缀)。配置里
outDir: OUT_DIR:默认值用./dist(相对docs/.vitepress)。发布目录:
- VPS:
SOURCE: "docs/.vitepress/dist-vps/" - GH:
publish_dir: docs/.vitepress/dist-gh
- VPS:
调试两招:
- 在配置里
console.log('[VitePress]', 'BASE=', BASE, 'OUT_DIR=', OUT_DIR) - 构建后
find docs -maxdepth 3 -type d -name "dist*"看实际落点。
- 在配置里