- 개인 웹사이트를 단일 바이너리로 만들면, 한 사람이 전체 구조를 이해하고 직접 유지보수할 수 있어 기존 SSG·호스팅 조합의 의존성 부담이 줄어듦
- Hugo와 GitHub Pages 같은 조합은 서비스 지속성, 프로젝트 유지, 플러그인 생태계, 배포 방식, Go 등 여러 외부 조건을 전제로 함
- 수동 HTML 편집은 단순하고 안정적이지만, 공통 기능을 반복해서 다루기 어렵고 작업 흐름이 피로해져 더 즐겁게 조정 가능한 방식이 필요했음
- Go 기반 동적 사이트는 IP 표시나 RSS 피드 갱신처럼 정적 사이트에서 번거로운 작업을 서버 측 코드로 처리하고, 브라우저가 아닌 도구에도 완성된 HTML을 반환함
- 개인 웹사이트는 작게 시작해 표준 라이브러리와 단순한 도구로 키우는 편이 오래가며, 큰 프레임워크로 시작하면 개인 시간 안에서 따라가기 어려움
기존 웹사이트 도구가 맞지 않았던 이유
- Ghost, Hugo, Jekyll, sr.ht와 tarball, 수동 HTML 편집까지 여러 방식을 시도했지만, 개인 기준에 맞지 않았고 흥미도 주지 못했음
- 가장 중요한 기준은 한 사람이 처음부터 끝까지 이해하고 쉽게 유지보수할 수 있는 시스템이었음
- 읽기 쉬운 코드
- 빠른 피드백 루프
- 재미와 영리함
- 고장 났을 때 직접 파고들 수 있는 구조
- Hugo 같은 정적 사이트 생성기(SSG)는 템플릿과 Markdown을 입력으로 받아 HTML을 만들고, 보통 호스팅 플랫폼과 함께 사용됨
- Hugo와 GitHub Pages 조합에는 여러 유지보수 조건이 따라붙음
- GitHub Pages 서비스가 계속 동작해야 함
- GitHub Pages 제품이 계속 유지되어야 함
- Hugo 프로젝트와 커뮤니티 문서가 유지되어야 함
- 플러그인 생태계에 의존할 수 있음
- Hugo 바이너리가 시간이 지나도 HTML을 거의 같은 방식으로 생성해야 함
- GitHub Pages 배포 메커니즘이 계속 작동해야 함
- Go가 필요함
- 특정 Hugo 버전을 고정해 쓰는 방법도 있지만, 실제로는 버그 때문에 업그레이드가 필요해지는 일이 생김
수동 HTML 편집의 장점과 한계
- 직접 제어하는 머신에 웹사이트를 호스팅하고, Vim으로 HTML을 손수 편집하는 방식도 선택했음
- j3s.sh의 첫 버전은 이 방식으로 만들어졌고, 현재 레이아웃 아이디어 중 상당수가 여기서 나왔음
- 손으로 HTML을 작성하면 고된 수작업처럼 느껴져 극단적인 미니멀리즘으로 이어짐
- 스타일을 HTML 안에 직접 넣음
- 사이트 전반의 공통 기능을 최소화함
- 스타일링을 많이 피함
- 이 방식은 단순하고 안정적이며 유지보수하기 쉬웠음
- 작성한 HTML은 수정 없이 재사용 가능했음
- 외부 의존성이 없었음
- 사이트가 오래 유지될 것이라는 확신을 줬음
- 다만 공통 기능의 템플릿화를 더 효율적으로 처리하고 싶었고, 기존 프레임워크 없이 재미있게 조정 가능한 방식이 필요했음
Go 단일 바이너리 웹사이트
- 웹사이트 전체를 하나의 언어로 작성하면, 결과물을 단일 바이너리에 담아 배포할 수 있음
- Go는 개인 유지보수와 단순 배포에 잘 맞는 선택지였음
- 한 사람이 유지보수하기 쉬움
- 의존성을 적게 쓰는 방향을 강조함
- 언어가 비교적 단순함
- 하위 호환성 보장이 있음
- 정적 컴파일 바이너리를 쉽게 만들 수 있음
- 대부분 10초 미만으로 컴파일됨
- 표준 라이브러리가 잘 발달해 있음
- 결과적으로 j3s.sh는 웹사이트를 서빙하는 하나의 바이너리가 됨
동적 웹사이트가 주는 단순함
- 경우에 따라 정적 생성 웹사이트보다 동적 생성 웹사이트가 더 단순할 수 있음
- 콘텐츠 생성을 위한 우회 방법을 고민하지 않아도 됨
- 필요한 내용을 즉석에서 생성할 수 있음
- 방문자의 IP 주소를 출력하는 기능은 Go의
http.HandlerFunc로 간단히 구현됨X-Forwarded-For헤더를 읽음/ip경로에 핸들러를 연결함- 필요한 곳에서 같은 함수를 호출할 수 있음
- 정적 사이트에서 같은 기능을 구현하려면 JavaScript 같은 외부 의존성이 필요할 수 있고, JavaScript가 없는 경우도 고려해야 함
- 일부 독자는 JavaScript 실행을 거부함
- 서버가 이미 IP 주소가 포함된 HTML을 반환하면, 클라이언트가 JavaScript를 이해하지 못해도 올바른 응답을 받을 수 있음
- 브라우저가 아닌 도구에도 같은 방식이 통함
- 홈페이지의 RSS 피드는 웹사이트 시작 시점에 생성됨
- 친구들의 최신 글을 새로 가져올 수 있음
- 직접 만든 RSS 피드 fetcher가 오랫동안 유지보수 없이 동작할 것으로 봄
- 내부 동작을 정확히 이해하고 있음
배포와 시작 방법
- 배포는 짧은 쉘 스크립트로 처리됨
- Git 저장소를 가져옴
- 로컬 브랜치가 뒤처져 있으면
git merge origin/main을 실행함 go build로 빌드함- 바이너리를
/usr/local/bin/j3s.sh로 옮김 service j3s.sh restart로 서비스를 재시작함
- 이 스크립트는 cronjob으로 매분 실행되어, 저장소가 업데이트되면 사이트를 다시 빌드함
- 로컬에서 테스트하고 업로드하면 1분 안에 공개 사이트에 반영됨
- 쉘을 조금 알면 10초 안에 이해할 수 있을 정도로 단순함
- 개인 웹사이트는 요즘 웹에서 독특한 느낌을 주며, 운영자가 중요하게 여기는 것을 깊게 반영할 수 있음
- 정적 사이트가 맞는 사람은 그대로 쓰면 되지만, 비슷한 가치관을 가진 사람에게는 동적 웹사이트 시도가 잘 맞을 수 있음
- 작게 시작할 수 있음
- 재미있는 아이디어를 반복적으로 추가할 수 있음
- 자기 사이트이므로 하드코딩해도 됨
- Rust, Perl, Python 등 좋아하는 언어로 만들 수 있음
- 시작은 작아야 함
- 먼저
index.html을 만들고, 선택한 언어로 이를 서빙하는 데 집중함 - RSS나 Markdown은 나중에 필요해질 때 추가함
- 가능하면 표준 라이브러리처럼 가장 단순하고 유지보수 가능한 도구를 씀
- Ruby에서는 Rails 대신 Sinatra, Python에서는 Flask 대신 Gin 같은 더 작은 선택지를 고려할 수 있음
- 라이브러리 0개로 직접 구현할 수 있는지도 먼저 시도해볼 수 있음
- 먼저
- 큰 프레임워크나 계속 breaking change가 나는 프로젝트로 시작하면 개인 시간 안에서 따라가기 어렵고 빠르게 지칠 수 있음
- 웹에는 더 많은 이상함, 흥분, 개성이 필요하며, 동적 웹사이트를 만들어보는 시도가 권장됨