Skip to content

How to use webhooks

SnejUgal edited this page Apr 3, 2020 · 11 revisions

We'll explain how you can use webhooks with tbot, including testing on your local machine and configuring it on your server.

Testing on your local machine

You can use ngrok to test webhooks on your machine. Follow their steps to install it on your computer. After you installed it, run this command:

./ngrok http $PORT

Remember the port you're listening on and the HTTPS server's URL ngrok provided you with. Then, configure tbot:

let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();
// ..
bot.webhook(URL, PORT).http().start().await.unwrap();

Configuring your server

First of all, you need to know your server's address so Telegram will be able to send you updates. Second, you need to get an HTTPS certificate. Using a trusted certificate will be easier, but such a certificate usually costs money. You can, though, generate a self-signed certificate, but it requires a few more steps to configure in tbot.

Then, you can choose one of two ways.

Proxying with nginx

If you choose this way, you will need to have nginx already installed on your server and properly configured, including HTTPS, and, per docs, running on one of these ports: 443, 80, 83 and 8443. Using nginx will allow you to use the same IP/domain and port for as many bots as you want (remember, though, that tbot can only run one bot per port). In your nginx config, you'll need to add a location block:

server {
    // ..
    location <PATH> {
        proxy_pass http://localhost:<PORT>/;
    }
}

Replace <PORT> with the port on which tbot will be running, and <PATH> with the path Telegram will be making requests to. For example, if your bot is running on localhost:4242, and you want Telegram to send requests to https://<your_ip_or_domain>/my_bot (we don't recommend this path, as you should use a hard-to-guess one instead), the location block will look like this:

location /my_bot {
    proxy_pass http://localhost:4242/;
}

If you, for some reason, configure tbot to only accept requests to some other path than /, don't forget to add it to proxy_pass's value.

Now, you need to configure tbot. The port which you want tbot to bind to should be closed from public access. Also, as HTTPS is handled by nginx, there's no need for tbot to start an HTTPS server and you can use an HTTP server instead. So, this is how you configure tbot:

let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();
// ..
bot.webhook(URL, PORT).http().start().await.unwrap();

If you use a self-signed certificate, you need to include the public key for Telegram to trust your certificate:

bot.webhook(URL, PORT)
    .certificate(include_str!("path/to/public/key/cert.pem"))
    .http()
    .start()
    .await
    .unwrap();

Running tbot on a public port directly

You can also start an HTTPS server with tbot, so that you don't need any proxy between Telegram and tbot.

#[cfg(feature = "tls")] (enabled by default)

First, you need to initialize an Identity (learn more about it in its docs):

use tbot::event_loop::webhook::https::Identity;
let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();
// ..
let identity = Identity::from_pkcs12(
    include_bytes!("path/to/identity.p12"),
    env!("IDENTITY_PASSWORD"),
).unwrap();

If you don't have an identity (a PKCS #12 archive) for your certificate yet, run this command to create one based on your private key and your certificate:

openssl pkcs12 -export -out identity.p12 -inkey private.key -in cert.pem

Then, pass identity to tbot:

// ..
let identity: Identity = ..;
bot.webhook(URL, PORT).https(identity).start().await.unwrap();

If you have a self-signed certificate, you need to include the public key for Telegram to trust your certificate:

bot.webhook(URL, PORT)
    .certificate(include_str!("path/to/public/key/cert.pem"))
    .https(identity)
    .start()
    .await
    .unwrap();

#[cfg(feature = "rustls")]

To initialize the HTTPS Rustls server, you first need to set up a [ServerConfig]:

use rustls::{internal::{rsa_private_keys, certs}, NoClientAuth, ServerConfig};

let mut bot = tbot::from_env!("BOT_TOKEN").event_loop();
// ..
let cert = include_bytes!("path/to/cert.pem");
let cert_chain = certs(cert).unwrap();

let key = include_bytes!("path/to/key.pem");
let key = rsa_private_keys(key).unwrap().into_iter().next().unwrap();

let mut config = ServerConfig::new(NoClientAuth::new());
config.set_single_cert(cert_chain, key).unwrap();

Then pass config to tbot:

// ..
bot.webhook(URL, PORT).https(config).start().await.unwrap();

If you have a self-signed certificate, you need to include the public key for Telegram to trust your certificate:

bot.webhook(URL, PORT)
    .certificate(include_str!("path/to/public/key/cert.pem"))
    .https(config)
    .start()
    .await
    .unwrap();

Remember that per docs, you may start the bot only on these ports: 443, 80, 83 and 8443.

Notes

  • tbot listens to connections on 127.0.0.1 by default, you can change it with Webhook::ip.
  • tbot ignores non-POST requests, or if the request is not sent to the allowed path (/ by default, configurable with Webhook::accept_updates_on).