안녕하세요! 드디어 Hugo 블로그 구축기 시리즈 5편이 나왔네요 🎉
지금까지 블로그를 만들고, 삽질하고, 자동배포하고, 애널리틱스까지 연동했는데… 뭔가 허전했어요. 바로 댓글 기능이 없었거든요!
특히 제가 주식 투자 관련 글도 쓸 예정인데, 주식하는 분들이 GitHub 계정이 있을 리가 없잖아요? 😅 그래서 이번엔 누구나 쉽게 댓글을 달 수 있는 시스템을 만들어보기로 했습니다.
결과부터 말씀드리면… 4시간 동안 5가지 문제와 씨름했고, 특히 CORS 에러는 정말 지옥이었어요. 하지만 결국 해냈습니다! 🔥
🤔 댓글 시스템 선택의 고민#
처음엔 당연히 GitHub 기반인 Giscus를 쓸 생각이었어요. 개발자들 사이에서 유명하고, 무료에 광고도 없고 좋잖아요?
하지만 곰곰 생각해보니… 🤔
- 내 블로그 독자층: 개발자 + 주식 투자자
- GitHub 계정 보유율: 개발자 90% vs 투자자 5%
- 결론: GitHub 계정 필수인 시스템은 절반의 독자를 포기하는 것
그래서 다른 대안들을 찾아봤어요:
시스템 | 장점 | 단점 | 결정 |
---|---|---|---|
Giscus | GitHub 기반, 무료, 광고 없음 | GitHub 계정 필요 | ❌ |
Utterances | GitHub Issues, 간단 설치 | GitHub 계정 필요 | ❌ |
Disqus | 누구나 사용 가능 | 광고 있음 | ❌ |
Cusdis | 이메일만으로 댓글 가능, 셀프 호스팅 | 설정 복잡 | ✅ |
Cusdis를 선택한 이유는 단순했어요. 이메일과 닉네임만 있으면 댓글을 달 수 있거든요! 게다가 셀프 호스팅이라 완전한 데이터 소유권도 가질 수 있고요.
🛠️ 구축 과정 - 생각보다 험난했던 여정#
1단계: DNS 설정 (무난함)#
Cloudflare에서 서브도메인 추가
Type: A
Name: comments
Content: 서버IP주소
Proxy: 🟠 Proxied (활성화)
이 부분은 금방 끝났어요. 이제 comments.coderred.com
으로 접근할 수 있게 됐네요!
2단계: Cusdis Docker 컨테이너 실행#
docker run -d \
--name cusdis \
--restart unless-stopped \
--network npm_default \
-p 3000:3000 \
-e USERNAME="admin" \
-e PASSWORD="강력한비밀번호" \
-e JWT_SECRET="ofcourseistillloveyou" \
-e DB_URL="file:/data/db.sqlite" \
-e NEXTAUTH_URL="https://comments.coderred.com" \
-v ~/cusdis-data:/data \
djyde/cusdis:latest
여기서부터 삽질이 시작됐어요… 😅
😭 삽질의 연속 - 5가지 문제 대방출#
문제 1: 포트 충돌 - “아, 그래 3000번 쓰고 있었지…”#
컨테이너가 시작이 안 되더라고요. 알고 보니 Grafana가 3000번 포트를 이미 사용 중이었어요.
# 확인해보니...
sudo netstat -tlnp | grep :3000
# Grafana가 떡하니 자리잡고 있음 ㅠㅠ
해결: Grafana를 잠시 꺼두고 Cusdis부터 설치했어요.
문제 2: Docker 네트워크 통신 실패 - 502 Bad Gateway#
Nginx Proxy Manager(NPM)에서 localhost:3000
으로 설정했는데 502 에러가 나더라고요.
원인: NPM은 별도 컨테이너라서 localhost
로 다른 컨테이너에 접근할 수 없었어요.
해결:
- Cusdis를 NPM과 같은 네트워크에 연결 (
--network npm_default
) - NPM Forward 설정을
cusdis:3000
으로 변경
이제 통신이 되기 시작했어요! 🎉
문제 3: Hugo 빌드 에러 - “내 프로젝트에 왜 SQLite가?”#
갑자기 Hugo 빌드할 때 permission denied on db.sqlite-journal
에러가 나더라고요.
원인: Docker 볼륨 마운트를 ~/cusdis-data
대신 Hugo 프로젝트 폴더에 했더니 SQLite 파일이 프로젝트에 생성됨.
해결:
rm -rf ~/coderblog/data/ # 잘못 생성된 폴더 삭제
간단했지만 당황스러웠어요 😅
문제 4: CORS 에러 1차 - “헤더가 허용되지 않습니다”#
이제 진짜 지옥의 시작이었어요…
Access to fetch at 'https://comments.coderred.com/api/open/comments'
from origin 'https://coderred.com' has been blocked by CORS policy:
Request header field x-timezone-offset is not allowed by Access-Control-Allow-Headers
해결: NPM Advanced 설정에 커스텀 헤더 추가
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,x-timezone-offset' always;
하나 해결! 그런데…
문제 5: CORS 에러 2차 - “헤더 값이 여러 개야?”#
The 'Access-Control-Allow-Origin' header contains multiple values
'https://coderred.com, https://coderred.com', but only one is allowed.
이건 정말 골치 아팠어요. Cusdis와 NPM에서 중복으로 CORS 헤더를 보내는 문제였거든요.
GPT한테 물어보고, 제미니한테 물어보고… 결국 제미니가 완벽한 해결책을 제시해줬어요! 🙏
최종 해결책 (NPM Advanced 설정):
location / {
# 백엔드가 보낸 중복 헤더를 먼저 숨김
proxy_hide_header 'Access-Control-Allow-Origin';
set $allowed_origin "";
if ($http_origin ~* "https://(www\.)?coderred\.com") {
set $allowed_origin $http_origin;
}
# 모든 CORS 헤더를 한번에 정의
add_header 'Access-Control-Allow-Origin' $allowed_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,x-timezone-offset' always;
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
add_header 'Access-Control-Max-Age' 1728000 always;
# Preflight OPTIONS 요청 처리
if ($request_method = 'OPTIONS') {
return 204;
}
# NPM의 기본 프록시 설정 사용
include conf.d/include/proxy.conf;
}
이 설정을 적용하고 나서야 드디어… 댓글 시스템이 작동했어요! 🎉🎉🎉
🎯 Hugo 블로그와 연결#
layouts/partials/comments.html
파일을 만들었어요:
<div class="article-comments">
<h3>💬 댓글</h3>
<div id="cusdis_thread"
data-host="https://comments.coderred.com"
data-app-id="APP_ID"
data-page-id="{{ .File.ContentBaseName }}"
data-page-url="{{ .Permalink }}"
data-page-title="{{ .Title }}">
</div>
<script async defer src="https://comments.coderred.com/js/cusdis.es.js"></script>
</div>
그리고 포스트 Front Matter에 showComments: true
만 추가하면 끝!
🎉 최종 결과 - 드디어 완성!#
4시간의 삽질 끝에 이런 멋진 기능들을 갖게 됐어요:
- ✅ GitHub 계정 없이 댓글 작성 가능 (이메일 + 닉네임만)
- ✅ 광고 없는 깨끗한 인터페이스
- ✅ 완전한 데이터 소유권 (셀프 호스팅)
- ✅ 다크/라이트 테마 자동 대응
- ✅ 모바일 반응형 지원
시스템 구조는 이렇게 됐어요:
블로그 사용자 → Cloudflare CDN → Nginx Proxy Manager → Cusdis Container
https://coderred.com → https://comments.coderred.com → localhost:3000
📚 이번에 배운 것들#
Docker 네트워킹의 중요성#
컨테이너끼리 통신하려면 같은 네트워크에 있어야 하고, localhost
대신 컨테이너 이름으로 접근해야 한다는 걸 확실히 알게됐어요.
CORS는 정말 복잡하다#
특히 서브도메인 간 리소스 공유 시 발생하는 CORS 정책과 헤더 중복 문제… 정말 골치 아팠지만 덕분에 웹 보안에 대해 많이 배웠어요.
끈기의 중요성#
복잡한 CORS 문제도 단계별로 접근하면 결국 해결할 수 있더라고요. 포기하지 않는 게 중요해요!
🚀 다음 계획#
이제 기본적인 블로그 시스템은 완성됐어요! 다음에는 이런 것들을 해보려고 합니다:
- 댓글 시스템 스타일링 개선 (더 자연스럽게)
- 검색 기능 추가
- SEO 최적화 심화
- 광고 시스템 연동 (수익화!)
💬 마무리#
정말 험난한 4시간이었지만, 결국 해냈어요! 🎉
이제 개발자 분들은 물론이고 주식 투자하시는 분들도 쉽게 댓글을 달 수 있게 됐네요. GitHub 계정 없어도 이메일과 닉네임만 있으면 바로 소통 가능해요!
혹시 비슷한 작업을 하시다가 막히시면 댓글로 알려주세요. 함께 해결해봐요! 😊
그리고 이 글이 도움이 되셨다면 댓글로 한 말씀 남겨주시면 정말 힘이 될 것 같아요. 아직 새로 만든 댓글 시스템이라 첫 댓글이 누가 될지 궁금하네요! 🤔
다음 편도 기대해 주세요! 🚀