How to Host Your Site for Free on GitHub Pages
How to Host Your Site for Free on GitHub Pages
GitHub Pages provides free hosting for static websites directly from a GitHub repository. Whether you're running a personal blog, project documentation, or a portfolio site, GitHub Pages offers a reliable and cost-effective solution with automatic deployments via GitHub Actions.
This guide covers setting up GitHub Pages, configuring custom domains, and creating deployment workflows for both Jekyll and other static site generators.
Prerequisites
Before proceeding, ensure you have the following:
- A GitHub account
- Git installed on your local machine
- A static website ready for deployment (HTML, Jekyll, Eleventy, Hugo, etc.)
Step 1: Create a GitHub Repository
Create a new repository on GitHub to host your site.
For a User/Organization Site
Create a repository named <username>.github.io, where <username> is your GitHub username. This repository will be accessible at https://<username>.github.io.
For a Project Site
Create a repository with any name. The site will be accessible at https://<username>.github.io/<repository-name>/.
# Clone your new repository
git clone https://github.com/<username>/<repository-name>.git
cd <repository-name>
Step 2: Add Your Site Files
Add your static site files to the repository:
# Add all files
git add .
# Commit the changes
git commit -m "Initial site setup"
# Push to GitHub
git push origin main
Step 3: Enable GitHub Pages
- Navigate to your repository on GitHub
- Go to Settings → Pages
- Under Source, select one of the following:
- Deploy from a branch: Select
main(orgh-pages) and the folder (/rootor/docs) - GitHub Actions: For custom build workflows
- Deploy from a branch: Select
For static HTML sites, selecting the main branch is sufficient. For sites requiring a build step, GitHub Actions is recommended.
Step 4: Configure GitHub Actions for Automated Deployment
GitHub Actions enables automated builds and deployments whenever you push changes to your repository.
For Jekyll Sites
Jekyll is natively supported by GitHub Pages. However, for more control or to use unsupported plugins, create a custom workflow.
Create .github/workflows/deploy.yml:
name: Deploy Jekyll Site
on:
push:
branches: [main]
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 Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Build with Jekyll
run: bundle exec jekyll build
env:
JEKYLL_ENV: production
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
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
For Eleventy Sites
Create .github/workflows/deploy.yml:
name: Deploy Eleventy Site
on:
push:
branches: [main]
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: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build site
run: npm run build
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: '_site'
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
For Hugo Sites
Create .github/workflows/deploy.yml:
name: Deploy Hugo Site
on:
push:
branches: [main]
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
with:
submodules: recursive
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest'
extended: true
- name: Build site
run: hugo --minify
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'public'
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
For Plain HTML/CSS Sites
For sites that don't require a build step:
name: Deploy Static Site
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: '.'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Step 5: Configure GitHub Pages to Use Actions
After creating your workflow:
- Go to Settings → Pages
- Under Build and deployment, select GitHub Actions as the source
- Push your workflow file to trigger the first deployment
Step 6: Set Up a Custom Domain (Optional)
To use your own domain instead of <username>.github.io:
Configure DNS Settings
Add the following DNS records with your domain registrar:
For apex domain (example.com):
| Type | Name | Value |
|---|---|---|
| A | @ | 185.199.108.153 |
| A | @ | 185.199.109.153 |
| A | @ | 185.199.110.153 |
| A | @ | 185.199.111.153 |
For subdomain (www.example.com):
| Type | Name | Value |
|---|---|---|
| CNAME | www | <username>.github.io |
Add CNAME File
Create a CNAME file in your repository root containing your domain:
example.com
Enable Custom Domain in GitHub
- Go to Settings → Pages
- Enter your custom domain under Custom domain
- Enable Enforce HTTPS (recommended)
Step 7: Create Pre-commit and Pre-push Hooks (Optional)
Git hooks automate tasks before commits or pushes, such as running tests or linting.
Pre-commit Hook for Linting
Create .git/hooks/pre-commit:
#!/bin/sh
# Run linting before commit
echo "Running pre-commit checks..."
# For Jekyll sites
if [ -f "Gemfile" ]; then
bundle exec jekyll doctor
if [ $? -ne 0 ]; then
echo "Jekyll doctor failed. Please fix errors before committing."
exit 1
fi
fi
# For Node.js sites (Eleventy, etc.)
if [ -f "package.json" ]; then
npm run lint 2>/dev/null
if [ $? -ne 0 ]; then
echo "Linting failed. Please fix errors before committing."
exit 1
fi
fi
echo "Pre-commit checks passed."
exit 0
Make it executable:
chmod +x .git/hooks/pre-commit
Pre-push Hook for Build Verification
Create .git/hooks/pre-push:
#!/bin/sh
echo "Running pre-push checks..."
# For Jekyll sites
if [ -f "Gemfile" ]; then
bundle exec jekyll build
if [ $? -ne 0 ]; then
echo "Jekyll build failed. Please fix errors before pushing."
exit 1
fi
fi
# For Node.js sites
if [ -f "package.json" ]; then
npm run build
if [ $? -ne 0 ]; then
echo "Build failed. Please fix errors before pushing."
exit 1
fi
fi
echo "Pre-push checks passed."
exit 0
Make it executable:
chmod +x .git/hooks/pre-push
Using Husky for Managed Git Hooks
For Node.js projects, Husky provides a more maintainable approach to Git hooks.
Install Husky:
npm install --save-dev husky
npx husky init
Create a pre-commit hook:
echo "npm run lint" > .husky/pre-commit
Create a pre-push hook:
echo "npm run build" > .husky/pre-push
Husky hooks are stored in the repository and shared across the team.
Step 8: Verify Your Deployment
After pushing your changes:
- Go to the Actions tab in your repository
- Monitor the workflow execution
- Once complete, visit your site at the configured URL
Troubleshooting Common Issues
Build Fails with Permission Errors
Ensure your workflow has the correct permissions:
permissions:
contents: read
pages: write
id-token: write
Custom Domain Not Working
- Verify DNS records have propagated (use
dig example.com) - Ensure the CNAME file contains only your domain
- Wait up to 24 hours for DNS propagation
404 Errors on Subpages
For single-page applications, create a 404.html that redirects to your index:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="refresh" content="0; url=/">
<script>window.location.href = "/";</script>
</head>
<body>
Redirecting...
</body>
</html>
Assets Not Loading
Ensure your base URL is configured correctly:
- Jekyll: Set
baseurlin_config.yml - Eleventy: Configure
pathPrefixin.eleventy.js - Hugo: Set
baseURLinconfig.toml
GitHub Pages Limitations
Be aware of these limitations:
- Repository size: 1 GB recommended maximum
- Site size: 1 GB maximum
- Bandwidth: 100 GB per month soft limit
- Builds: 10 builds per hour soft limit
- No server-side code: Static files only
Conclusion
GitHub Pages provides an excellent free hosting solution for static websites. Combined with GitHub Actions, you can automate your entire deployment pipeline with minimal configuration.
Key takeaways:
- Create a repository and enable GitHub Pages
- Configure GitHub Actions for automated builds
- Set up a custom domain for a professional appearance
- Use Git hooks to catch errors before deployment
- Monitor your deployments through the Actions tab
For complex deployments or if you encounter issues, contact us at [email protected]. We offer consulting services for a small fee to help you get your site up and running.