Skip to content

目标:当你 git pushmain自动构建 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-site

2)把 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_PORT22(或你的自定义端口)
  • SSH_USERdeploy(上面创建的用户)

3)安装 Nginx 并配置站点

bash
# 复杂逻辑:安装并启动 Nginx
sudo apt update && sudo apt -y install nginx
sudo systemctl enable --now nginx
nginx
# 复杂逻辑:最小静态站配置(/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 deploy
bash
# 复杂逻辑:切换到 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-site
bash
# 复杂逻辑:启用站点并重载 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_KEYSSH_HOSTSSH_PORTSSH_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 即可。

三、你需要改的最少几处(按你偏好仅列修改点)

  1. Nginx 配置:把 server_name 改成你的域名或 IP。

  2. GitHub Secrets:填入 SSH_KEY/SSH_HOST/SSH_PORT/SSH_USER

  3. 工作流中的两处路径

    • path: ./.vitepress/dist(如果你的产物不在这里,改成你的 dist 路径)
    • TARGET: "/var/www/vitepress-site/"(如果你想换目录,这里和 Nginx 的 root 要一致)
  4. 构建命令npm run docs:build ↔ 改成你实际的构建脚本。


四、常见问题速查

  • SSH 权限问题:服务器 deploy 家目录与 ~/.ssh/authorized_keys 权限需为 700/600sshd_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-pagesdeploy-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)就对了。

给你一份「不再踩坑」清单(超短):

  1. CI 里传 OUT_DIR:写相对 docs/ 的路径(不加 docs/ 前缀)。

  2. 配置里 outDir: OUT_DIR:默认值用 ./dist(相对 docs/.vitepress)。

  3. 发布目录

    • VPS:SOURCE: "docs/.vitepress/dist-vps/"
    • GH:publish_dir: docs/.vitepress/dist-gh
  4. 调试两招

    • 在配置里 console.log('[VitePress]', 'BASE=', BASE, 'OUT_DIR=', OUT_DIR)
    • 构建后 find docs -maxdepth 3 -type d -name "dist*" 看实际落点。

本站总访问