Your first web server

Now that your build environment is ready, you can create your first web server.

Step 1 - Create a project directory

Create an empty directory for the example project. Download mongoose.c and mongoose.h into that directory.

Step 3 - Create main.c

This is the minimal embedded HTTP server example:

#include "mongoose.h"

// Connection event handler function
static void ev_handler(struct mg_connection *c, int ev, void *ev_data) {
  if (ev == MG_EV_HTTP_MSG) {  // New HTTP request received
    struct mg_http_message *hm = (struct mg_http_message *) ev_data;  // Parsed HTTP request
    if (mg_match(hm->uri, mg_str("/api/hello"), NULL)) {              // REST API call?
      mg_http_reply(c, 200, "", "{%m:%d}\n", MG_ESC("status"), 1);    // Yes. Respond JSON
    } else {
      struct mg_http_serve_opts opts = {.root_dir = ".", .fs = &mg_fs_posix};
      mg_http_serve_dir(c, hm, &opts);  // For all other URLs, Serve static files
    }
  }
}

int main() {  
  struct mg_mgr mgr;  // Mongoose event manager. Holds all connections
  mg_mgr_init(&mgr);  // Initialise event manager
  mg_http_listen(&mgr, "http://0.0.0.0:8000", ev_handler, NULL);
  for (;;) {
    mg_mgr_poll(&mgr, 1000);  // Infinite event loop
  }
  return 0;
}

This example does two things:

  • serves static files from the current directory
  • exposes a simple JSON endpoint at /api/hello

Step 4 - Build and run

Compile and run the example:

cc main.c mongoose.c -I. -o http_server
./http_server

Then open http://localhost:8000 in your browser. You can also test the API endpoint at http://localhost:8000/api/hello . It should return:

{"status":1}

How it works

The example starts an HTTP server on port 8000 and runs the Mongoose event loop forever.

When a request arrives:

  • /api/hello returns a JSON response
  • any other URL is served from the current directory

That means if you place an index.html file in the same directory, Mongoose will serve it automatically.

Next steps

Congratulations - your first web server is now running.

The same Mongoose code structure also works on microcontrollers and other embedded systems. In most cases, you just copy mongoose.c and mongoose.h into your firmware project and adapt main() to your platform startup code and event loop.

For embedded targets, you will also add a third file called mongoose_config.h to define build options, as described in the Build options section.

From here, you can continue with:

  • building a device dashboard
  • connecting your device to MQTT cloud
  • enabling HTTPS / TLS
  • adding OTA firmware updates