텔레그램으로 Claude Code 원격 제어하기
설치 오류 해결부터 실전 봇 완성까지
스마트폰 텔레그램 앱에서 메시지 하나로 PC의 Claude Code를 실행하는 봇을 직접 만들어봤습니다.
왜 만들었나
유튜브에서 텔레그램으로 Claude Code를 원격 실행하는 영상을 보고 바로 따라해보고 싶었습니다. PC 앞에 없어도 스마트폰으로 코드 작업을 시킬 수 있다면 꽤 쓸만하겠다 싶었거든요. 막상 시작하니 PATH 오류부터 네트워크 에러까지 자잘한 문제가 연달아 터졌는데, 이 글에 그 과정을 그대로 담았습니다.
준비물
| 항목 | 비고 |
|---|---|
| Claude Code CLI | Anthropic 공식 CLI — claude 명령어 |
| Python 3.x | 3.11 기준으로 진행 |
| pyTelegramBotAPI | pip install pyTelegramBotAPI python-dotenv |
| Telegram 계정 | 봇 생성용 (@BotFather) |
1단계 — Claude Code 설치 및 PATH 설정
Claude Code를 설치하면 실행 파일이 C:\Users\{사용자}\.local\bin에 생성됩니다. Windows 환경변수에 이 경로를 추가했는데도 PowerShell에서 claude가 인식되지 않는 문제가 생겼습니다.
환경변수에
C:\Users\jinwh\.local\bin을 추가했지만 PowerShell에서 claude를 실행하면 "찾을 수 없다"는 오류가 발생. VS Code를 재시작해도 동일.
원인을 파보니 Git Bash와 PowerShell은 PATH를 읽는 방식이 달랐습니다. Git Bash용 .bashrc를 아무리 수정해도 PowerShell엔 적용이 안 됩니다. PowerShell 전용 프로필을 따로 수정해야 합니다.
PowerShell에서 아래 명령어를 실행하면
$PROFILE 파일에 경로가 추가되어 새 세션부터 영구 적용됩니다.
# 프로필 파일이 없으면 폴더 먼저 생성 New-Item -ItemType Directory -Path (Split-Path $PROFILE) -Force # PATH에 claude 경로 추가 Add-Content -Path $PROFILE -Value '$env:PATH += ";C:\Users\{사용자명}\.local\bin"' -Encoding utf8
VS Code를 완전히 닫았다가 다시 열고 PowerShell 터미널에서
claude --version을 입력. 2.x.x (Claude Code)가 출력되면 성공입니다.
2단계 — Telegram Bot 생성 (@BotFather)
/newbot을 입력하면 봇 이름과 username을 차례로 물어봅니다. username은 반드시 bot으로 끝나야 합니다. (예: MyClaude_bot)1234567890:ABCdef... 형태의 문자열로, 이후 모든 API 호출에 사용됩니다.토큰이 유출되면 누구든 내 봇을 제어할 수 있습니다. 코드에 직접 넣지 말고
.env 파일에 보관하세요. 만약 유출됐다면 BotFather에서 /revoke로 즉시 재발급하세요.
3단계 — bot.py 작성
프로젝트 폴더에 두 파일만 만들면 됩니다. 토큰은 .env에 분리 보관합니다.
# .env TELEGRAM_BOT_TOKEN=여기에_발급받은_토큰_입력
# bot.py import telebot import subprocess import os from dotenv import load_dotenv load_dotenv() bot = telebot.TeleBot(os.environ.get("TELEGRAM_BOT_TOKEN")) @bot.message_handler(commands=["start", "help"]) def handle_start(message): bot.reply_to(message, "안녕하세요! Claude Code 봇입니다.") @bot.message_handler(func=lambda message: True) def handle_message(message): bot.send_message(message.chat.id, "⏳ 처리 중...") try: result = subprocess.run( ["claude", "--print", "--dangerously-skip-permissions", message.text], capture_output=True, text=True, encoding="utf-8", timeout=120, cwd=r"D:\ClaudeCode", # Claude가 접근할 작업 디렉토리 ) response = result.stdout.strip() or result.stderr.strip() or "응답이 없습니다." except subprocess.TimeoutExpired: response = "시간 초과 (2분). 더 짧은 질문을 시도해보세요." except FileNotFoundError: response = "claude 명령어를 찾을 수 없습니다. PATH를 확인하세요." except Exception as e: response = f"오류 발생: {e}" # Telegram 메시지 최대 4096자 제한 처리 for i in range(0, len(response), 4096): bot.send_message(message.chat.id, response[i:i+4096]) print("봇 시작됨. 종료하려면 Ctrl+C") bot.infinity_polling(timeout=20, long_polling_timeout=15)
•
--dangerously-skip-permissions — 파일 읽기/쓰기 시 매번 뜨는 권한 확인 프롬프트를 생략. 자동화 실행에 필수입니다.•
cwd=r"D:\ClaudeCode" — Claude가 이 폴더를 기준으로 파일을 탐색하고 수정합니다.
4단계 — 보안 강화
봇을 처음 만들고 나서 문득 깨달았습니다. 봇 username만 알면 누구든 메시지를 보낼 수 있고, 그 메시지가 그대로 내 PC의 Claude Code로 전달된다는 것을. --dangerously-skip-permissions까지 붙어있으니 사실상 내 PC에 원격 접근 권한을 열어둔 것과 다름없는 상태였습니다.
텔레그램 봇은 기본적으로 공개 상태입니다. 봇 username을 아는 사람이라면 누구든 메시지를 보낼 수 있고, 그 메시지가 내 PC의 Claude Code로 그대로 전달됩니다.
본인 user_id 확인하기
텔레그램에서 @userinfobot에게 아무 메시지나 보내면 숫자로 된 본인 ID를 알려줍니다. 이 ID를 화이트리스트에 등록합니다.
user_id 화이트리스트 + 추가 보완 3가지
화이트리스트 적용과 함께 점검 중 발견한 3가지 문제도 함께 수정했습니다.
| 문제 | 조치 |
|---|---|
| 누구나 접근 가능 | user_id 화이트리스트 — 등록된 ID 외 모든 메시지 무시 |
| 사진·스티커 전송 시 크래시 | message.text None 체크 후 안내 메시지 반환 |
| 작업 중 중복 실행 | threading.Lock()으로 동시 요청 차단 |
| 토큰 미설정 시 조용한 실패 | 시작 시점에 RuntimeError로 즉시 종료 |
# bot.py — 보안 강화 최종본 import telebot import subprocess import os import threading from dotenv import load_dotenv load_dotenv() BOT_TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN") if not BOT_TOKEN: raise RuntimeError(".env 파일에 TELEGRAM_BOT_TOKEN이 없습니다.") ALLOWED_USER_ID = 본인_user_id_숫자 # @userinfobot 에서 확인 bot = telebot.TeleBot(BOT_TOKEN) _processing = threading.Lock() def is_authorized(message): return message.from_user.id == ALLOWED_USER_ID @bot.message_handler(commands=["start", "help"]) def handle_start(message): if not is_authorized(message): return # 무시 — 봇 존재 여부조차 노출 안 함 bot.reply_to(message, "안녕하세요! Claude Code 봇입니다.") @bot.message_handler(func=lambda message: True) def handle_message(message): if not is_authorized(message): return if not message.text: bot.reply_to(message, "텍스트 메시지만 지원합니다.") return if not _processing.acquire(blocking=False): bot.reply_to(message, "이전 작업이 진행 중입니다. 잠시 후 다시 시도하세요.") return try: bot.send_message(message.chat.id, "⏳ 처리 중...") result = subprocess.run( ["claude", "--print", "--dangerously-skip-permissions", message.text], capture_output=True, text=True, encoding="utf-8", timeout=120, cwd=r"D:\ClaudeCode", ) response = result.stdout.strip() or result.stderr.strip() or "응답이 없습니다." except subprocess.TimeoutExpired: response = "시간 초과 (2분). 더 짧은 질문을 시도해보세요." except FileNotFoundError: response = "claude 명령어를 찾을 수 없습니다. PATH를 확인하세요." except Exception as e: response = f"오류 발생: {e}" finally: _processing.release() for i in range(0, len(response), 4096): bot.send_message(message.chat.id, response[i:i+4096]) print("봇 시작됨. 종료하려면 Ctrl+C") bot.infinity_polling(timeout=20, long_polling_timeout=15)
return으로 조용히 무시합니다. 아무 응답도 보내지 않기 때문에 봇이 존재하는지조차 알 수 없습니다.
트러블슈팅 — ConnectTimeout 오류
봇이 잘 돌아가다가 갑자기 아래 에러를 내뱉고 죽는 경우가 있었습니다.
requests.exceptions.ConnectTimeout: HTTPSConnectionPool(host='api.telegram.org', port=443): Max retries exceeded네트워크가 일시적으로 불안정할 때 Telegram 서버 연결이 끊기면서 발생.
bot.polling()은 이 오류를 처리하지 못하고 프로세스 자체가 종료됩니다.
bot.polling(none_stop=True) 대신 bot.infinity_polling()을 사용하면 ConnectTimeout, ConnectionError 등 네트워크 오류 발생 시 자동으로 재연결을 시도합니다. 봇이 혼자 죽지 않습니다.
# 변경 전 bot.polling(none_stop=True) # 변경 후 — 네트워크 오류 자동 재연결 bot.infinity_polling(timeout=20, long_polling_timeout=15)
실행 및 결과
python bot.py 실행 → 봇 시작됨. 출력 확인✔ 텔레그램 메시지 → Claude Code CLI 실행
✔ D:\ClaudeCode 폴더 전체 파일 접근 권한
✔ 권한 확인 프롬프트 없이 자동 실행
✔ 4096자 초과 응답 자동 분할 전송
✔ 네트워크 오류 시 자동 재연결
✔ user_id 화이트리스트 — 본인 외 접근 차단
✔ 비텍스트 메시지(사진·스티커) 크래시 방지
✔ 중복 실행 방지 (Lock)
✔ 토큰 미설정 시 시작 단계에서 즉시 오류 감지
마치며
코드 자체는 60줄 남짓으로 단순하지만, PATH 설정 하나 때문에 삽질하는 데 시간이 꽤 걸렸습니다. Windows에서 Git Bash와 PowerShell의 PATH가 따로 논다는 걸 이번에 제대로 알게 됐습니다. 그리고 봇을 완성하고 나서야 "아무나 접근할 수 있겠구나"를 깨닫고 보안을 덧붙였는데, 처음부터 보안을 고려하고 만드는 습관이 필요하다는 걸 느꼈습니다. Claude Code를 텔레그램으로 연결하면 PC를 켜놓고 외출해도 스마트폰에서 코드 작업을 시킬 수 있어서 활용 폭이 꽤 넓어집니다.
최종 파일 구조
D:\ClaudeCode\ClaudeByTelegram\ ├── bot.py ← 봇 메인 코드 ├── .env ← 텔레그램 토큰 (비공개) └── .gitignore ← .env 제외
댓글 없음:
댓글 쓰기