DEV Community

Cover image for Deploy Jekyll to GitHub Pages in 2026: GitHub Actions, Custom Domain & Cloudflare
Pooya Golchian
Pooya Golchian

Posted on • Originally published at pooya.blog

Deploy Jekyll to GitHub Pages in 2026: GitHub Actions, Custom Domain & Cloudflare

GitHub Pages remains the best free static site host for developers in 2026. The catch: the built-in Jekyll builder is limited to a small set of allowed gems. The solution is a GitHub Actions workflow that builds Jekyll with full plugin support and deploys the output to GitHub Pages. This guide walks through the complete setup, from a blank repo to a custom domain served over HTTPS via Cloudflare.

Prerequisites

  • A GitHub account with a repository for your Jekyll site
  • A custom domain (optional but recommended)
  • A Cloudflare account (free tier is sufficient)
  • Ruby ≥ 3.1 and Jekyll ≥ 4.3 installed locally for testing

Step 1: Configure Jekyll for Production

Ensure _config.yml sets the correct URL:

# _config.yml
url: "https://yourdomain.com"
baseurl: ""
plugins:
  - jekyll-feed
  - jekyll-sitemap
  - jekyll-seo-tag
Enter fullscreen mode Exit fullscreen mode

Add a Gemfile:

source "https://rubygems.org"
gem "jekyll", "~> 4.3"
group :jekyll_plugins do
  gem "jekyll-feed"
  gem "jekyll-sitemap"
  gem "jekyll-seo-tag"
end
Enter fullscreen mode Exit fullscreen mode

Step 2: Create the GitHub Actions Workflow

Create .github/workflows/deploy.yml:

name: Deploy Jekyll 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:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.3'
          bundler-cache: true   # Caches gems for faster builds

      - name: Configure GitHub Pages
        uses: actions/configure-pages@v5

      - name: Build with Jekyll
        run: bundle exec jekyll build --destination ./_site
        env:
          JEKYLL_ENV: production

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3

  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
Enter fullscreen mode Exit fullscreen mode

This workflow uses the official upload-pages-artifact + deploy-pages pattern, the recommended approach since 2024 that avoids pushing to a gh-pages branch.

Step 3: Enable GitHub Pages in Repository Settings

  1. Go to Settings > Pages
  2. Under Source, select GitHub Actions (not a branch)
  3. Save

Push to main, the workflow runs automatically and your site deploys within ~2 minutes.

Step 4: Configure a Custom Domain

4a. Create the CNAME File

Add a CNAME file to the root of your repo (no extension, plain text):

yourdomain.com
Enter fullscreen mode Exit fullscreen mode

Commit and push it. GitHub Pages reads this file to know which custom domain to serve.

4b. Set the Domain in GitHub Pages Settings

In Settings > Pages > Custom domain, enter yourdomain.com and save.

Step 5: Configure DNS (Cloudflare)

In the Cloudflare dashboard for your domain, add these records:

Type Name Content Proxy
A @ 185.199.108.153 ✔ On
A @ 185.199.109.153 ✔ On
A @ 185.199.110.153 ✔ On
A @ 185.199.111.153 ✔ On
CNAME www yourusername.github.io ✔ On

These are GitHub's current (2026) IP addresses. The old addresses from 2016 (192.30.252.x) are deprecated.

Step 6: Enable HTTPS

Once DNS propagates (usually minutes with Cloudflare):

  1. In Settings > Pages, check Enforce HTTPS
  2. In Cloudflare SSL/TLS, set mode to Full (not Full Strict)
  3. Add a Cloudflare Redirect Rule: www.yourdomain.comhttps://yourdomain.com (301)

Step 7: Cloudflare Performance Optimizations (Free Tier)

In the Cloudflare dashboard, enable:

  • Speed > Optimization > Auto Minify: HTML, CSS, JS
  • Caching > Configuration > Browser Cache TTL: 4 hours
  • Speed > Optimization > Brotli: on

Verify Everything Works

# Check DNS resolves to GitHub Pages IPs
dig yourdomain.com A +short

# Verify HTTPS and response headers
curl -I https://yourdomain.com
# Look for: strict-transport-security, cf-ray (Cloudflare edge hit)
Enter fullscreen mode Exit fullscreen mode

The Result

Feature Status
Unlimited plugins & custom gems ✔ via GitHub Actions
Custom domain ✔ CNAME file + DNS
HTTPS / TLS ✔ Let's Encrypt via GitHub
Global CDN ✔ Cloudflare
DDoS protection ✔ Cloudflare
Deploy on push ✔ Auto via Actions
Cost $0

Your Jekyll site is now fully production-grade: CI/CD deploys on every push, TLS is enforced, and Cloudflare caches assets at 300+ edge nodes worldwide.

Top comments (0)