mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
855 字
4 分钟
Astro GitHub Pages Deployment

Complete deployment guide for Astro static sites (e.g., Mizuki blog) to GitHub Pages with custom domain, HTTPS enforcement, and automated CI/CD via GitHub Actions.

When to Invoke#

  • User wants to deploy an Astro site to GitHub Pages
  • User wants to configure a custom domain on GitHub Pages
  • User needs to set up GitHub Actions deployment workflow for Astro
  • User encounters GitHub Pages deployment failures
  • User wants to enable HTTPS on GitHub Pages custom domain
  • User needs to fork a template repo and deploy with custom content

Prerequisites#

Required Tools#

Terminal window
# Verify tools are available
git --version
gh --version
pnpm --version # or npm/node

If gh is missing, install via scoop (preferred per user rules):

Terminal window
scoop install gh

Required Information from User#

Before starting, ask the user for:

  1. GitHub Personal Access Token (scopes: repo, workflow, admin:repo_hook)
  2. Custom domain (e.g., blog.example.com) — must already have DNS configured
  3. Repository strategy: Fork existing template or create new repo
  4. Proxy address if behind a firewall (default: http://127.0.0.1:7890)

DNS Prerequisites#

The custom domain must have DNS records pointing to GitHub Pages BEFORE deployment:

Option A — CNAME Record (recommended for subdomains):

Type: CNAME
Name: blog
Value: username.github.io

Option B — A Records (for apex domains):

Type: A
Name: @
Value: 185.199.108.153
Value: 185.199.109.153
Value: 185.199.110.153
Value: 185.199.111.153

Verify DNS propagation before proceeding:

Terminal window
Resolve-DnsName blog.example.com

Phase 1: GitHub Authentication#

Set Environment Variables#

Terminal window
# Set token and proxy for all subsequent commands
$env:GH_TOKEN = "ghp_YOUR_TOKEN_HERE"
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"

Authenticate with gh CLI#

Terminal window
# Login using token (recommended for automation)
$env:GH_TOKEN | gh auth login --with-token
# Verify authentication
gh auth status

Common Auth Issues#

Issue: Missing read:org scope

! Missing required token scopes: 'read:org'

Fix: Use GH_TOKEN environment variable instead of keyring storage. All gh commands will use the token directly.

Issue: Network timeout connecting to GitHub Fix: Set HTTP_PROXY and HTTPS_PROXY environment variables. Verify connectivity:

Terminal window
Test-NetConnection -ComputerName api.github.com -Port 443

Issue: Keyring token invalid

X Failed to log in to github.com account (keyring)

Fix: This is expected when using GH_TOKEN env var. The keyring account can be ignored as long as the GH_TOKEN account shows as active.

Configure Git Credential Helper#

Terminal window
gh auth setup-git

Phase 2: Repository Setup#

Use this when deploying a template-based project (e.g., Mizuki) while keeping upstream sync capability.

Terminal window
# Fork the template repository
gh repo fork owner/template-repo --clone=no
# If already cloned locally, set up remotes
cd project-directory
git remote add origin https://github.com/YOUR_USERNAME/repo-name.git
git remote add upstream https://github.com/original-owner/repo-name.git
# Verify remotes
git remote -v

Option B: Create New Repository#

Terminal window
cd project-directory
gh repo create repo-name --public --description "Site description" --source . --push

Verify Repository State#

Terminal window
# Check git status is clean
git status --short
# Check local and remote are in sync
git log --oneline -3
git rev-list origin/master..master --count # Should be 0

Phase 3: Project Configuration#

Update Site URL#

Locate the site configuration file and update the URL to the custom domain.

For Mizuki-style projects (src/config/siteConfig.ts):

export const siteConfig: SiteConfig = {
// ...
siteURL: "https://blog.example.com/", // Must end with slash
// ...
};

For standard Astro projects (astro.config.mjs):

export default defineConfig({
site: "https://blog.example.com",
// ...
});

Important: Always verify the actual config file path. Some projects use src/config.ts, others use src/config/siteConfig.ts or inline in astro.config.mjs. Check the project structure first.

Create Deployment Workflow#

Create .github/workflows/deploy.yml:

name: Deploy to GitHub Pages
on:
push:
branches: [master]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build with Astro
run: pnpm build
env:
ENABLE_CONTENT_SYNC: "false"
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

Notes on Workflow Configuration#

  • Branch name: Change master to main if the default branch is main
  • Package manager: If using npm instead of pnpm, replace pnpm steps with npm ci and npm run build
  • Content sync: Set ENABLE_CONTENT_SYNC: "false" to disable content separation during CI build
  • Build output: Ensure the path matches Astro’s output directory (default: dist)
  • Lock file: Ensure pnpm-lock.yaml exists for --frozen-lockfile to work

Commit and Push#

Terminal window
git add -A
git commit -m "deploy: configure GitHub Pages deployment and custom domain"
git push origin master

Phase 4: Enable GitHub Pages#

Configure Pages via API#

Terminal window
# Enable GitHub Pages with custom domain
gh api repos/YOUR_USERNAME/REPO_NAME/pages `
-X POST `
-f source[branch]=master `
-f source[path]=/ `
-f build_type=workflow `
-f cname=blog.example.com

If Pages Already Exists (Update Instead)#

Terminal window
gh api repos/YOUR_USERNAME/REPO_NAME/pages `
-X PUT `
-f build_type=workflow `
-f cname=blog.example.com

Verify Pages Configuration#

Terminal window
gh api repos/YOUR_USERNAME/REPO_NAME/pages --jq '{
cname,
build_type,
https_enforced,
status,
url: .html_url,
https_certificate: .https_certificate.state
}'

Phase 5: Trigger and Monitor Deployment#

Check Workflow Status#

Terminal window
# List workflows
gh workflow list --repo YOUR_USERNAME/REPO_NAME
# List recent runs
gh run list --repo YOUR_USERNAME/REPO_NAME --limit 5

Trigger Deployment Manually#

If no run was triggered automatically (e.g., workflow was just added):

Terminal window
gh workflow run "Deploy to GitHub Pages" --repo YOUR_USERNAME/REPO_NAME --ref master

Monitor Deployment#

Terminal window
# Get the run ID from the previous command output, then:
gh run watch <RUN_ID> --repo YOUR_USERNAME/REPO_NAME
# Or view run details
gh run view <RUN_ID> --repo YOUR_USERNAME/REPO_NAME

Common Build Failures#

Issue: pnpm install --frozen-lockfile fails

  • Cause: pnpm-lock.yaml is outdated or missing
  • Fix: Run pnpm install locally, commit the updated lock file, push again

Issue: Astro build fails with missing dependencies

  • Fix: Check package.json scripts, ensure build script exists and outputs to dist

Issue: Node.js 20 deprecation warning

  • This is a warning, not an error. The build will still succeed.
  • To fix: Update workflow actions to newer versions (e.g., actions/checkout@v5)

Issue: Deploy job fails with “environment not found”

  • Fix: The github-pages environment is auto-created on first deployment. Re-run the workflow.

Phase 6: Enable HTTPS#

Enable HTTPS Enforcement#

Terminal window
# IMPORTANT: Use -F (not -f) for boolean values in gh api
gh api repos/YOUR_USERNAME/REPO_NAME/pages -X PUT -F https_enforced=true

Critical: Use -F for boolean values, -f for strings. Using -f true will fail with HTTP 422: "true" is not of type boolean.

Verify HTTPS Configuration#

Terminal window
gh api repos/YOUR_USERNAME/REPO_NAME/pages --jq '{
https_enforced,
https_certificate: .https_certificate.state,
https_expires: .https_certificate.expires_at
}'

HTTPS certificate provisioning may take a few minutes after the domain is first configured. If the certificate state is pending, wait and check again.


Phase 7: Verify Deployment#

Check Site Accessibility#

Terminal window
# Verify DNS resolution
Resolve-DnsName blog.example.com
# Verify HTTP response
$response = Invoke-WebRequest -Uri "https://blog.example.com/" -UseBasicParsing -TimeoutSec 30
Write-Host "Status: $($response.StatusCode)"
Write-Host "Content Length: $($response.Content.Length)"
# Extract page title
if ($response.Content -match '<title[^>]*>([^<]+)</title>') {
Write-Host "Title: $($matches[1])"
}

Verify HTTPS Redirect#

Terminal window
# HTTP should redirect to HTTPS
try {
$response = Invoke-WebRequest -Uri "http://blog.example.com/" -UseBasicParsing -MaximumRedirection 0 -ErrorAction Stop
} catch {
# A 301/302 redirect is expected
Write-Host "Redirect status: $($_.Exception.Response.StatusCode)"
}

Quick Reference: Complete Workflow#

Terminal window
# ============================================
# 1. Setup environment
# ============================================
$env:GH_TOKEN = "ghp_YOUR_TOKEN"
$env:HTTP_PROXY = "http://127.0.0.1:7890"
$env:HTTPS_PROXY = "http://127.0.0.1:7890"
# ============================================
# 2. Authenticate
# ============================================
$env:GH_TOKEN | gh auth login --with-token
gh auth status
gh auth setup-git
# ============================================
# 3. Configure project
# ============================================
# Edit siteConfig.ts or astro.config.mjs to set siteURL
# Create .github/workflows/deploy.yml
# ============================================
# 4. Commit and push
# ============================================
git add -A
git commit -m "deploy: configure GitHub Pages deployment and custom domain"
git push origin master
# ============================================
# 5. Enable Pages with custom domain
# ============================================
gh api repos/USER/REPO/pages -X POST `
-f source[branch]=master -f source[path]=/ `
-f build_type=workflow -f cname=blog.example.com
# ============================================
# 6. Trigger deployment
# ============================================
gh workflow run "Deploy to GitHub Pages" --repo USER/REPO --ref master
# Wait for completion
gh run list --repo USER/REPO --limit 1
# ============================================
# 7. Enable HTTPS
# ============================================
gh api repos/USER/REPO/pages -X PUT -F https_enforced=true
# ============================================
# 8. Verify
# ============================================
gh api repos/USER/REPO/pages --jq '{cname, https_enforced, status}'
Invoke-WebRequest -Uri "https://blog.example.com/" -UseBasicParsing | Select-Object StatusCode

Troubleshooting#

Token Permission Issues#

ErrorCauseFix
Missing required token scopes: 'read:org'Token lacks org read scopeUse GH_TOKEN env var; read:org is optional for personal repos
HTTP 403: Resource not accessibleToken lacks repo or workflow scopeRegenerate token with repo, workflow, admin:repo_hook scopes
gh auth login hangsNetwork issueSet proxy env vars, use --with-token instead of interactive

API Parameter Issues#

ErrorCauseFix
HTTP 422: "true" is not of type booleanUsed -f for booleanUse -F flag for boolean values
HTTP 422: Invalid property /https_enforcedWrong parameter formatUse -F https_enforced=true not -f https_enforced=true

Deployment Issues#

ErrorCauseFix
No workflow runs after pushWorkflow file not on default branchEnsure deploy.yml is pushed to master/main
Build job: 0s runtimeSyntax error in workflow YAMLValidate YAML syntax, check indentation
Deploy job failsPages not enabled or wrong build_typeEnsure build_type: workflow in Pages config
pnpm-lock.yaml mismatchLock file outdatedRun pnpm install locally, commit updated lock file

Domain Issues#

ErrorCauseFix
Certificate state: pendingDNS not propagated or domain newWait 5-15 minutes, verify DNS with Resolve-DnsName
Site shows GitHub 404Pages not deployed or wrong branchCheck gh run list for successful deployment
HTTP not redirecting to HTTPSHTTPS enforcement not enabledRun gh api ... -X PUT -F https_enforced=true
Domain shows “not verified”CNAME doesn’t matchEnsure DNS CNAME points to username.github.io

Content Separation (Optional)#

For projects supporting content separation (like Mizuki), you can keep custom content in a separate repository:

Local Mode (Default — No Config Needed)#

Content lives in src/content/ and public/images/, committed with the code.

Remote Content Repository#

# In .env file:
ENABLE_CONTENT_SYNC=true
CONTENT_REPO_URL=https://github.com/your-username/Content-Repo.git

For CI/CD deployment, set ENABLE_CONTENT_SYNC=false in the workflow to use local content, or configure secrets for remote sync.

Upstream Sync Strategy#

When using a fork, sync updates from the original template:

Terminal window
# Fetch and merge upstream changes
git fetch upstream
git merge upstream/master
# Resolve any conflicts in config files, then push
git push origin master

Tip: Keep custom content (articles, images, config changes) in separate commits to make conflict resolution easier during upstream syncs.

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Astro GitHub Pages Deployment
https://blog.xzones.top/posts/skills/astro-github-pages-deploy/
作者
まつざか ゆき
发布于
2026-07-24
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录