GitHub 15 ๐ GitHub Pages: Hosting Static Sites
GitHub Pages turns a repository into a static website. It is not a general-purpose web host. It serves HTML, CSS, JavaScript, and assets directly from a branch or a GitHub Actions artifact, with no server-side execution, no database, and no dynamic request handling. For documentation, project landing pages, and personal blogs, it is free, integrated with the repository, and requires no infrastructure. The exam tests two things: how to configure the publishing source, and how to attach a custom domain without breaking HTTPS.
Key point: GitHub Pages can publish from a branch (/ or /docs) or from a GitHub Actions workflow. If you need a custom build process, use Actions. If you are serving pre-built static files, publishing from a branch is simpler. Custom domains require a CNAME file (branch publishing) or a DNS record (Actions publishing) and an HTTPS certificate provisioned by GitHub.
Why GitHub Pages exists
The hosting problem. A documentation site or project page does not need a server. It needs files served over HTTP. GitHub Pages provides that for free: the repository already contains the source, and Pages serves the output. There is no separate deployment pipeline, no FTP, no bucket policy. A push to the configured branch is the deployment .
The build problem. Static site generators (Hugo, Jekyll, Vite, Astro) produce a directory of files. If those files are committed to a branch, Pages can serve them directly. If they are generated during CI, an Actions workflow can build them and deploy the artifact to Pages without ever committing the output. The choice depends on whether the generated files should be versioned or ephemeral .
The custom domain problem. A github.io URL is functional but not professional. A custom domain maps docs.example.com or example.com to the Pages site. The mapping requires DNS records and a verification step on GitHub. Once verified, GitHub provisions a free TLS certificate through Let’s Encrypt and serves the site over HTTPS .
The security problem. A custom domain that is configured in DNS but not verified on GitHub is vulnerable to domain takeover. If the Pages site is disabled and the DNS record remains, an attacker can claim the subdomain and serve content under the organization’s name. Verification (via a TXT record) and removing stale DNS records are the defenses .
The limits problem. GitHub Pages is not for commerce. It is not for SaaS. It has soft bandwidth limits (100 GB/month), soft build limits (10 per hour for branch publishing), and a 1 GB published site size limit. Deployments time out after 10 minutes. Exceeding these limits results in a polite email, not immediate termination, but the site may not be served reliably .
a. Configuring the publishing source
The publishing source is configured in the repository settings under Settings โ Pages. The “Source” dropdown offers two paths: Deploy from a branch and GitHub Actions.
For branch publishing, the source branch can be any branch, and the folder can be / (root) or /docs. When a push lands on the configured branch and folder, Pages builds and publishes the site. The default is the root of the default branch. For a simple HTML site, the root is sufficient. For a project that keeps documentation alongside code, /docs is the common choice .
For Actions publishing, the source is set to GitHub Actions. This removes the branch-based build trigger entirely. The workflow must check out the repository, build the site (if needed), upload the artifact with actions/upload-pages-artifact, and deploy with actions/deploy-pages. The workflow needs permissions: pages: write and id-token: write to function .
A critical caveat for branch publishing: commits pushed by a GitHub Actions workflow using GITHUB_TOKEN do not trigger a Pages build. If a workflow generates files and pushes them to the source branch, the site will not update. The fix is to use a personal access token for the push, or to switch to Actions publishing where the workflow deploys directly .
b. Publishing with GitHub Actions
The Actions workflow pattern for Pages is standardized. The sequence is: checkout, build, configure-pages, upload-pages-artifact, deploy-pages. The configure-pages action sets up the Pages environment. The upload-pages-artifact action packages the output directory. The deploy-pages action publishes it .
name: Deploy to Pages
on:
push:
branches: ['main']
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: 'pages'
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- name: Build
run: npm ci && npm run build
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: './dist'
- id: deployment
uses: actions/deploy-pages@v4
The path in the upload step must point to the directory containing the final static files (e.g., dist, build, _site). If the site is already pre-built and committed, the path can be ./ or ./docs. The environment block creates a deployment record that GitHub links from the repository sidebar .
The concurrency block prevents two deployments from running simultaneously. Without it, a rapid sequence of pushes can cause the second deployment to fail because the first is still in progress. cancel-in-progress: true cancels the older run, but for production sites, false allows the running deployment to finish .
c. Custom domains and HTTPS
A custom domain can be a subdomain (docs.example.com) or an apex domain (example.com). The DNS configuration differs. For a subdomain, a CNAME record points to <username>.github.io. For an apex domain, A records point to GitHub’s IP addresses: 185.199.108.153, 185.199.109.153, 185.199.110.153, 185.199.111.153 (and AAAA records for IPv6) .
For branch publishing, a CNAME file at the root of the source branch (or in the /docs folder if that is the source) records the custom domain. This file is served by Pages and tells GitHub which domain the site expects. For Actions publishing, no CNAME file is created or required. The custom domain is configured in the Pages settings, and the DNS records are the only external configuration .
After DNS propagation (up to 24 hours), GitHub verifies the domain and provisions a TLS certificate. The “Enforce HTTPS” checkbox becomes available. Enabling it redirects all HTTP traffic to HTTPS. If the certificate is not yet issued, the checkbox is disabled. The verification step is separate from the DNS configuration: a TXT record proves ownership and prevents domain takeover. Without it, a dangling DNS record can be claimed by another GitHub user .
Complete Example Session
# ============================================
# PART 1: ENABLE PAGES FROM A BRANCH
# ============================================
# Settings โ Pages
# Source: Deploy from a branch
# Branch: main
# Folder: /docs
# Click Save
# ============================================
# PART 2: PUSH CONTENT TO THE SOURCE
# ============================================
mkdir -p docs
echo "<h1>Hello Pages</h1>" > docs/index.html
git add docs/index.html
git commit -m "Add docs index"
git push origin main
# Pages builds and serves the site at https://user.github.io/repo/
# ============================================
# PART 3: CONFIGURE CUSTOM DOMAIN (BRANCH)
# ============================================
echo "docs.example.com" > docs/CNAME
git add docs/CNAME
git commit -m "Add custom domain"
git push origin main
# The CNAME file is served by Pages.
# ============================================
# PART 4: CONFIGURE DNS FOR SUBDOMAIN
# ============================================
# At the DNS provider:
# Type: CNAME
# Name: docs
# Value: username.github.io
# ============================================
# PART 5: ENABLE HTTPS
# ============================================
# Settings โ Pages โ Custom domain: docs.example.com
# Wait for DNS propagation (up to 24h)
# Check "Enforce HTTPS" once the certificate is provisioned
# ============================================
# PART 6: SWITCH TO ACTIONS PUBLISHING
# ============================================
# Settings โ Pages โ Source: GitHub Actions
# Create .github/workflows/pages.yml
name: Deploy
on:
push:
branches: ['main']
permissions:
contents: read
pages: write
id-token: write
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: './docs'
- id: deployment
uses: actions/deploy-pages@v4
# ============================================
# PART 7: VERIFY THE DEPLOYMENT
# ============================================
# Actions tab โ Deploy workflow โ completed
# Repository sidebar โ Environments โ github-pages
# The site URL is displayed.
# ============================================
# PART 8: APEX DOMAIN DNS
# ============================================
# Type: A
# Name: @
# Value: 185.199.108.153
# (repeat for .109, .110, .111)
# Optionally add AAAA records for IPv6
The eight parts trace both publishing paths: branch publishing with a CNAME file, and Actions publishing with a workflow. The custom domain configuration is the same in the Pages settings, but the file requirement differs.
Quick Reference
Publishing Source
| Source | Configuration | Trigger |
|---|---|---|
Branch (/) | Settings โ Pages โ Deploy from branch | Push to branch root |
Branch (/docs) | Settings โ Pages โ Deploy from branch | Push to docs/ |
| GitHub Actions | Settings โ Pages โ GitHub Actions | Workflow deploy-pages |
Custom Domain DNS
| Domain Type | Record | Value |
|---|---|---|
Subdomain (docs.example.com) | CNAME | <username>.github.io |
Apex (example.com) | A | 185.199.108.153, 185.199.109.153, 185.199.110.153, 185.199.111.153 |
| Apex (IPv6) | AAAA | 2606:50c0:8000::153 โฆ |
Limits
| Limit | Value |
|---|---|
| Site size | 1 GB |
| Bandwidth | 100 GB/month (soft) |
| Builds per hour | 10 (branch publishing) |
| Deployment timeout | 10 minutes |
| Source repo size | 1 GB (recommended) |
Best Practices
โ Do This:
permissions:
pages: write
id-token: write
- โ
Required for
actions/deploy-pages
# Verify custom domain before configuring DNS
- โ Prevents domain takeover
# Use /docs for documentation alongside code
- โ Keeps source and output in one place
โ Don’t Do This:
# Push to source branch from a GITHUB_TOKEN workflow
- โ Does not trigger a Pages build
# Configure DNS before adding domain in GitHub
- โ Domain takeover risk
# Use Pages for e-commerce or SaaS
- โ Violates usage limits
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Site not updating | Push from GITHUB_TOKEN workflow | Use PAT or Actions publishing |
| Custom domain 404 | CNAME missing from source folder | Add CNAME to /docs or root |
| HTTPS not available | Certificate not yet provisioned | Wait for DNS propagation; check verification |
| Actions deploy fails | Missing pages: write permission | Add permissions block |
| Site exceeds 1 GB | Large assets committed | Use Git LFS or external CDN |
Real-World Examples
1. Branch Publishing
Settings โ Pages โ Deploy from branch โ main /docs
2. Actions Publishing
uses: actions/deploy-pages@v4
3. CNAME File
docs.example.com
4. Subdomain DNS
CNAME docs โ username.github.io
5. Apex A Records
A @ โ 185.199.108.153
6. Verify DNS
dig docs.example.com CNAME +short
7. Enforce HTTPS
Settings โ Pages โ Enforce HTTPS
8. Workflow Permissions
permissions:
pages: write
id-token: write
9. Upload Artifact
uses: actions/upload-pages-artifact@v3
with:
path: './dist'
10. Environment URL
environment:
name: github-pages
Visual
Publishing Paths
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ BRANCH PUBLISHING โ
โ โ
โ push to main/docs โ Pages build โ serve โ
โ CNAME file required for custom domain โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ACTIONS PUBLISHING โ
โ โ
โ workflow โ build โ upload โ deploy โ
โ No CNAME file; domain set in settings โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Both paths produce a site. The difference is who builds it and where the output lives.
Custom Domain Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Add domain in Settings โ Pages โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Configure DNS (CNAME or A records) โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ GitHub verifies + provisions TLS โ
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Enable "Enforce HTTPS" โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
DNS without verification is a takeover risk. Verification proves ownership.
Summary
| Item | Value |
|---|---|
| Branch source folders | / or /docs |
| Actions source | actions/deploy-pages |
| Custom domain file (branch) | CNAME in source folder |
| Subdomain DNS | CNAME to <user>.github.io |
| Apex DNS | A records to GitHub IPs |
| HTTPS | Enforced in Pages settings |
| Site size limit | 1 GB |
| Bandwidth limit | 100 GB/month (soft) |
| Build limit | 10/hour (branch) |
Key takeaways:
- Pages serves static files only. No server-side code, no database, no dynamic rendering .
- Two publishing paths exist. Branch publishing is simpler; Actions publishing is required for custom builds or when symbolic links are present .
- Custom domains require DNS and verification. The
CNAMEfile is for branch publishing only. Actions publishing ignores it . - HTTPS is automatic but not immediate. GitHub provisions the certificate after DNS verification. The “Enforce HTTPS” checkbox appears when it is ready.
- Pages has limits. It is not for commerce or SaaS. The 1 GB site size and 100 GB bandwidth limits are soft but enforced .
Remember: GitHub Pages is a static host tied to a repository. The source is either a branch folder or an Actions workflow. A custom domain maps a DNS record to the Pages service, and a CNAME file (for branch publishing) tells GitHub which domain to expect. Configure the domain in GitHub first, then DNS. Verify ownership. Enable HTTPS. The site is served from GitHub’s infrastructure, but the repository remains the source of truth.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!