Jekyll은 Markdown, 레이아웃, 설정 파일을 정적 HTML로 변환한다. 별도의 애플리케이션 서버나 데이터베이스가 없어도 되는 구조라 GitHub Pages와 잘 맞는다.

이 글에서는 사용자명.github.io 형태의 사용자 사이트를 기준으로 다음 과정을 연결한다.

  1. 저장소와 로컬 Jekyll 프로젝트를 만든다.
  2. 로컬에서 동일한 의존성으로 빌드되는지 확인한다.
  3. GitHub Pages의 배포 방식을 선택한다.
  4. GitHub Actions가 만든 _site 아티팩트를 배포하고 결과를 검증한다.

사용자 사이트와 프로젝트 사이트를 먼저 구분하기

GitHub Pages URL은 저장소 종류에 따라 달라진다. 이 차이를 놓치면 배포는 성공했는데 CSS와 이미지 경로만 깨지는 문제가 생길 수 있다.

종류 저장소 이름 기본 URL Jekyll 설정에서 확인할 값
사용자·조직 사이트 <username>.github.io https://<username>.github.io/ 보통 baseurl: ""
프로젝트 사이트 자유롭게 지정 https://<username>.github.io/<repository>/ 보통 baseurl: "/<repository>"

이 블로그는 sunbang123.github.io 저장소를 사용하는 사용자 사이트이므로 _config.ymlurlhttps://sunbang123.github.io, baseurl은 빈 문자열이다.

1. 로컬 개발 환경 준비

Jekyll 공식 설치 문서는 Ruby 2.7 이상, RubyGems, GCC와 Make를 요구한다. Windows에서는 RubyInstaller의 Ruby+Devkit을 설치하고 마지막 단계에서 MSYS2 개발 도구까지 설치하는 방법이 가장 단순하다.

새 터미널을 열고 먼저 명령이 인식되는지 확인한다.

ruby -v
gem -v
gcc -v

그다음 Jekyll과 Bundler를 설치한다.

gem install jekyll bundler
jekyll -v
bundle -v

jekyll -v 단계에서 네이티브 확장 관련 오류가 난다면 Jekyll을 반복 설치하기 전에 Ruby+Devkit과 ridk install 수행 여부를 확인한다.

2. Jekyll 프로젝트 생성과 로컬 확인

아래 명령은 blog 폴더에 새 사이트를 만들고, 생성된 Gemfile에 맞는 gem을 사용해 개발 서버를 실행한다.

jekyll new blog
cd blog
bundle exec jekyll serve

브라우저에서 http://127.0.0.1:4000을 열어 기본 페이지가 나오면 로컬 실행까지 성공한 것이다. Ruby 3 환경에서 웹 서버 의존성 오류가 발생한다면 Jekyll Quickstart의 안내에 따라 bundle add webrick을 실행한 뒤 다시 시작한다.

Windows 터미널에서 jekyll new blog 명령으로 Bundler 의존성을 설치하는 화면
처음 사이트를 만들 때 남긴 jekyll new blog 실행 화면

기본 골격은 다음과 비슷하다. 사용하는 Jekyll 버전에 따라 세부 파일은 달라질 수 있으므로 테마 이름을 추측하지 말고 Gemfile_config.yml에서 직접 확인한다.

blog/
├─ _posts/
│  └─ YYYY-MM-DD-welcome-to-jekyll.markdown
├─ .gitignore
├─ _config.yml
├─ 404.html
├─ about.markdown
├─ Gemfile
└─ index.markdown

serve는 개발 서버 실행까지 포함한다. 배포 전에 정적 파일 생성만 따로 검증하려면 다음 명령을 사용한다.

bundle exec jekyll build
bundle exec jekyll doctor
  • 빌드가 성공하면 결과물이 _site에 생성된다.
  • _site/index.html이 있는지 확인한다.
  • _site는 생성 결과물이므로 일반적으로 커밋하지 않는다.
  • _config.yml을 바꾼 뒤에는 개발 서버를 다시 시작해야 한다.

3. GitHub 저장소에 첫 소스 올리기

GitHub에서 <username>.github.io 이름으로 저장소를 만든다. 로컬 프로젝트 루트에서 다음 명령을 실행하되 <username>은 실제 GitHub 사용자명으로 바꾼다.

git init
git add .
git commit -m "docs: initialize Jekyll site"
git branch -M main
git remote add origin https://github.com/<username>/<username>.github.io.git
git push -u origin main

여기까지는 소스를 저장소에 올린 것이다. 실제 공개 사이트를 만드는 배포 설정은 다음 단계다.

4. 브랜치 배포와 GitHub Actions 중 선택하기

GitHub 공식 문서는 별도의 빌드 제어가 필요 없다면 브랜치 배포를, 빌드 과정과 의존성을 직접 관리해야 한다면 사용자 정의 Actions 워크플로를 사용하도록 안내한다.

방법 A: 브랜치에서 바로 배포

  1. 저장소의 Settings를 연다.
  2. 왼쪽 메뉴에서 Pages를 선택한다.
  3. Build and deploymentSourceDeploy from a branch로 바꾼다.
  4. main/(root)를 선택하고 저장한다.

구성이 단순한 사이트에는 편리하지만 GitHub Pages의 Jekyll 빌드는 안전 모드에서 동작하므로 사용할 수 있는 플러그인이 제한된다. 로컬에서는 작동하는 사용자 정의 플러그인이 브랜치 배포에서 빠진다면 지원 플러그인인지 확인해야 한다.

방법 B: GitHub Actions에서 빌드 후 배포

Ruby·Jekyll 버전을 고정하거나 빌드 과정을 직접 검증하고 싶다면 Settings > Pages > Build and deployment > Source에서 GitHub Actions를 선택한다.

이 블로그의 현재 배포 흐름은 다음과 같다.

main push
  → 저장소 checkout
  → Ruby 3.2와 Bundler 의존성 준비
  → bundle exec jekyll build
  → _site를 Pages 아티팩트로 업로드
  → github-pages 환경에 배포

아래는 2026년 7월 GitHub 공식 문서의 Pages 액션 구성을 Jekyll 빌드에 맞춘 예다. 액션의 최신 메이저 버전은 시간이 지나면 달라질 수 있으므로 새로 적용할 때 공식 문서도 함께 확인한다.

name: Deploy Jekyll site to 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:
      - name: Checkout
        uses: actions/checkout@v6

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

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: "3.2"
          bundler-cache: true

      - name: Build with Jekyll
        run: bundle exec jekyll build
        env:
          JEKYLL_ENV: production

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v4
        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

중요한 부분은 액션 이름보다 단계 사이의 계약이다.

  • bundle execGemfile.lock에 맞는 Jekyll과 플러그인을 사용한다.
  • 빌드 작업은 배포할 정적 파일을 _site에 만들어야 한다.
  • upload-pages-artifactpath는 실제 출력 폴더와 같아야 한다.
  • 배포 작업에는 pages: write, id-token: write 권한과 github-pages 환경이 필요하다.
  • deploy 작업은 needs: build로 빌드 성공 뒤에 실행돼야 한다.

이 저장소에서 실제 사용하는 구성은 GemfileJekyll Pages 워크플로에서 확인할 수 있다.

5. 배포가 끝난 뒤 확인할 것

푸시 직후 주소만 새로고침하기보다 아래 순서로 확인하면 빌드 문제와 배포 문제를 분리할 수 있다.

  1. 저장소 Actions에서 Jekyll 빌드 작업이 성공했는지 확인한다.
  2. 이어지는 Pages 배포 작업이 성공했는지 확인한다.
  3. Settings > Pages에 표시되는 방문 주소를 연다.
  4. 홈뿐 아니라 글, CSS, 이미지 주소도 각각 열어 본다.
  5. 프로젝트 사이트라면 개발자 도구의 Network 탭에서 /assets/... 요청이 404인지 확인한다.

검색엔진의 site: 결과는 배포 직후 검증 수단이 아니다. 먼저 공개 URL이 200 응답을 내고 내부 링크로 이동되는지 확인한 다음 사이트맵과 Search Console을 점검하는 편이 순서상 맞다.

자주 생기는 문제

로컬에서는 되는데 Pages에서 플러그인이 동작하지 않는다

브랜치 배포의 안전 모드에서 허용되지 않는 플러그인일 수 있다. 지원 플러그인으로 교체하거나, 이 글의 방법 B처럼 Actions에서 Gemfile 기준으로 직접 빌드한다.

배포는 성공했는데 CSS와 이미지가 404다

프로젝트 사이트인데 사용자 사이트처럼 baseurl: ""로 두었는지 확인한다. 템플릿에서도 고정 문자열 대신 Jekyll의 relative_url 필터를 사용하면 하위 경로 배포에 안전하다.

_config.yml을 바꿨는데 로컬 화면이 그대로다

Jekyll 개발 서버는 _config.yml 변경을 자동으로 다시 읽지 않는다. 실행 중인 서버를 종료하고 bundle exec jekyll serve를 다시 실행한다.

자동 커밋 뒤 브랜치 배포가 시작되지 않는다

GitHub 공식 문서에 따르면 Actions의 GITHUB_TOKEN으로 푸시한 커밋은 브랜치 기반 Pages 빌드를 다시 트리거하지 않는다. 자동화가 소스를 갱신하는 구조라면 별도의 Pages Actions 워크플로에서 빌드·배포까지 수행하는 편이 흐름을 명확하게 만든다.

Actions를 실제 블로그 자동화에 연결하며 겪은 권한과 Secret 문제는 GitHub Actions CI/CD 자동화 기록에 따로 정리했다.

공식 참고 자료