Mod_wasm - an extension module for the Apache HTTP Server (httpd) that enables the usage of WebAssembly (Wasm).

Overview

mod_wasm

mod_wasm is an Apache Server (httpd) extension module able to run and serve WebAssembly binaries as endpoints.

It was unveiled at the ApacheCon North America on Oct 3rd, 2022 (see the slides). In addition, a full-detailed article can be found at VMware's Wasm Labs page.

Features

mod_wasm can be useful in the different scenarios:

  • Run existing applications from a variety of languages without modification.
  • Execute untrusted third-party code in a secure environment without using containers.
  • The Wasm capabilities model allows to enable/disable capabilites per HTTP request.

▶️ Quick Demo

  1. Run the container:
docker run -p 8080:8080 projects.registry.vmware.com/wasmlabs/containers/httpd-mod-wasm:latest
  1. Open browser at: http://localhost:8080/wasm-module-endpoint

More details about the 'PrettyFy' WebApp Demo below.

📔 Contents

🔭 Overview

The mod_wasm project is composed by two different libraries:

  • mod_wasm.so (written in C) acts as the extension module for the Apache Server (httpd).
  • libwasm_runtime.so (written in Rust) offers a very high-level C-API to manage WebAssembly modules via Wasmtime.

alt Architecture

New Directives

To setup and manage WebAssembly binaries, mod_wasm offers new directives to the httpd.conf configuration file:

Directive Description
WasmRoot Set the root directory for Wasm modules.
WasmModule Set the Wasm module file name.
WasmDir Pre-open a host directory for the Wasm context.
WasmMapDir Pre-open a host directory for the Wasm context and mount into a given directory.
WasmArg Set an argument to be passed to the Wasm module context.
WasmEnv Set an environment variable to be passed to the Wasm module context.
WasmEnableCGI Enable/Disable CGI emulation mode for HTTP requests.

Workflow

mod_wasm plays a role in two different stages of the Apache Server workflow:

  1. The different WasmXXX directives are read from httpd.conf during the boot up sequence. Once the configuration if fully processed, mod_wasm requests to the Wasm runtime to start loading the Wasm binaries. This is by far the most expensive operation and that is why it is executed only once during the Apache boot up sequence. When completed, the Apache Sever is ready to response to incoming HTTP requests.
  2. For each HTTP request, mod_wasm builds the WASI context for the already-loaded Wasm binary. Next, the Wasm module is instantiated and the entry point is executed. The stdout from the Wasm module is redirected to the HTTP response, and the stderr is appended to Apache Server's trace (usually at /dist/logs/error_log).

mod_wasm also offers the ability to build a specific execution context per HTTP request. When setting up WasmEnableCGI On, mod_wasm will pass HTTP headers as environtment variables to the Wasm module (they will be prefixed as HTTP_). In addition, URL parameters are also passed in the environment variable QUERY_STRING.

alt Workflow

'PrettyFy' WebApp Demo

The 'PrettyFy' demo is a simple one-script, Python-based WebApp (see Examples).

🕹️ Examples

This repo cointains several pre-built WebAssembly examples to play with.

Feel free to explore, modify and crash them!

🏗️ Building mod_wasm

As introduced in the overview, there are two main libraries in the mod_wasm project, being libwasm_runtime.so a dependency for mod_wasm.so. So, you might want to build libwasm_runtime.so first:

  1. To build libwasm_runtime.so, the Wasm management and runtime library, go to wasm_runtime for detailed instructions.
  2. For mod_wasm.so, the Apache Server module extension, go to mod_wasm.

📦 Building the container image

This repository contains all you need to build a local container image. Go to image for detailed instructions.

⚠️ Troubleshooting

Cannot load modules/mod_wasm.so into server

This is a common error related to LD_LIBRARY_PATH:

$ httpd
httpd: Syntax error on line XXX of <...>/httpd/dist/conf/httpd.conf:
Cannot load modules/mod_wasm.so into server: libwasm_runtime.so: cannot open shared object file: No such file or directory

Apache is loading modules/mod_wasm.so but during the process it cannot find libwasm_runtime.so. Either run Apache with LD_LIBRARY_PATH pointing to the directory where libwasm_runtime.so is located, or copy libwasm_runtime.so to a directory such as /usr/lib.

🐛 Debugging

To get detailed debugging information about the Wasm execution, run the Apache Server with the following environment variables:

  • WASMTIME_BACKTRACE_DETAILS=1
  • RUST_BACKTRACE=full

Also, it is recommended to run Apache in debug mode (-X option), this means only one process, only one worker, and without detaching from the terminal.

WASMTIME_BACKTRACE_DETAILS=1 RUST_BACKTRACE=full ./httpd -X
Comments
  • Can't build libwasm_runtime.so on aarch64-unknown-linux-gnu

    Can't build libwasm_runtime.so on aarch64-unknown-linux-gnu

    The current build status is:

    • ✅ x86_64 / darwin
    • ✅ x86_64 / gnu-linux
    • ✅ aarch64 / darwin
    • ❌ aarch64 / gnu-linux

    The build error is:

    error[E0308]: mismatched types
      --> src/ffi_utils.rs:64:55
       |
    64 |         let cstring_to_deallocate = CString::from_raw(ptr as *mut i8);
       |                                     ----------------- ^^^^^^^^^^^^^^ expected `u8`, found `i8`
       |                                     |
       |                                     arguments to this function are incorrect
       |
       = note: expected raw pointer `*mut u8`
                  found raw pointer `*mut i8`
    note: associated function defined here
    
    For more information about this error, try `rustc --explain E0308`.
    error: could not compile `wasm_runtime` due to previous error
    

    I suspect that c_char alias is working differently for aarch64/gnu-linux than for aarch64/darwin.

    ⚠️ bug 
    opened by gzurl 2
  • Improve performance on stdout buffers

    Improve performance on stdout buffers

    Currently, only one Vector<u8> is used as a buffer to manage the stdout from the Wasm module.

    This becomes a bottleneck since Apache can run several workers at a time, but if they receive requests to the Wasm endpoint, then each worker will have to wait until getting mutual exclusion over the buffer.

    🚀 enhancement 
    opened by gzurl 1
  • Shared Wasm modules with different configurations

    Shared Wasm modules with different configurations

    This feature request comes originally from #6.

    In this case, we might want the same Wasm module to be used in different routes but with different configurations (ie: different WasmMapDir directives, etc.). The reason to use the same Wasm module is to save memory by not loading the same module several times.

    🚀 enhancement 
    opened by gzurl 1
  • Multi-module container image

    Multi-module container image

    Now WordPress is downloaded while building the Docker image, and then the following files are copied or overwritten:

    wordpress-patch
    ├── .htaccess
    ├── wp-config.php
    ├── wp-content
    │   ├── database
    │   │   └── .ht.sqlite
    │   └── db.php
    └── wp-includes
        ├── blocks.php
        └── functions.php
    
    cla-not-required 
    opened by gzurl 0
  • Multi-module and Multi-configuration support

    Multi-module and Multi-configuration support

    Here is the long-awaited PR allowing different Wasm modules and multiple configurations simultaneously. It aims to fix #6, #7, and #16.

    In #6, we allow now to specify different Wasm modules to be used in other routes. For instance, now it’s possible with one-single Apache instance to load simultaneously the Wasm builds for the PHP and Python interpreters.

    And in #7, we now allow specifying different per-route configurations to the same Wasm module. In this case, the Wasm binary is loaded in memory only once, and the different configurations are applied to the Wasm module per-HTTP request.

    Combining all together, we can have a more flexible configuration such as:

    <Location /wordpress>
        SetHandler wasm-handler
        WasmModule /var/www/modules/php7.4.32.wasm
        WasmDir    /tmp
        …
    </Location>
     
    <Location /python-app>
        SetHandler wasm-handler
        WasmModule /var/www/modules/python3.11.wasm
        WasmArg    /var/www/python-app/app.py
        …
    </Location>
     
    <Location /python-app2>
        SetHandler wasm-handler
        WasmModule /var/www/modules/python3.11.wasm
        WasmArg    /var/www/python-app2/app2.py
        …
    </Location>
    

    In addition, we have run some preliminary stress tests using ApacheBench and mod_wasm performs really great in both MPM event and MPM worker modes.

    cla-not-required 
    opened by gzurl 0
  • Adding version compatibility check to Autoconf

    Adding version compatibility check to Autoconf

    New functions will soon land in wasm_runtime.h due to implementing #6. So it's likely that some versions won't be compatible between them.

    In this PR, a simple mechanism is implemented in Autoconf so when mod_wasm is checking for the availability of libwasm_runtime.so, it will also check for its version.

    cla-not-required 
    opened by gzurl 0
  • HTTP Request Body to WASI `stdin`

    HTTP Request Body to WASI `stdin`

    Missing feature #13 for reading the HTTP Request Body and putting it into WASI stdin so it can be accessible for the WebAssembly modules.

    The code for reading the body at mod_wasm.so is very tricky. More info here:

      • https://httpd.apache.org/docs/trunk/developer/modguide.html (section: "Reading the request body into memory")
      • https://docstore.mik.ua/orelly/apache_mod/139.htm
    cla-not-required 
    opened by gzurl 0
  • Multi-module support

    Multi-module support

    Currently, only one Wasm module with a unique configuration can be loaded at a time.

    At first glance, we might want to consider two different scenarios:

    1. Different Wasm modules on the same Apache instance, each of them attached to a different route.
    2. One Wasm module serving different routes, but with different configurations.

    In this issue, we will focus on 1). See #7 for the scenario 2).

    Different Wasm modules at the same time involve, at least:

    • Data structures storing httpd.conf mod_wasm directives need to be duplicated (once per module).
    • Data structures for WASI context need to be duplicated too (ie: stdout buffer)
    • Incoming HTTP requests need to be routed to the right Wasm module.

    A first goal for this feature could be to serve PHP and Python Wasm modules by only one Apache instance.

    🚀 enhancement 
    opened by gzurl 0
  • Support for Apache merge configurations

    Support for Apache merge configurations

    At httpd.conf, we might have different <Location> groups that overlap with each other:

    <Location /python_apps/app_1>
       WasmModule /var/www/modules/python3.11
    </Location>
    
    <Location /python_apps/app_2>
       WasmModule /var/www/modules/python3.12
    </Location>
    
    <Location /python_apps>
       WasmModule /var/www/modules/python3.11
    </Location>
    

    The latest <Location> group above will shadow the other more specific configurations.

    This can be solved by adding support for merge configurations in mod_wasm.c.

    🚀 enhancement 
    opened by gzurl 0
  • Allow different `wasmtime::Engine` configurations

    Allow different `wasmtime::Engine` configurations

    Today, we use wasmtime::Engine::default() to get an Engine instance. Many parameters could be configured to load an Engine instance and they should be available from httpd.conf.

    🚀 enhancement 
    opened by gzurl 0
  • Support for Apache Server dry run on `httpd.conf`

    Support for Apache Server dry run on `httpd.conf`

    Depending on the configuration, during the boot up, Apache Server performs a dry-run over httpd.conf and then if everything went well then executes a second pass over httpd.conf.

    A dry run for Apache Server means directives are invoked but they shouldn't have any effect. Currently, we do not support this in mod_wasm.c, and the side effect is the next warning:

    ./httpd -X
    [Thu Nov 17 11:51:04.318334 2022] [wasm:notice] [pid 13747:tid 281472847323168]
    [Thu Nov 17 11:51:04.318630 2022] [so:warn] [pid 13747:tid 281472847323168] AH01574: module wasm_module is already loaded, skipping`
    

    As a consequence, wasm_runtime is also trying to load Wasm modules twice. In this case, either 1) mod_wasm emits a "Wasm module already loaded" warning message, or 2) we turn off that check and then we cannot really identify such a doubled-load scenario.

    While this is not supported, the doubled-load check in pub fn from_file() in module.rs won't emit any warning.

    🚀 enhancement 
    opened by gzurl 0
  • Allow executing different entry points than `_start`

    Allow executing different entry points than `_start`

    When executing a Wasm module, _start is the function executed by default.

    We might want to invoke different entry points into a single module. A new directive (i.e.: WasmEntryPoint ) could do the job.

    🚀 enhancement 👋 good first issue 
    opened by gzurl 0
  • Try to get rid of max body size limitation

    Try to get rid of max body size limitation

    From @ereslibre at #22 (HTTP Request Body to WASI stdin):

    I think we could get rid of the max body limitation if we follow mod_cgi's approach.

    They call to cgi_handle_request. It reads the request body and writes it to a file descriptor. We could use this file descriptor to pass the body of the request to wasi_stdin instead of building an ad-hoc pipe.

    I think it would be feasible, but haven't checked it.

    I believe it could be worth it to take a look at this.

    🚀 enhancement 
    opened by gzurl 0
  • Allow pull Wasm modules from remote sources

    Allow pull Wasm modules from remote sources

    @ereslibre suggested adding support for pulling the Wasm modules from a remote source. This way, httpd.conf files can be redistributed without the Wasm modules.

    @ereslibre, could you please add more detail?

    🚀 enhancement 
    opened by gzurl 0
Owner
VMware Labs
This organization contains experimental open source projects.
VMware  Labs
Fast regex in Rust for Apache Arrow, compiled to WASM

Rust regex in wasm I have been looking for a fast regular expression library in Javascript that runs on Apache Arrow for a few years. Arrow uses UTF-8

Nomic AI 3 May 3, 2023
`wasm-snip` replaces a WebAssembly function's body with an `unreachable`

wasm-snip wasm-snip replaces a Wasm function's body with an unreachable instruction. API Docs | Contributing | Chat Built with ?? ?? by The Rust and W

Rust and WebAssembly 177 Dec 28, 2022
WebAssembly (Wasm) interpreter.

Continuous Integration Test Coverage Documentation Crates.io wasmi- WebAssembly (Wasm) Interpreter wasmi was conceived as a component of parity-ethere

Parity Technologies 1k Jan 4, 2023
Low level tooling for WebAssembly in JavaScript using wasm-tools

js-wasm-tools js-wasm-tools compiles some of the API of wasm-tools to JavaScript and WebAssembly via wasm-bindgen. This offers low level tooling for W

Dominic Elm 59 Dec 19, 2022
Distribute a wasm SPA as HTML by wrapping it as a polyglot "html+wasm+zip"

A packer that adds a webpage to WASM module, making it self-hosted! Motivation At the moment, Browsers can not execute WebAssembly as a native single

Andreas Molzer 3 Jan 2, 2023
👾 Run WebAssembly (WASM-4) games on small devices (like PyBadge)

?? gamgee Run WebAssembly (WASM-4) games on small devices. Gamgee is a WASM-4 games emulator written in Rust and designed to be executed on devices wi

Orsinium Labs 5 Feb 27, 2024
Arrowdantic is a small Python library backed by a mature Rust implementation of Apache Arrow

Welcome to arrowdantic Arrowdantic is a small Python library backed by a mature Rust implementation of Apache Arrow that can interoperate with Parquet

Jorge Leitao 52 Dec 21, 2022
Build frontend browser apps with Rust + WebAssembly. Supports server side rendering.

Percy Build frontend browser apps with Rust + WebAssembly. Supports server side rendering. The Percy Book This README gives a light introduction to Pe

Chinedu Francis Nwafili 2.1k Jan 1, 2023
Easy way to write Node.js module using Rust

node-bindgen Easy way to write native Node.js module using idiomatic Rust Features Easy: Just write idiomatic Rust code, node-bindgen take care of gen

InfinyOn 346 Jan 3, 2023
Another cursed Garry's Mod module. This time, it adds the C preprocessor to Lua scripts

gm_cpreprocessor Another cursed Garry's Mod module. This time, it adds the C preprocessor to Lua scripts. It works by detouring RunStringEx and overri

William 6 Aug 14, 2022
Python module implemented in Rust for counting the number of one bits in a numpy array.

bit-counter Package for counting the number of one bits in a numpy array of uint8 values. Implemented as a Python module using Rust, providing high pe

Andrew MacDonald 3 Jul 9, 2022
A setuptools/wheel/cffi extension to embed a binary data in wheels

Milksnake Milksnake is an extension for setuptools that allows you to distribute dynamic linked libraries in Python wheels in the most portable way im

Sentry 752 Dec 30, 2022
A safe Rust FFI binding for the NVIDIA® Tools Extension SDK (NVTX).

NVIDIA® Tools Extension SDK (NVTX) is a C-based Application Programming Interface (API) for annotating events, code ranges, and resources in your applications. Official documentation for NVIDIA®'s NVTX can be found here.

Spencer Imbleau 78 Jan 2, 2023
📦✨ your favorite rust -> wasm workflow tool!

?? ✨ wasm-pack Your favorite Rust → Wasm workflow tool! Docs | Contributing | Chat Built with ?? ?? by The Rust and WebAssembly Working Group About Th

Rust and WebAssembly 4.8k Jan 5, 2023
Facilitating high-level interactions between Wasm modules and JavaScript

wasm-bindgen Facilitating high-level interactions between Wasm modules and JavaScript. Guide | API Docs | Contributing | Chat Built with ?? ?? by The

Rust and WebAssembly 5.9k Jan 8, 2023
WebAssembly implementation from scratch in Safe Rust with zero dependencies

wain wain is a WebAssembly INterpreter written in Rust from scratch with zero dependencies. An implementation of WebAssembly. Features: No unsafe code

Linda_pp 328 Jan 2, 2023
A notebook app integrated with todo lists utility. Developed with Rust, WebAssembly, Yew and Trunk.

Flow.er A notebook app integrated with todo-list utility. Project flow.er is a Rust WASM app running in browser. Taking advantage of Yew and Trunk, it

null 45 Dec 31, 2022
NPM package distributing biscuit in WebAssembly for web components

Biscuit playground This is an example application for Biscuit tokens, where you can manipulate tokens and their verification in your browser. build wi

null 0 Dec 30, 2021
Gun port in rust & wasm

gun-rs-wasm Rust & WASM port of Gun. For a non-wasm version, check out gun-rs Example (source) Use npm install rusty-gun import { Node as Gun } from "

Martti Malmi 39 Dec 19, 2022