Trouble Accessing Flask Server on ngrok from ESP32: SSL Connection Refused

Thread Starter

MateoEV

Joined May 26, 2023
22
Hello everyone! I'm working on a project that sets up a Flask-based web server on an ngrok endpoint, allowing Internet access. The goal is to serve static files (JSON and binary) to manage some parameters and configuration on an ESP32 microcontroller.

I've successfully deployed my Flask application using the free-tier ngrok static domain. I can access it on both my cellphone and computer without any issues. I also managed to serve a JSON file containing some data needed by the ESP32. However, I encounter SSL certificate errors when trying to access the static domain via an HTTPClient instance on the microcontroller. The error occurs when this function is called:

C++:
float getDataFromServer(const char* url) {
  HTTPClient http;
  WiFiClientSecure client;
  client.setCACert(root_ca);
  http.begin(client, url);
  int httpCode = http.GET();

  float data = 0.0;

  if (httpCode > 0) {
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println("Update Info: " + payload);

      const size_t capacity = JSON_OBJECT_SIZE(2) + 60;
      DynamicJsonDocument doc(capacity);

      DeserializationError error = deserializeJson(doc, payload);
      if (!error) {
        data = doc["data-to-retrieve"].as<float>();
      } else {
        Serial.print("JSON deserialization failed: ");
        Serial.println(error.f_str());
      }
    } else {
      Serial.printf("HTTP GET failed, error: %s\n", http.errorToString(httpCode).c_str());
    }
  } else {
    Serial.printf("Unable to connect, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();
  return data;
}
Instead of retrieving the intended data, I receive a connection error (line 29):

Error messages printed on Serial Monitor:
[  7124][E][ssl_client.cpp:37] _handle_error(): [start_ssl_client():273]: (-29312) SSL - The connection indicated an EOF
[  7124][E][WiFiClientSecure.cpp:144] connect(): start_ssl_client: -29312
Unable to connect, error: connection refused
This code was written using the Arduino framework on PlatformIO. It's also worth mentioning that the required SSL certificates are already included in my code (as a const char* declared with the name root_ca). However, the server is not allowing the connection to be established. Any advice on resolving this SSL issue would be greatly appreciated!
 
Last edited:

geekoftheweek

Joined Oct 6, 2013
1,429
If you haven't done so already check the server / SSL logs for clues.

I'll admit SSL is not an area I have dealt with yet, but from the little bit of searching I did confirms it's a server issue.

Good luck!!
 

Thread Starter

MateoEV

Joined May 26, 2023
22
If you haven't done so already check the server / SSL logs for clues.

I'll admit SSL is not an area I have dealt with yet, but from the little bit of searching I did confirms it's a server issue.

Good luck!!
I'll have to say I'm not familliar with SSL either to be honest.

Interestingly, the server logs show requests made from my cellphone and computer, but there are no logs when the microcontroller tries to access it.

Very strange indeed.
 

geekoftheweek

Joined Oct 6, 2013
1,429
In the example on this https://randomnerdtutorials.com/esp32-https-requests/#esp32-https-requests-wificlientsecure it shows

Code:
if (!client.connect(server, 443))
    Serial.println("Connection failed!");
    else {
        Serial.println("Connected to server!");
        // Make a HTTP request:
        client.println("GET https://www.howsmyssl.com/a/check HTTP/1.0");
        client.println("Host: www.howsmyssl.com");
        client.println("Connection: close");
        client.println();

        while (client.connected()) {
            String line = client.readStringUntil('\n');
            if (line == "\r") {
                Serial.println("headers received");
                break;
            }
        }
        // if there are incoming bytes available
        // from the server, read them and print them:
        while (client.available()) {
            char c = client.read();
            Serial.write(c);
     }
     client.stop();
}
instead of

Code:
int httpCode = http.GET();
...
...
...
I'm going to guess http.GET() is not using HTTPS, but rather a basic HTTP request instead unless you found that in another SSL example. If you did find this somewhere else then don't pay attention to anything I said.
 

Thread Starter

MateoEV

Joined May 26, 2023
22
I'm going to guess http.GET() is not using HTTPS, but rather a basic HTTP request instead unless you found that in another SSL example. If you did find this somewhere else then don't pay attention to anything I said.
It could be. I altered my function momentarily based on the tutorial you shared. Connection still cannot be established but the error code changed:

Error code shown on Serial monitor:
[  5902][E][ssl_client.cpp:37] _handle_error(): [start_ssl_client():273]: (-9984) X509 - Certificate verification failed, e.g. CRL, CA or signature check failed
[  5906][E][WiFiClientSecure.cpp:144] connect(): start_ssl_client: -9984
Connection failed!
It seems like the certificates are somehow not set properly on the microcontroller or maybe I'm missing some extra certificate.
 

geekoftheweek

Joined Oct 6, 2013
1,429
That sounds promising to some extent. Does the server at least show some sort of activity now? Unfortunately now we're at a point where I don't know anymore and guesses aren't going to get anywhere. It looks like certificates are pretty finicky from the few minutes I could spend searching this morning... part of the reason I have never bothered with SSL so far.

Maybe https://arduino.stackexchange.com/q...ith-mosquitto-on-raspberry-using-certificates can offer some insight, but other than that I really don't know at this point.
 

Thread Starter

MateoEV

Joined May 26, 2023
22
That sounds promising to some extent. Does the server at least show some sort of activity now?
No, the server does not show any activity anyways. I'm out of ideas, since I tried changing certificates and had no luck whatsoever.

Maybe https://arduino.stackexchange.com/q...ith-mosquitto-on-raspberry-using-certificates can offer some insight, but other than that I really don't know at this point.
Thanks for the advice, from the link you shared I understand there must be some error on certificate generation, maybe I should regenerate certificates for my ESP32 to establish the secure connection but I will have to keep looking for a way to do this. I will keep updating this thread on the next few weeks as I try to work around the errors.
 

geekoftheweek

Joined Oct 6, 2013
1,429
No, the server does not show any activity anyways. I'm out of ideas, since I tried changing certificates and had no luck whatsoever.
That kind of makes sense about the server activity. I did a little more looking around earlier when I had a few minutes to spare and realized that error typically comes from the client side.

Good luck with it and I'll make sure to keep an eye for updates. SSL has always been something I wanted to learn about, but never really had any real use for it.
 

Thread Starter

MateoEV

Joined May 26, 2023
22
I know this is an old thread but I honestly forgot to update my findings. For anyone interested in this matter, the problem was not really solved. Although, the problem seems to come from the reverse proxy or endpoint provided by Ngrok on my server side. I know this since I tried changing the ESP32 code multiple times to try and make requests on the provided endpoint unsuccesfully, but I also decided to try HTTPS requests using a SSL/TLS certificate for a GitHub raw content page from my own repository and the code worked without any trouble. Here is the function I got working:


C++:
const char* rootCACertificate = R"string_literal(
-----BEGIN CERTIFICATE-----
Data contained on the certificate for the github page the ESP32 has to access...
-----END CERTIFICATE-----


float getDataFromServer(const char* url) {
  WiFiClientSecure *client = new WiFiClientSecure;
  float data = -1.0;
  if(client) {
    client->setCACert(rootCACertificate);
    {
      HTTPClient https;
      if(https.begin(*client, url)){
        Serial.println("HTTPS Connection Established!");
        int httpCode = https.GET();
        if (httpCode > 0) {
          if (httpCode == HTTP_CODE_OK) {
            String payload = https.getString();
            Serial.println("Update Info: " + payload);
            const size_t capacity = JSON_OBJECT_SIZE(2) + 180;
            DynamicJsonDocument doc(capacity);
            DeserializationError error = deserializeJson(doc, payload);
            if (!error) {
              data = doc["data-to-retrieve"].as<float>();
            } else {
              Serial.print("JSON deserialization failed: ");
              Serial.println(error.f_str());
            }
          } else {
            Serial.printf("HTTPS GET failed, error: %s\n", https.errorToString(httpCode).c_str());
          }
        } else {
          Serial.printf("Unable to connect, error: %s\n", https.errorToString(httpCode).c_str());
        }
       
        https.end();
      }
      else {
        Serial.printf("HTTPS Unable to connect\n");
      }
    }
    delete client;
  }
  else{
    Serial.println("Unable to create client");
  }
 
  return data;
}
)string_literal";
So as you may notice, the function I'm sharing uses both the HTTPClient and WiFiClientSecure classes included on the Arduino Core for ESP32 to ensure the HTTPS connection. The function receives my raw file URL provided by GitHub as a parameter and uses the rootCACertificate also retreived from the GitHub page using a web browser. The file on the repository is just a JSON file containing some data the ESP32 must get for some reason. The code was succesfull in retrieving the data from the raw file.

In any case, in order for this to work using the Ngrok reverse proxy, further tests must be performed. Maybe there is some server configuration I am missing, but at least this seems to reveal the error is not on the client side apparently.
 
Top