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