Why cannot I receive any POST request on my Telegram bot written with Flask (Python)?
Asked Answered
F

3

2

I don't want to use getUpdates method to retrieve updates from Telegram, but a webhook instead.

Error from getWebhookInfo is:

has_custom_certificate: false,
pending_update_count: 20,
last_error_date: 1591888018,
last_error_message: "SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"

My code is:

from flask import Flask
from flask import request
from flask import Response

app = Flask(__name__)

@app.route('/', methods=['POST', 'GET']) 
def bot():
    if request.method == 'POST':
        return Response('Ok', status=200)
    else:
        return f'--- GET request ----'

if __name__ == "__main__":
    app.run(host='0.0.0.0', port='8443', debug=True, ssl_context=('./contract.crt', '.private.key'))

When I hit https://www.mydomain.ext:8443/ I can see GET requests coming but not POST ones when I write something on my telegram-bot chat Also that's how I set a webhook for telegram as follow:

https://api.telegram.org/botNUMBER:TELEGRAM_KEY/setWebhook?url=https://www.mydomain.ext:8443

result:

{
  ok: true,
  result: true,
  description: "Webhook was set"
}

Any suggestion or something wrong I've done?

https://core.telegram.org/bots/api#setwebhook

I'm wondering if the problem it's caused because I'm using 0.0.0.0, the reason it's that if I use 127.0.0.0 the url/www.mydomain.ext cannot be reached

Update

ca_certitificate = {'certificate': open('./folder/ca.ca-bundle', 'rb')}
r = requests.post(url, files=ca_certitificate)
print(r.text)

that print gives me:

{
  "ok": false,
  "error_code": 400,
  "description": "Bad Request: bad webhook: Failed to set custom certificate file"
 }
Fluke answered 11/6, 2020 at 13:45 Comment(10)
So, your question is that telegram's webhooks are sending GET instead of POST requests where you expect? Is that it?Malarkey
No, I tested GET requests just hitting the url, and I was expecting to see POST request coming writing messages on my chat bot (on telegram)Fluke
I think that's what I mean. Your problem is that Telegram is sending you GET requests, and you're expecting it to send POST requests.Malarkey
Sorry mate, what you're saying it's not what I meant. I said that I tested GET requests, hitting the url/domain where my python bot is placed, so Telegram doesn't have nothing to do with that. Then I said that I was expecting to receive POST request from Telegram when I write any message on my bot-chat (on Telegram)Fluke
Sorry, I'm perhaps still misunderstanding. So you get your own request, you're making a call to Telegram, but Telegram isn't sending you an expected request after all that happens? Is that correct?Malarkey
I'm getting my own GET request by hitting https://www.mydomain.ext:8443 but when I write some messages on my chat-bot (on Telegram), which it supposed to trigger a POST request to my URL(the same I wrote above), nothing happens/comes core.telegram.org/bots/api#setwebhookFluke
Apparently from Telegram getWebhookInfo I know what's the error has_custom_certificate: false, pending_update_count: 20, last_error_date: 1591888018, last_error_message: "SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"Fluke
Are you using testing using localhost or with a dns domain? can you share your domain?Scud
@Scud That code is places in my hosting domain vallotta-party-bot.comFluke
Does this answer your question? telegram bot SSL error: SSL error {error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}Scud
M
0

I deployed a Telegram chatbot without Flask a while ago. I remember that the POST and GET requests required /getUpdates and /sendMessage added to the bot url. Maybe it will help.

Militate answered 11/6, 2020 at 14:6 Comment(2)
Thanks, but I'm trying to set up a Webhook instead of using getUpdates for retrieving updatesFluke
Wish I could help but I have zero experience with Webhooks. I may need soon, so I'll bookmark your question.Militate
S
0

Telegram bots only works with full chained certificates. And the error in your getWebHookInfo:

"last_error_message":"SSL error {337047686, error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed}"

Is Telegram saying that it needs the whole certificate chain (it's also called CA Bundle or full chained certificate). as answered on the question.

If you validate your certificate using the SSLlabs you will see that your domain have chain issues:

https://www.ssllabs.com/ssltest/analyze.html?d=www.vallotta-party-bot.com&hideResults=on

To solve this need you need to set the CA Certificate. In this way, you need to find the CA certificate file with your CA provider.

Also, the best option in production sites is to use gunicorn instead of Flask.

If you are using gunicorn, you can do this with command line arguments:

$ gunicorn --certfile cert.pem --keyfile key.pem --ca_certs cert.ca-bundle -b 0.0.0.0:443 hello:app

Or create a gunicorn.py with the following content:

import multiprocessing

bind = "0.0.0.0:443"

workers = multiprocessing.cpu_count() * 2 + 1

timeout = 120

certfile = "cert/certfile.crt"

keyfile = "cert/service-key.pem"

ca_certs = "cert/cert.ca-bundle"

loglevel = 'info'

and run as follows:

gunicorn --config=gunicorn.py hello:app

If you use Nginx as a reverse proxy, then you can configure the certificate with Nginx, and then Nginx can "terminate" the encrypted connection, meaning that it will accept encrypted connections from the outside, but then use regular unencrypted connections to talk to your Flask backend. This is a very useful setup, as it frees your application from having to deal with certificates and encryption. The configuration items for Nginx are as follows:

server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    # ...
}

Another important item you need to consider is how are clients that connect through regular HTTP going to be handled. The best solution, in my opinion, is to respond to unencrypted requests with a redirect to the same URL but on HTTPS. For a Flask application, you can achieve that using the Flask-SSLify extension. With Nginx, you can include another server block in your configuration:

server {
    listen 80;
    server_name example.com;
    location / {
        return 301 https://$host$request_uri;
    }
}

A good tutorial of how setup your application with https can be found here: Running Your Flask Application Over HTTPS

Scud answered 11/6, 2020 at 16:58 Comment(2)
The hosting provider gave me Root CA and Intermediate CA (BEGIN CERT - END CERT), how shall I save them on the server and what shall I send to Telegram setWebhook API? requests.post(f'{API_URL}/setWebhook?url={bot_details["domain"]}', files={'certificate': open('./intermediate-ca.pem', 'rb')}) ?Fluke
Change your code to use gunicorn instead of Flask, that is the best option in Production add the --ca_certs option passing your .ca file. I added this on my answer please check it. Will be something like this: gunicorn --certfile cert.pem --keyfile key.pem --ca_certs cert.ca-bundle -b 0.0.0.0:443 hello:appScud
A
0

I had similar case. I was developing bot on localhost (yet without SSL) and tunneled it to web through ngrok. In beginning all was OK, but once I found no POST-requests are coming. It turned out time of tunneling expired. I laughed and restarted tunneling. But requests weren't coming. It turned out, I forgot to change address of webhook (it switches every ngrok session). Don't repeat my errors.

Autoradiograph answered 18/8, 2021 at 22:18 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.