# Onion embeds an HTTP server inside your C program instead of the other way round

> Onion is a C library for embedding HTTP handling into an existing application, licensed Apache2 or GPLv2+, with optional SSL, threading, WebDAV, PAM auth and pluggable session backends. It suits a C or C++ program that needs a few HTTP endpoints without taking on a server framework, and it does not suit anyone wanting a general-purpose web server binary or a maintained release stream, since the last tagged release is v0.8 from 2016.

**davidmoreno/onion** — C library to create simple HTTP servers and Web Applications.

- Repository: https://github.com/davidmoreno/onion
- Website: http://www.coralbits.com/libonion/
- Stars: 2,085 · Forks: 256
- Language: C
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/davidmoreno-onion

## The inversion: you have the functionality, you add the webserver

Onion is described as a C library to create simple HTTP servers and web applications, and the README explains the intended use case precisely: an existing application, or a new one, that needs some HTTP interconnection with the world. You add handlers for specific URLs and generate and serve dynamic data as needed.

The distinguishing claim is architectural, and the README puts it directly. Onion is not a web server per se, as it is not an executable. If you want to compare it to a web server, a web server would use a module or plugin to add functionality. With libonion you have the functionality and add the webserver as a plugin.

That inversion has concrete consequences. There is no daemon to install, no configuration file, no separate process to supervise. Your program links against the library, registers handlers, and owns the event loop. One binary ships. One set of runtime state exists.

It also has a matching cost. Because Onion is a library and not a server, none of the operational surface you might expect is present. There is no access log daemon, no TLS certificate renewal, no graceful reload, no rate limiting, no request body size cap. If you deploy it on a public network, all of that becomes your responsibility.

The stated security goal is narrower and modest: SSL support, so that you concentrate on what you want to serve, and serve it.

## Compiling from source: cmake, then make, then install

The build is a standard out-of-tree CMake build, and the README gives the exact sequence:

```bash
git clone git@github.com:davidmoreno/onion.git
cd onion
mkdir build
cd build
cmake ..
make
sudo make install
```

A debug build differs by one flag:

```bash
cmake -DCMAKE_BUILD_TYPE=Debug ..
```

Runtime debug messages are controlled separately from the build type, through two environment variables. `ONION_DEBUG` and `ONION_DEBUG0` take a list of source file names, so you can turn on tracing for specific translation units rather than everything:

```bash
export ONION_DEBUG0='request.c url.c'
```

The repository root explains the rest of the build surface. `CMakeLists.txt` is where compile-time options live, `CMakeModules/` holds find-modules for dependencies, `onion.pc.in` generates the pkg-config file, `git-version-gen` derives the version from git state, and `git-version-gen` is paired with the instruction to check `onion/version.h` for version details. There is a `Doxyfile` for the API documentation, `CPackConfig.cmake` for packaging, `manpages/`, and distribution directories for `debian/` and `gentoo/`.

Third-party packages exist for openSUSE as an RPM, for Raspberry Pi as a Debian pool package, and for Arch Linux through the AUR as `libonion-git`. The README's warning about them is worth heeding: they may be outdated, and if you want the latest you should compile manually.

## Dependencies decide what the library can do at runtime

The required set is short and the conditional part is long, which is the design: one of three event backends, then a list of optional capabilities compiled in or left out.

Required are a C compiler, cmake, make, and exactly one of epoll on Linux, libevent, or libev for multi-architecture targets. The compilers the README says are known to work on Linux are GCC 4.4 and clang 3.0, and for the C++ bindings a C++11 compiler is needed, with GCC 4.8 or clang 3.7. Those version numbers are themselves a signal about the era the code targets.

The optional dependencies each unlock a specific feature, and each is a compile-time decision:

* gnutls and gcrypt enable SSL support
* pthreads enables threading support
* libxml2 enables WebDAV support
* libpam enables HTTP Basic Auth using PAM
* a C++ compiler enables the C++ bindings
* systemd enables listening on systemd sockets
* sqlite3 enables the sqlite3 session backend
* hiredis enables the Redis session backend

For the examples specifically, cairo, libpng2, boehm gc and libjpeg are listed as optional.

So the library compiles whether or not these are present. What changes is capability: no gnutls means no SSL, no pthreads means no threading. The README is explicit that it will compile but some functionality will not be available, and that SSL can also be deactivated at `./CMakeLists.txt` even when gnutls is found.

Two capabilities are worth calling out as design choices rather than conveniences. systemd socket activation means Onion can be started by systemd and inherit its listening socket, which is how you get privilege separation without a root-owned process. Redis and sqlite3 session backends mean the session store is a swappable plugin rather than an in-process decision.

## Threading has three modes and only one is safe by default

The threading section is the most careful part of the README, and it contains an explicit warning that any user should read before enabling threads.

The first mode is threaded, set with O_THREADED, which creates a new thread per connection. The README states there is no data protection, on the grounds that on the listen phase there should not be any change to Onion structures. Nevertheless, if new handlers are created they must set their own threading support as necessary. That is the library declining to protect your data structures, and the responsibility moving to you.

The second is detached listen, set with the O_DETACH_LISTEN flag, which lets the Onion server work on a non-main thread. The README calls this independent from O_THREADED operation: one thread runs your normal application and another listens and processes web requests. The stated use is adding a web server to an application without changing its flow, with the caveat that you need to thread-protect your data if the web server accesses it.

The third is the pool mode, where you set a default thread count with `onion_set_max_threads` and, using epoll, the data is handed to the threads. The README calls this the highest performing method and attaches a figure of up to 30k web requests on an Intel Core 2 Duo T6500 at 2.10GHz.

That number deserves context rather than adoption as a target. The CPU named is a decade-old dual-core part, the figure is stated as an upper bound, and the README does not describe the workload, concurrency level or request type behind it. Use it as evidence that pool mode is a real approach, not as a capacity estimate for anything you are sizing.

## Semantic versioning promises, and where they stop

Starting with Onion 0.8.0 the project states a set of versioning promises, and they are unusually specific.

The version format is MAJOR.MINOR.PATCH. Only API and ABI changes happen at major versions; minor releases can add functionality. API functions are only removed at major versions. Minor versions are always ABI back-compatible, so code compiled against a previous minor version with the same major version will still compile and work. Minor versions only add API functions, and patch revisions only fix patches.

There is one wrinkle the README calls out: patch revision numbers are not sequential. After 0.8.0 the next version is not 0.8.1 but perhaps 0.8.23, and it will always increase. So you cannot infer anything from a patch number's size, and a build script that assumes monotonic small patches will be wrong.

The practical consequence of these promises is that you can pin a minor version and expect ABI compatibility across it. That is a stronger guarantee than most C libraries offer.

It is also, in practice, a promise about a line whose last tagged release is v0.8 from 2016-04-29. The README names `master` as the development branch and `onion-0-8` as the current stable branch, and the last push was on 2026-10-07. So development continues on `master` while the stable branch has not been tagged in a long time. Anyone adopting this should decide early whether they track `master` and accept churn, or stay on `onion-0-8` and accept an old code base. The repository topics include maintainer-wanted, which is the project's own signal about capacity.

## The examples directory is the real documentation

The example directories form a useful map of the API.

The minimal entry points are `examples/hello/`, `examples/basic/` and `examples/interactive/`. File serving has its own examples in `examples/fileserver/` and `examples/ofileserver/`. Networking topology is covered by `examples/multiport/` and `examples/multiport-cpp/` for several listeners and `examples/userver/` for the Unix socket case.

Then there are the feature-specific ones. `examples/websockets/` covers WebSocket handling, `examples/longpoll/` covers long-polling, `examples/jsonrpc/` covers JSON-RPC, `examples/post/` covers request bodies, and `examples/oterm/` and `examples/otop/` cover the terminal and the network top terminal views Onion can drive. `examples/cairo/` renders with cairo, `examples/mandelbrot/` is a compute example, and `examples/cpp/` shows the C++ bindings.

`examples/boehm-gc/` is the one to look at if you care about the memory customisation path, because it pairs with the low-level initialisation described below.

The pairing matters for anyone deciding whether to adopt. The examples covering the features you need can lower research costs and let you confirm the library does what the prose claims before you commit to it.

The README also points to a wiki for getting started and internal workings, API documentation hosted at coralbits.com, a mailing list, and a blog for news.

## Substituting malloc, and when Onion is the wrong tool

The last mechanical feature worth describing is low-level control over allocation and threads. The README explains the motivation: sometimes you need to customise memory allocation or thread operation, for example to use an alternative malloc, or to plug in Hans Boehm's conservative garbage collector, which is useful if you use GNU Guile. You define your own memory routines and pass them to `onion_low_initialize_memory_allocation` before any other call to Onion. The same section begins to describe the equivalent for threads and is cut off in the README.

The requirement that this call happens before any other Onion call is the kind of constraint that is easy to get wrong and hard to debug, so it is worth flagging even though it is only two lines of documentation.

On suitability, three cases argue against Onion.

If you want a web server to put in front of an application, this is the wrong shape. You have to write the process, the signal handling and the supervision.

If your team does not write C or C++, the value evaporates. There are C++ bindings, but they need a C++11 compiler and the whole library is a C API with manual lifetimes.

If you need a maintained upstream with a security response process, weigh the release gap. The repository carries a `CONTRIBUTING.md` and a `LICENSE.txt`, and the README links to a blog and a mailing list, but the last tagged release predates most modern TLS expectations, and the build detects SSL by finding gnutls at compile time rather than by configuring a modern TLS policy.

Licence is the easy part: dual licensed under Apache2 and GPLv2+, so you can use it in commercial or free software and modify it, with `APACHE2.txt` and `GPLv2.txt` both in the repository.

## Conclusion

Adopt Onion when you have a C or C++ program that needs to serve a handful of URLs and you want the HTTP layer inside your own process, so one binary is deployed and one set of process state exists. Do not adopt it for a public-facing service that needs a maintained release stream, because the last tagged version is v0.8 from 2016 and the stable branch is `onion-0-8` while `master` is the development branch. Before building, confirm you can meet the required dependency, since exactly one of epoll, libevent or libev must be present, and decide early whether you need SSL or threads, because both are compile-time options in `CMakeLists.txt` rather than runtime settings.

## FAQ

### How do I build and install Onion?

Clone the repository, create a `build` directory inside it, run `cmake ..`, `make` and `sudo make install`. Use `cmake -DCMAKE_BUILD_TYPE=Debug ..` for a debug build, and set `ONION_DEBUG` or `ONION_DEBUG0` with source file names for runtime debug messages.

### What does Onion require as dependencies?

A C compiler, cmake, make, and one of epoll on Linux, libevent or libev. Known working compilers on Linux are GCC 4.4 and clang 3.0, and the C++ bindings need a C++11 compiler.

### How do I enable SSL support in Onion?

The build script detects gnutls at compile time and compiles SSL in if found, and you can deactivate it at `./CMakeLists.txt`. You set the certificates yourself and check the `O_SSL_ACTIVATED` flag, and setting certificates fails if SSL was not compiled in.

### What are Onion's threading modes?

O_THREADED creates a thread per connection with no data protection from the library, O_DETACH_LISTEN moves the server onto a non-main thread, and pool mode sets a thread count with `onion_set_max_threads` and uses epoll to hand work to them.

### Is Onion an executable web server?

No. The README states it is not a web server per se, as it is not an executable. With libonion you have the functionality and add the webserver as a plugin to your own program.

### What licence is Onion released under?

Dual licensed under Apache2 and GPLv2+, so you can use it in commercial and free software and modify it. `APACHE2.txt` and `GPLv2.txt` are both in the repository.

## Sources

- [davidmoreno/onion on GitHub](https://github.com/davidmoreno/onion)
- [Issues](https://github.com/davidmoreno/onion/issues)
- [Project website](http://www.coralbits.com/libonion/)
- [README](https://github.com/davidmoreno/onion/blob/master/README.md)
- [Releases](https://github.com/davidmoreno/onion/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/davidmoreno-onion
