尝试使用本地 Telegram 机器人 API 来利用较大的文件来为我的机器人提供服务并帮助超级组中的用户处理文件如此处所述 使用 Telegram Bot API 构建堆栈,nginx 作为反向代理,我的机器人工作正常,基于 docker-compose 模板:
version: '3.7'
networks:
int:
name: internal
driver: bridge
services:
api:
hostname: local-api
image: aiogram/telegram-bot-api:latest
restart: always
networks:
- int
environment:
TELEGRAM_API_ID: BOT_ID
TELEGRAM_API_HASH: BOT_HASH
TELEGRAM_LOCAL: "true"
TELEGRAM_HTTP_IP_ADDRESS: 0.0.0.0
TELEGRAM_HTTP_PORT: 8081
TELEGRAM_MAX_FILESIZE: 1000000000 # задава максимален размер на файла на 1GB
volumes:
- telegram-bot-api-data:/var/lib/telegram-bot-api
nginx:
hostname: nginx
image: nginx:1.19-alpine
restart: always
depends_on:
- api
volumes:
- telegram-bot-api-data:/var/lib/telegram-bot-api
- ./nginx:/etc/nginx/conf.d/
ports:
- "88:88"
networks:
- int
telegram-bot:
depends_on:
- api
- nginx
hostname : telegram-bot
networks:
- int
restart: unless-stopped
build:
context: /root/docker/telegram-bot
dockerfile: Dockerfile
image: telegram-bot/latest
environment:
LOCAL_API_URL: http://nginx:88/bot
LOCAL_API_FILES: http://nginx:88/file/bot
labels:
- "com.centurylinklabs.watchtower.enable=false"
volumes:
- /root/docker/telegram-bot/:/app/
volumes:
telegram-bot-api-data:
并根据 nginx 配置进行重定向:
# use $sanitized_request instead of $request to hide Telegram token
log_format token_filter '$remote_addr - $remote_user [$time_local] '
'"$sanitized_request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
upstream telegram-bot-api {
server local-api:8081;
}
server {
listen 88;
chunked_transfer_encoding on;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
client_max_body_size 2G;
client_body_buffer_size 30M;
keepalive_timeout 0;
proxy_http_version 1.1;
rewrite_log on;
set $sanitized_request $request;
if ( $sanitized_request ~ (\w+)\s(\/bot\d+):[-\w]+\/(\S+)\s(.*) ) {
set $sanitized_request "$1 $2:<hidden-token>/$3 $4";
}
access_log /var/log/nginx/access.log token_filter;
error_log /var/log/nginx/error.log notice;
location ~* \/file\/bot\d+:(.*) {
rewrite ^/file\/bot(.*) /$1 break;
proxy_http_version 1.1;
try_files $uri @files;
}
location / {
try_files $uri @api;
proxy_http_version 1.1;
}
location @files {
root /var/lib/telegram-bot-api;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 64 8k;
gzip_http_version 1.1;
gzip_min_length 1100;
}
location @api {
proxy_pass http://telegram-bot-api;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
最后 Telegram 机器人已设置为可与本地 Telegram Bot API 配合使用:
.env
LOCAL_API=True
LOCAL_API_URL=http://nginx:88/bot
LOCAL_API_FILES=http://nginx:88/file/bot
PTB 电报机器人设置
updater = Updater(config["BOT_TOKEN"], use_context = True, base_url = config["LOCAL_API_URL"], base_file_url = config["LOCAL_API_FILES"], arbitrary_callback_data = True)
一切正常,但文件重定向无法按预期工作 - 限制仍然存在,无法获取从机器人文件接收的本地链接
2023/04/04 11:15:52 [错误] 30#30: *15 open() “/var/lib/telegram-bot-api/TOKEN_ID:TOKEN_HASH/var/lib/telegram-bot-api/TOKEN_ID:TOKEN_HASH/documents/file_16.apk” 失败(2:没有这样的文件或目录),客户端:172.19.0.4,服务器:_, 请求:“获取 /file/botTOKEN_ID%3ATOKEN_HASH//var/lib/telegram-bot-api/TOKEN_ID%3ATOKEN_HASH/documents/file_16.apk HTTP/1.1”,主机:“nginx:81” 172.19.0.4 - - [04/Apr/2023:11:15:52 +0000]“获取/file/botTOKEN_ID%3ATOKEN_HASH//var/lib/telegram-bot-api/TOKEN_ID%3ATOKEN_HASH/documents/file_16.apk HTTP/1.1" 404 154 "-" "Python Telegram 机器人 (https://github.com/python-telegram-bot/python-telegram-bot)”
日志中有“重复路径” /var/lib/telegram-bot-api/TOKEN_ID:TOKEN_HASH/var/lib/telegram-bot-api/TOKEN_ID:TOKEN_HASH/documents/file_16.apk
尽管如此,curl 请求仍按预期工作
curl -i http://nginx:81/file/botTOKEN_ID:TOKEN_HASH/documents/file_16.apk
HTTP/1.1 200 OK 服务器:nginx/1.19.10 日期:2023 年 4 月 4 日星期二 14:31:01 GMT 内容类型:application/octet-stream 内容长度:10066456 最后修改时间:2023 年 4 月 4 日星期二 06:26:47 GMT 连接:关闭 ETag: “642bc327-999a18”接受范围:字节
警告:二进制输出可能会弄乱您的终端。使用“--输出-”来 告诉警告:卷曲将其输出到您的终端,或者考虑 “--output警告:”保存到文件。
无法意识到错误从哪里开始,机器人本身请求本地 API 或 nginx 重定向? 由于没有足够的时间进行 Probono 项目,因此无法在 PTB 20.x 上重写机器人。 欢迎任何想法!
编辑:错误的路径来自 context.bot.get_file(file_id) 并返回 file_path !
致其他遇到该用例的人 nginx.conf
# use $sanitized_request instead of $request to hide Telegram token
log_format token_filter '$remote_addr - $remote_user [$time_local] '
'"$sanitized_request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
upstream telegram-bot-api {
server local-api:8081;
}
server {
listen 88;
listen 8443 ssl;
ssl_certificate /etc/nginx/conf.d/PUBLIC.pem;
ssl_certificate_key /etc/nginx/conf.d/PRIVATE.key;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
server_name api.thetopper.eu;
chunked_transfer_encoding on;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
client_max_body_size 2G;
client_body_buffer_size 30M;
keepalive_timeout 0;
set $sanitized_request $request;
if ( $sanitized_request ~ (\w+)\s(\/bot\d+):[-\w]+\/(\S+)\s(.*) ) {
set $sanitized_request "$1 $2:<hidden-token>/$3 $4";
}
access_log /var/log/nginx/access.log token_filter;
location ~* \/file\/bot\d+:(.*) {
rewrite ^/file\/bot(.*) /$1 break;
try_files $uri @files;
}
location / {
try_files $uri @api;
}
location @files {
root /var/lib/telegram-bot-api;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 64 8k;
gzip_http_version 1.1;
gzip_min_length 1100;
# Remove /var/lib/telegram-bot-api/TOKEN_ID:TOKEN_HASH prefix from file path
#rewrite ^/file/bot(.*)/(.*)$ /$1/$2 break;
# Log $uri variable to Nginx error log
error_log /var/log/nginx/error.log info;
error_log /var/log/nginx/error.log debug_http;
}
location @api {
proxy_pass http://telegram-bot-api;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
config.env
LOCAL_API=True
LOCAL_API_URL=http://nginx:88/bot
LOCAL_API_FILES=http://nginx:88/file/bot
bot.py(PTB v13.15)
updater = Updater(config["BOT_TOKEN"], use_context=True, base_url=config["LOCAL_API_URL"],arbitrary_callback_data=True, base_file_url=config["LOCAL_API_FILES"])
....
file_name = update.message.document.file_name
file_name_id = update.message.document.file_id
file_path = f"/var/lib/telegram-bot-api/{config["BOT_TOKEN"]}/documents/{update.message.document.file_id.file_path.split('/')[-1]}"