
虽然每天都在用 Telegram Bot,但一直没深入了解过,最近折腾了一下,发现 TG 机器人能实现的功能太多了,非常实用,API 也很完善,然而还是遇到了不少问题,特别是用 Nginx 配合 Webhook 的时候,搞了一晚上都没成功,因此这里简单的记录一下,排一下坑。
准备工作
这里跳过 Bot 的申请过程。网上有多种语言的集成 API,PHP、Node.js、Rust、Python 等等,虽然对 Python 的学习并不深入,但看了看文档相对简单,因此就决定是它了。API 则选择了 pyTelegramBotAPI,pyTelegramBotAPI 推荐使用 Python3.6-3.9 版本,我这里使用的是 Python3.7.3。
以下所有演示为在 Debian 10 系统中使用 root 用户进行。
安装 Virtual Environment
apt install python3-pip
pip3 install virtualenv
创建一个工程目录:
mkdir /home/mybot
cd /home/mybot
virtualenv env
激活virtualenv:
source env/bin/activate
接下来的依赖就会安装到虚拟环境中,要退出环境的话使用 deactivate
命令。
如果以后要将项目转移到别的地方,先进入虚拟环境中导出所有包到 requirements.txt
:
pip3 freeze > requirements.txt
然后在新的环境中安装:
pip3 install -r requirements.txt
安装所需依赖
pip3 install pyTelegramBotAPI
pip3 install uwsgi
pip3 install flask
设置 Webhook
获取 Bot 的更新可以通过 Polling 或者 Webhook,这里选择更适合生产环境的 Webhook,设置 Webhook 很简单,只需要访问一下下面的链接就行了:
https://api.telegram.org/bot{bot_token}/setWebhook?url={your_link}
例如:
https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/setWebhook?url=https://www.example.com
之后可以通过下面的链接查看设置的 Webhook 信息:
https://api.telegram.org/bot{bot_token}/getWebhookInfo
配置 uWSGI
uWSGI
是一个 Web Server,在这里主要是为了用 uwsgi 协议充当网关作用,连接 Nginx 和 Python 应用程序。uwsgi 执行可以通过命令行或者文件配置,这里使用 .ini
文件配置,创建一个 uwsgi.ini
文件,写入:
[uwsgi]
project = mybot
path = /home/mybot
wsgi-file = %(path)/mybot.py
socket = %(path)/run/%(project).sock
pidfile = %(path)/run/uwsgi.pid
stats = %(path)/run/uwsgi.status
chmod-socket = 666
callable = app
master = true
vacuum = true
processes = 4
threads = 2
为了方便运行调试,你可以创建一个脚本 mybot.sh
:
#!/usr/bin/env bash
cd /home/mybot
source env/bin/activate
uwsgi --ini uwsgi.ini
记得赋予脚本可执行权限 chmod +x mybot.sh
,后台的运行的方式有很多种,可以在前面的脚本最后一行改为:
uwsgi -d --ini uwsgi.ini
或者使用 nohup 运行脚本也可以。如果要停止运行 Bot 可以直接使用 pkill -9 uwsgi
kill 掉 uwsgi 进程。等投入生产环境运行时,推荐使用下面介绍的通过 systemd 控制进程。
创建守护进程
这里简单写一个使用 systemd 来创建进程并保持后台运行的示例:
vim /etc/systemd/system/mybot.service
[Unit]
Description=uWSGI - Telegram Bot by ATP BLOG - atpx.com
After=network.target
[Service]
WorkingDirectory=/home/mybot
ExecStart=/home/mybot/env/bin/uwsgi --ini /home/mybot/uwsgi.ini
ExecStop=/home/mybotenv/bin/uwsgi --stop /home/mybot/run/uwsgi.pid
ExecReload=/home/mybot/env/bin/uwsgi --reload /home/mybot/run/uwsgi.pid
Restart=on-failure
RestartSec=20s
[Install]
WantedBy=multi-user.target
配置 Nginx
Webhook 只能使用 https,因此你需要签发 SSL 证书,可以申请免费的 Let’s Encrypt 证书,具体步骤可查看这篇文章 使用acme.sh自动签发和更新证书,Nginx 配置文件中的反代部分配置如下:
location /SECRET_PATH {
include uwsgi_params;
uwsgi_pass unix:/home/mybot/run/mybot.sock;
}
其中的 SECRET_PATH
可以是任意的字符串,推荐使用足够长的随机字符串,这里用 ATPBLOG404 作为示例,下方编写 Bot 时也会用到。
编写第一个 Bot
这里的 /home/mybot/mybot.py
是一个简单的 Bot 示例,来源于 pyTelegramBotAPI 的 webhook_examples,并由 atpX 稍作修改,以便从 Nginx 获取内容。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import time
import telebot
from flask import Flask, request, abort
# Bot Token / 你申请到的 Bot API Token
API_TOKEN = ''
# Your domain / 前面 Webhook 中设置的域名,例如 https://www.example.com
WEBHOOK_HOST = ''
# Nginx reverse proxy path / Nginx 反代中设置的自定义路径,例如 ATPBLOG404
SECRET_PATH = ''
WEBHOOK_URL = "%s/%s" % (WEBHOOK_HOST, SECRET_PATH)
bot = telebot.TeleBot(API_TOKEN, threaded=False)
app = Flask(__name__)
@app.route('/', methods=['GET', 'HEAD'])
def index():
return ''
@app.route(WEBHOOK_URL_PATH, methods=['POST'])
def webhook():
if request.headers.get('content-type') == 'application/json':
json_string = request.get_data().decode('utf-8')
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return 'success'
else:
abort(403)
# Handle '/start'
@bot.message_handler(commands=['start'])
def send_welcome(message):
bot.send_message(message.chat.id, 'Nyanpasu~~')
# Handle all other messages
@bot.message_handler(func=lambda message: True, content_types=['text'])
def echo_message(message):
bot.reply_to(message, message.text)
bot.remove_webhook()
time.sleep(0.1)
bot.set_webhook(url=WEBHOOK_URL)
到这里,一个简单的 Bot 就完成了,接下来运行脚本,访问你的 Bot 发送 /start
就可以看到自动回复,输入其他文本信息就会变成复读机( ̄、 ̄)

接下来,你可以使用 Python 配合 API 实现任何你想实现的功能。
如果你认为这篇文章还不错,可以考虑为我充电 ⚡️