A VPN client that runs entirely in user space — no root, no kernel tunnels, no global routing.
erebus speaks OpenVPN and IPsec/IKEv2 itself, builds its own IP packets, runs its own minimal TCP/IP stack, and hands you VPN access through an ordinary local HTTP proxy. It's a VPN agent, not a system-wide VPN.
Traditional VPN clients assume they own the machine: they create a kernel tun/tap interface, rewrite your routing table, and need root to do it. That model breaks in containers, CI runners, sandboxes, and other locked-down hosts.
erebus takes the opposite approach. It does all the VPN work — the OpenVPN protocol, IP packets, TCP state, encryption — inside a single user-space process. Nothing about the host's networking is touched. Connectivity is explicit and opt-in: you point a client at a local proxy, and only that traffic crosses the VPN.
A local HTTP/1.x proxy forwards requests from local clients to resources living on the VPN.
Port forwards expose a chosen local service back to VPN peers — bidirectional, still rootless.
A Debian package (Debian/Ubuntu and derivatives) is attached to every GitHub Release. Download it and install:
sudo apt install ./erebus_*_amd64.deb
That gives you the erebus binary, the man page (man erebus), and an annotated config under /usr/share/doc/erebus/. Prefer to build it yourself? See the README.
erebus is driven by a single INI file. A minimal outbound proxy over UDP:
[erebus]
client-ip = 10.8.0.2
[openvpn-server]
proto = udp
host = vpn.example.com
port = 1194
secret = /etc/erebus/static.key
cipher = AES-256-CBC
auth = SHA256
[proxy-out]
address = 127.0.0.1
port = 11023
Run it, then use it like any other HTTP proxy:
$ erebus --config erebus.ini &
$ http_proxy=http://127.0.0.1:11023 curl http://10.8.0.1/
Want to expose a local service to the VPN too? Add a forward — a peer reaches your 127.0.0.1:8080 at 10.8.0.2:8080 over the tunnel:
[proxy-in]
web = 8080 127.0.0.1:8080
Full reference: the erebus(1) man page (make man) and the annotated default-config.ini.
A conventional VPN leans on the kernel for routing and TCP. erebus replaces that whole column with its own code, so the only privilege it needs is the ability to open a socket.
local HTTP client VPN peer
│ │
▼ ▼
HTTP proxy accept & relay ← outbound / inbound
│ │
▼ ▼
user-space TCP/IP stack ◄───┘ ← keeps connections reliable
│
▼
IPv4 / TCP / ICMP packets ← built & parsed by hand
│
▼
OpenVPN encrypt + HMAC + packet-id ← static-key (wire format v1)
│
▼
UDP datagram / TCP frame ← transport-agnostic
│
▼
OpenVPN server
The same minimal TCP stack serves both directions; outbound and inbound differ only in who opens the connection. The transport layer is genuinely abstract — UDP and TCP share all protocol logic.
Deeper dive, with the design rationale and the trade-offs behind it: doc/architecture.md.
NET_ADMINCONNECT tunnelling or SOCKS — explicit HTTP/1.x onlyThese aren't oversights — they're the other side of the rootless coin. Correctness, interoperability and clarity come first; performance is explicitly deferred. See the measured performance.
Correct. erebus never creates a network interface, never edits a routing table, and needs no capabilities beyond opening an ordinary client socket. All VPN logic — protocol, IP packets, TCP state, crypto — lives in one user-space process.
Static-key mode only (pre-shared key, also called wire format v1), over UDP or TCP. CBC ciphers — AES, ARIA and Camellia at 128/192/256 — and a wide range of HMAC digests. The cipher and auth values must match the server. TLS mode, certificates and the control channel are planned but not yet implemented.
Yes — an IKEv2 control plane and an ESP data plane that interoperate with strongSwan, all in the same rootless user space. Authentication is pre-shared key for now; the suite is MODP-2048 Diffie-Hellman with AES-256-CBC and HMAC-SHA-256. Since a rootless process can't send raw ESP, everything is UDP-encapsulated (NAT-T), and your VPN address is assigned by the server during the handshake. Certificate and EAP authentication are not implemented yet.
Because there's no kernel interface to route into. Without a tun device, the way to hand VPN connectivity to a local app is through an explicit endpoint — a local HTTP proxy for outbound, port forwards for inbound. That explicitness is a feature: only the traffic you point at erebus crosses the VPN.
Fast enough for what it's built for — quick, small requests — and deliberately not tuned for moving large amounts of data. To keep the code simple, it sends data one piece at a time and waits for each piece to be confirmed before sending the next, so big downloads run several times slower than a normal proxy. Numbers and methodology are in stress-results.md.
Not yet. The outbound proxy speaks plain HTTP/1.x; there's no HTTPS CONNECT tunnelling, SOCKS, or TLS-to-backend. Those are future work.
Common Lisp (SBCL). The codebase is intentionally small and readable — implementing the protocols incrementally in user-space code is part of the point.
No — it's an early-stage, experimental project. It prioritizes correctness and clarity over completeness, and the roadmap is explicit about what's deferred. Treat it as a capable tool for specific constrained-environment use cases, not a hardened VPN client.