Cameleeringsimoom

simoom / Use cases / Edge and IoT

Edge devices and IoT gateways

An HTTP server that fits on the device

A gateway on a factory floor has a small CPU, little RAM and a firmware image that has to stay small. It still needs to take readings over HTTP, show a status page and push live values to a browser. simoom gives it that door without an async runtime, a C toolchain or a dependency tree to cross-compile.

215 KBadded to the binary by an HTTP/1.1-only build (stripped, x86-64 Linux)
901 KBmemory at rest (PSS) of the default build; campaign 4, 2026-11-12
532 Bmemory per idle connection with 100,000 open; level with nginx, hyper 30x more
0C libraries to cross-compile, even with TLS

Build only what the device needs

Every protocol is a cargo feature. A device that speaks plain HTTP/1.1 to a local network turns everything else off; one that talks to the cloud adds TLS. A script in the repository fails the build when a size budget is exceeded.

# Cargo.toml: HTTP/1.1 only
simoom = { version = "0.1", default-features = false, features = ["http1"] }
buildadded to the binarybudget
HTTP/1.1 only214,568 B256,000 B
HTTP/1.1, HTTP/2, TLS, io_uring583,680 B614,400 B
everything, HTTP/3 included935,064 B1,048,576 B

Bytes added to examples/hello.rs over an empty fn main, stripped, x86-64 Linux, dist profile (scripts/size.sh). As whole programs in benchmark campaign 4 (2026-11-12), simoom's default build (HTTP/1.1, HTTP/2, WebSocket) was 735 KB stripped, against may-minihttp's 515 KB (HTTP/1.1 only) and hyper's 2,069 KB. Budgets are targets the build enforces, not measurements. Details: features and size.

Memory that stays flat

A device keeps connections open for a long time: dashboards, sensors that poll, a technician's browser left open. simoom holds an idle connection in about half a kilobyte, because it runs one event loop per CPU core instead of a thread per connection.

Measured

  • At rest: 901 KB of PSS for the default build, 1,844 KB for the full server with TLS 1.3 and HTTP/3 (campaign 4, 2026-11-12).
  • 100,000 idle connections: 532 bytes each, level with nginx (528 B) on the same droplet; with 10,000 open, 573 B, where nginx used 6% less and hyper 31x more (campaign 4).
  • On a workstation, against the server it replaced: 1,000 idle connections took 2.7 MB in total, against 7.7 MB for Cameleer's old thread-per-connection server.

Bounded by default

  • Every limit has a default: head and body size, timeouts, minimum body rate, write deadline, connections per IP.
  • Guards against slow clients such as slowloris, and against reconnect storms.
  • Memory is returned after bursts (the idle-trim feature).

Sources: idle connections and memory at rest in campaign 4, and against the original server. Limits: limits and security.

A status API and live readings

A router answers fast requests on the loop thread. Server-sent events push readings to a browser from any thread, with no async code.

use simoom::{Outcome, Reply, Request, Router};
use std::time::Duration;

let router = Router::new()
    .get("/health", |_: &mut Request<'_>, r: Reply<'_>| r.body_static(b"ok"))
    .get("/events", |_: &mut Request<'_>, r: Reply<'_>| -> Outcome {
        let mut sink = r.sse();
        std::thread::spawn(move || {
            for i in 0..3 {
                if sink.send_event(&format!("tick {i}")).is_err() { return; }
                std::thread::sleep(Duration::from_secs(1));
            }
            sink.finish();
        });
        Outcome::Done
    });

More in routing and streaming and server-sent events.

What has not been measured yet

ARM

The ARM SIMD and crypto code paths compile, but they are compile-checked only. The test suite runs on x86-64 Windows and Linux, and every benchmark ran on x86-64. Reports from Raspberry Pi and other ARM boards are welcome.

Not a microcontroller library

simoom is std-only, not no_std: it needs an operating system (Linux, Windows or macOS). It fits embedded Linux, not bare-metal firmware.

Need the integration side too (MQTT, store and forward, syslog)? Cameleer, which uses simoom as its HTTP engine, has MQTT edge gateway routes.

Common questions

Can simoom run on a Raspberry Pi?

It is built for small Linux devices, and its ARM code paths compile. They are compile-checked only so far: the tests run on x86-64 and the benchmarks ran on x86-64. Reports from ARM hardware are welcome.

Does it work without an operating system (no_std)?

No. simoom is std-only, not no_std. It uses the Rust standard library and needs Linux, Windows or macOS. It fits embedded Linux, not bare-metal microcontrollers.

How small can the HTTP server be?

An HTTP/1.1-only build adds 214,568 bytes to a stripped x86-64 Linux binary. Turn off the default features and keep only http1.

Do I need OpenSSL or a C compiler for TLS on the device?

No. simoom has its own TLS 1.3 written in Rust with only the standard library, so a cross-compile needs the Rust toolchain and nothing else.

How much memory does it use?

In benchmark campaign 4 (2026-11-12), the default build's process used 901 KB of PSS at rest, and each idle connection about 530 to 575 bytes: 532 B with 100,000 open, level with nginx (528 B) on the same droplet, and 573 B with 10,000 open, where nginx used 6% less. hyper used 17,790 B per idle connection on the same droplet.

Try it on your device

Build the HTTP/1.1-only server for your target and check its size and memory there.

cargo add simoom --no-default-features --features http1
cargo build --release
ls -l target/release/