202X년에 개인 홈페이지 만들기

오타쿠 트윗 아카이빙용 웹사이트 구축기.

안내:
이 글은 오래되었습니다.

목차

  1. 들어가며
  2. 정적 사이트 생성기 Jekyll
  3. jekyll-twitter-plugin으로 트윗 스크랩하기
  4. Vercel에서 사이트 배포하기
  5. 정리와 예고

들어가며

이 글은 나의 개인 홈페이지, 유월당(바로 이곳)을 어떻게 만들었는지에 대한 기록이다.

(‘홈페이지’에는 여러 뜻이 있지만 여기서는 웹 초창기에 비롯된, 개인적인 웹사이트를 가리키는 용어로서 사용한다.)

내 홈페이지 유월당은 2021년 12월 13일(당시에 작성된 공지 트윗)에 오픈했다. 계획과 개발은 그 한 달여 전부터 설렁설렁 했던 것 같다.

부제목(‘오타쿠 트윗 아카이빙용 웹사이트 구축기’)에서부터 명시되었듯 사이트의 주 목적은 이미 써 둔 내 (오타쿠) 트윗을 아카이빙하는 것이다. 트위터 서버에 묻힌 막대한 텍스트 무더기 중에서 볼 만한 것들을 건져 가지런히 정리하고자 홈페이지를 열었다. 기왕이면 긴 글을 올릴 공간으로도 쓸 겸해서.

처음에는 적당한 게시 플랫폼을 찾으려고 했는데, 마땅히 마음에 드는 곳이 없기도 했고 다룰 데이터의 양이 방대하고 트위터 사이트 구조상 복붙도 까다롭기에, 트윗 스크랩 플러그인이 있는 정적 사이트 생성기로 아예 웹사이트를 하나 파는 게 편의상 낫겠다는 결론을 내렸다.

(결론부터 따지자면 정답이었다. 볼드모트 타래 같은 걸 수동으로 복붙했다간 미쳐버렸을 거다. 개수 — 총 118개 — 가 너무 많아서 스크래퍼마저 뻗었고 그 탓에 여러 차례 나눠서 긁어야 했었다.)

‘어떻게 해야 하는지’를 안다면 이런 간단한 요구사항을 가진 웹사이트를 만드는 게 어렵지 않고, 비용도 거의 들지 않는다는 걸 알고 있기 때문에 내릴 수 있었던 결론이기도 하다.

열심히 만들고 나니까 혼자서 품고 있기엔 좀 아깝다는 느낌이 들어 주저리주저리 떠들고 싶어진 게 이 글을 쓰는 이유다. 찾아봐도 나 같은 특이한 케이스(오타쿠의, 트윗 아카이빙을 중심으로 한, 텍스트 중심 웹사이트 구축)에 대한 수기가 없더라. 누군가에게 참고나 도움이 될지 어쩔지는 잘 모르겠다. 그러면 좋겠지만.

정적 사이트 생성기 Jekyll

이미 만들어진 파일을 변형 없이 그대로 제공할 뿐인 정적 페이지(static page)는 서버에서 특별히 뭔가를 하는 일이 없다. 회원가입, 글 쓰기, 댓글 달기, 조회수 세기, 비밀글 따위의 동적(dynamic) 기능을 가지지 못한다는 뜻이다.

반대로 그 이상 복잡해질 이유가 없는 사이트라면 정적 페이지로 구성된 형태가 적합하다. 단순해서 제작과 유지보수도 간단하고, 가볍고, 저렴하기 때문이다.

내 사이트는 일종의 개인 트위터 서드파티 개념으로서 트윗을 아카이빙해 정리하는 게 목적이고, 복잡한 기능이 필요 없기 때문에 정적 페이지의 집합, 즉 정적 사이트면 충분했다.

그런 정적 사이트를 만드는 도구가 정적 사이트 생성기(static site generator)다. 다양한 기능이 있지만 변환(마크다운 텍스트를 HTML로)과 복붙(템플릿 안에 각 페이지의 콘텐츠를)이 핵심이다.

정적 사이트 생성기는 많지만 내가 사용할 정적 사이트 생성기는 Jekyll(번역)로 정해져 있다. 트윗 스크랩 플러그인이 있기 때문이다.

jekyll-twitter-plugin으로 트윗 스크랩하기

그렇다면 이제 핵심적인 트윗 스크래핑에 대해 적어 보겠다.

jekyll-twitter-plugin은 Jekyll용 트윗 스크랩 플러그인이다. 내 홈페이지에서 절대 빼놓을 수 없는 중대 요소인데, 이게 없으면 그냥 이 머리 아픈 프로젝트를 시작하기로 한 전제 자체가 성립되지 않기 때문이다. 인간이 그 많은 트윗을 일일이 복붙하는 건 미친 짓이다. 트위터는 Ctrl+A(전체 선택)도 듣지 않는단 말이다.

이 플러그인은 지정된 Liquid(Jekyll이 사용하는 템플릿 언어) 태그에 트윗의 URL을 집어넣으면 그것을 트위터 API가 제공하는 트윗 전문이 포함된 HTML 스니펫으로 변환해 준다. 즉, 복붙과 일괄 변환 작업을 대신해 준다.

jekyll-twitter-plugin은 상냥하게도 단일 파일로 만들어졌기 때문에 프로젝트 루트의 _plugin 폴더에 플러그인 파일을 내려받기만 하면 복잡하지 않게 바로 설치된다. 알기 쉬운 단일 파일이므로 입맛대로 개조하기도 수월하다.

기본적으로 이 플러그인이 렌더링하는 모든 트윗은 jekyll-twitter-plugin 클래스가 있는 <div> 요소 안에 들어가도록 되어 있는데, 이것을 없애고, 렌더링되는 트윗에서 필요없는 부분을 지우고 줄바꿈을 추가하는 등의 변형을 가하도록 살짝만 손을 봤다.

원본:

"<div class='jekyll-twitter-plugin'>#{body}</div>"

변경:

body.sub(/ data-lang="ko"><p lang="[a-z]+" dir="ltr"/, ">\n  <p")
    .sub('</p>&mdash;', "</p>\n  <p>—")
    .sub('?ref_src=twsrc%5Etfw">', '">')
    .sub('</blockquote>', "</p>\n</blockquote>")
    .gsub('&quot;', '"')
    .gsub('&#39;', "'")
    .gsub('<br>', "<br>\n  ")

개조까지 마쳤으면 사용할 차례다. 기본적으로 내가 트윗을 아카이빙하는 과정은 다음과 같다. (예시의 트윗 URL들은 실제 트윗이다.)

1. 글의 YAML 머리말(번역)에 트윗 URL의 배열을 입력한다.

tweets:
  - https://twitter.com/JuYuwol/status/1501043785840484353
  - https://twitter.com/JuYuwol/status/1501044450327515146
  - https://twitter.com/JuYuwol/status/1501076060170960898

이때 텍스트 에디터 Notepad++를 사용해 브라우저에서 링크를 바로 드래그 앤 드롭한다.

과정 스크린샷

2. 본문에 트윗 스레드용 조각파일(번역)을 삽입한다.

{% include tweets.txt %}

여기서 삽입된 tweets.txt 파일의 내용은 이렇다.

<div class="twitter-thread">
{%- capture _thread -%}
{%- for tweet in page.tweets -%}
{% twitter tweet lang=ko omit_script=true %}
{%- endfor %}
{%- endcapture %}
  {{ _thread | indent: 1 }}
</div>

작업할 때 매번 입력하기 번거로우므로 include 태그로 템플릿을 삽입하는 것이다.

(여기서 사용된 twitter-thread 클래스가 있는 <div> 요소는 한 스레드의 트윗들을 연결하기 위한 꾸미기용 블록이고, indent 필터는 들여쓰기를 위해 자체적으로 만들어 추가한 필터(번역)다.)

3. 빌드하고, 출력을 확인한다. 주로 로컬 서버를 켠 채로 작업하므로 브라우저에서 바로 확인한다.

페이지 스크린샷

매번 빌드할 때마다 트위터에서 트윗을 긁어올 수는 없으므로, 출력된 결과물에서 스크랩된 트윗 블록을 본문에 도로 복붙한다. 주로, 브라우저에서 출력을 확인한 즉시 Ctrl+U를 눌러 소스 보기에서 바로 복사하는 편이다.

소스 보기 스크린샷

그렇게 만들어진 코드는 이렇다.

<div class="twitter-thread">
  <blockquote class="twitter-tweet">
    <p>아이 울음소리에 거의 알레르기적 반응을 일으키는 볼드모트. (진짜임. 7권 봐라.)</p>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501043785840484353">2022년 3월 8일</a></p>
  </blockquote>
  <blockquote class="twitter-tweet">
    <p>아니 진짜로 고드릭 골짜기에서 증발당하기 전 해리를 보면서 마지막으로 한 생각이 '아놔 저 애새끼 울기 시작했잖아'였다고 <a href="https://t.co/Ym9zQebQi9">pic.twitter.com/Ym9zQebQi9</a></p>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501044450327515146">2022년 3월 8일</a></p>
  </blockquote>
  <blockquote class="twitter-tweet">
    <p>죽기 전(?) 마지막으로 하는 생각이 '나는 애들 우는 소리가 정말 싫어'라니 정말... 정말 볼드모트답다고 생각함</p>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501076060170960898">2022년 3월 8일</a></p>
  </blockquote>
</div>

뭐……. 결국 복붙을 하긴 한다. 하지만 어차피 수정해야 하기 때문에 필연이다. 결국 정리는 사람 손으로 해야 하는 법이다.

4. 위에서 말했듯, 트윗에 인용된 이미지/트윗/링크 따위의 세부사항을 수정한다. 지워야 할 내용은 지우고, 주석이 필요하면 달고, 가끔 내키면 오탈자도 고친다.

예시에서는 트윗의 이미지 링크를 인용문 텍스트 블록으로 바꾸고 비문을 고쳤다.

<div class="twitter-thread">
  <blockquote class="twitter-tweet">
    <p>아이 울음소리에 거의 알레르기적 반응을 일으키는 볼드모트. (진짜임. 7권 봐라.)</p>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501043785840484353">2022년 3월 8일</a></p>
  </blockquote>
  <blockquote class="twitter-tweet">
    <p>아니 진짜로 고드릭 골짜기에서 증발당하기 전 해리를 보면서 마지막으로 한 생각이 '아놔 저 애새끼 울기 시작했잖아'였다고</p>
    <blockquote>
      <p>그는 지팡이를 아이의 얼굴에 아주 조심스럽게 겨눴다. 그는 이 설명할 수 없는 위험한 존재가 파괴되는 것을 보고 싶었다. 아이가 울기 시작했다. 그가 제임스가 아니라는 것을 알아차린 것이다. 그는 아이가 우는 것이 마음에 들지 않았다. 고아원에 있을 때도 어린애들의 칭얼거림을 도저히 참을 수가 없었다…….</p>
      <p>“아바다 케다브라!”</p>
      <p>그리고 그는 부서졌다.</p>
      <p class="cite">— J. K. 롤링, 해리 포터와 죽음의 성물, 20주년 개정판</p>
    </blockquote>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501044450327515146">2022년 3월 8일</a></p>
  </blockquote>
  <blockquote class="twitter-tweet">
    <p>죽기 전(?) 마지막으로 한 생각이 '나는 애들 우는 소리가 정말 싫어'라니 정말... 정말 볼드모트답다고 생각함</p>
    <p>— 주유월 (@JuYuwol) <a href="https://twitter.com/JuYuwol/status/1501076060170960898">2022년 3월 8일</a></p>
  </blockquote>
</div>

페이지 스크린샷

완성!

트윗 아카이브 글, 즉 사이트의 대부분을 차지하는 글들은 이런 과정으로 작성되었다.

Vercel에서 사이트 배포하기

콘텐츠를 만들었다면 만들어진 사이트를 인터넷에 올려야 한다.

이런 올 사람 없는 극소규모의 사이트에는 월 500원 전후의 초저가 웹호스팅을 쓰는 게 가장 잘 알려진, 오래된 솔루션일 것이다. 커스텀 도메인을 포기한다면 그냥 무료 호스팅에 올려도 무방하겠고.

하지만 지금은 2020년대고 더 좋고 똑똑한 선택지가 더 많다. 진짜로 요즘 시대에 정적 사이트, 그러니까 HTML/CSS/JS 파일만을 올리는 데에는 돈이 들지 않는다. 엄청나게 관대한 조건의 무료 플랜을 제공하는 배포 플랫폼이 여럿 있기 때문이다.

무료 트래픽 월 100 GB가 업계 표준이고, 커스텀 도메인도 무료고, SSL도 자동으로 설치된다. 콘텐츠도 자동으로 압축되어 전송되고, 직접 웹 서버 설정을 만지려면 꽤나 복잡한 HTTP 헤더/리다이렉트/리라이트 설정도 간단하게 할 수 있다. 배포도 자동화되어 있어서 엄청 간단하다. 텍스트 에디터에 붙은 푸시 버튼 한 번 딸깍 누르면 웹사이트에 글이 알아서 올라와 있다.

그러니 PHP와 DB를 사용하지 않는 정적 사이트라면 국내 업체의 무료 혹은 저가형 웹호스팅을 이용할 이유가 없다.

이런 여러 플랫폼 중 내가 선택한 것은 Vercel이다. Netlify, Cloudflare Pages 등의 다른 경쟁자도 있지만, 그냥 한국 CDN을 제공하고 대시보드가 Netlify보다 미세하게 편리해서 Vercel을 선택했다. 솔직히 그 외에는 Netlify가 더 나은 것 같긴 하다.

Vercel에서 배포하려면 Git 저장소가 필요하다. 그냥 오타쿠질용 Gmail 계정으로 Github 계정을 새로 파고 비공개 저장소를 만들어서 Jekyll 프로젝트 폴더를 연결시켰다.

그냥 하라는 대로 따라가기만 하면 복잡하게 설정할 것 없이(사실 여기까지 간 시점에서 이미 복잡한 것이긴 한데) 알아서 자동으로 감지하고 배포해 준다. 현대의 웹서비스는 굉장해.

정리와 예고

제목에 붙은 숫자에서 예고되었듯 ‘202X년에 개인 홈페이지 만들기’는 여러 편으로 나눠서 발행될 예정이다.

(원래는 모든 내용을 한 글에 몰아넣으려고 했는데 분량이 너무 길어지고 작성 기간도 너무 길어졌다. 진짜로, 글 쓰는 데 사이트 만드는 것보다 시간이 더 걸리고 있다. 현재진행형으로.)

이번 글에서는 사이트를 기본적으로 구성하는 시스템에 대해 설명했다.

다음 글에서는 사이트 구조 정책과 레이아웃, 색상, 동적 기능의 설계와 같은 세부적인 내용을 다룰 것이다. 무사히 발행될 수만 있다면…….

다음에 계속.