Exposrd
🚀 Horizontally scalable reverse tunnel relay server for exposing services behind NAT/Firewalls without port forwarding (Self-hosted cloudflared/ngrok alternative).
Install / Use
/learn @exposr/ExposrdREADME
exposr - dynamic reverse tunnel relay server
exposr is a self-hosted reverse tunnel relay server that allows you to securely expose devices and services behind NATs or firewalls to the Internet through public URLs.
exposr can for example be used for development and previews or for exposing services behind NAT/firewalls to the Internet without port-forwarding and risk of exposing your IP address.
Why another "reverse tunnel server"? exposr takes a slightly different approach than other servers of the same type. exposr is designed to run as a container with horizontal elastic scaling properties, and is well suited to run in container-orchestration systems like Kubernetes.
Features
- Clustering support with horizontally scalability - more nodes can be added to increase capacity.
- Multi-client connection - each client can maintain multiple persistent connection per tunnel.
- No configuration files! - All configuration can be done as environment variables or command line options.
- Designed to run behind a load balancer (HTTP/TCP) (ex. nginx or HAProxy).
- Suitable to run in container-orchestration systems such as Kubernetes.
- Multiple transports - multiplexed websocket with custom client or SSH client forwarding.
- Multiple ingress methods - HTTP (with custom domain support) or SNI for TLS/TCP protocols.
- Custom client can forward to any host, does not require root privileges and only requires outbound HTTP(s) connections.
- Tunnel configuration through restful APIs.
- No passwords or e-mails - but still secure. An account number together with the tunnel identifier serves as credentials.
What it does not do
- Certificate provisioning.
- DNS provisioning.
This is on purpose as the server is designed to be stateless and to have elastic scaling properties. Meaning these are more suitable to handle in other parts of the deployment stack, for example at the load balancer.
Demo
Supported transports
exposr supports two different transport methods. This is the way a tunnel client connects and establishes the tunnel.
| Type | Method | Endpoint | Client support |
| ---------- | -------------------------- |----------- | --------------------- |
| Websocket | Custom multiplex websocket | HTTP | exposr |
| SSH | SSH TCP forwarding | TCP | Any SSH client |
The Websocket transport endpoint can run behind a HTTP load balancer on the same port as the API. The SSH transport endpoint requires a dedicated TCP port and requires a TCP load balancer in multi-node setups.
Supported ingress methods
The following ingress methods are supported. Ingress is the way clients (or users) connect to the tunnel to connect to the exposed services.
| Type | Method | Protocol support | Requirements | Load balancer req. | | ----- | ------------------------ | ---------------- | --------------------------- | ------------------ | | HTTP | Virtual host (subdomain) | HTTP | Wildcard domain | HTTP | | SNI | SNI | TLS | Wildcard certificate+domain | TCP |
Supported storage options
The following storage options are supported. The default is no persistence, SQLite is recommended for single-node setups. Tunnel configuration and accounts are written to persistent storage.
| Type | Single/multi-node | Note | | ---------- | ------------------------ | -------------------- | | Memory | Single-node | Data lost on restart | | SQLite | Single node | | | PostgreSQL | Multi-node | | | Redis | Multi-node | |
Clustering support
exposr can be run in a multi-node setup, ingress connections are re-routed to the node that have the tunnel established. This allows for horizontal load balancing in round-robin fashion without the need for sticky sessions.
| Type | Discovery methods | Note | | ----------- | ---------------------------------- | ---------------------------- | | Single-node | Single-node | No clustering | | UDP | IP Multicast or Native Kubernetes | K8S through headless service | | Redis | Redis | |
To run exposr in clustering mode you need to select a cluster mode, the default is UDP with node discovery through IP multicast or through Kubernetes headless service, exposr will try to auto-detect the best discovery method to use. To use the UDP mode IP connectivity on UDP port 1025 (default) between nodes is required.
It is also possible to use a Redis cluster with pub/sub capabilities.
NB: Multi-node storage is required for clustering setup.
Architecture
exposr have three core concepts; transports, endpoints and ingress.
A tunnel is composed of a transport and a connection endpoint. The endpoint is used by the client to establish a tunnel connection. The transport of the tunnel is the underlying data stream of the tunnel, it supports multiple independent streams over one connection.
The ingress is for traffic destined for the tunnel target, an ingress supports one specific protocol and have a distinct way of identifying which tunnel the request is bound for.
+-----------------------+
+----------------+ | +-----------------+ |
----->| Ingress +--|->| Transport +--|-----------+
+----------------+ | +-----------------+ | v
| | +----------------+ +--------------+
| Tunnel | | Client +---->| Target |
| | +-------+--------+ +--------------+
| +-----------------+ | |
| | Endpoint |<-|-----------+
| +-----------------+ | |
+-----------------------+ |
+-----------------+ |
| API |<-------------+
+-----------------+
Tunnels and accounts
A tunnel is identified by a string consisting of alphanumeric (a-z, 0-9) characters and dashes (-).
Minimum 4 characters and maximum 63 characters. The tunnel identifier have to start with a alpha character.
This is chosen so that the tunnel identifier can be used as a DNS label.
Example
my-tunnel-identifier-14
An account number is a 16 character string selected from the case-insensitive alphabet CDEFHJKMNPRTVWXY2345689.
The number is formatted into 4 groups of 4 characters separated by a separator.
Dashes and spaces are accepted as separator, as well as no separator.
Example
MNF4-P6Y6-M2MR-RVCT
MNF4 P6Y6 M2MR RVCT
MNF4P6Y6M2MRRVCT
A tunnel is owned by one account, one account can have multiple tunnels. There is no password or key associated with an account.
It's not possible for a user to list all tunnels belonging to an account. This makes it possible to use the account number together with the tunnel identifier as credentials as both needs to be known in order to perform privileged operations on a tunnel.
Running exposr
Runtime artifacts
Containers
Containers are available for deployments in container runtime environments.
Latest release is available with the latest tag, latest development (master branch) is available with the unstable tag.
Quick start
You can quickly try out exposr without installing anything.
Run the server, the server will listen on port 8080 and the API will be exposed at http://host.docker.internal:8080.
HTTP ingress sub-domains will be allocated from http://localhost:8080.
docker run --rm -ti -p 8080:8080 ghcr.io/exposr/exposrd:latest --allow-registration --ingress-http-url http://localhost:8080
Start the client with, this will create a tunnel called example and connect it to http://example.com.
The tunnel will be available at http://example.localhost:8080.
docker run --rm -ti ghcr.io/exposr/exposr:latest -s http://host.docker.internal:8080/ tunnel connect example http://example.com
Try the tunnel
curl --resolve example.localhost:8080:127.0.0.1 http://example.localhost:8080
Configuration
exposr needs to have at least one ingress and one transport method enabled. The default option enables the HTTP ingress and the WS transport.
Account creation
Account creation is disabled by default and needs to be enabled. It can be enabled in two ways, either through the public API or by enabling the administration API. It's recommended to only use the admin API for account creation.
To enable it through the public API start exposr with the flag --allow-registration.
⚠️ Warning: Enabling public account registration will allow anyone to register an account and to create tunnels on your server.
Administration
Interface
The administration interface runs on a separate port from public API. By default it uses 8081.
The interface can be enabled by passing the flag --admin-enable true.
The administration interface exposes a /ping endpoint for load balancer health checks.
API
The administration API runs on a separate port from public API. By default it uses 8081.
The API can be enabled by passing the flag --admin-api-enable true.
To further enable the administration API an API key must be configured.
exposrd --admin-api-enable true --admin-api-key <insert key>
⚠️ Warning: The API key allows full privileged access to all accounts and tunnels.
Configuring HTTP in
Related Skills
node-connect
337.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.2kCommit, push, and open a PR
