포스트

[이제와서 시작하는 GitHub 마스터하기 - 실전편 #6] GitHub Pages: 무료 정적 사이트 호스팅

[이제와서 시작하는 GitHub 마스터하기 - 실전편 #6] GitHub Pages: 무료 정적 사이트 호스팅

들어가며

“이제와서 시작하는 GitHub 마스터하기” 실전편의 여섯 번째 시간입니다. 이번에는 GitHub Pages를 활용하여 무료로 정적 웹사이트를 호스팅하는 방법을 알아보겠습니다. 개인 블로그부터 프로젝트 문서까지 다양하게 활용할 수 있습니다.

1. GitHub Pages란?

GitHub Pages는 GitHub 저장소에서 직접 정적 웹사이트를 호스팅하는 서비스입니다.

GitHub Pages vs 다른 호스팅 서비스

서비스 무료 제공 대역폭 커스텀 도메인 HTTPS 빌드 시간 가격
GitHub Pages 1GB 저장소 100GB/월 ✅ ✅ 10분 무료
Netlify 100GB 대역폭 100GB/월 ✅ ✅ 300분/월 무료/$19
Vercel 100GB 대역폭 100GB/월 ✅ ✅ 6000분/월 무료/$20
Cloudflare Pages 무제한 무제한 ✅ ✅ 500회/월 무료
GitLab Pages 10GB 저장소 무제한 ✅ ✅ 400분/월 무료

주요 특징

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
무료 호스팅:
  - Public 저장소: 무제한 무료
  - Private 저장소: GitHub Pro 이상에서 가능
  - 대역폭: 월 100GB
  - 저장 공간: 1GB

지원 기능:
  - HTTPS 기본 제공
  - 커스텀 도메인
  - Jekyll 내장 지원
  - 정적 사이트 생성기 호환

제한 사항:
  - 정적 콘텐츠만 가능
  - 서버사이드 코드 실행 불가
  - 상업적 사용 제한
  - 파일 크기: 100MB 이하

GitHub Pages 유형

1
2
3
4
5
6
7
8
9
User/Organization Pages:
  - URL: username.github.io
  - 저장소 이름: username.github.io
  - 소스: main 브랜치 루트

Project Pages:
  - URL: username.github.io/repository
  - 저장소 이름: 아무거나
  - 소스: gh-pages 브랜치 또는 docs 폴더

2. 빠른 시작 가이드

개인 사이트 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 1. 저장소 생성 (username을 본인 GitHub 사용자명으로 변경)
# 저장소 이름: username.github.io

# 2. 로컬에 클론
git clone https://github.com/username/username.github.io.git
cd username.github.io

# 3. index.html 생성
cat > index.html << 'EOF'
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>내 GitHub Pages 사이트</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 2rem;
            background: #f6f8fa;
        }
        .container {
            background: white;
            padding: 2rem;
            border-radius: 8px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.12);
        }
        h1 {
            color: #24292e;
            border-bottom: 1px solid #e1e4e8;
            padding-bottom: 0.5rem;
        }
        .links a {
            display: inline-block;
            margin: 0.5rem;
            padding: 0.5rem 1rem;
            background: #0366d6;
            color: white;
            text-decoration: none;
            border-radius: 6px;
        }
        .links a:hover {
            background: #0256c7;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>안녕하세요! 👋</h1>
        <p>GitHub Pages로 만든 내 웹사이트입니다.</p>
        <div class="links">
            <a href="https://github.com/username">GitHub</a>
            <a href="/blog">블로그</a>
            <a href="/projects">프로젝트</a>
        </div>
    </div>
</body>
</html>
EOF

# 4. 커밋 및 푸시
git add index.html
git commit -m "Initial GitHub Pages site"
git push origin main

# 5. 몇 분 후 https://username.github.io 접속

프로젝트 문서 사이트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 1. 기존 프로젝트에서 docs 폴더 생성
mkdir docs
cd docs

# 2. 문서 페이지 생성
cat > index.md << 'EOF'
# 프로젝트 문서

## 소개
이 프로젝트는 ...

## 설치 방법
```bash
npm install my-awesome-project
```

## 사용법
```javascript
const awesome = require('my-awesome-project');
awesome.doSomething();
```

## API 문서
- [시작하기](./getting-started.md)
- [API 레퍼런스](./api-reference.md)
- [예제](./examples.md)

## 기여하기
PR은 언제나 환영입니다!
EOF

# 3. Jekyll 설정 (선택사항)
cat > _config.yml << 'EOF'
theme: jekyll-theme-minimal
title: My Awesome Project
description: 프로젝트 설명
EOF

# 4. 커밋 및 푸시
git add docs/
git commit -m "Add project documentation"
git push origin main

# 5. GitHub 저장소 Settings → Pages
# Source: Deploy from a branch
# Branch: main / docs

3. Jekyll로 블로그 만들기

Jekyll 기본 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Jekyll 사이트 생성
gem install bundler jekyll
jekyll new my-blog
cd my-blog

# 구조
├── _config.yml      # 사이트 설정
├── _posts/          # 블로그 포스트
├── _layouts/        # 레이아웃 템플릿
├── _includes/       # 재사용 가능한 조각
├── _sass/           # Sass 스타일시트
├── assets/          # CSS, JS, 이미지
├── _data/           # 데이터 파일
├── _site/           # 생성된 사이트 (gitignore)
├── index.html       # 홈페이지
└── about.md         # 정적 페이지

Jekyll 설정

_config.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 사이트 설정
title: 내 기술 블로그
email: your-email@example.com
description: >-
  프로그래밍과 기술에 대한 이야기를 나누는 블로그입니다.
baseurl: "" # 서브경로 (예: "/blog")
url: "https://username.github.io"
twitter_username: yourusername
github_username:  yourusername

# 빌드 설정
markdown: kramdown
theme: minima
plugins:
  - jekyll-feed
  - jekyll-seo-tag
  - jekyll-sitemap
  - jekyll-paginate

# 페이지네이션
paginate: 10
paginate_path: "/page:num/"

# 한국어 설정
lang: ko
timezone: Asia/Seoul

# 퍼머링크
permalink: /:year/:month/:day/:title/

# 컬렉션
collections:
  projects:
    output: true
    permalink: /projects/:name/

# 기본값
defaults:
  - scope:
      path: ""
      type: "posts"
    values:
      layout: "post"
      comments: true
  - scope:
      path: ""
      type: "projects"
    values:
      layout: "project"

# 제외 파일
exclude:
  - Gemfile
  - Gemfile.lock
  - node_modules
  - vendor/bundle/
  - vendor/cache/
  - vendor/gems/
  - vendor/ruby/
  - README.md

블로그 포스트 작성

_posts/2025-01-28-my-first-post.md:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
---
layout: post
title: "Jekyll로 블로그 시작하기"
date: 2025-01-28 10:00:00 +0900
categories: [블로그, Jekyll]
tags: [jekyll, github-pages, blog]
author: YourName
image: /assets/images/jekyll-blog.jpg
excerpt: "GitHub Pages와 Jekyll을 사용하여 무료 블로그를 만드는 방법을 소개합니다."
---

## 들어가며

Jekyll은 정적 사이트 생성기로, GitHub Pages와 완벽하게 통합됩니다.

## 주요 기능

### 1. Markdown 지원
마크다운으로 편하게 글을 작성할 수 있습니다.

### 2. 코드 하이라이팅
```ruby
def hello
  puts "Hello, Jekyll!"
end
```

### 3. 수식 지원
LaTeX 수식도 지원합니다: $$E = mc^2$$

## 이미지 삽입
![Jekyll Logo]({{ "/assets/images/jekyll-logo.png" | relative_url }})

## 링크
- [내부 링크](/posts/github-basic-01-intro-and-signup/)
- [외부 링크](https://jekyllrb.com)

## 결론
Jekyll과 GitHub Pages로 쉽게 블로그를 시작할 수 있습니다!

커스텀 레이아웃

_layouts/post.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
---
layout: default
---
<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

  <header class="post-header">
    <h1 class="post-title p-name" itemprop="name headline">{{ page.title | escape }}</h1>
    <p class="post-meta">
      <time class="dt-published" datetime="{{ page.date | date_to_xmlschema }}" itemprop="datePublished">
        {%- assign date_format = site.minima.date_format | default: "%Y년 %m월 %d일" -%}
        {{ page.date | date: date_format }}
      </time>
      {%- if page.author -%}
        • <span itemprop="author" itemscope itemtype="http://schema.org/Person">
          <span class="p-author h-card" itemprop="name">{{ page.author }}</span>
        </span>
      {%- endif -%}
      • 읽는 시간: {% include read-time.html %}
    </p>
    
    {%- if page.tags.size > 0 -%}
    <p class="post-tags">
      {%- for tag in page.tags -%}
        <span class="tag">{{ tag }}</span>
      {%- endfor -%}
    </p>
    {%- endif -%}
  </header>

  <div class="post-content e-content" itemprop="articleBody">
    {{ content }}
  </div>

  {%- if page.comments -%}
    <!-- Comments section -->
  {%- endif -%}

  <nav class="post-nav">
    {%- if page.previous -%}
      <a href="{{ page.previous.url | relative_url }}" class="prev">
        ← {{ page.previous.title }}
      </a>
    {%- endif -%}
    {%- if page.next -%}
      <a href="{{ page.next.url | relative_url }}" class="next">
        {{ page.next.title }} →
      </a>
    {%- endif -%}
  </nav>

  <a class="u-url" href="{{ page.url | relative_url }}" hidden></a>
</article>

4. 현대적인 정적 사이트 생성기

2025년 정적 사이트 생성기 비교

생성기 언어 특징 빌드 속도 생태계 학습 곡선
Jekyll Ruby GitHub 기본 지원 중간 크다 쉬움
Hugo Go 매우 빠른 빌드 매우 빠름 중간 중간
Next.js JavaScript React 기반 빠름 매우 크다 중간
Gatsby JavaScript GraphQL 내장 느림 크다 어려움
Astro JavaScript 부분 수화 빠름 성장 중 쉬움
SvelteKit JavaScript 컴파일러 기반 빠름 성장 중 중간
VitePress JavaScript Vue 기반 매우 빠름 중간 쉬움

GitHub Pages 배포 플로우

graph LR
    A[소스 코드] --> B{생성기 선택}
    
    B --> C[Jekyll]
    B --> D[기타 SSG]
    
    C --> E[GitHub 자동 빌드]
    D --> F[로컬/CI 빌드]
    
    E --> G[gh-pages 브랜치]
    F --> G
    
    G --> H[GitHub Pages 배포]
    H --> I[CDN 배포]
    I --> J[사용자 접속]
    
    subgraph "빌드 옵션"
        K[GitHub Actions]
        L[로컬 빌드]
        M[외부 CI/CD]
    end
    
    K --> F
    L --> F
    M --> F

Next.js + GitHub Pages

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// package.json
{
  "name": "my-nextjs-site",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "export": "next export",
    "deploy": "npm run build && npm run export && touch out/.nojekyll && gh-pages -d out -t true"
  },
  "dependencies": {
    "next": "^14.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "gh-pages": "^6.0.0"
  }
}

next.config.js:

1
2
3
4
5
6
7
8
9
10
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  basePath: process.env.NODE_ENV === 'production' ? '/repository-name' : '',
  images: {
    unoptimized: true,
  },
}

module.exports = nextConfig

Hugo + GitHub Actions

.github/workflows/hugo.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
name: Deploy Hugo site to Pages

on:
  push:
    branches: ["main"]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: "pages"
  cancel-in-progress: false

defaults:
  run:
    shell: bash

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      HUGO_VERSION: 0.120.0
    steps:
      - name: Install Hugo CLI
        run: |
          wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
          && sudo dpkg -i ${{ runner.temp }}/hugo.deb
          
      - name: Checkout
        uses: actions/checkout@v4
        with:
          submodules: recursive
          fetch-depth: 0
          
      - name: Setup Pages
        id: pages
        uses: actions/configure-pages@v4
        
      - name: Build with Hugo
        env:
          HUGO_ENVIRONMENT: production
          HUGO_ENV: production
        run: |
          hugo \
            --gc \
            --minify \
            --baseURL "${{ steps.pages.outputs.base_url }}/"
            
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2
        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@v3

Vue.js 프로젝트

vue.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
  publicPath: process.env.NODE_ENV === 'production'
    ? '/repository-name/'
    : '/',
  outputDir: 'dist',
  
  // PWA 설정
  pwa: {
    name: 'My Vue App',
    themeColor: '#4DBA87',
    msTileColor: '#000000',
    appleMobileWebAppCapable: 'yes',
    appleMobileWebAppStatusBarStyle: 'black',
  },
}

.github/workflows/deploy-vue.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
name: Deploy Vue.js site

on:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
        
    - name: Install dependencies
      run: npm ci
      
    - name: Build
      run: npm run build
      
    - name: Deploy to GitHub Pages
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./dist
        cname: custom-domain.com  # 커스텀 도메인 사용 시

5. 커스텀 도메인 설정

도메인 연결하기

  1. DNS 설정 (도메인 제공업체에서)
1
2
3
4
5
6
7
8
# Apex 도메인 (example.com)
A     @     185.199.108.153
A     @     185.199.109.153
A     @     185.199.110.153
A     @     185.199.111.153

# 서브도메인 (www.example.com)
CNAME www   username.github.io
  1. GitHub Pages 설정

CNAME 파일 생성:

1
example.com

또는 저장소 Settings → Pages → Custom domain

HTTPS 강제 적용

1
2
3
4
5
6
7
# _config.yml (Jekyll)
enforce_ssl: example.com

# 또는 .htaccess (정적 사이트)
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

리다이렉트 설정

404.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Redirecting...</title>
    <script>
        // 커스텀 리다이렉트 로직
        const redirects = {
            '/old-page': '/new-page',
            '/blog': '/posts',
            '/about-me': '/about',
        };
        
        const path = window.location.pathname;
        const redirect = redirects[path];
        
        if (redirect) {
            window.location.replace(redirect);
        } else {
            // 404 페이지 표시
            document.addEventListener('DOMContentLoaded', () => {
                document.getElementById('error').style.display = 'block';
            });
        }
    </script>
</head>
<body>
    <div id="error" style="display: none;">
        <h1>404 - Page Not Found</h1>
        <p>The page you're looking for doesn't exist.</p>
        <a href="/">Go Home</a>
    </div>
</body>
</html>

6. 고급 기능 구현

검색 기능 추가

assets/js/search.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// Lunr.js를 사용한 클라이언트 사이드 검색
(function() {
    function displaySearchResults(results, store) {
        const searchResults = document.getElementById('search-results');
        
        if (results.length) {
            let resultHTML = '';
            results.forEach(function(result) {
                const item = store[result.ref];
                resultHTML += `
                    <li>
                        <h3><a href="${item.url}">${item.title}</a></h3>
                        <p>${item.excerpt}</p>
                    </li>
                `;
            });
            searchResults.innerHTML = resultHTML;
        } else {
            searchResults.innerHTML = '<li>검색 결과가 없습니다.</li>';
        }
    }
    
    function getQueryVariable(variable) {
        const query = window.location.search.substring(1);
        const vars = query.split('&');
        
        for (let i = 0; i < vars.length; i++) {
            const pair = vars[i].split('=');
            if (pair[0] === variable) {
                return decodeURIComponent(pair[1].replace(/\+/g, '%20'));
            }
        }
    }
    
    const searchTerm = getQueryVariable('query');
    
    if (searchTerm) {
        document.getElementById('search-box').setAttribute('value', searchTerm);
        
        // 검색 인덱스 로드
        fetch('/search-index.json')
            .then(response => response.json())
            .then(data => {
                const idx = lunr(function () {
                    this.field('id');
                    this.field('title', { boost: 10 });
                    this.field('author');
                    this.field('category');
                    this.field('content');
                    
                    data.forEach(function (doc) {
                        this.add(doc);
                    }, this);
                });
                
                const results = idx.search(searchTerm);
                displaySearchResults(results, data);
            });
    }
})();

댓글 시스템 통합

_includes/comments.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- Utterances (GitHub Issues 기반) -->
<script src="https://utteranc.es/client.js"
        repo="username/username.github.io"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async>
</script>

<!-- 또는 Giscus (GitHub Discussions 기반) -->
<script src="https://giscus.app/client.js"
        data-repo="username/username.github.io"
        data-repo-id="REPO_ID"
        data-category="Comments"
        data-category-id="CATEGORY_ID"
        data-mapping="pathname"
        data-strict="0"
        data-reactions-enabled="1"
        data-emit-metadata="0"
        data-input-position="top"
        data-theme="light"
        data-lang="ko"
        crossorigin="anonymous"
        async>
</script>

Analytics 추가

_includes/analytics.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Google Analytics 4 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>

<!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js' 
        data-cf-beacon='{"token": "YOUR_TOKEN"}'></script>

<!-- 개인정보 보호를 위한 옵션 -->
<script>
  // IP 익명화
  gtag('config', 'G-XXXXXXXXXX', { 'anonymize_ip': true });
  
  // Do Not Track 존중
  if (navigator.doNotTrack === "1") {
    window['ga-disable-G-XXXXXXXXXX'] = true;
  }
</script>

7. 성능 최적화

이미지 최적화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 반응형 이미지 -->
<picture>
  <source media="(max-width: 640px)" 
          srcset="/assets/images/hero-mobile.webp" 
          type="image/webp">
  <source media="(max-width: 640px)" 
          srcset="/assets/images/hero-mobile.jpg" 
          type="image/jpeg">
  <source srcset="/assets/images/hero-desktop.webp" 
          type="image/webp">
  <img src="/assets/images/hero-desktop.jpg" 
       alt="Hero Image" 
       loading="lazy"
       decoding="async">
</picture>

리소스 최적화

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 중요 CSS 인라인 -->
<style>
  /* Critical CSS */
  body { margin: 0; font-family: -apple-system, sans-serif; }
  .header { background: #24292e; color: white; padding: 1rem; }
</style>

<!-- 나머지 CSS 비동기 로드 -->
<link rel="preload" href="/assets/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/css/main.css"></noscript>

<!-- JavaScript 지연 로드 -->
<script defer src="/assets/js/main.js"></script>

<!-- 리소스 힌트 -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

Service Worker로 오프라인 지원

sw.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const CACHE_NAME = 'site-cache-v1';
const urlsToCache = [
  '/',
  '/assets/css/main.css',
  '/assets/js/main.js',
  '/offline.html',
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(urlsToCache))
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => {
        if (response) {
          return response;
        }
        
        return fetch(event.request).then(response => {
          if (!response || response.status !== 200 || response.type !== 'basic') {
            return response;
          }
          
          const responseToCache = response.clone();
          caches.open(CACHE_NAME)
            .then(cache => {
              cache.put(event.request, responseToCache);
            });
          
          return response;
        });
      })
      .catch(() => {
        return caches.match('/offline.html');
      })
  );
});

8. 문제 해결

빌드 오류 해결

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Jekyll 빌드 오류 시
# .github/workflows/jekyll.yml
name: Build and Deploy

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.1'
          bundler-cache: true
          
      - name: Build site
        run: bundle exec jekyll build
        env:
          JEKYLL_ENV: production
          
      - name: Test site
        run: |
          bundle exec htmlproofer ./_site \
            --disable-external \
            --check-html \
            --allow_hash_href

일반적인 문제들

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
페이지가 나타나지 않음:
  - GitHub Pages 활성화 확인
  - 브랜치 이름 확인 (main vs master)
  - index.html 또는 README.md 존재 확인
  - 몇 분 대기 (최대 10분)

404 오류:
  - baseurl 설정 확인
  - 파일 경로 대소문자 확인
  - .nojekyll 파일 추가 (Jekyll 비활성화)

CSS/JS 로드 실패:
  - 상대 경로 사용: {{ "/assets/css/style.css" | relative_url }}
  - HTTPS 혼합 콘텐츠 확인
  - 캐시 비우기

빌드 실패:
  - _config.yml 문법 확인
  - Gemfile.lock 삭제 후 재빌드
  - 플러그인 호환성 확인

2025년 GitHub Pages 최적화 팁

성능 최적화 체크리스트

최적화 항목 설명 효과 구현 난이도
이미지 최적화 WebP, AVIF 형식 사용 50-80% 크기 감소 쉬움
CDN 활용 Cloudflare 연동 전 세계 빠른 로딩 중간
Asset 압축 Brotli 압축 20-30% 크기 감소 쉬움
코드 분할 페이지별 번들 초기 로딩 개선 중간
PWA 구현 오프라인 지원 UX 크게 개선 어려움
캐시 전략 브라우저 캐싱 재방문 속도 향상 쉬움

GitHub Pages 활용 사례

프로젝트 유형 예시 적합한 생성기 특징
개인 블로그 기술 블로그 Jekyll, Hugo SEO 최적화
포트폴리오 개발자 포트폴리오 Next.js, Gatsby 인터랙티브
문서 사이트 API 문서 VitePress, Docusaurus 검색 기능
랜딩 페이지 제품 소개 Astro, 11ty 빠른 로딩
온라인 이력서 CV/Resume 순수 HTML/CSS 간단함

마무리

GitHub Pages는 정적 웹사이트를 호스팅하는 가장 쉽고 빠른 방법입니다.

핵심 포인트:

  • 무료이면서도 안정적인 호스팅
  • Jekyll 내장 지원으로 쉬운 블로그 구축
  • 다양한 정적 사이트 생성기 호환
  • GitHub Actions와 통합으로 자동 배포
  • 커스텀 도메인과 HTTPS 지원

개인 블로그, 프로젝트 문서, 포트폴리오 등 다양한 용도로 활용해보세요.

다음 편에서는 보안 설정과 모범 사례에 대해 알아보겠습니다.

📚 GitHub 마스터하기 시리즈

🌱 기초편 (입문자)

  1. GitHub 시작하기
  2. Repository 기초
  3. Git 기본 명령어
  4. Branch와 Merge
  5. Fork와 Pull Request

💼 실전편 (중급자)

  1. Issues 활용법
  2. Projects로 프로젝트 관리
  3. Code Review 잘하기
  4. GitHub Discussions
  5. Team 협업 설정
  6. [GitHub Pages] (현재 글)(/posts/github-practical-06-github-pages/)

🚀 고급편 (전문가)

  1. GitHub Actions 입문
  2. Actions 고급 활용
  3. Webhooks와 API
  4. GitHub Apps 개발
  5. 보안 기능
  6. GitHub Packages
  7. Codespaces
  8. GitHub CLI
  9. 통계와 인사이트

🏆 심화편 (전문가+)

  1. Git Submodules & Subtree
  2. Git 내부 동작 원리
  3. 고급 브랜치 전략과 릴리스 관리
  4. GitHub GraphQL API
  5. GitHub Copilot 완벽 활용

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.