Parent Skill: tutorial-writer Standalone Available: ✅ Can be triggered directly via
/github-pages(L1 direct) Architecture: Self-contained single-file skill — includes a complete GitHub Pages deployment guide Usage Frequency: 🟢 Low frequency — usually invoked after the build is complete (2-3 times per project)
🎯 Scope of Responsibility
Scope of Responsibility: Only responsible for deploying the build artifacts of the web package to GitHub Pages
Not responsible for:
- Website build →
/websub-skill- PDF/EPUB generation →
/booksub-skill- Content management →
/contentsub-skill
| ✅ Responsible for | ❌ Not responsible for |
|---|---|
| GitHub Pages-specific configuration and deployment | Astro project build → /web |
| GitHub Actions workflow setup | Starlight theme configuration → /web |
| base path / trailingSlash configuration | Content Collections → /web |
| Custom domain / DNS / SSL | Component development → /web |
| CI/CD pipelines and automation | Performance optimization (at build time) → /web |
| Deployment monitoring, rollback, notifications | Local development environment → /web |
PDF/EPUB generation → /book |
Design Philosophy: This skill is alow-frequency operationin the Tutorial Writer workflow, but its content is complete and detailed. The Agent obtains all the information it needs at once when deployment is required.
Prerequisites
Before starting configuration, confirm that the following build-phase deliverables are ready:
✅ Build Artifact Verification (Basics)
- Completed the
/webphase (Astro project build complete) -
bun run --filter @repo/web buildsucceeded, with no error output -
apps/web/dist/directory structure is correct - Local
bun run devpage displays correctly
⚠️ This skill only handles website deployment to GitHub Pages. For PDF/EPUB generation, use the
/booksub-skill.
⚠️ If the above conditions are not met, please first run /web to complete the website build.
🚀 Quick Publish: 4 Steps to Deploy to GitHub Pages
Step 1: Key Deployment Configuration
astro.config.mjs(the 3 key items that must be set correctly):
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
export default defineConfig({
// ⭐ 关键 1:完整站点 URL(影响 SEO、sitemap、OG 图片路径)
site: 'https://username.github.io',
// ⭐ 关键 2:项目路径前缀(GitHub Pages 项目站点必填!)
// 用户站点(username.github.io)可不填或设为 '/'
base: '/repo-name/',
// ⭐ 关键 3:避免 GitHub Pages 404 问题
trailingSlash: 'always', // 输出 /about/index.html 而非 /about.html
integrations: [
starlight({
title: '教程标题',
description: '教程描述',
social: {
github: 'https://github.com/username/repo',
},
sidebar: [
{ label: '首页', slug: 'index' },
{
label: '章节',
autogenerate: { directory: 'chapters' },
},
],
editLink: {
baseUrl: 'https://github.com/username/repo/edit/main/',
},
lastUpdated: true,
pagination: true,
search: { mode: 'auto' },
}),
],
});
Key Configuration Items:
| Configuration Item | Value | Description |
|---|---|---|
site |
Full URL | Affects SEO, sitemap, OG image paths |
base |
'/repo-name/' |
Required for GitHub Pages project sites |
trailingSlash |
'always' |
Avoids GitHub Pages 404 |
Configuration Differences Between the Two Scenarios:
| Scenario | site Value |
base Value |
Final URL Example |
|---|---|---|---|
| User/Organization Site | https://username.github.io |
Leave blank or '/' |
https://username.github.io/ |
| Project Site(recommended) | https://username.github.io |
'/repo-name' |
https://username.github.io/repo/ |
⚠️ Common Mistake: Forgetting to set base causes all static assets (CSS/JS/images) to 404!
Step 2: Create a GitHub Actions Workflow
File Location: .github/workflows/deploy.yml
Option A: Official withastro/action (recommended, simplest)
name: Deploy to GitHub Pages
on:
# 推送到 main 分支时自动触发
push:
branches: ['main']
# 支持手动触发(可选)
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deploy.outputs.page_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Deploy to GitHub Pages
id: deploy
uses: withastro/action@v3
Option B: Standard Actions workflow (more controllable)
name: Deploy to GitHub Pages
on:
push:
branches: ['main']
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
# Job 1: 构建
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
env:
NODE_OPTIONS: --max-old-space-size=4096 # 大型项目防 OOM
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./dist
# Job 2: 部署(依赖构建完成)
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Option comparison:
| Dimension | Option A (withastro/action) | Option B (standard workflow) |
|---|---|---|
| Configuration complexity | ⭐ Simple (~30 lines) | ⭐⭐ Medium (~60 lines) |
| Controllability | Medium | High (each step can be customized) |
| Use cases | Standard tutorial sites | Large projects requiring additional build steps |
| Officially recommended | ✅ Yes | ✅ Also a standard practice |
Step 3: Configure GitHub repository Settings
- Go to the target repository → Settings(Settings)
- In the left menu, find Pages(Pages)
- Source(Source) select GitHub Actions
- ⚠️ Do not select "Deploy from a branch" (old method, not recommended)
- Wait for the first Actions run to complete (about 2-5 minutes)
- Visit the displayed URL to verify the deployment succeeded:
https://username.github.io/repo-name/
Step 4: Post-deployment verification
Must-check items:
- The homepage opens normally and styles load correctly
- All navigation links are clickable with no 404s
- Image, CSS, and JS file paths are correct (no red errors in the browser console)
- Search works (Pagefind index is normal)
- Dark mode toggle works normally
- Mobile responsive layout works normally
- Lighthouse score ≥ 90 (Performance + Accessibility)
Quick verification command(simulate the GitHub Pages environment locally):
# 模拟 base 路径环境
GH_PAGES_BASE=/repo-name npm run build
# 使用 serve 模拟静态服务器
npx serve dist -l 3000
# 访问测试地址
# http://localhost:3000/repo-name/
🔧 Detailed configuration guide
In-depth analysis of the base path
Why must base be set?
URL structure of a GitHub Pages project site:
https://username.github.io/<repository-name>/
Astro assumes by default that the site is at the root path /, but it is actually under /<repo>/ . This causes:
- ❌ CSS/JS requests
/_astro/style.css→ should actually be/<repo>/_astro/style.css - ❌ Image requests
/images/bg.png→ 404 - ❌ Navigation links jump to the wrong address
What base does: adds a prefix to all relative paths.
Dynamic base configuration(compatible with local development + production environment):
// astro.config.mjs
export default defineConfig({
base: process.env.GH_PAGES_BASE || '/',
// 开发环境:base = '/'(默认)
// 生产环境:GH_PAGES_BASE='/repo-name/' npm run build
});
package.json scripts:
{
"scripts": {
"dev": "astro dev",
"build": "astro build",
"build:gh": "GH_PAGES_BASE=/repo-name astro build",
"preview": "astro preview"
}
}
trailingSlash must be set to 'always'
Reason: GitHub Pages behavior mechanism
| Request path | GitHub Pages lookup | Astro default output | Result |
|---|---|---|---|
/about |
/about/index.html |
/about.html |
404 ❌ |
/about/ |
/about/index.html |
/about/index.html |
200 ✅ |
Configuration method:
trailingSlash: 'always', // ✅ 正确
// trailingSlash: 'ignore', // ❌ 错误:导致 GitHub Pages 404
outDir configuration options
Option A: Use the default dist/ directory (recommended)
// 不设置 outDir(默认值即可)
// GitHub Actions 使用 actions/upload-pages-artifact 上传 dist/
Advantages:
- ✅ Follows Astro conventions
- ✅ Best support from the official Action
- ✅ No need for
.nojekyllfile
Option B: Output to docs/ directory (traditional method)
outDir: './docs',
Use cases:
- Not using GitHub Actions (manual deployment)
- Select "Deploy from branch" in Settings →
gh-pagesbranch or/docsfolder
⚠️ must be in the docs/ directory, create .nojekyll file:
# 方式一:构建后自动创建
echo "" > docs/.nojekyll
# 方式二:在 public/ 中放置(每次构建自动复制)
echo "" > public/.nojekyll
Reason: GitHub Pages uses Jekyll by default, which ignores directories starting with _ (such as _astro/), causing all JS/CSS to be lost!
🌐 Custom Domain Configuration
Method 1: Via GitHub Settings (recommended)
- Settings → Pages → Custom domain
- Enter the domain (such as
www.example.comorexample.com) - Wait for GitHub to automatically create the DNS record prompt
- Add the DNS record at your domain registrar:
Apex Domain Configuration(example.com):
| Type | Name | Value | TTL |
|---|---|---|---|
| A | @ | 185.199.108.153 |
3600 |
| A | @ | 185.199.109.153 |
3600 |
| A | @ | 185.199.110.153 |
3600 |
| A | @ | 185.199.111.153 |
3600 |
| CNAME | www | username.github.io |
3600 |
Subdomain Configuration(www.example.com / blog.example.com):
| Type | Name | Value | TTL |
|---|---|---|---|
| CNAME | www/blog | username.github.io |
3600 |
- Wait for DNS to take effect (usually a few minutes, up to 48 hours)
- Enable Enforce HTTPS(force HTTPS, improve security)
Method 2: CNAME file
In public/CNAME add:
www.example.com
Or Apex domain:
example.com
Update astro.config.mjs
site: 'https://www.example.com', // 更新为自定义域名
base: '/', // 自定义域名通常不需要 base(根路径)
trailingSlash: 'always',
SSL/TLS Certificate
✅ GitHub Pages automatically provides a Let's Encrypt certificate:
- Free, automatic renewal
- Supports HTTP/2
- Enable forced redirect in Settings → Pages → Enforce HTTPS
🔄 Advanced CI/CD Configuration
Multi-environment Deployment (Staging / Production)
Branch Strategy:
main → Production 部署(正式站点)
staging → Staging 部署(预发布测试)
develop → 开发环境(开发者日常验证)
.github/workflows/deploy-staging.yml:
name: Deploy to Staging
on:
push:
branches: ['staging']
permissions:
contents: read
pages: write
id-token: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages-staging # 单独的环境名称
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- run: npm run build
- uses: withastro/action@v3
⚠️ Note: GitHub Free only supports 1 GitHub Pages environment. Staging and Production share the same URL. If you need fully isolated environments, consider using Cloudflare Pages or Vercel (which support multiple environments for free).
Preview Deployments (PR preview deployments)
Automatically create a preview deployment for each Pull Request:
# .github/workflows/preview.yml
name: Preview Deployment
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pages: write
id-token: write
jobs:
preview:
runs-on: ubuntu-latest
environment:
name: github-pages-preview-${{ github.event.pull_request.number }}
url: ${{ steps.deploy.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
- run: npm ci
- run: npm run build
- uses: withastro/action@v3
Deployment Notifications (Slack / Discord / Email)
In deploy.yml add a notification step at the end:
- name: Notify Success
if: success()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "✅ 教程站点部署成功!\n仓库: ${{ github.repository }}\n提交: ${{ github.sha }}\n作者: ${{ github.actor }}\nURL: ${{ steps.deploy.outputs.page_url }}"
}' \
${{ secrets.SLACK_WEBHOOK_URL }}
- name: Notify Failure
if: failure()
run: |
curl -X POST -H 'Content-type: application/json' \
--data '{
"text": "❌ 部署失败!\n仓库: ${{ github.repository }}\n查看: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}' \
${{ secrets.SLACK_WEBHOOK_URL }}
Automatic Rollback Mechanism (advanced)
Automatic rollback based on health checks (add after the deploy job):
health-check:
runs-on: ubuntu-latest
needs: [build-and-deploy] # 依赖部署完成
if: always() # 即使部署成功也执行检查
steps:
- name: Wait for Deployment
run: sleep 30 # 等待 CDN 生效
- name: Health Check
id: health
run: |
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
"${{ needs.build-and-deploy.outputs.page_url }}")
if [ "$STATUS" != "200" ]; then
echo "❌ Health check failed! Status: $STATUS"
echo "rollback_needed=true" >> $GITHUB_OUTPUT
exit 1
fi
echo "✅ Site healthy"
echo "rollback_needed=false" >> $GITHUB_OUTPUT
- name: Create Rollback Issue
if: failure()
run: |
gh issue create \
--title "🚨 部署失败 - 需要回滚" \
--body "部署未通过健康检查。\n\n**操作建议**:\n1. \`git revert HEAD\`\n2. 推送到 main 触发重新部署\n3. 或手动回滚到上一个稳定版本" \
--repo ${{ github.repository }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
🐛 Common Troubleshooting Guide
Issue 1: All static assets return 404
Symptoms:
- The page HTML loads successfully, but styles are lost and images do not display
- Console error:
GET https://username.github.io/_astro/style.css 404
Cause: base is not set or the base value is incorrect
Solution:
// astro.config.mjs
base: '/your-repo-name/', // 必须与仓库名完全一致
Verification Method:
# 检查生成的 HTML 中的资源路径
cat dist/index.html | grep '_astro'
# 应该看到:/_astro/style.abc123.css
# 如果是 /your-repo-name/_astro/style.abc123.css 则正确
Issue 2: 404 after clicking a navigation link
Symptoms:
- The homepage works, but clicking a sidebar or internal link returns 404
- Directly refreshing the page also returns 404
Cause: trailingSlash: 'always'
Solution:
trailingSlash: 'always',
Issue 3: _astro/ directory is ignored (all JS/CSS missing)
Symptoms:
- The build succeeds, but the website has no styles or interactive functionality at all
- The browser Network panel shows all
/_astro/*requests return 404
Cause: GitHub Pages uses Jekyll processing, which ignores directories starting with _ Directory at the beginning
Solution(in order of priority):
- Using GitHub Actions(Recommended): Automatically bypass Jekyll
- Add
.nojekyllfile:touch public/.nojekyll # 或 touch docs/.nojekyll
Issue 4: Out of memory during build (OOM)
Symptoms:
- GitHub Actions error:
FATAL ERROR: Ineffective mark-compacts near heap limit - Large tutorial sites (100+ chapters) easily trigger this
Solution:
# deploy.yml 的 build step 中添加环境变量
- name: Build
run: npm run build
env:
NODE_OPTIONS: --max-old-space-size=4096 # 增加到 4GB
Long-term optimization:
- Reduce the amount of content per build (build in batches)
- Enable Astro 6.0+ experimental Queued Rendering (2x rendering speed improvement)
- Clean up unused dependencies and plugins
Issue 5: Slow deployment (>10 minutes)
Optimization strategies:
- ✅ Enable dependency caching(already configured in the template)
- ✅ Reduce the number of Content Collections: If there are hundreds of pieces of content, consider batching
- ✅ Enable experimental Queued Rendering(Astro 6.0+):
experimental: { queuedRendering: { enabled: true }, }, - ✅ Optimize images: Use WebP format, reduce the number and size of images
- ✅ Streamline plugins: Remove unnecessary Starlight plugins
📋 Complete deployment checklist
Before deployment (build-stage deliverable verification)
-
npm run buildNo errors (exit 0) -
astro.config.mjsinsiteandbasecorrectly set -
trailingSlash: 'always'configured - local
npm run previewdisplays correctly - No 404/500 errors in the browser console
- All images, CSS, and JS resources load successfully
- All internal links are clickable and do not 404
- Responsive layout verification passed (375px / 768px / 1280px)
- Dark mode toggle works correctly
- Search function is available
- Lighthouse Performance ≥ 90, Accessibility ≥ 90
Configuration verification
-
.github/workflows/deploy.ymlexists and has correct syntax - Actions permissions are configured correctly (contents: read, pages: write, id-token: write)
- Node.js version ≥ 18 (20 recommended)
- If using a custom domain, DNS records are configured
After deployment (production environment verification)
- GitHub Actions workflow runs successfully (green ✓)
- Accessing the GitHub Pages URL opens normally
- Homepage styles, layout, and images display correctly
- Navigation menu is clickable, and all chapters are reachable
- In-page search is available
- Mobile display works correctly
- No sensitive information leakage (API keys, passwords, etc.)
- Custom domain HTTPS works correctly (if configured)
- Lighthouse score meets the standard (online version)
📊 Monitoring and maintenance
Uptime monitoring (free options)
| Service | Features | Price |
|---|---|---|
| UptimeRobot | Checks every 5 minutes, email/Slack notifications | Free |
| Better Uptime | Includes status page, phone/SMS alerts | Free basic version |
| GitHub Status | Limited monitoring (only view deployment history) | Free |
UptimeRobot configuration example:
- Monitoring URL:
https://username.github.io/repo/ - Check frequency: 5 minutes
- Keyword detection:
<title>site name in the tag - Notifications: Slack Webhook / Email
Core Web Vitals monitoring (optional)
Add in the layout component:
---
// src/layouts/BaseLayout.astro(如果自定义布局)
---
<script>
import { onCLS, onFID, onINP, onLCP } from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
navigator.sendBeacon('/api/vitals', body);
}
onCLS(sendToAnalytics);
onFID(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
</script>
Sentry error tracking (recommended for production)
# 安装 SDK
npm install @sentry/astro
// astro.config.mjs
import sentry from '@sentry/astro';
export default defineConfig({
integrations: [
sentry({
dsn: import.meta.env.SENTRY_DSN,
tracesSampleRate: 0.1,
}),
],
});
🔗 Integration with the build phase
Trigger conditions
When the following conditionsare all met, invoke this skill to enter the deployment process:
# ✅ 构建成功
npm run build && echo "Exit code: $?"
# ✅ 本地预览正常
npm run preview &
# 浏览器访问 http://localhost:4321 确认无误
# 准备就绪,调用部署技能
→ /github-pages # 进入 GitHub Pages 部署流程
Common integration issues
| Issue | Cause | Solution |
|---|---|---|
| URL path 404 | base Configuration does not match the repository name |
Ensure base: '/repo-name/' matches the GitHub repository name |
| Build artifacts missing | /web phase not completed |
First run /web to complete the build |
| Static assets missing | Jekyll processing issue | Use GitHub Actions or add .nojekyll |
| Deployment timeout | Build time too long | Increase Node memory or optimize build performance |
📂 Structure of this skill
skills/tutorial-writer-github-pages/
├── SKILL.md ← 本文件(自含型 ~650行)
└── references/
├── web-publishing.md ← Web 发布基础参考
├── decision-record-rules.md ← 决策细则
└── github-pages-guide.md ← 高级部署场景详解
📚 Reference documentation index
| Document | Content | When to read |
|---|---|---|
| web-publishing.md | Web publishing basic configuration + Astro/Starlight reference | When build details are needed |
| github-pages-guide.md | Multi-environment deployment, rollback strategies, security hardening, migration guide | When advanced deployment scenarios are needed |
💡 Loading timing: Read only when additional details are needed; this file already covers the main deployment process
🔗 Related resources
| Resource | Path/Link | Purpose |
|---|---|---|
| Parent skill | ../SKILL.md | Tutorial Writer main router |
| Web build sub-skill | ../skills/tutorial-writer-web/SKILL.md | Astro build process |
| Book generation sub-skill | ../skills/tutorial-writer-book/SKILL.md | PDF/EPUB generation |
| Astro official deployment documentation | https://docs.astro.build/guides/deploy/github/ | Official authoritative guide |
| withastro/action | https://github.com/withastro/action | Official Action repository |
| GitHub Pages documentation | https://docs.github.com/en/pages | Complete GitHub Pages documentation |
Version history
| Version | Date | Changes |
|---|---|---|
| v1.0.0 | 2026-05-31 | 🔄 Monorepo architecture refactor: Renamed from publish to github-pages; removed multi-format publishing support (PDF/EPUB/Releases → /book sub-skill); focused on pure GitHub Pages deployment; added scope of responsibility statement; prerequisites simplified to only checking the web package build artifacts; metadata added focus/target fields; version number reset to v1.0.0 |
| v7.0.0 | 2026-05-31 | Content-First v2 alignment upgrade (previous version, deprecated) |
| v6.1.0 | 2026-05-30 | Flattening refactor: upgraded from 1-Sub Router to a self-contained single-file skill |
| v6.0.0 | 2026-05-30 | 1-Sub Router (publish → website-deploy) (previous version) |