All Products
Search
Document Center

Microservices Engine:Develop gateway plug-ins in Rust or C++

Last Updated:Mar 11, 2026

The Microservices Engine (MSE) cloud-native gateway supports custom plug-in development through WebAssembly (Wasm). Write your plug-in logic in Rust or C++, compile it to a .wasm binary, and deploy it to the gateway. Both SDKs are part of the Higress open-source gateway project and follow the proxy-wasm standard.

LanguageSDK
RustSDK for Rust
C++SDK for C++

Both SDKs include ready-to-use example plug-ins in the extensions/ directory.

How plug-ins work

Gateway plug-ins use a callback-based model. The gateway invokes your plug-in at specific points in the HTTP request lifecycle -- for example, when request headers arrive or when the response body is ready. Your plug-in can make hostcalls back to the gateway to read headers, modify responses, or access shared data.

                    Gateway (Envoy Proxy)
 ┌──────────────────────────────────────────────────┐
 │                                                  │
 │  RootContext (1 per plug-in instance)            │
 │  ├── on_configure: parse plug-in config          │
 │  ├── create_http_context: spawn per-request ctx  │
 │  │                                               │
 │  ├── HttpContext (1 per HTTP request)             │
 │  │   ├── on_http_request_headers                 │
 │  │   ├── on_http_request_body                    │
 │  │   ├── on_http_response_headers                │
 │  │   └── on_http_response_body                   │
 │  │                                               │
 │  └── HttpContext (another request)                │
 │      └── ...                                     │
 │                                                  │
 │  RuleMatcher ── routes config per domain/route   │
 └──────────────────────────────────────────────────┘

Key concepts:

  • RootContext -- Created once per plug-in instance. The on_configure callback parses plug-in configuration. The create_http_context method spawns a new context for each incoming request.

  • HttpContext -- Created per HTTP request. Implements callbacks such as on_http_request_headers and on_http_response_body to inspect and modify traffic.

  • RuleMatcher -- A Higress SDK utility that routes different configurations to different domains or routes. One plug-in binary can apply distinct rules per ingress or domain.

Develop a Rust plug-in

Prerequisites

Before you begin, make sure you have:

  • Rust 1.80 or later, installed through rustup

  • The WASI compile target: rustup target add wasm32-wasip1

  • Docker

  • Make

Step 1: Create the plug-in project

Clone the Higress repository and create a new plug-in directory:

git clone https://github.com/alibaba/higress.git
cd higress/plugins/wasm-rust/

# Create the plug-in directory
mkdir -p extensions/my-plugin

Create extensions/my-plugin/Cargo.toml:

[package]
name = "my-plugin"
version = "0.1.0"
edition = "2021"
publish = false

[lib]
crate-type = ["cdylib"]

[dependencies]
higress-wasm-rust = { path = "../../", version = "0.1.0" }
proxy-wasm = { git = "https://github.com/higress-group/proxy-wasm-rust-sdk", branch = "main", version = "0.2.2" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Step 2: Write the plug-in code

Create extensions/my-plugin/src/lib.rs. The following example adds a custom header to every incoming request:

use higress_wasm_rust::*;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::rc::Rc;

// Define the plug-in configuration struct.
#[derive(Default, Clone, Serialize, Deserialize)]
struct MyPluginConfig {
    header_name: String,
    header_value: String,
}

// RootContext: handles configuration and spawns per-request contexts.
struct MyPluginRoot {
    log: Log,
    rule_matcher: SharedRuleMatcher<MyPluginConfig>,
}

impl MyPluginRoot {
    fn new() -> Self {
        Self {
            log: Log::new("my-plugin".to_string()),
            rule_matcher: Rc::new(RefCell::new(RuleMatcher::new())),
        }
    }
}

impl Context for MyPluginRoot {}

impl RootContext for MyPluginRoot {
    fn on_configure(&mut self, plugin_configuration_size: usize) -> bool {
        on_configure(
            self,
            plugin_configuration_size,
            &mut self.rule_matcher.borrow_mut(),
            &self.log,
        )
    }

    fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {
        Some(Box::new(MyPlugin {
            log: self.log.clone(),
            rule_matcher: self.rule_matcher.clone(),
            context_id,
        }))
    }

    fn get_type(&self) -> Option<ContextType> {
        Some(ContextType::HttpContext)
    }
}

// HttpContext: processes each HTTP request.
struct MyPlugin {
    log: Log,
    rule_matcher: SharedRuleMatcher<MyPluginConfig>,
    context_id: u32,
}

impl Context for MyPlugin {}

impl HttpContext for MyPlugin {
    fn on_http_request_headers(&mut self, _num_headers: usize, _end_of_stream: bool) -> Action {
        // Match the current request against configured rules.
        let binding = self.rule_matcher.borrow();
        if let Some(config) = binding.get_match_config() {
            self.log.info(&format!(
                "Adding header {}={} to request",
                config.header_name, config.header_value
            ));
            self.add_http_request_header(&config.header_name, &config.header_value);
        }
        Action::Continue
    }
}

// Register the plug-in entry point.
proxy_wasm::main! {{
    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> {
        Box::new(MyPluginRoot::new())
    });
}}

Step 3: Build the Wasm binary

Run the build from the plugins/wasm-rust/ directory:

# Build the plug-in Wasm file
make build PLUGIN_NAME=my-plugin

After a successful build, the compiled Wasm file is at extensions/my-plugin/plugin.wasm.

To build a container image for deployment:

# Build a Docker image containing the Wasm binary
make build-image PLUGIN_NAME=my-plugin PLUGIN_VERSION=1.0.0

The image follows the OCI artifact specification. Push it to any OCI-compatible registry.

Step 4: Test the plug-in

# Run unit tests
make test PLUGIN_NAME=my-plugin

# Run lint checks
make lint PLUGIN_NAME=my-plugin

For more Rust plug-in examples, see the extensions/ directory in the SDK for Rust repository. Available examples include say-hello, request-block, and ai-data-masking.

Develop a C++ plug-in

Prerequisites

Before you begin, make sure you have:

  • Docker

  • Make

The C++ SDK uses a Docker-based build environment, so no local C++ toolchain is required.

Step 1: Set up the project

Clone the Higress repository:

git clone https://github.com/alibaba/higress.git
cd higress/plugins/wasm-cpp/

Plug-in source code goes in the extensions/ directory. Use the built-in examples such as hello-world and request-block as a starting point.

Step 2: Build the plug-in

Build a specific plug-in with the Makefile:

PLUGIN_NAME=request_block make build

This command:

  1. Builds the Wasm binary inside a Docker container.

  2. Outputs the compiled .wasm file to extensions/<plug-in-name>/.

  3. Creates a Docker image tagged with the plug-in name, build timestamp, and git commit ID.

Build parameters:

ParameterRequiredDefaultDescription
PLUGIN_NAMENohello-worldName of the plug-in to build
IMGNoAuto-generated from registry, plug-in name, timestamp, and commit IDCustom image tag

Step 3: Deploy the plug-in

After building, push the image to a container registry. Then reference it in a WasmPlugin custom resource:

apiVersion: extensions.higress.io/v1alpha1
kind: WasmPlugin
metadata:
  name: request-block
  namespace: higress-system
spec:
  defaultConfig:
    block_urls:
    - "swagger.html"
  url: oci://<your-registry>/request_block:1.0.0

To apply different configurations per route or domain, use matchRules:

spec:
  defaultConfig:
    block_urls:
    - "swagger.html"
  matchRules:
  - ingress:
    - default/foo
    config:
      block_bodies:
      - "foo"
  - domain:
    - "*.example.com"
    config:
      block_bodies:
      - "bar"

Rules are evaluated in order. The first matching rule determines which configuration the plug-in uses for that request.

For more C++ plug-in examples and API details, see the SDK for C++ repository.

Project structure

Both SDKs follow a similar layout:

plugins/wasm-{rust,cpp}/
├── src/ or common/     # SDK core library
├── extensions/         # Plug-in implementations
│   ├── hello-world/    # Basic example
│   ├── request-block/  # Request blocking example
│   └── ...
├── Makefile            # Build commands
└── Dockerfile          # Container build definition

Related topics