目录
本文记录 Astro 静态站点从本地开发到 GitHub Actions 自动部署的完整流程。部署链路为:本地或 CI 执行构建 → 生成 dist/ → 通过 SSH + rsync 同步到服务器目录,由 Nginx 等 Web 服务器提供静态文件服务。
1. 环境要求
| 项目 | 版本或说明 |
|---|---|
| Node.js | 22(与 CI 保持一致) |
| 包管理器 | pnpm(package.json 中可通过 packageManager 字段锁定版本) |
| Astro | 5.x |
| 服务器 | 开放 SSH(22)端口,已安装 Nginx 或其他静态文件服务 |
新建项目:
pnpm create astro@latest
cd <project-name>
pnpm install
2. Astro 命令
2.1 项目脚本(package.json)
常见定义方式:
{
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
}
}
对应命令:
pnpm dev # 开发服务器,默认 http://localhost:4321
pnpm build # 生产构建,输出到 dist/
pnpm preview # 在本地预览 dist/ 的构建结果
部分项目会在 build 前增加资源同步、搜索索引生成等步骤,例如 pnpm assets:sync && astro build && pagefind --site dist。CI 中应执行与线上一致的 pnpm run build,而不是单独跑 astro build,除非已确认两者等价。
2.2 Astro CLI
通过 pnpm astro 调用:
pnpm astro dev [--host 0.0.0.0] [--port 4321]
pnpm astro build
pnpm astro preview [--host 0.0.0.0] [--port 4321]
pnpm astro check # 结合 @astrojs/check 做类型与模板检查
pnpm astro sync # 生成 .astro/types.d.ts
pnpm astro add <integration>
开发服务器监听地址与端口可在 astro.config.mjs 的 server.host、server.port 中配置,也可用环境变量 HOST、PORT(或 ASTRO_HOST、ASTRO_PORT)覆盖。
2.3 构建产物
astro build 在 output: 'static' 模式下将所有静态文件写入项目根目录下的 dist/。部署时上传的是 dist/ 内的内容,不是源码目录。
本地验证构建结果:
pnpm build
pnpm preview
3. 关键配置
astro.config.mjs 中与部署相关的字段:
import { defineConfig } from 'astro/config';
export default defineConfig({
output: 'static',
site: 'https://example.com',
});
| 字段 | 作用 |
|---|---|
output: 'static' | 生成纯静态 HTML/CSS/JS,适合 rsync 部署 |
site | 站点根 URL,供 sitemap、RSS、canonical 等使用;改为实际域名 |
4. 服务器:SSH 密钥
在服务器上生成专用于 GitHub Actions 的密钥对:
ssh-keygen -m PEM -t rsa -b 4096 -C "github-actions-deploy" -f ~/.ssh/github_actions
生成时不设置 passphrase(GitHub Actions 无法交互输入)。
公钥写入 authorized_keys,并设置目录权限:
cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
权限不正确时,sshd 会拒绝密钥登录。
导出私钥,供下一节填入 GitHub Secret:
cat ~/.ssh/github_actions
输出须包含 -----BEGIN ... PRIVATE KEY----- 与 -----END ... PRIVATE KEY----- 行。
5. GitHub Secrets
在仓库 Settings → Secrets and variables → Actions 中新建:
| 名称 | 值 |
|---|---|
SERVER_HOST | 服务器 IP 或域名 |
SERVER_USER | SSH 登录用户名 |
SERVER_SSH_KEY | 第 4 节生成的私钥全文 |
私钥与服务器密码不应出现在 workflow 文件或 Git 提交记录中,仅通过 ${{ secrets.* }} 引用。
6. GitHub Actions Workflow
在项目根目录创建 .github/workflows/deploy.yml:
name: Build and Deploy Astro
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
steps:
- name: Checkout Code
uses: actions/checkout@v5
- name: Setup pnpm
uses: pnpm/action-setup@v6
with:
version: 10.28.0
- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '22'
cache: 'pnpm'
- name: Install Dependencies
run: pnpm install --frozen-lockfile
- name: Restore Image Caches
uses: actions/cache@v5
with:
path: |
node_modules/.astro/assets
public/generated-previews
key: ${{ runner.os }}-image-cache-${{ hashFiles('src/assets/images/**/*.avif', 'src/assets/images/config.json', 'src/assets/photos/**/*.avif', 'src/assets/photos/**/*.json', 'src/utils/asset-image.ts', 'src/utils/public-image.ts', 'src/utils/photography.ts', 'src/utils/hero-image.ts', 'astro.config.mjs', 'package.json', 'pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-image-cache-
- name: Build Astro Site
run: pnpm run build
- name: Check Deploy Host Connectivity
env:
REMOTE_HOST: ${{ secrets.SERVER_HOST }}
run: |
set -eu
getent ahosts "$REMOTE_HOST"
timeout 10 bash -c 'cat < /dev/null > /dev/tcp/'"$REMOTE_HOST"'/22'
- name: Deploy to Server
uses: easingthemes/ssh-deploy@main
env:
SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
ARGS: "-rl --delete --info=progress2,stats2 --human-readable -i --exclude=files/images-originals/*** --exclude=files/photos-originals/***"
SOURCE: "dist/"
REMOTE_HOST: ${{ secrets.SERVER_HOST }}
REMOTE_USER: ${{ secrets.SERVER_USER }}
TARGET: "/var/www/your-site"
6.1 步骤说明
| 步骤 | 说明 |
|---|---|
concurrency | 同一分支的新推送会取消尚未完成的部署任务 |
pnpm install --frozen-lockfile | 按锁文件安装,不更新依赖版本 |
Restore Image Caches | 缓存 Astro 图片处理产物;hashFiles 列表需按项目实际资源路径调整,无图片管线时可删除此步 |
pnpm run build | 执行 package.json 中定义的完整构建流程 |
Check Deploy Host Connectivity | 部署前检查 DNS 解析与 22 端口连通性;不需要时可删除 |
easingthemes/ssh-deploy | 在 runner 上对 SOURCE 目录执行 rsync,通过 SSH 写入 TARGET |
6.2 rsync 参数
ARGS 中各选项含义:
| 选项 | 含义 |
|---|---|
-r | 递归 |
-l | 保留符号链接 |
--delete | 删除目标端存在但源端不存在的文件 |
-i | 以 SSH 为传输通道 |
--exclude=... | 排除指定路径,不纳入同步 |
SOURCE: "dist/" 末尾斜杠表示同步 dist/ 内部文件到 TARGET 根目录,不会在远端产生 dist/dist/ 嵌套。
TARGET 改为服务器上网站根目录的实际路径。
7. 服务器 Web 配置
Nginx 将域名指向部署目录的示例:
server {
listen 80;
server_name example.com;
root /var/www/your-site;
index index.html;
location / {
try_files $uri $uri/ $uri.html =404;
}
}
HTTPS 需另行配置证书(如 Let’s Encrypt)。root 路径须与 workflow 中 TARGET 一致。
若服务器上另有手动维护的目录(如原图存储),通过 rsync 的 --exclude 排除,避免 --delete 在反向同步时误删。
8. 部署流程
- 本地修改代码,
pnpm build确认构建通过。 - 提交并 push 到
main。 - GitHub Actions 自动执行 workflow。
- 在仓库 Actions 页查看任务状态;失败时展开对应步骤的日志定位错误。
手动在服务器上首次部署时,可先本地构建再 rsync:
pnpm build
rsync -rl --delete -e ssh dist/ user@host:/var/www/your-site/
9. 常见问题
密钥登录失败
- 检查
~/.ssh权限是否为700,authorized_keys是否为600。 - 确认 GitHub Secret 中的私钥完整,无多余空格或换行缺失。
- 确认
SERVER_USER与服务器实际用户一致。
构建通过但站点未更新
- 确认
TARGET与 Nginxroot指向同一目录。 - 检查 rsync 是否因权限不足写入失败(查看 Actions 日志)。
--delete 删除了服务器上的额外文件
--delete会使目标目录与dist/严格一致。不应出现在构建产物中、但需保留在服务器上的路径,须通过--exclude排除。
开发端口被占用
PORT=4322 pnpm dev
或在 astro.config.mjs 中修改 server.port。