Building a Web File Manager on STM32, ESP32, and Embedded Linux with Mongoose Wizard

Embedded systems often require a simple and reliable way to interact with the device's internal storage. Whether for diagnostics, logging, or configuration, a web interface that enables file upload, download, and deletion can dramatically improve development efficiency and end-user experience. In this article, we demonstrate how to build a web file manager using Mongoose Web Server and the Mongoose Wizard across three platforms: Embedded Linux, ESP32, and STM32.

Why a Web File Manager?

A web file manager lets users interact with files stored on an embedded device through a web browser. With drag-and-drop uploads and clickable file links, it becomes easy to handle firmware logs, configuration files, or even firmware updates without needing serial tools or command-line access.

Step 1: Create the File Manager Dashboard

We start by designing a web-based UI using the Mongoose Wizard:

The Wizard automatically sets up HTTP endpoints for uploading (/api/upload/FNAME), listing (/api/files), and deleting files (/api/delete), allowing full file lifecycle management.

Step 2: Implement Custom Handlers

The wizard generates placeholder handlers in mongoose_glue.c. We replace them with custom implementations in main.c:

The default upload directory (/tmp) is replaced with a configurable upload directory. The mg_fs_ls API is used to iterate through files and stat them for size metadata.

Here is the source code for the reference:

size_t print_files(void (*out)(char, void *), void *ptr, va_list *ap) {
  char buf[128] = {}, full[256];
  size_t len = 0;
  while (mg_fs_ls(s_fs, s_dir, buf, sizeof(buf))) {
    MG_INFO(("FILE: %s", buf));
    size_t size = 0;
    mg_snprintf(full, sizeof(full), "%s/%s", s_dir, buf);
    s_fs->st(full, &size, NULL);
    if (len > 0) len += mg_xprintf(out, ptr, ",");
    len += mg_xprintf(out, ptr, "{%m:%m,%m:%lu}",   //
                      MG_ESC("name"), MG_ESC(buf),  //
                      MG_ESC("size"), (long) size);
  }
  (void) ap;
  return len;
}

void my_reply_files(struct mg_connection *c, struct mg_http_message *hm) {
  const char *headers =
      "Cache-Control: no-cache\r\n"
      "Content-Type: application/json\r\n";
  (void) hm;
  mg_http_reply(c, 200, headers, "[%M]\n", print_files);
}

bool my_check_delete(void) {
  return false;
}

void my_start_delete(struct mg_str params) {
  struct mg_str tok = mg_json_get_tok(params, "$.name");
  if (tok.len > 2 && tok.buf[0] == '"') {
    char path[128];
    mg_snprintf(path, sizeof(path), "%s/%.*s", s_dir, tok.len - 2, tok.buf + 1);
    MG_DEBUG(("PATH [%s]", path));
    s_fs->rm(path);
  }
}

void *my_file_open_upload(char *file_name, size_t file_size) {
  char path[128];
  mg_snprintf(path, sizeof(path), "%s/%s", s_dir, file_name);
  if (file_size > 1024 * 1024) MG_INFO(("%lu is kinda big", file_size));
  return mg_fs_open(s_fs, path, MG_FS_WRITE);
}
void my_file_serve_upload(struct mg_connection *c, struct mg_http_message *hm,
                          char *file_name) {
  struct mg_http_serve_opts opts = {};
  char path[128];
  opts.fs = s_fs;
  mg_snprintf(path, sizeof(path), "%s/%s", s_dir, file_name);
  mg_http_serve_file(c, hm, path, &opts);
}

The initialisation snippet:

  s_fs->mkd(s_dir);
  mongoose_set_http_handlers("files", my_reply_files);
  mongoose_set_http_handlers("upload", my_file_open_upload,
                             my_file_serve_upload);
  mongoose_set_http_handlers("delete", my_check_delete, my_start_delete);

Step 3: Porting to ESP32

For ESP32 file upload, we target the ESP32-C6 board using ESP-IDF. After generating the ESP32 project with the Wizard:

This allows full ESP32 file upload support with browsing and deletion directly via the web UI.

Step 4: Porting to STM32 with CubeIDE and FreeRTOS

For STM32 file upload, we use the Nucleo-H563ZI development board. The board lacks external storage, but its internal flash can be used to implement a POSIX-style stm32 filesystem using LittleFS.

Web File Manager screenshot

Steps:

After flashing, open the board’s IP in a browser and test STM32 file upload. The stm32 filesystem supports full read/write/delete capabilities through the dashboard UI.

Final Result

The result is a cross-platform web file manager that:

Whether you’re building a device dashboard, an OTA update panel, or just need to move files to/from your hardware, this setup delivers fast, reliable, and repeatable functionality.

Conclusion

Implementing a web file manager for embedded systems has never been easier. With Mongoose Wizard and POSIX-compatible filesystems, full-featured ESP32 file upload and STM32 file upload support can be achieved in just an hour. Integrate it once and reuse across your product lines.

For full code examples and board-specific tips, visit https://mongoose.ws.