−25%

Windows 연간 결제, 10월 31일까지. 요금제 보기

EQVPS
시작하기

VPS에서 Telegram 봇을 24시간 내내 돌리기: aiogram, systemd, polling 대 webhook

2026년 7월 4일 · 4 분 읽기 · EQVPS Team

aiogram으로 Telegram 봇을 쓰고, 로컬에서 테스트했고, 됩니다. 이제 노트북을 닫아도 잠들지 않는 어딘가에 살아야 합니다. 작은 VPS가 자연스러운 보금자리 — 하지만 SSH 세션의 python bot.py와 크래시, 재부팅, 연결 끊김을 통해 실제로 떠 있는 봇 사이에는 간극이 있습니다.

이것이 프로덕션 버전입니다: virtualenv, 코드 밖에 둔 토큰, 봇을 스스로 되살리는 systemd 서비스, 그리고 누구나 결국 묻는 질문 — polling이냐 webhook이냐? — 에 대한 또렷한 답.

왜 그냥 노트북에서 돌리면 안 되나

봇에는 Telegram으로의 안정적인 아웃바운드 연결이 필요합니다. 노트북은 잠들고, 업데이트로 재부팅하고, 네트워크 사이를 넘나듭니다 — 그 하나하나가 봇을 떨구고, 사용자는 침묵의 벽에 부딪힙니다. VPS는 그 연결을 밤낮없이 유지합니다. 그것이 기기에서 옮기는 전체 이유이고, Discord 봇도 서버에 속하는 것과 같은 이유입니다.

최소한의 봇으로 가능한 한 빠른 "온라인으로" 경로만 원하면, Telegram 봇 호스팅 안내가 그것을 다룹니다. 이 글은 한 단계 깊이 갑니다: aiogram, 안전한 토큰 다루기, 그리고 언제 스케일할지 아는 것.

봇, virtualenv 안에서

SSH로 들어가 봇을 자체 venv 안에 격리하세요 — 패키지를 시스템 전체에 설치하지 마세요, 나중에 업그레이드와 정리가 엉망이 됩니다:

sudo apt update && sudo apt install -y python3-venv
mkdir ~/tgbot && cd ~/tgbot
python3 -m venv venv && source venv/bin/activate
pip install -U aiogram

토큰을 하드코딩된 문자열이 아니라 환경에서 읽는 최소한의 aiogram 3 봇:

# bot.py
import asyncio, logging, os
from aiogram import Bot, Dispatcher
from aiogram.types import Message
from aiogram.filters import CommandStart

logging.basicConfig(level=logging.INFO)
dp = Dispatcher()

@dp.message(CommandStart())
async def start(m: Message):
    await m.answer("Alive and running on a VPS.")

async def main():
    bot = Bot(os.environ["BOT_TOKEN"])
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

토큰을 코드 밖에 두기

BotFather 토큰을 결코 bot.py에 붙여 넣지 마세요 — 공개 리포로 한 번 푸시하면 샙니다. 대신 root가 읽을 수 있는 env 파일에 두세요:

sudo tee /etc/tgbot.env >/dev/null <<'EOF'
BOT_TOKEN=123456:your-token-from-botfather
EOF
sudo chmod 600 /etc/tgbot.env

새어 나간 토큰은 BotFather의 /revoke 하나로 고칠 수 있습니다 — 하지만 공유 기기에서 새어 나간 다른 무엇이든은 더 나쁩니다. 봇 전용 VPS는 솔직히 일상 노트북보다 토큰에게 안전한 보금자리입니다: 새면 토큰 하나를 돌리는 것이지 설정 전체가 아닙니다.

살려 두는 부분: systemd

이것이 도는 봇과 계속 도는 봇을 가릅니다. 서비스를 만드세요:

# /etc/systemd/system/tgbot.service
[Unit]
Description=Telegram bot (aiogram)
After=network-online.target
Wants=network-online.target

[Service]
User=botuser
WorkingDirectory=/home/botuser/tgbot
EnvironmentFile=/etc/tgbot.env
ExecStart=/home/botuser/tgbot/venv/bin/python bot.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

비-root 사용자(위의 botuser)로 돌리세요, root가 아니라 — 봇이 침해되어도 상자 안에 가두고 싶으니까요. 그다음:

sudo systemctl daemon-reload
sudo systemctl enable --now tgbot

Restart=always와 RestartSec=3은 크래시 — Telegram의 나쁜 업데이트, 처리되지 않은 예외, OOM — 가 봇을 당신이 알아챌 때까지 죽여 두는 대신 3초 만에 되돌린다는 뜻입니다. 라이브로 보기:

journalctl -u tgbot -f

그것이 당신의 로깅 설정 전부입니다. 돌릴 로그 파일도, 추가 도구도 없음 — journald가 이미 갖고 있습니다.

다운타임 드라마 없이 업데이트하기

코드를 바꾸거나 aiogram을 올릴 때:

cd ~/tgbot && source venv/bin/activate
pip install -U aiogram          # 라이브러리를 업그레이드한다면
sudo systemctl restart tgbot
journalctl -u tgbot -n 30 --no-pager   # 깨끗이 돌아왔는지 확인

재시작은 봇을 1~2초 깜빡입니다. polling 봇에는 그것이 사용자에게 보이지 않습니다 — Telegram이 업데이트를 큐에 넣고 봇이 재연결하면 전달합니다.

polling 대 webhook — 솔직한 버전

이것이 사람들이 과하게 고민하는 결정입니다. 담백한 버전은 이렇습니다:

polling(start_polling, 위 코드가 쓰는 것)은 장수명 연결에서 봇이 Telegram에 "새 거 있어?"를 묻게 합니다. 아웃바운드 인터넷 말고는 아무것도 필요 없습니다 — 도메인도, TLS도, 열린 인바운드 포트도. NAT 뒤에서 잘 됩니다. 봇의 압도적 다수에게 이것이 옳고, 여기서 멈춰야 합니다.

webhook은 Telegram이 업데이트를 당신에게 밀므로 공개 HTTPS 엔드포인트를 노출해야 합니다. 그것은 도메인과 닿을 수 있는 인바운드 포트가 필요하고 — 즉 전용 공개 IP나 앞단의 리버스 프록시. 설정이 늘고, 깨질 것이 늘어납니다. 보상은 대규모에서의 낮은 지연과 적은 오버헤드 — 수천 동시 사용자, 무거운 업데이트 양.

실용적 규칙: NAT 요금제의 polling으로 시작. webhook으로 옮기는 것은 실제로 polling을 넘어 자랐을 때뿐 — 그리고 그렇다면, 그때야말로 전용 IP가 제자리를 법니다, 그 인바운드 HTTPS 엔드포인트가 필요하니까요.

돌리는 데 드는 비용

polling 봇은 가볍습니다. Telegram의 롱폴에서 유휴 상태로 메시지에 반응하므로 박스는 대체로 기다립니다:

  • $3 Nano(2 vCPU / 1 GB) — 대부분의 봇에, 꽤 수다스러운 것도 괜찮음.
  • $5 Micro(2 vCPU / 2 GB) — 봇이 데이터베이스(SQLite/Postgres)를 쥐거나, 미디어를 다루거나, 많은 사용자를 서빙할 때.
  • 그 이상은 봇 자신이 진짜 일을 할 때뿐 — 이미지 처리, 로컬 모델, 무거운 메시지별 로직.

가입은 이메일만이고 Base나 Ethereum의 USDC나 USDT로 결제합니다 — 카드도 신분증도 없이. 카드도 되지만 온램프에 ~$27 최소액이 있으니, $3 요금제에는 작은 잔액을 한 번 채우고 갱신이 거기서 빠지게 하는 편이 매끄럽습니다. CPU 전용, 독일과 핀란드 두 곳(사용 가능 여부는 주문할 때 표시됩니다) — 봇에는 문제없음, GPU나 특정 지역이 필요했다면 알아둘 가치.

솔직한 결론

Telegram 봇은 자체 호스팅할 수 있는 가장 싼 것 중 하나입니다: $3 박스, systemd 유닛, 그리고 polling이 당신이 지켜보지 않아도 크래시와 재부팅을 통해 온라인인 봇을 줍니다. webhook과 더 큰 요금제로 손을 뻗는 것은 규모가 실제로 강제할 때뿐 — 튜토리얼이 webhook이 "낫다"고 해서가 아니라. 작은 박스를 얻고, 토큰을 env 파일에 두고, systemd에 가동 시간을 맡기고, 그리고 — 무엇보다 먼저 — 새 VPS 보안 체크리스트를 돌려 박스 자체를 잠그세요.


당신 것을 호스팅할 준비가 됐나요? Telegram 봇은 리소스를 거의 안 씁니다 — Nano 요금제(월 $3)가 군더더기 없이 24시간 내내 돌립니다.

FAQ

polling이냐 webhook이냐 — 무엇을 써야 하나요?

polling으로 시작하세요. 아웃바운드 인터넷이 있는 박스면 무엇에서든 동작하고 — 도메인도, 열린 포트도, TLS도 불필요 — 대부분의 봇에 충분합니다. webhook으로 바꾸는 것은 대규모(수천 사용자)로 돌리거나 가능한 한 낮은 지연이 필요할 때뿐; webhook은 공개 HTTPS 엔드포인트가 필요하고, 즉 도메인과 닿을 수 있는 인바운드 포트(전용 IP나 리버스 프록시)라 움직이는 부품이 늘어납니다. 95%의 봇에는 작은 VPS의 polling이 정답입니다.

Telegram 봇에 전용 IP나 도메인이 필요한가요?

polling에는 불필요 — 봇은 Telegram으로 아웃바운드 호출만 하므로 포트 포워딩 SSH의 NAT 요금제면 충분합니다. 공개 HTTPS 엔드포인트(도메인 + 인바운드 포트, 즉 전용 IP나 리버스 프록시)가 필요한 것은 webhook 모드로 바꿀 때뿐. 대부분의 봇은 결코 필요 없습니다.

aiogram 봇에 어떤 크기의 VPS가 필요한가요?

가장 작은 것. polling 봇은 대체로 Telegram의 롱폴을 기다리므로 2 vCPU / 1 GB($3 Nano)가 대부분의 봇을 편안히 처리합니다. 크기를 올리는 것은 봇 자신이 무거운 일을 할 때 — 데이터베이스, 미디어 처리, 로컬 모델 — 뿐이고, 그것이 2 GB($5) 이상으로 밉니다.

로그아웃한 뒤 봇을 어떻게 계속 돌리나요?

Restart=always와 함께 systemd 서비스로 돌리세요. 터미널에서 실행하면 SSH를 닫을 때 죽지만, systemd 아래에서는 로그아웃을 견디고, 크래시에 재시작하고, 재부팅 후 돌아옵니다. 그것이 시연과 의지할 수 있는 것의 경계입니다.

댓글

아직 댓글이 없습니다. 첫 번째가 되세요.

댓글 남기기

댓글은 표시되기 전에 검토됩니다.