GitHub Pages 로 개인 블로그 만들기 — 0 에서 giscus 까지
하루 동안 GitHub Pages 로 개인 블로그를 만들었습니다 — 지금 보고 계신 이 사이트입니다. 다음에 또 만들 일이 생길 것 같아서 과정을 기록해 둡니다.
결과물: glenn-yu.github.io — Jekyll · 로그캣 부팅 인트로 · ⌘K 팔레트 · 다크/라이트 · giscus 댓글 · 커스텀 404. 전체 코드: glenn-yu/glenn-yu.github.io
왜 GitHub Pages 인가
선택지는 많습니다 — Vercel, Netlify, Cloudflare Pages 등. 그중 GitHub Pages 를 고른 이유는 단순합니다.
- 레포 = 사이트 —
username.github.io레포를 만들면 그게 그대로 사이트 URL. - Jekyll 자동 빌드 — 마크다운만 push 하면 GitHub 가 알아서 빌드. CI 설정 필요 없음.
- 무료 + HTTPS 자동.
- 버전 관리가 곧 발행 이력 —
git log가 변경사항 기록.
단점이라면 “GitHub 화이트리스트된 Jekyll 플러그인만 쓸 수 있다” 정도. 일반 블로그로는 충분합니다.
5분 컷 — 한 줄로 사이트 띄우기
가장 빠른 코스부터 가봅시다.
- GitHub 에서 새 레포: 이름은 정확히
<본인-username>.github.io, Public. - 클론하고
index.html하나 만들어 push:
git clone https://github.com/<본인>/<본인>.github.io.git
cd <본인>.github.io
echo "<h1>Hello, world</h1>" > index.html
git add index.html
git commit -m "init"
git push origin main
- 1~2분 후
https://<본인>.github.io접속.
여기서 끝내도 됩니다. 정적 HTML/CSS/JS 만 잘 짜도 사이트 하나 만드는 데 충분해요. 하지만 글이 늘어나면 레이아웃·메타·목록 처리가 귀찮아지니, 다음 단계로 넘어갑니다.
Jekyll 로 본격 블로그 만들기
블로그 운영에는 Jekyll 이 편합니다. 마크다운 파일을 추가하면 곧 글이 됩니다.
최소 구성:
.
├── _config.yml # 사이트 설정
├── _layouts/
│ ├── default.html # 모든 페이지 공통 레이아웃
│ └── post.html # 블로그 글 레이아웃
├── _includes/
│ ├── head.html
│ ├── header.html
│ └── footer.html
├── _posts/
│ └── YYYY-MM-DD-제목.md
├── assets/css/main.css
├── index.html # 홈
└── about.md # 소개
_config.yml 예시:
title: Glenn Yu
tagline: Mobile · Adtech Engineer
url: "https://glenn-yu.github.io"
author:
name: Glenn Yu
email: gwangy.yu@gmail.com
github: glenn-yu
markdown: kramdown
permalink: /posts/:title/
timezone: Asia/Seoul
plugins:
- jekyll-feed
- jekyll-sitemap
Gemfile (로컬 미리보기 안 할 거면 없어도 됨):
source "https://rubygems.org"
gem "github-pages", group: :jekyll_plugins
group :jekyll_plugins do
gem "jekyll-feed"
gem "jekyll-sitemap"
end
글 한 편 (_posts/2026-05-08-hello.md):
---
title: "안녕하세요"
date: 2026-05-08 14:00:00 +0900
tags: [intro]
---
본문...
push 하면 /posts/안녕하세요/ 로 자동 발행됩니다.
한국어 친화 셋업
기본 시스템 폰트로도 작동하지만, 한국어 가독성에 진심이라면 Pretendard 추천입니다. CDN 한 줄로 끝납니다.
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable.min.css">
CSS 폰트 스택:
:root {
--font-sans: "Pretendard Variable", Pretendard, -apple-system,
BlinkMacSystemFont, "Apple SD Gothic Neo",
"Segoe UI", Roboto, sans-serif;
}
body { font-family: var(--font-sans); }
다크/라이트 자동 + 수동 토글
prefers-color-scheme 미디어 쿼리만 쓰면 시스템 설정에 따라 자동 전환됩니다.
:root { --bg: #ffffff; --fg: #111418; }
@media (prefers-color-scheme: dark) {
:root { --bg: #0e1116; --fg: #e6edf3; }
}
수동 토글까지 원하면 data-theme 속성으로 오버라이드를 추가합니다.
:root[data-theme="light"] { --bg: #ffffff; }
:root[data-theme="dark"] { --bg: #0e1116; }
JS 로 토글하면서 localStorage 에 저장하면 페이지 이동에도 유지됩니다.
function toggleTheme() {
var cur = document.documentElement.getAttribute('data-theme');
var next = cur === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
페인트 깜빡임을 막으려면 <head> 에서 동기 스크립트로 미리 적용해 두세요.
색다른 한 끗 — 로그캣 부팅 인트로
여기부터는 취향 영역입니다.
저는 안드로이드 개발자 정체성을 살리고 싶어서, 사이트 첫 진입 시 adb logcat 같은 텍스트가 흐르는 인트로를 넣었습니다.
핵심 아이디어:
sessionStorage로 세션당 1회만 표시- 클릭 / 키 입력으로 즉시 skip
- 텍스트는 한 줄씩
setTimeout으로 출력 - 페이지 본문은
boot-pending클래스로 잠시 숨김 → 인트로 끝나면 해제
요지만 옮기면:
function runBoot() {
if (sessionStorage.getItem('boot-seen') === '1') return;
// overlay 생성, 줄 단위로 setTimeout 출력
// 끝나면 sessionStorage.setItem('boot-seen', '1')
}
⌘K 커맨드 팔레트
Linear / VSCode 의 그 팔레트입니다. Cmd+K 누르면 페이지·글·명령을 한 번에 검색.
페이지·글 데이터는 _layouts/default.html 에서 Liquid 로 주입합니다:
<script>
window.SITE_DATA = {
pages: [
{ title: "Home", url: "{{ '/' | relative_url }}" },
{ title: "About", url: "{{ '/about/' | relative_url }}" }
],
posts: [
{%- for p in site.posts -%}
{ title: {{ p.title | jsonify }},
url: {{ p.url | relative_url | jsonify }} }
{%- unless forloop.last -%},{%- endunless -%}
{%- endfor -%}
]
};
</script>
JS 쪽에서는 Cmd+K 핸들링 + 간단한 퍼지 매칭 + 화살표 키 네비게이션만 있으면 됩니다.
SEO · 공유 기본 — 파비콘 + OG 이미지
여기는 건너뛰면 안 됩니다. 카카오톡·슬랙·트위터 어디든 링크 미리보기가 안 뜨면 사이트가 빈약해 보여요.
파비콘 (SVG 추천 — 모던 브라우저 모두 지원):
<link rel="icon" type="image/svg+xml" href="/assets/favicon.svg">
<link rel="icon" type="image/png" sizes="64x64" href="/assets/favicon.png">
<link rel="apple-touch-icon" href="/assets/apple-touch-icon.png">
Open Graph / Twitter Card 메타:
<meta property="og:type" content="website">
<meta property="og:title" content="{{ site.title }}">
<meta property="og:description" content="{{ site.description }}">
<meta property="og:image" content="{{ '/assets/og-image.png' | absolute_url }}">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="{{ '/assets/og-image.png' | absolute_url }}">
OG 이미지는 1200×630 권장이지만 1200×1200 도 대부분 플랫폼이 받아줍니다.
디자이너 없으면 SVG 로 직접 그리고 macOS 의 qlmanage 로 PNG 변환 가능:
qlmanage -t -s 1200 -o . og-image.svg
mv og-image.svg.png og-image.png
포스트 UX 폴리시
읽기 시간 — kramdown 의 size 필터로 글자 수 세고 분 단위 환산. 한국어 기준 ~500자/분:
{%- assign chars = content | strip_html | size -%}
{%- assign rt = chars | divided_by: 500 | plus: 1 -%}
📖 {{ rt }}분 읽기
코드 복사 버튼 — <pre> 마다 버튼 주입:
document.querySelectorAll('.post-content pre').forEach(function (pre) {
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.onclick = function () {
var code = (pre.querySelector('code') || pre).textContent;
navigator.clipboard.writeText(code);
btn.textContent = 'Copied!';
setTimeout(function () { btn.textContent = 'Copy'; }, 1500);
};
pre.appendChild(btn);
});
헤딩 앵커 — kramdown 은 auto_ids 가 기본 활성이라 h2 / h3 에 자동으로 id 가 붙습니다.
JS 로 호버 시 보이는 # 링크만 추가하면 됩니다.
document.querySelectorAll('.post-content h2[id], .post-content h3[id]')
.forEach(function (h) {
var a = document.createElement('a');
a.className = 'heading-anchor';
a.href = '#' + h.id;
a.textContent = '#';
h.appendChild(a);
});
giscus 댓글
Disqus 대신 GitHub Discussions 기반 giscus 를 썼습니다. 광고 없고, 댓글이 곧 디스커션이라 통계 보기도 편합니다.
셋업 순서:
- 레포에 Discussions 활성화:
gh api -X PATCH repos/<유저>/<레포> -f has_discussions=true - github.com/apps/giscus 에서 giscus 앱을 레포에 설치.
- giscus.app 에서 설정 후 스크립트 카피.
스크립트 (_includes/giscus.html 같은 곳에 두고 post 레이아웃에서 include):
<script src="https://giscus.app/client.js"
data-repo="<유저>/<레포>"
data-repo-id="..."
data-category="Announcements"
data-category-id="..."
data-mapping="pathname"
data-theme="preferred_color_scheme"
data-lang="ko"
crossorigin="anonymous"
async>
</script>
수동 테마 토글이 있으면 giscus iframe 한테도 알려줘야 합니다:
iframe.contentWindow.postMessage(
{ giscus: { setConfig: { theme: 'dark' } } },
'https://giscus.app'
);
404 페이지에도 정체성을
/404.html 만들어 두면 GitHub Pages 가 안 잡히는 경로마다 자동으로 띄워줍니다.
저는 안드로이드 크래시 화면 미러링한 logcat 스타일로 만들었습니다.
FATAL EXCEPTION: main
Process: io.glenn.site, PID: 404
com.gwangy.site.RouteNotFoundException: no route matched "/asdf"
at com.gwangy.site.Router.resolve(Router.kt:42)
...
JS 로 잘못 입력된 경로를 동적으로 박아 넣어서 어디서 길을 잃었는지 보여줍니다.
document.getElementById('bad-path').textContent
= '"' + (location.pathname + location.search).slice(0, 80) + '"';
정리하며
하루 만에 만든 셋업이지만 글 쓸 환경으로는 충분합니다. 정리하면 이렇습니다.
필수
username.github.io레포 +index.html- Jekyll layouts / includes / posts
- 다크 · 라이트 + 한국어 폰트
- 파비콘 + OG 이미지
있으면 좋은
- 정체성을 드러내는 한 끗 (부팅 인트로 같은)
- ⌘K 팔레트
- 읽기 시간 + 코드 복사 + 헤딩 앵커
- giscus 댓글
- 커스텀 404
다음은 사이트를 만지는 게 아니라 글을 쓰는 것입니다. 만든 도구를 실제로 쓰면서 부족한 부분을 발견하는 게 다음 사이클이에요.
읽어주셔서 감사합니다. 질문 / 제보 / 잘못된 부분은 아래 댓글이나 이슈 로 부탁드립니다 🙇♂️
💬 Comments
GitHub 계정으로 댓글을 남길 수 있어요.