搭建推送机器人Telegram bot实现消息推送

原先一直在软路由上用server酱配合微信实现消息推送,但是最近微信相关政策开始收紧,1月27号微信发布了一条关于下线服务号模板消息功能的通知,即后期有无法使用的可能。于是在找替代品,常见的便是自建服务器实现消息的Push,比如iOS的bark,安卓上的gotify,更小众的有小米用自带的mipush等。但是用起来都需要自建服务,或者面临复杂的编写环境。一个合适的替代品是Telegram bot,支持多种语言,既操作简便又功能众多,倘若只想达到类似server酱的功能,直接导入token并post即可。

简介

先前微信端使用的是方糖消息推送,但是由于2021年1月27号的一篇关于“服务号订阅通知灰度测试”的文章中指明灰度测试期至2021年4月30日24:00结束,未来该功能将会何去何从尚未可知。本着未雨绸缪的思想和精神,此时此刻需要物色另一种消息推送的渠道和方式以满足相关的业务需求。

经过一番了解和考量,我选择使用tg_push_bot程序来构建我的Telegram消息推送机器人。

创建机器人

申请telegram bot,打开@BotFather,点击 /newbot生成新一个的bot,系统会让你给它取一个昵称,方便记忆即可,而后系统会再次让你取一个名字并输入,现在的名字必须以bot结尾,且不可以和其他任何bot重名。一旦你输入的bot名字可用,系统会生成一个token给你,形如123456789:ABcd6asdacssfdvBgHjKoLkkjLu8,请务必保存好此token并且不泄露,这是唯一的用户凭证。

此时,你已经拥有了一个bot,但是还无法使用,打开 https://t.me/yourBotName 这个链接,注意这里的yourBotName为你刚才新建的bot的名字,点击/start进入对话框,发送@userinfobot后并点击它。在userinfobot的对话中,点击或者输入/start,你将获取一个Id/chat_id,具体表现为一串数字,比如387980691。至此,电报的机器人已经申请完成,你获得了机器人的bot名字,一个token,还有一个chat_id。

构建程序

获取源码

1
2
git clone https://github.com/DkWyatt/tg_push_bot.git
cd tg_push_bot

创建Sqlite3数据库

1
2
3
4
apt install sqlite3 -y
sqlite3 bot.db
sqlite> CREATE TABLE users (chatId int unique, chatToken text unique);
sqlite> .quit

创建配置文件 config.js,位于tg_push_bot文件夹下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
https = {}
bot = {}
ui = {}

https.domain = '0.0.0.0' // 域名
https.privateKey = 'xxx.key' // Key文件
https.certificate = 'xxx.crt' // CSR文件

bot.token = 'https://api.telegram.org/bot{token}/' // BotFather返回的Token,以/结尾,{}去掉。

ui.startHint = '您的推送链接: \r\nhttps://tgbot.szc.me/sendMessage/%s' // 用户发送/start时返回的内容,%s表示用户唯一URL
ui.stopHint = "用户记录已经删除,旧链接已经失效\r\n如需继续发送消息,请输入/start重新获取"
ui.userNotExistHint = 'no user' // 用户不存在时的返回内容
ui.httpsTestHint = 'hello from nodejs with https'
ui.errorHint = 'error' // 错误提示

module.exports = {
https: https,
bot: bot,
ui: ui
}

下面给出一份已经处于生产环境中的config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
https = {}
bot = {}
ui = {}

https.domain = '0.0.0.0' // 域名。原作者备注这里是填写域名的,我试过填写域名,会导致502 Bad Request。我用的也是这个0.0.0.0。
https.privateKey = '/usr/local/nginx/conf/ssl/kixcs.com/kixcs.com.key' // Key文件
https.certificate = '/usr/local/nginx/conf/ssl/kixcs.com/fullchain.cer' // CSR文件,就是我们把两个文件合并成一个的ssl.crt文件。

bot.token = 'https://api.telegram.org/bot16676666666:AAaaBBBBBBBBBBaaAAAAA/' // BotFather返回的Token,以/结尾

ui.startHint = 'Your Info push links address is: \r\nhttps://tgbot.kixcs.com/sendMessage/%s' // 用户发送/start时返回的内容,%s表示用户唯一URL
ui.stopHint = "The user record has been deleted and the old link has expired.\r\n如需继续发送消息,请输入/start重新获取" //用户记录已经删除,旧链接已经失效
ui.userNotExistHint = 'no user' // 用户不存在时的返回内容
ui.httpsTestHint = 'Hello from nodejs with https(TG_info_push_bot), this program was deployed by https://github.com/Fndroid/tg_push_bot.'
ui.errorHint = 'Something went error:(' // 错误提示

module.exports = {
https: https,
bot: bot,
ui: ui
}

修改程序运行端口,将server.js 197行443端口修改为8443,本人的配置文件为212行,处于文件末尾。

1
2
3
httpsServer.listen(8443, config.https.domain, () => {
console.log('listening on port 433')
})

配置服务环境

安装Node.js

1
2
3
4
5
6
7
8
9
10
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
npm install #安装依赖(安装完后可能会出现几个warn警告,无伤大雅)
npm install -g pm2 #安装pm2模块
pm2 start server.js #运行服务
pm2 startup #设置开机启动
#可选
#保存当前 pm2 运行的各个应用保存到 /root/.pm2/dump.pm2 下,
#开机重启时读取该文件中的内容启动相关
#pm2 save

*可选 不同Linux系统发行版本关于Node.js安装的命令行操作或许稍有不同

1
2
3
4
5
6
7
8
9
10
11
12
13
#Ubuntu 版本号数字可酌情更改
curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
apt-get install -y nodejs
#Debian
curl -sL https://deb.nodesource.com/setup_9.x | bash -
apt-get install -y nodejs
#CentOS
curl -sL https://rpm.nodesource.com/setup_9.x | bash -
yum install nodejs -y

#查看输出结果判断是否安装成功
node -v
npm -v

*可选 可能会用到的PM2命令

1
2
3
4
5
6
7
pm2 list                      #列表 PM2 启动的所有的应用程序
pm2 restart all #重启所有程序
pm2 kill #终止PM2

#卸载pm2
pm2 kill
npm remove pm2 -g

*可选 卸载npm

1
npm uninstall npm -g

配置Nginx反向代理

vhost目录下新建一个配置文件,相关数据替换成自己的网站。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
server {
listen 443 ssl http2;
ssl_certificate /usr/local/nginx/conf/ssl/ssl.cer;
ssl_certificate_key /usr/local/nginx/conf/ssl/ssl.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_timeout 10m;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_buffer_size 1400;
add_header Strict-Transport-Security max-age=15768000;
ssl_stapling on;
ssl_stapling_verify on;
server_name your.domain;
#access_log /data/wwwlogs/your.domain_nginx.log combined;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;

proxy_redirect off;
# Socket.IO Support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

location / {
proxy_pass https://127.0.0.1:8443;
}
}

然后重启nginx

1
service nginx restart

给出一份部署于生产环境的Nginx vhost文件配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
server
{
listen 80;
#listen [::]:80;
server_name tgbot.kixcs.com ;
#index index.html index.htm index.php default.html default.htm default.php;
#root /home/tgbot.kixcs.com;


if ($scheme = http ) {
return 301 https://$host$request_uri;
}

include rewrite/none.conf;
#error_page 404 /404.html;
# Deny access to PHP files in specific directory
#location ~ /(wp-content|uploads|wp-includes|images)/.*\.php$ { deny all; }

access_log /home/wwwlogs/tgbot.kixcs.com.log;
}

server
{
listen 443 ssl http2;
#listen [::]:443 ssl http2;
server_name tgbot.kixcs.com ;

#index index.html index.htm index.php default.html default.htm default.php;
#root /home/tgbot.kixcs.com;

ssl_certificate /usr/local/nginx/conf/ssl/kixcs.com/fullchain.cer;
ssl_certificate_key /usr/local/nginx/conf/ssl/kixcs.com/kixcs.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
ssl_session_cache builtin:1000 shared:SSL:10m;
# openssl dhparam -out /usr/local/nginx/conf/ssl/dhparam.pem 2048
ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /usr/local/nginx/conf/ssl/kixcs.com/fullchain.cer;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;

proxy_redirect off;
# Socket.IO Support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

location / {
proxy_pass https://127.0.0.1:8443;
}
access_log /home/wwwlogs/tgbot.kixcs.com.log;
}

设置Bot webhook地址

浏览器访问下面地址,将token和域名替换成自己的地址,记得花括号{}要删去哦。

1
https://api.telegram.org/bot{token}/setWebhook?url=https://{domain}/inlineQuery

再通过下面链接检查webhook是否正常

1
https://api.telegram.org/bot{token}/getWebhookInfo

获取推送链接

添加自己的机器人,输入/start就能获取自己的推送链接了,形如下列代码。

1
2
3
4
Your Info push links address is:
https://tgbot.kixcs.com/sendMessage/2p32vaaaaaaaa
#填入推送链接,如https://tgbot.lbyczf.com/sendMessage/:Token
#即为所需链接

推荐使用json格式发送数据

1
curl -H "Content-Type: application/json" -d '{"text":"HelloWorld","disable_notification": true }' -X POST https://tgbot.szc.me/sendMessage/:Token

可以使用如下链接给我的bot发送消息

1
curl -H "Content-Type: application/json" -d '{"text":"HelloWorld","disable_notification": true }' -X POST https://tgbot.kixcs.com/sendMessage/2p32va2d4kks5lfrd

写在最后

Chrome应用插件有可能会出现服务器限制跨域,即在插件上输入了推送链接,但是没有反应。

这时候需要到服务器里面找到server.js,在第20行添加一下内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);

// Pass to next layer of middleware
next();
})

然后cd /文件所在位置,例如cd /home/tg_push_bot ,重启pm2 pm2 restart all 即可。

1
2
cd /home/tg_push_bot
pm2 restart all

最后附上我的消息推送机器人bot:Router_bot

鸣谢:Telegram推送机器人 在VPS/ECS上搭建Bot Server Chrome插件消息推送跨域问题