본문으로 건너뛰기

Hugo 블로그 구축기 6편 - 텔레그램 실시간 알림의 마법

·1152 단어수·6 분
Hugo 블로그 구축기 - 이 글은 시리즈의 일부입니다.
부분 : 이 글

🤔 또 다른 문제 발견!
#

안녕하세요! Hugo 블로그 구축기 6편으로 돌아온 CoderRed입니다 😄

5편에서 드디어 댓글 시스템을 구축했잖아요? 이제 독자들이 댓글을 달 수 있게 되었어요! 🎉

그런데… 문제가 하나 더 있더라고요.

“언제 댓글이 달렸는지 어떻게 알지?” 🤦‍♂️

매번 https://comments.coderred.com 대시보드에 들어가서 확인할 수는 없잖아요. 특히 새벽에 댓글이 달렸는데 오후에 발견하면… 댓글 작성자분께 너무 죄송하죠.

그래서 오늘은 텔레그램으로 실시간 댓글 알림을 받는 시스템을 구축해봤어요! 진짜 이번엔 끝이라고 생각했는데… 또 4시간 넘게 삽질했네요 😅

📱 텔레그램 봇 만들기부터 시작!
#

BotFather와의 첫 만남
#

텔레그램에서 봇을 만들려면 @BotFather를 찾아가야 해요. 이름부터 뭔가 권위있어 보이죠? 😂

/newbot 명령어 입력
봇 이름: CoderRed Blog Bot
봇 사용자명: coderred_blog_bot

그러면 이런 식으로 봇 토큰을 받을 수 있어요:

123456789:ABCdefGHIjklMNOpqrsTUVwxyz

채팅 ID 찾기의 모험
#

봇 토큰은 받았는데, 이제 어디로 메시지를 보낼지 알아야 하죠. 그게 바로 채팅 ID예요.

봇에게 아무 메시지나 보낸 다음, 이 URL에 접속하면 됩니다:

https://api.telegram.org/bot[봇토큰]/getUpdates

JSON 응답에서 chat.id 값을 찾으면 그게 제 채팅 ID! 간단하죠? 😊

🚀 웹훅 서버 구축 - Node.js의 힘
#

이제 Cusdis에서 댓글이 달렸을 때 텔레그램으로 알림을 보내주는 웹훅 서버를 만들어야 해요.

프로젝트 구조 설계
#

~/telegram-webhook/
├── Dockerfile
├── webhook-telegram.js
└── package.json (자동 생성)

Dockerfile 작성
#

FROM node:18-alpine

WORKDIR /app

# package.json 생성 및 의존성 설치
RUN npm init -y && npm install express axios

# webhook 서버 파일 복사
COPY webhook-telegram.js .

EXPOSE 3001

CMD ["node", "webhook-telegram.js"]

웹훅 서버 코드의 핵심
#

가장 중요한 webhook-telegram.js 파일이에요:

const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

const BOT_TOKEN = process.env.BOT_TOKEN;
const CHAT_ID = process.env.CHAT_ID;

app.post('/cusdis-telegram', async (req, res) => {
  try {
    console.log('📥 웹훅 요청 받음:', JSON.stringify(req.body, null, 2));
    
    const { type, data } = req.body;
    
    if (type === 'new_comment') {
      const {
        by_nickname,
        by_email,
        content,
        page_title,
        page_id,
        approve_link
      } = data;
      
      // 댓글 URL 구성
      const postUrl = `https://coderred.com/posts/${page_id}/`;
      
      const message = `🔔 새 댓글 알림!

📝 **${page_title}**
👤 작성자: ${by_nickname}${by_email ? ` (${by_email})` : ''}
💬 댓글: ${content}

🔗 [포스트 보기](${postUrl})
⚡ [댓글 승인](${approve_link})
🎛️ [관리 대시보드](https://comments.coderred.com)`;

      const telegramUrl = `https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`;
      
      await axios.post(telegramUrl, {
        chat_id: CHAT_ID,
        text: message,
        parse_mode: 'Markdown',
        disable_web_page_preview: false
      });
      
      console.log(`✅ 댓글 알림 전송 완료: ${by_nickname}${page_title}`);
    }
    
    res.status(200).send('OK');
  } catch (error) {
    console.error('❌ 텔레그램 알림 실패:', error);
    res.status(500).send('Error');
  }
});

app.listen(3001, '0.0.0.0', () => {
  console.log('🤖 텔레그램 웹훅 서버 실행: http://0.0.0.0:3001');
});

🐳 Docker로 안전하게 배포하기
#

보안을 고려한 컨테이너 실행
#

여기서 중요한 건 포트를 외부에 노출하지 않는 것이에요! Cusdis와 같은 내부 네트워크에서만 통신하면 되거든요.

# 프로젝트 생성
mkdir -p ~/telegram-webhook && cd ~/telegram-webhook

# 파일들 생성 후...

# 빌드
docker build -t telegram-webhook .

# 포트 노출 없이 실행 (보안 강화!)
docker run -d \
  --name telegram-webhook \
  --restart unless-stopped \
  --network npm_default \
  -e BOT_TOKEN="123456789:ABCdefGHIjklMNOpqrsTUVwxyz" \
  -e CHAT_ID="987654321" \
  telegram-webhook

Cusdis 웹훅 설정
#

Cusdis 대시보드(https://comments.coderred.com)에서:

  1. 사이트 선택 → Settings
  2. Webhook URL 입력:
http://telegram-webhook:3001/cusdis-telegram

여기서 localhost가 아니라 telegram-webhook를 쓰는 게 중요해요!

🎉 마법 같은 실시간 알림!
#

이제 누군가 댓글을 달면 이런 알림이 바로 텔레그램으로 와요:

🔔 새 댓글 알림!

📝 Hugo 블로그 구축기 5편 - 댓글 시스템 구축 대작전
👤 작성자: 개발자김씨 ([email protected])
💬 댓글: CORS 에러 해결 과정이 너무 리얼하네요!

🔗 포스트 보기
⚡ 댓글 승인
🎛️ 관리 대시보드

💻 프로젝트: coderred.com

⚡ 댓글 승인 링크를 누르면 바로 댓글이 승인돼요! 원클릭이라니… 감동 😭

🔥 또 발생한 문제들과 해결책
#

문제 1: BOT_TOKEN이 인식 안 됨
#

처음엔 환경변수가 제대로 전달되지 않았어요.

# 환경변수 확인
docker exec telegram-webhook printenv | grep -E "(BOT_TOKEN|CHAT_ID)"

알고 보니 -e 옵션에서 따옴표 처리를 잘못했더라고요.

문제 2: 웹훅 URL 접근 실패
#

Cusdis에서 http://localhost:3001/cusdis-telegram으로 설정했는데 안 되더라고요.

해결: Docker 네트워크 내에서는 컨테이너 이름으로 접근해야 함!

http://telegram-webhook:3001/cusdis-telegram

문제 3: 텔레그램 API 에러
#

가끔 텔레그램 API에서 메시지가 너무 길다고 에러가 나더라고요. 댓글 내용을 적절히 자르는 로직을 추가했어요.

🎨 추가로 개선한 것들
#

iframe 높이 자동 조정
#

5편에서 만든 댓글창이 고정 높이라 스크롤바가 생기는 게 거슬렸어요. JavaScript로 동적 조정 기능을 추가했습니다:

<script>
document.addEventListener('DOMContentLoaded', function() {
  function adjustIframeHeight() {
    const iframe = document.querySelector('#cusdis_thread iframe');
    if (iframe) {
      try {
        const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
        const height = iframeDoc.body.scrollHeight;
        const adjustedHeight = Math.max(400, Math.min(height + 50, 1000));
        iframe.style.height = adjustedHeight + 'px';
      } catch (e) {
        iframe.style.height = '500px';
      }
    }
  }
  
  // iframe 감지 및 주기적 조정
  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      if (mutation.addedNodes.length > 0) {
        const iframe = mutation.target.querySelector('iframe');
        if (iframe) {
          iframe.addEventListener('load', () => {
            setTimeout(adjustIframeHeight, 500);
          });
          setInterval(adjustIframeHeight, 2000);
        }
      }
    });
  });
  
  const cusdisContainer = document.getElementById("cusdis_thread");
  if (cusdisContainer) {
    observer.observe(cusdisContainer, { 
      childList: true, 
      subtree: true 
    });
  }
});
</script>

이제 댓글 개수에 따라 iframe 높이가 자동으로 조정돼요! 😊

GitHub Actions 안정화
#

또 하나 발견한 문제는 GitHub Actions에서 YAML multiline 때문에 Docker 명령어가 실패하는 거였어요.

# ❌ 문제 버전 (줄바꿈으로 분리됨)
docker run -d \
  --name hugo-blog \
  nginx:alpine

# ✅ 해결 버전 (한 줄로 작성)
docker run -d --name hugo-blog --restart unless-stopped --network npm_default -p 9572:80 -v ~/coderblog/public:/usr/share/nginx/html:ro nginx:alpine

이것 때문에 몇 번 배포가 실패했어요 😅

🔧 유용한 명령어들
#

텔레그램 웹훅 관리
#

# 컨테이너 재빌드
cd ~/telegram-webhook
docker stop telegram-webhook && docker rm telegram-webhook
docker build -t telegram-webhook .
docker run -d --name telegram-webhook --restart unless-stopped \
  --network npm_default \
  -e BOT_TOKEN="봇토큰" -e CHAT_ID="채팅ID" \
  telegram-webhook

# 로그 실시간 모니터링
docker logs telegram-webhook --follow

# 직접 텔레그램 API 테스트
curl -X POST "https://api.telegram.org/bot[봇토큰]/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{"chat_id": "[채팅ID]", "text": "테스트 메시지"}'

전체 시스템 상태 확인
#

# 모든 컨테이너 확인
docker ps | grep -E "(hugo-blog|cusdis|npm|telegram)"

# 네트워크 연결 테스트
docker exec cusdis ping telegram-webhook

🚨 트러블슈팅 가이드
#

텔레그램 알림이 안 올 때
#

  1. 웹훅 컨테이너 확인: docker ps | grep telegram-webhook
  2. 웹훅 로그 확인: docker logs telegram-webhook --follow
  3. 환경변수 확인: docker exec telegram-webhook printenv | grep -E "(BOT_TOKEN|CHAT_ID)"
  4. Cusdis 웹훅 URL 확인: http://telegram-webhook:3001/cusdis-telegram
  5. 네트워크 연결 테스트: docker exec cusdis ping telegram-webhook

봇 토큰이나 채팅 ID 문제
#

# 직접 API 테스트로 확인
curl -X POST "https://api.telegram.org/bot[봇토큰]/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{"chat_id": "[채팅ID]", "text": "테스트"}'

🎯 이제 정말 완전체!
#

드디어 완성됐어요! 이제 블로그 운영이 이렇게 간단해졌답니다:

📝 포스트 작성 → 📤 Git 푸시 → 🚀 자동 배포
                    ↓
💬 독자 댓글 작성 → 📱 텔레그램 알림 → ⚡ 원클릭 승인

정말로 포스트 쓰고 푸시만 하면 끝인 시스템이 완성되었어요! 🎉

달성한 것들
#

  • ✅ GitHub 계정 없이 댓글 작성 가능
  • ✅ 실시간 텔레그램 알림
  • ✅ 원클릭 댓글 승인
  • ✅ iframe 높이 자동 조정
  • ✅ 완전 자동화된 배포 시스템
  • ✅ 안정적인 Docker 네트워킹

소요 시간 총 정리
#

  • 1편 (환경 설정): 3시간
  • 2편 (삽질 해결): 2시간
  • 3편 (GitHub Actions): 3시간
  • 4편 (Google Analytics): 1시간
  • 5편 (댓글 시스템): 4시간
  • 6편 (텔레그램 알림): 4시간

총 17시간의 여정이었네요! 😅

📈 앞으로의 계획
#

이제 정말 블로그 시스템은 완성됐으니, 앞으로는:

  • 📊 더 많은 기술 글 쓰기
  • 💰 주식 투자 경험담 공유
  • 🔍 검색 기능 추가 (언젠가…)
  • 🎨 디자인 개선 (CSS 공부 중…)

댓글로 어떤 주제를 더 다뤘으면 좋겠는지 알려주세요! 이제 실시간으로 알림이 와서 바로바로 답변드릴 수 있어요 😄

다음 편에서는 뭘 다룰까요? 아마 실제 블로그 운영 경험이나 새로운 기술 도전기가 될 것 같아요!

함께 성장해나가요! 🚀

Hugo 블로그 구축기 - 이 글은 시리즈의 일부입니다.
부분 : 이 글

💬 댓글