ESP32 Arduino HTTPS webserver example using certificate from LittleFS
The following example reads a HTTPS/TLS certificate from LittleFS (cert.pem
and privkey.pem
- these are just standard X.509 PEM files) and uses those to initialize a HTTPS server. Most of this example is based on the esp-idf https_server
example.
Our code to initialize the HTTPS server uses code from the following posts:
- How to initialize LittleFS in Arduino on the ESP32 (PlatformIO)
- How to read LittleFS file to std::string (using Arduino/PlatformIO)
- How to fix esp-tls-mbedtls: mbedtls_x509_crt_parse returned -0x2180
The core initialization sequence works like this:
// These need to be GLOBAL variables, they still need to exist
// after initialization!
std::string cert;
std::string privkey;
httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
httpd_handle_t server = nullptr;
void InitializeHTTPServer() {
std::string cert = ReadFileToString("/cert.pem");
std::string privkey = ReadFileToString("/privkey.pem");
conf.cacert_pem = (const uint8_t*)this->cert.c_str();
conf.cacert_len = this->cert.size() + 1;
conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
conf.prvtkey_len = this->privkey.size() + 1;
esp_err_t ret = httpd_ssl_start(&server, &conf);
if (ESP_OK != ret) {
ESP_LOGI(TAG, "Error starting server!");
return;
}
}
However it is typically far more convenient to use our HTTPSServer
class:
class HTTPSServer {
public:
HTTPSServer(): conf(HTTPD_SSL_CONFIG_DEFAULT()) {
}
void ReadCertificateInfoFromFilesystem() {
cert = ReadFileToString("/cert.pem");
privkey = ReadFileToString("/privkey.pem");
}
void StartServer() {
// Start the httpd server
ESP_LOGI(TAG, "Starting server");
ReadCertificateInfoFromFilesystem();
conf.cacert_pem = (const uint8_t*)this->cert.c_str();
conf.cacert_len = this->cert.size() + 1;
conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
conf.prvtkey_len = this->privkey.size() + 1;
esp_err_t ret = httpd_ssl_start(&server, &conf);
if (ESP_OK != ret) {
ESP_LOGI(TAG, "Error starting server!");
return;
}
}
void RegisterHandler(const httpd_uri_t *uri_handler) {
httpd_register_uri_handler(this->server, uri_handler);
}
httpd_handle_t server = nullptr;
httpd_ssl_config_t conf;
std::string cert;
std::string privkey;
};
Usage example:
void setup() {
InitFilesystem();
// TODO setup wifi network
httpsServer.StartServer();
// Register your
httpsServer.RegisterHandler(&root);
}
Full example:
#include <Arduino.h>
#include <WiFi.h>
#include <LittleFS.h>
#include <string>
#include <esp_https_server.h>
#include "esp_tls.h"
//AsyncWebServer server(80);
static const char *TAG = "https-littlefs-example";
volatile bool filesystemOK = false;
void InitFilesystem() {
// Initialize LittleFS
if (!LittleFS.begin(false /* false: Do not format if mount failed */)) {
Serial.println("Failed to mount LittleFS");
if (!LittleFS.begin(true /* true: format */)) {
Serial.println("Failed to format LittleFS");
} else {
Serial.println("LittleFS formatted successfully");
filesystemOK = true;
}
} else { // Initial mount success
filesystemOK = true;
}
}
/* An HTTP GET handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "text/html");
httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);
return ESP_OK;
}
static const httpd_uri_t root = {
.uri = "/",
.method = HTTP_GET,
.handler = root_get_handler
};
size_t LittleFSFilesize(const char* filename) {
auto file = LittleFS.open(filename, "r");
size_t filesize = file.size();
// Don't forget to clean up!
file.close();
return filesize;
}
std::string ReadFileToString(const char* filename) {
auto file = LittleFS.open(filename, "r");
size_t filesize = file.size();
// Read into temporary Arduino String
String data = file.readString();
// Don't forget to clean up!
file.close();
return std::string(data.c_str(), data.length());
}
class HTTPSServer {
public:
HTTPSServer(): conf(HTTPD_SSL_CONFIG_DEFAULT()) {
}
void ReadCertificateInfoFromFilesystem() {
cert = ReadFileToString("/cert.pem");
privkey = ReadFileToString("/privkey.pem");
}
void StartServer() {
// Start the httpd server
ESP_LOGI(TAG, "Starting server");
ReadCertificateInfoFromFilesystem();
conf.cacert_pem = (const uint8_t*)this->cert.c_str();
conf.cacert_len = this->cert.size() + 1;
conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
conf.prvtkey_len = this->privkey.size() + 1;
esp_err_t ret = httpd_ssl_start(&server, &conf);
if (ESP_OK != ret) {
ESP_LOGI(TAG, "Error starting server!");
return;
}
// Set URI handlers
ESP_LOGI(TAG, "Registering URI handlers");
httpd_register_uri_handler(server, &root);
return;
}
void RegisterHandler(const httpd_uri_t *uri_handler) {
httpd_register_uri_handler(this->server, uri_handler);
}
httpd_handle_t server = nullptr;
httpd_ssl_config_t conf;
std::string cert;
std::string privkey;
};
HTTPSServer httpsServer;
void setup() {
Serial.begin(115200);
delay(500);
InitFilesystem();
// Connect Wifi, restart if not connecting
// https://techoverflow.net/2021/01/21/how-to-fix-esp32-not-connecting-to-the-wifi-network/
WiFi.begin("MyWifi", "Lobae1tie5achokef8riequohgohx");
uint32_t notConnectedCounter = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.println("Wifi connecting...");
notConnectedCounter++;
if(notConnectedCounter > 150) { // Reset board if not connected after 5s
Serial.println("Resetting due to Wifi not connecting...");
ESP.restart();
}
}
Serial.print("Wifi connected, IP address: ");
Serial.println(WiFi.localIP());
httpsServer.StartServer();
httpsServer.RegisterHandler(&root);
}
void loop() {
// put your main code here, to run repeatedly:
delay(1000);
}
[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5
board = esp32dev
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200