Weird issue using ngrok and wifi

I had an issue yesterday where my board couldn't connect to ngrok free app running on my local machine using the url but could with the IP address.

I also tried using the root_ca but that didn't work. Couldn't figure out what was going on. Once it resolved the IP and I included the Host: in the request everything worked fine and it was stable all night.

Below is just a test program. I pulled out the wifi/client code and just trying to test it.

Any idea?

#include <ESP8266WiFi.h>

// WiFi credentials
const char* ssid = "";
const char* password = "";

// Web server settings
const char* host = "8a15b2f181c5.ngrok-free.app";  // Your server hostname
const int httpsPort = 443;
const char* endpoint = "/weather";  // Your API 

// Basic Auth credentials
const char* api_username = "";
const char* api_password = "";

void setup() {
  Serial.begin(115200);
  Serial.println("Weather Station Starting...");
  
  delay(5000);
}

void loop() {
  sendDataToServer(0, 0, 0);

  delay(20000);

}

bool connectToWiFi() {
  if (WiFi.status() == WL_CONNECTED) return true;
  
  Serial.print("Connecting to WiFi");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  
  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 20) {
    delay(500);
    Serial.print(".");
    attempts++;
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println(" Connected!");
    Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str());
    return true;
  } else {
    Serial.println(" Failed to connect");
    return false;
  }
}

void sendDataToServer(float temperature, float humidity, int rainTips) {
  if (WiFi.status() != WL_CONNECTED) {
    if (!connectToWiFi()) {
      Serial.println("Failed to connect to WiFi for data transmission");
      return;
    }
  }
  
  Serial.println("Sending data to server...");
  
  // Create JSON payload
  String payload = "{";
  payload += "\"temperature\":"; payload += String(temperature, 1);
  payload += ",\"humidity\":"; payload += String(humidity, 1);
  payload += ",\"rain_bucket_tips\":"; payload += String(rainTips);
  payload += ",\"timestamp\":"; payload += String(time(nullptr));
  payload += "}";
  
  Serial.println("Payload: " + payload);

  // Test DNS resolution first
  Serial.println("Testing DNS resolution...");
  IPAddress serverIP;
  if (WiFi.hostByName(host, serverIP)) {
    Serial.printf("DNS resolved to: %s\n", serverIP.toString().c_str());
  } else {
    Serial.println("DNS resolution failed!");
    disconnectWiFi();
    return;
  }
  
  // Use WiFiClientSecure for HTTPS
  WiFiClientSecure client;
  client.setInsecure(); // Skip certificate validation (use for testing)
  // For production, use: client.setTrustAnchors(&cert); with proper certificate
  
  // BearSSL::X509List cert(root_ca);
  // client.setTrustAnchors(&cert);

  Serial.println("Attempting to connect to server...");
  unsigned long connectStart = millis();

  if (!client.connect(host, httpsPort)) {
    Serial.println("Connection to server failed!");
    Serial.printf("Connection attempt took: %lu ms\n", millis() - connectStart);
    
    // Try to get more detailed error info
    Serial.println("Trying to connect to IP directly...");
    if (!client.connect(serverIP, httpsPort)) {
      Serial.println("Direct IP connection also failed");
      disconnectWiFi();
      return;
    } else {
      Serial.println("Connection by IP worked.");
    }
  }

  // Create Basic Auth header
  String auth = String(api_username) + ":" + String(api_password);
  String encodedAuth = base64Encode(auth);
  
  // Create HTTP POST request
  String request = "POST ";
  request += endpoint;
  request += " HTTP/1.1\r\n";
  request += "Host: ";
  request += host;
  request += "\r\n";
  request += "ngrok-skip-browser-warning: true\r\n";  // Skip ngrok warning page
  request += "User-Agent: ESP8266-WeatherStation/1.0\r\n";  // Some servers require User-Agent
  request += "Authorization: Basic ";
  request += encodedAuth;
  request += "\r\n";
  request += "Content-Type: application/json\r\n";
  request += "Content-Length: ";
  request += payload.length();
  request += "\r\n";
  request += "Connection: close\r\n\r\n";
  request += payload;
  request += "\r\n";
  
  // Send request
  client.print(request);
  Serial.println("Request sent");
  
  // Read response
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      Serial.println("Server timeout");
      client.stop();
      disconnectWiFi();
      return;
    }
  }
  
  // Print response
  String response = "";
  while (client.available()) {
    response += char(client.read());
  }
  
  Serial.println("Server response:");
  Serial.println(response);
  
  // Check if response indicates success
  if (response.indexOf("200 OK") > 0 || response.indexOf("201") > 0) {
    Serial.println("Data sent successfully!");
  } else {
    Serial.println("Server returned error");
  }
  
  client.stop();
  disconnectWiFi();
}

// Base64 encoding for Basic Auth
String base64Encode(String str) {
  String encoded = "";
  const char* chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  int i = 0;
  unsigned char char_array_3[3];
  unsigned char char_array_4[4];
  
  while (i < str.length()) {
    char_array_3[0] = str[i++];
    char_array_3[1] = (i < str.length()) ? str[i++] : 0;
    char_array_3[2] = (i < str.length()) ? str[i++] : 0;
    
    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;
    
    for (int j = 0; j < 4; j++) {
      if (j < 4 - (3 - (str.length() - i + 3) % 3) % 3) {
        encoded += chars[char_array_4[j]];
      } else {
        encoded += '=';
      }
    }
  }
  
  return encoded;
}

// Disconnect WiFi to save power
void disconnectWiFi() {
  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  Serial.println("WiFi disconnected for power saving");
}

I believe that ngrok uses the Host: header to route the request to the correct tunnel so you do need to have that (and the Host: header must remain as the domain name (e.g. 8a15b2f181c5.ngrok-free.app ) or the reverse proxy (ngrok) won’t recognize or route the request correctly.)

That’s working fine. Issue is I can’t even connect using the domain name. Only the IP address.

hum... unsure then what's going on. I no longer use ESP8266, moved to ESP32 which are more robust when it comes to https.

Tried out an ESP32-S2 and it works as expected. Must be something with the 8266