Apache httpd is a modular web server that powers 31% of all websites you access every day. One of its most compelling features is the ability to extend it with new modules. Developers can choose among different modules to add or remove features like CGI, TLS, PHP, and many others.
Today, we announce a new Apache module to run WebAssembly modules: mod_wasm. This module opens a new set of possibilities as many languages and projects can run securely in Apache.
What is WebAssembly?
WebAssembly (Wasm) is a binary instruction format designed for a lightweight virtual machine, typically called runtime. Different languages can be compiled into Wasm and run in any place where a runtime is available. This makes Wasm a polyglot format that can run applications from a wide variety of languages such as C, C++, Rust, Go, etc.
You may notice that all languages we mentioned are compiled languages. Fortunately, Wasm is not limited to that. Most existing interpreters for dynamic languages are developed in one of those compiled languages, so you can compile both the interpreter and the source code into a Wasm module. This approach allowed us to run WordPress and PHP in the browser several months ago.
Wasm was created to bring new languages into web browsers and the adoption was incredible. After that, people started to think on the capabilities of Wasm on the server side. We strongly agree with this mindset and today, we helped to bring Wasm to one of the most popular web servers in the world: Apache httpd.
mod_wasm is an Apache httpd module to run Wasm modules. It allows you to reply to HTTP requests with applications compiled to Wasm. Internally, it uses the wasmtime runtime to configure, initialize, and run the Wasm modules. The rest of this section explains how it works internally. If you are just interested in using it, you can skip to the next one.
The module is composed of two libraries:
mod_wasm.so: this is the interface between the Apache C API and the Rust library that manages the Wasm runtime. It is responsible for the Apache configuration options and the bindings to connect the rust library with Apache.
libwasm_runtime.so: it receives HTTP requests from Apache, configures the Wasm module and runs it. Then, it parses the response and returns the control to mod_wasm.so.
When you run an Apache httpd server with mod_wasm enabled, it preloads the Wasm module in memory. During the Apache initialization phase, mod_wasm.so reads the configuration and sends it to libwasm_runtime.so. Then, the module is read from the filesystem and preloaded in memory with wasmtime. This approach speeds up the request handling by not loading the Wasm module from scratch every time it receives a request.
The server is now ready to start processing requests. mod_wasm.so evaluates every request to process the ones that belongs to the configured path. Then, the request is processed and passed to the libwasm_runtime.so. This library configures a new wasmtime context with the HTTP headers and the request body and runs the module.
To pass this information, we use the WebAssembly System Interface (WASI), a modular system interface for WebAssembly. WASI allows you to configure common system interfaces such as environment variables, filesystem, and standard input / output (stdio). libwasm_runtime.so takes advantage of these features to configure HTTP headers as environment variables and pass the request body through the standard input (stdin).
Finally, the Wasm module returns all the data through the standard output (stdout). There, we process the response as with CGI by looking for the HTTP response headers at the top and the content right after.
This approach provides the ability to use multiple compiled and interpreted languages to serve content through Apache httpd. And now, let's jump right to the demo!
Try mod_wasm
To run mod_wasm you need to compile the module and configure it in Apache httpd. To skip these steps, we created a container image you can run directly. So, to try mod_wasm you only need a container image runtime such as docker or podman, and then run the following command:
docker run -p8080:8080 \ projects.registry.vmware.com/wasmlabs/containers/httpd-mod-wasm:latest