ربات تلگرام

راه‌اندازی ربات تلگرام روی سرور مجازی — از صفر تا آنلاین دائمی

تصویر شاخص مقاله راه‌اندازی ربات تلگرام روی سرور مجازی؛ یک کارت ترمینال تیره که مسیر کار را نشان می‌دهد: گرفتن توکن از BotFather، نوشتن ربات با پایتون، تعریف سرویس systemd برای اجرای دائمی و انتخاب بین polling و webhook روی سرور لینوکسی

راه‌اندازی ربات تلگرام روی سرور مجازی یعنی تبدیل یک اسکریپت پایتون که فقط تا وقتی ترمینال باز است کار می‌کند، به سرویسی که ۲۴ ساعته آنلاین می‌ماند و بعد از هر کرش و هر ریبوت خودش برمی‌گردد. رباتی که روی لپ‌تاپ شخصی اجرا می‌شود با اولین قطعی برق از دسترس خارج می‌شود — و کاربری که دو بار پیام بدهد و جواب نگیرد، بار سوم نمی‌آید. در این راهنما مسیر کامل را می‌رویم: توکن از BotFather، ربات با پایتون، یونیت systemd، انتخاب بین polling و webhook، و محدودیت‌های خود تلگرام که تا به آن‌ها نخورید معلوم نمی‌شوند.

چرا ربات تلگرام روی سرور مجازی اجرا کنیم؟

ربات تلگرام یک پروسه‌ی همیشه‌روشن است: باید دائم به سرورهای تلگرام وصل باشد تا پیام‌ها را بگیرد و جواب بدهد. همین یک جمله تکلیف زیرساخت را روشن می‌کند:

  • کامپیوتر شخصی مناسب نیست: خاموش می‌شود، ویندوز ری‌استارت می‌گیرد، اینترنت خانگی IP ثابت و پایدار ندارد.
  • هاست اشتراکی هم مناسب نیست: وقتی دنبال «هاست ربات تلگرام» می‌گردید، منظور واقعی یک سرور مجازی کوچک است. هاست اشتراکی برای سایت‌های PHP طراحی شده و اجازه‌ی اجرای پروسه‌ی دائمی پایتون را نمی‌دهد؛ مقایسه‌ی هاست اشتراکی و سرور مجازی همین مرز را باز می‌کند.
  • سرور مجازی همان چیزی است که لازم دارید: دسترسی root، ماشین همیشه‌روشن، و systemd که ربات را بعد از هر کرش یا ریبوت خودکار دوباره اجرا می‌کند.

ربات تلگرام جزو سبک‌ترین بارهای کاری دنیاست و به کوچک‌ترین پلن هم راضی است؛ پایین‌تر دقیق‌تر حساب می‌کنیم. اما «همیشه آنلاین بودن» را با «سرور روشن بودن» یکی نگیرید: سرور روشن است و پروسه‌ی ربات می‌تواند با یک استثنای مدیریت‌نشده، قطعی موقت شبکه یا OOM killer از بین برود. بخش اصلی این راهنما درباره‌ی همین لایه است.

قدم اول: گرفتن توکن از BotFather و تست آن

هویت هر ربات یک «توکن» است که از ربات رسمی مادر می‌گیرید:

  1. در تلگرام @BotFather را جست‌وجو و باز کنید (تیک تأیید آبی داشته باشد).
  2. دستور /newbot را بفرستید.
  3. یک نام نمایشی بدهید (مثلاً «ربات فروشگاه من»).
  4. یک نام کاربری یکتا بدهید که به bot ختم شود (مثلاً MyShopHelperBot).

BotFather توکنی شبیه 123456789:AAE...xyz می‌دهد؛ این رشته کلید کامل کنترل ربات شماست. پیش از هر کار دیگری سالم‌بودنش را با getMe بسنجید — همان متدی که مستندات تلگرام آن را «روشی ساده برای تست توکن احراز هویت ربات» توصیف می‌کند:

curl -sS "https://api.telegram.org/bot123456789:AAE...xyz/getMe"
{"ok":true,"result":{"id":123456789,"is_bot":true,"first_name":"Shop Helper",
"username":"MyShopHelperBot","can_join_groups":true,
"can_read_all_group_messages":false,"supports_inline_queries":false}}

اگر توکن اشتباه یا باطل‌شده باشد، پاسخ کوتاه و بدون ابهام است:

{"ok":false,"error_code":401,"description":"Unauthorized"}

دو دستور دیگر BotFather را هم یاد بگیرید: /setcommands فهرست دستورهای ربات را در منوی تلگرام ثبت می‌کند (معادل برنامه‌نویسی‌اش setMyCommands) و /setprivacy تعیین می‌کند ربات در گروه‌ها چه پیام‌هایی را ببیند.

⚠️ توکن را مثل رمز عبور نگه دارید: در کد عمومی، گیت‌هاب یا اسکرین‌شات قرارش ندهید. اگر لو رفت، مستندات تلگرام صریح است — «اگر توکن فعلی شما لو رفته یا آن را گم کرده‌اید، با دستور /token یکی جدید بسازید». توکن قدیمی بلافاصله از کار می‌افتد، پس مقدار جدید را روی سرور هم به‌روز کنید.

آماده‌سازی سرور: پایتون، محیط مجازی و کاربر بدون shell

با SSH به سرور وصل شوید و محیط را تمیز بچینید. کتابخانه‌ی python-telegram-bot از نسخه‌ی ۲۲ به بعد حداقل پایتون 3.10 می‌خواهد؛ اوبونتو ۲۴٫۰۴ با 3.12 و دبیان ۱۲ با 3.11 هر دو از این خط جلوترند.

apt update && apt install -y python3-venv
mkdir -p /opt/echobot && cd /opt/echobot
python3 -m venv venv
venv/bin/pip install "python-telegram-bot[job-queue,rate-limiter]==22.*"

چرا venv و نه نصب مستقیم؟ چون از دبیان ۱۲ و اوبونتو ۲۴٫۰۴ به بعد پایتونِ سیستم «externally managed» علامت‌گذاری شده و pip install بیرون از محیط مجازی با پیام error: externally-managed-environment رد می‌شود. این رفتار عمدی است و از PEP 668 می‌آید تا pip بسته‌های موردنیاز خود سیستم‌عامل را بازنویسی نکند. راه درست همان است که خود PEP توصیه می‌کند: محیط مجازی بسازید و از path/to/venv/bin/pip استفاده کنید. سراغ پرچم --break-system-packages نروید؛ اسمش دقیقاً همان کاری را توصیف می‌کند که انجام می‌دهد.

دو افزونه‌ی بالا اختیاری‌اند اما تقریباً همیشه لازم می‌شوند: job-queue کارهای زمان‌بندی‌شده را داخل ربات ممکن می‌کند و rate-limiter کلاس AIORateLimiter را فعال می‌کند که در بخش محدودیت‌ها به آن برمی‌گردیم. حالا کاربری بسازید که ربات با آن اجرا شود — عمداً بدون shell:

useradd -r -s /usr/sbin/nologin botuser
chown -R botuser: /opt/echobot

ساخت ربات تلگرام با پایتون: یک ربات اکو در بیست خط

برای ساخت ربات تلگرام با پایتون، کتابخانه‌ی python-telegram-bot استاندارد عملی ماجراست: بالغ، مستندسازی‌شده و کاملاً async. فایل /opt/echobot/bot.py را بسازید:

import logging, os
from telegram import Update
from telegram.ext import (Application, CommandHandler,
                          MessageHandler, filters, ContextTypes)

logging.basicConfig(format="%(asctime)s %(name)s %(levelname)s %(message)s",
                    level=logging.INFO)

TOKEN = os.environ["BOT_TOKEN"]

async def start(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text("Salam! Har chi befresti, bar migardoonam.")

async def echo(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(update.message.text)

app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
app.run_polling(allowed_updates=["message"])

سه تصمیم عمدی است. اول، توکن از متغیر محیطی خوانده می‌شود نه از داخل کد. دوم، logging.basicConfig خروجی کتابخانه را به stdout می‌فرستد و systemd همان را در ژورنال ذخیره می‌کند — بدون آن، وقتی ربات کار نکند هیچ سرنخی ندارید. سوم، allowed_updates فقط پیام‌های متنی را می‌خواهد؛ اگر مشخصش نکنید تلگرام همه‌ی انواع به‌روزرسانی به‌جز chat_member و رویدادهای واکنش را می‌فرستد.

توکن را در یک فایل جدا نگه دارید

فایل /etc/echobot.env را بسازید و دسترسی‌اش را ببندید. systemd این فایل را پیش از تعویض کاربر و با دسترسی root می‌خواند، پس لازم نیست botuser بتواند بازش کند:

printf 'BOT_TOKEN=123456789:AAE...xyz\n' > /etc/echobot.env
chown root:root /etc/echobot.env
chmod 600 /etc/echobot.env

cd /opt/echobot
BOT_TOKEN=123456789:AAE...xyz venv/bin/python bot.py

به رباتتان /start بفرستید؛ باید جواب بگیرید و هر متنی بفرستید عیناً برگردد. همین بیست خط اسکلت هر ربات جدی‌تری است؛ فقط هندلر اضافه می‌کنید.

آنلاین دائمی با systemd

اجرای دستی با python bot.py فقط تا وقتی زنده است که ترمینال SSH باز باشد. راه‌حل حرفه‌ای، تعریف ربات به‌عنوان سرویس systemd است. فایل /etc/systemd/system/echobot.service را بسازید:

[Unit]
Description=Telegram Echo Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=exec
User=botuser
WorkingDirectory=/opt/echobot
EnvironmentFile=/etc/echobot.env
ExecStart=/opt/echobot/venv/bin/python /opt/echobot/bot.py
Restart=always
RestartSec=5
StateDirectory=echobot
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes

[Install]
WantedBy=multi-user.target

خط Restart=always قلب ماجراست: اگر ربات کرش کند، systemd پنج ثانیه بعد دوباره اجرایش می‌کند. مستندات systemd برای سرویس‌های بلندمدت مقدار on-failure را «انتخاب توصیه‌شده» می‌داند و تفاوت این دو فقط یک حالت است: با always حتی خروج تمیز با کد صفر هم باعث اجرای دوباره می‌شود. برای رباتی که هیچ‌وقت نباید خودش تمام شود always منطقی است.

Type=exec به systemd می‌گوید سرویس را فقط بعد از اجرای واقعی فایل اجرایی «بالا آمده» حساب کند، نه بلافاصله بعد از fork؛ یعنی خطای «فایل پیدا نشد» همان‌جا خودش را نشان می‌دهد. چهار خط بعدی سخت‌سازی‌اند: NoNewPrivileges جلوی امتیازگرفتن از راه فایل‌های setuid را می‌گیرد، ProtectSystem=strict کل فایل‌سیستم را جز /dev و /proc و /sys فقط‌خواندنی می‌کند، ProtectHome پوشه‌های خانگی را پنهان می‌کند و StateDirectory=echobot یک مسیر نوشتنی مخصوص همین سرویس زیر /var/lib می‌سازد — جای درست دیتابیس SQLite ربات، نه کنار کد.

systemctl daemon-reload
systemctl enable --now echobot
systemctl status echobot

● echobot.service - Telegram Echo Bot
     Loaded: loaded (/etc/systemd/system/echobot.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-09-07 11:04:18 UTC; 12min ago
   Main PID: 1841 (python)
      Tasks: 4 (limit: 2296)
     Memory: 71.4M (peak: 78.2M)
     CGroup: /system.slice/echobot.service
             └─1841 /opt/echobot/venv/bin/python /opt/echobot/bot.py

از این لحظه ربات تلگرام روی سرور مجازی شما یک سرویس واقعی است — و مزیت جانبی دارد: systemctl stop سیگنال SIGTERM می‌فرستد و run_polling به‌طور پیش‌فرض همین سیگنال (به‌همراه SIGINT و SIGABRT) را می‌گیرد و ربات را تمیز خاموش می‌کند، بدون رهاکردن پیامی وسط پردازش.

💡 نکته: سرویس را عمداً با کاربر محدود botuser اجرا کردیم، نه root — اگر کد ربات آسیب‌پذیری داشته باشد، دامنه‌ی خسارت کوچک می‌ماند. یک عارضه‌ی بی‌خطر ProtectSystem=strict این است که پایتون دیگر نمی‌تواند پوشه‌ی __pycache__ را کنار کد بنویسد؛ برنامه بدون خطا اجرا می‌شود و فقط یک لایه کش بایت‌کد را از دست می‌دهد. بقیه‌ی کارهای پایه را از چک‌لیست امنیت سرور لینوکس انجام دهید.

وقتی سرویس بالا نمی‌آید: journalctl و تله‌ی نرخ شروع

لاگ زنده را با journalctl -u echobot -f ببینید و برای خطاهای گذشته از journalctl -u echobot --since "1 hour ago" -p err. رایج‌ترین صحنه‌ی جرم این است:

journalctl -u echobot -n 6 --no-pager
Sep 07 12:02:39 vps python[2107]: telegram.error.InvalidToken: Invalid token
Sep 07 12:02:39 vps systemd[1]: echobot.service: Main process exited, code=exited, status=1/FAILURE
Sep 07 12:02:39 vps systemd[1]: echobot.service: Failed with result 'exit-code'.
Sep 07 12:02:44 vps systemd[1]: echobot.service: Scheduled restart job, restart counter is at 3.
Sep 07 12:03:04 vps systemd[1]: echobot.service: Start request repeated too quickly.
Sep 07 12:03:04 vps systemd[1]: Failed to start echobot.service - Telegram Echo Bot.

دو خط آخر همان تله‌ای است که خیلی‌ها را سردرگم می‌کند. systemd علاوه بر Restart= یک محدودکننده‌ی نرخ شروع هم دارد: اگر یونیت بیش از StartLimitBurst بار در بازه‌ی StartLimitIntervalSec شروع شود، دیگر اجازه‌ی شروع نمی‌گیرد و وضعیتش failed (Result: start-limit-hit) می‌شود. مقادیر پیش‌فرض را روی همان سرور ببینید:

systemctl show -p DefaultStartLimitBurst -p DefaultStartLimitIntervalUSec
DefaultStartLimitIntervalUSec=10s
DefaultStartLimitBurst=5

یعنی پنج شروع در ده ثانیه — و حالا معلوم می‌شود چرا RestartSec=5 تزئینی نیست: مقدار پیش‌فرض RestartSec فقط ۱۰۰ میلی‌ثانیه است و رباتی که به‌خاطر توکن غلط بلافاصله می‌میرد، در کمتر از یک ثانیه سقف را می‌زند و سرویس در حالت failed قفل می‌شود. بعد از اصلاح مشکل، سرویس قفل‌شده را با systemctl reset-failed echobot آزاد کنید. اگر کرش‌ها پراکنده‌اند، به‌جای بالابردن سقف از RestartSteps و RestartMaxDelaySec استفاده کنید تا فاصله‌ی تلاش‌ها نمایی زیاد شود.

Polling یا Webhook؟

ربات از دو راه می‌تواند پیام‌های جدید را بگیرد و مستندات تلگرام صریحاً آن‌ها را «دو راه ناسازگار» می‌نامد. کد بالا از polling استفاده می‌کند: ربات مدام می‌پرسد «پیام تازه‌ای هست؟». در webhook برعکس است: تلگرام هر پیام را مستقیم به آدرس HTTPS شما push می‌کند.

معیارPollingWebhook
پیچیدگی راه‌اندازیصفر — همین کد بالادامنه + گواهی TLS + پورت
نیاز به IP یا دامنه‌ی عمومیندارددارد (تلگرام باید سرور شما را ببیند)
پورت‌های مجازمحدودیتی ندارد (خروجی HTTPS)فقط 443، 80، 88 و 8443
گواهیلازم نیستمعتبر یا self-signed، با TLS 1.2 به بالا
تأخیر پاسخمعمولاً زیر یک ثانیهتقریباً لحظه‌ای
چند نمونه‌ی هم‌زمانممنوع — خطای 409مشکلی ندارد
مناسب برایاکثر ربات‌ها، شروع کارترافیک خیلی بالا، چند ربات روی یک سرور

توصیه‌ی صادقانه: با polling شروع کنید؛ برای اکثر ربات‌ها کافی می‌ماند و دو قطعه‌ی خراب‌شدنی کمتر دارد. یک نکته‌ی مشترک بین هر دو روش: به‌روزرسانی‌ها روی سرور تلگرام می‌مانند تا ربات آن‌ها را بگیرد، اما طبق مستندات «بیش از ۲۴ ساعت نگه داشته نمی‌شوند». اگر ربات یک شبانه‌روز خاموش بماند، پیام‌های آن بازه برای همیشه از دست می‌روند.

راه‌اندازی webhook: دامنه، گواهی و توکن مخفی

ترتیب کار این است: یک رکورد A بسازید که زیردامنه را به IP سرور برساند، Nginx را روی اوبونتو راه بیندازید و با Certbot گواهی رایگان بگیرید. مسیر URL را حدس‌ناپذیر انتخاب کنید و حتماً secret_token ست کنید:

curl -sS -X POST "https://api.telegram.org/bot$BOT_TOKEN/setWebhook" \
  -d "url=https://bot.example.ir/tg/9f3c1a" \
  -d "secret_token=$WEBHOOK_SECRET" \
  -d "max_connections=20" \
  -d 'allowed_updates=["message","callback_query"]'
{"ok":true,"result":true,"description":"Webhook was set"}

تلگرام مقدار secret_token را در هدر X-Telegram-Bot-Api-Secret-Token هر درخواست می‌فرستد و کد شما باید هر درخواست بدون این هدر را دور بیندازد. طول مجازش ۱ تا ۲۵۶ کاراکتر است و فقط حروف انگلیسی، ارقام، خط تیره و زیرخط در آن مجازند. max_connections هم پیش‌فرض ۴۰ است با بازه‌ی ۱ تا ۱۰۰. سلامت webhook را همیشه از خود تلگرام بپرسید، نه از لاگ Nginx:

curl -sS "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo"
{"ok":true,"result":{"url":"https://bot.example.ir/tg/9f3c1a",
"has_custom_certificate":false,"pending_update_count":137,
"last_error_date":1757246400,
"last_error_message":"Wrong response from the webhook: 502 Bad Gateway",
"max_connections":20,"ip_address":"203.0.113.10",
"allowed_updates":["message","callback_query"]}}

این خروجی همه‌چیز را می‌گوید: ۱۳۷ پیام در صف مانده و آخرین خطا یک 502 بوده، یعنی Nginx بالاست ولی پروسه‌ی پشت آن جواب نمی‌دهد. برای برگشتن به polling باید webhook را حذف کنید — تا وقتی فعال باشد متد getUpdates کار نمی‌کند:

curl -sS "https://api.telegram.org/bot$BOT_TOKEN/deleteWebhook?drop_pending_updates=true"
{"ok":true,"result":true}
⚠️ اگر فایروال دارید بدانید تلگرام درخواست‌های webhook را فقط از دو محدوده‌ی 149.154.160.0/20 و 91.108.4.0/22 می‌فرستد. محدودکردن ورودی به همین دو محدوده کار درستی است، اما جایی یادداشتش کنید — وگرنه روزی ربات بی‌صدا پیام دریافت نمی‌کند و لاگ Nginx هم چیزی نشان نمی‌دهد، چون درخواستی اصلاً نرسیده است.

محدودیت‌هایی که تلگرام تحمیل می‌کند

این سقف‌ها همه از مستندات رسمی تلگرام‌اند و هیچ‌کدام با بزرگ‌ترکردن سرور جابه‌جا نمی‌شوند:

  • در یک چت، بیش از یک پیام در ثانیه نفرستید.
  • در یک گروه، ربات‌ها بیش از ۲۰ پیام در دقیقه نمی‌توانند بفرستند.
  • برای اطلاع‌رسانی انبوه، سقف تقریبی ۳۰ پیام در ثانیه است؛ تلگرام پیشنهاد می‌کند ارسال گروهی را روی بازه‌های ۸ تا ۱۲ ساعته پخش کنید.
  • دانلود فایل با متد getFile حداکثر تا ۲۰ مگابایت ممکن است.
  • ارسال فایل با آپلود مستقیم تا ۵۰ مگابایت و تصویر تا ۱۰ مگابایت مجاز است.

وقتی از سقف رد شوید پاسخ تلگرام کد 429 است و در فیلد retry_after می‌گوید چند ثانیه باید صبر کنید. نوشتن دستی این منطق لازم نیست: با افزونه‌ی rate-limiter، کلاس AIORateLimiter هم سقف هر چت و هم سقف کلی ربات را رعایت می‌کند و موقع خطای RetryAfter همه‌ی درخواست‌ها را به‌اندازه‌ی اعلام‌شده متوقف نگه می‌دارد:

from telegram.ext import AIORateLimiter

app = (Application.builder().token(TOKEN)
       .rate_limiter(AIORateLimiter(max_retries=3))
       .build())

اگر به فایل‌های بزرگ‌تر نیاز دارید، تنها راه رسمی اجرای «سرور محلی Bot API» است؛ در آن حالت طبق مستندات، دانلود بدون محدودیت اندازه و آپلود تا ۲۰۰۰ مگابایت ممکن می‌شود — به قیمت نگهداری یک سرویس جداگانه.

چرا ربات پیام‌های گروه را نمی‌بیند؟

جواب یک قابلیت است، نه باگ: همه‌ی ربات‌ها به‌طور پیش‌فرض با Privacy Mode به گروه اضافه می‌شوند و فقط این‌ها را می‌بینند — دستورهایی که صریحاً برای خودشان است (/command@this_bot)، دستورهای عمومی مثل /start اگر ربات آخرین رباتی باشد که در گروه پیام داده، و پاسخ‌ها به پیام‌های خودشان. تنها استثنا رباتی است که ادمین گروه باشد؛ ادمین‌ها همیشه همه‌ی پیام‌ها را می‌بینند. برای خاموش‌کردن این حالت در BotFather سراغ /setprivacy بروید و — نکته‌ی مهم — ربات را از گروه حذف و دوباره اضافه کنید وگرنه تغییر اعمال نمی‌شود. وضعیت فعلی را از فیلد can_read_all_group_messages در خروجی getMe بخوانید: مقدار true یعنی privacy خاموش است.

شبکه و انتخاب سرور برای ربات تلگرام

یک واقعیت فنی که باید قبل از استقرار بدانید: ربات برای کار کردن باید از خود سرور به api.telegram.org دسترسی داشته باشد. مسیر شبکه در شبکه‌های مختلف یکسان نیست و این موضوع در زیرساخت‌های داخل ایران هم مطرح است؛ پس به‌جای حدس زدن، از خود سرور تست بگیرید:

curl -sS -m 10 -o /dev/null -w "%{http_code}\n" https://api.telegram.org
302

اگر یک کد HTTP برگشت (این آدرس ریشه در حالت عادی 302 می‌دهد) مسیر باز است؛ اگر timeout شد یعنی از این سرور دسترسی مستقیم ندارید و باید پیش از هر کاری تکلیف مسیر ارتباطی را روشن کنید. مزیت پرداخت ساعتی همین‌جاست: سرور را می‌سازید، در دو دقیقه تست شبکه می‌گیرید و اگر سناریو جواب نداد حذفش می‌کنید. یک نکته‌ی مهم درباره‌ی همین صورتحساب: خاموش‌کردن سرور شمارنده را متوقف نمی‌کند و ماشین خاموش هم درصدی از نرخ ساعتی (پیش‌فرض نصف) را می‌پردازد، چون RAM و دیسکش هنوز رزرو است. تنها کاری که هزینه را صفر می‌کند حذف سرور است، و اگر موجودی کیف پول به صفر برسد سرورهای فعال خودکار معلق می‌شوند. جزئیات در راهنمای سرور ابری ساعتی آمده است.

چقدر منابع لازم است؟

در انتخاب سرور برای ربات تلگرام، بزرگ‌ترین اشتباه بزرگ خریدن است. یک ربات python-telegram-bot معمولی حدود ۶۰ تا ۱۲۰ مگابایت RAM مصرف می‌کند و CPU آن اکثر اوقات نزدیک صفر است:

  • ربات شخصی یا فروشگاه کوچک: کوچک‌ترین پلن (۱ هسته / ۱ گیگ RAM) با فاصله کافی است.
  • ربات با دیتابیس و چند هزار کاربر: ۲ گیگ RAM انتخاب راحتی است؛ دیسک NVMe اینجا خودش را در سرعت کوئری‌ها نشان می‌دهد.
  • دیسک: کل پروژه با venv معمولاً زیر ۲۰۰ مگابایت است — فضای دیسک تقریباً هیچ‌وقت گلوگاه ربات نیست.

به همین دلیل یک سرور کوچک به‌راحتی چند ربات را کنار هم اجرا می‌کند، به شرطی که هرکدام یونیت systemd و کاربر جداگانه‌ی خودش را داشته باشد. سرور ابری مهران هاست در دیتاسنتری داخل ایران است و اگر سناریو به مقصد خارج نیاز دارد، سرورهای خارج در دیتاسنترهای Hetzner و با صورتحساب ریالی در دسترس‌اند.

خطاهای رایج ربات تلگرام و راه‌حلشان

تقریباً همه‌ی مشکلات بعد از استقرار در یکی از این شش سطر جا می‌گیرد:

نشانهعلت محتملکار بعدی
لاگ پر است از Conflict: terminated by other getUpdates requestدو نمونه‌ی ربات هم‌زمان با یک توکن polling می‌کننداجرای دستی را ببندید؛ فقط سرویس یا ترمینال، نه هر دو
ربات هیچ پیامی نمی‌گیرد ولی سرویس active استwebhook هنوز ست است و getUpdates کار نمی‌کندخروجی getWebhookInfo را ببینید و در صورت لزوم deleteWebhook بزنید
401 Unauthorized در همان ثانیه‌ی اولتوکن غلط، باطل‌شده یا با فاصله‌ی اضافه کپی شدهمقدار /etc/echobot.env را با getMe راستی‌آزمایی کنید
سرویس در حالت failed (start-limit-hit) گیر کردهکرش‌های پشت‌سرهم سقف نرخ شروع را زده‌اندعلت را از ژورنال بخوانید، بعد systemctl reset-failed
پیام‌ها با تأخیر چنددقیقه‌ای یا اصلاً نمی‌رسندخطای 429 و صف عقب‌افتادهAIORateLimiter را فعال و نرخ ارسال را کم کنید
ربات در چت خصوصی کار می‌کند، در گروه نهPrivacy Mode روشن استبا /setprivacy خاموش و ربات را دوباره به گروه اضافه کنید

بعد از آنلاین‌شدن: پایش، به‌روزرسانی و بکاپ

سه عادت ربات را زنده نگه می‌دارد. اول پایش: مصرف حافظه‌ی سرویس را با systemctl status یا systemd-cgtop ببینید و اگر عدد روزبه‌روز بالا می‌رود دنبال نشتی حافظه بگردید؛ ابزارهای کلی‌تر را در راهنمای مانیتورینگ سرور لینوکس جمع کرده‌ایم. سقف حافظه با MemoryMax=512M در یونیت هم عاقلانه است: به‌جای اینکه یک نشتی کل سرور را زمین بزند، فقط همان سرویس کشته و ری‌استارت می‌شود.

دوم به‌روزرسانی: نسخه‌ی کتابخانه را پین کنید و ارتقا را عمدی انجام دهید — داخل همان محیط مجازی، بعد ری‌استارت و چند دقیقه تماشای لاگ:

/opt/echobot/venv/bin/pip install -U "python-telegram-bot[job-queue,rate-limiter]==22.*"
systemctl restart echobot
journalctl -u echobot -f

سوم بکاپ: کد ربات معمولاً در گیت است، اما دیتابیس داخل /var/lib/echobot و فایل توکن در /etc هیچ نسخه‌ی دومی ندارند. یک اسنپ‌شات روزانه از همین دو مسیر، تفاوت بین «نیم ساعت کار» و «از صفر ساختن همه‌چیز» است. حالا نقشه‌ی کامل را دارید — یک سرور کوچک بسازید و مسیر را با پرداخت ساعتی تمرین کنید.

سؤالات پرتکرار

برای راه‌اندازی ربات تلگرام روی سرور مجازی چه منابعی لازم است؟

کوچک‌ترین سرور مجازی با ۱ هسته پردازنده و ۱ گیگابایت RAM برای اکثر ربات‌ها کافی است، چون یک ربات پایتونی معمولی حدود ۶۰ تا ۱۲۰ مگابایت حافظه می‌گیرد و پردازنده‌اش بیشتر اوقات بی‌کار است. کل پروژه با محیط مجازی پایتون معمولاً زیر ۲۰۰ مگابایت فضا می‌خواهد. اگر ربات دیتابیس و چند هزار کاربر فعال دارد، ۲ گیگابایت RAM راحت‌تر است. آنچه واقعاً اهمیت دارد دسترسی پایدار سرور به API تلگرام است، نه بزرگی ماشین.

چطور ربات تلگرام را همیشه آنلاین نگه دارم؟

ربات را به‌عنوان یک سرویس systemd تعریف کنید تا سیستم‌عامل خودش زنده نگهش دارد. یک فایل یونیت با Restart=always و RestartSec=5 بسازید و با systemctl enable --now فعالش کنید؛ از آن به بعد ربات هم بعد از کرش و هم بعد از ریبوت خودکار بالا می‌آید. فاصله‌ی پنج‌ثانیه‌ای مهم است، چون systemd به‌طور پیش‌فرض بیش از پنج شروع در ده ثانیه را رد می‌کند و سرویس در حالت failed قفل می‌شود.

تفاوت polling و webhook در ربات تلگرام چیست؟

در polling ربات خودش مرتب از تلگرام می‌پرسد پیام تازه‌ای هست یا نه، و در webhook تلگرام هر پیام را به آدرس HTTPS شما ارسال می‌کند. polling به دامنه، گواهی و پورت باز نیاز ندارد و ساده‌ترین راه شروع است؛ webhook تأخیر کمتری دارد اما دامنه، گواهی TLS 1.2 به بالا و یکی از پورت‌های 443، 80، 88 یا 8443 را می‌خواهد. این دو ناسازگارند: تا وقتی webhook فعال باشد getUpdates کار نمی‌کند.

اگر توکن ربات تلگرام لو برود چه باید کرد؟

فوراً در BotFather دستور /token را بزنید تا توکن تازه‌ای ساخته شود؛ توکن قبلی همان لحظه از کار می‌افتد و دسترسی هر کسی که آن را داشته قطع می‌شود. بعد مقدار جدید را روی سرور جایگزین و سرویس را ری‌استارت کنید، وگرنه ربات با خطای 401 بالا نمی‌آید. برای اینکه تکرار نشود، توکن را در فایلی جدا با دسترسی محدود نگه دارید تا هرگز وارد مخزن گیت نشود.

چرا ربات من پیام‌های داخل گروه را دریافت نمی‌کند؟

چون همه‌ی ربات‌ها به‌طور پیش‌فرض با Privacy Mode روشن به گروه اضافه می‌شوند و در این حالت فقط دستورهایی را می‌بینند که مستقیماً برای خودشان فرستاده شده یا پاسخ به پیام‌های خودشان است. برای دیدن همه‌ی پیام‌ها یا ربات را ادمین گروه کنید، یا در BotFather با /setprivacy این حالت را خاموش کرده و ربات را از گروه حذف و دوباره اضافه کنید. وضعیت فعلی در فیلد can_read_all_group_messages خروجی getMe دیده می‌شود.

آموزش‌های مرتبط

آماده‌ی تمرین عملی هستید؟

سرور ابری ساعتی مهران هاست در ۶۰ ثانیه تحویل می‌شود — تمرین کنید و فقط بابت همان ساعت‌ها پرداخت کنید. هزینه را پیش از ثبت‌نام با محاسبه‌گر برآورد کنید.