Ceryx keeps its routing table in Redis and its proxy in OpenResty
Dynamic reverse proxy based on NGINX OpenResty with an API
At a glance
- What is it?
- Ceryx is a programmable HTTP(S) reverse proxy made of two components over a Redis backend: an NGINX OpenResty proxy that routes on the Host header or TLS server name, and an API that creates, updates and deletes routes at runtime. It ships as Docker images and a Helm chart, and its newest tagged release is from 2019.
- Who is it for?
- Teams that need to hand out HTTPS endpoints to many internal services without editing a proxy configuration file each time should adopt Ceryx, because the routing table is data in Redis and the API changes it at runtime. It is the wrong tool when the API must not be reachable from the internet, since the README says in plain terms that exposing it publicly lets anyone mess with it, and the wrong tool when you need per-user authorisation or auditing of route changes.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two components and one Redis backend
Ceryx is described as a rock-solid, programmable reverse proxy, and the architecture is deliberately small: the HTTP(S) reverse proxy, an API, and a Redis backend.
The simplicity is the point. The README attributes the reliability to that simplicity in design, and then explains what each piece does.
The proxy uses NGINX OpenResty under the hood to route requests, based on the HTTP request's Host header or the Server Name Indication in HTTPS requests. It queries the Redis backend to decide which target each request should go to.
The API lets users dynamically create, update and delete Ceryx routes via any HTTP client. The API validates, sanitizes and eventually stores input in the Ceryx backend, to be queried by the proxy.
That separation is the interesting design decision. The routing table is not a file on disk and not an in-memory map in the proxy. It is a set of keys in Redis, which means the proxy can be restarted or scaled without losing routes, and a route can be created by a completely different process than the one serving traffic. The API is also the only writer, which keeps sanitisation in one place rather than spread across whoever edits configuration.
The origin of the project is worth noting. The README says Ceryx is used to provide tens of thousands of SourceLair projects with their unique HTTPS-enabled public URLs, and it names SourceLair, an in-browser IDE for web applications made publicly accessible via development web servers powered by Ceryx, and Stolos, a managed Docker development environment, among the real-world uses. This is a proxy built for the problem of exposing many short-lived development services, not for a static set of production upstreams.
Routes are created over HTTP, not written into a config file
The API surface is REST-shaped and small. Adding a route is a POST with a source and a target:
curl -H "Content-Type: application/json" \
-X POST \
-d '{"source":"publicly.accessible.domain","target":"http://service.internal:8000"}' \
http://ceryx-api-host/api/routesThe same endpoint with PUT and the source in the path updates a route, and DELETE on that path removes it. The source is the hostname the public request carries, the target is the internal URL the request is proxied to.
Two settings change the behaviour of a route rather than its endpoints. enforce_https turns HTTP to HTTPS redirection on for that host, and the README notes the same works in PUT update requests:
curl -H "Content-Type: application/json" \
-X POST \
-d '{"source":"publicly.accessible.domain","target":"http://service.internal:8000", "settings": {"enforce_https": true}}' \
http://ceryx-api-host/api/routesThe second setting changes the proxying model itself. With mode set to redirect, Ceryx does not proxy the request at all, it prompts the client to redirect to the target itself:
curl -H "Content-Type: application/json" \
-X POST \
-d '{"source":"sourcelair.com","target":"https://www.sourcelair.com", "settings": {"mode": "redirect"}}' \
http://ceryx-api-host/api/routesThat is a useful escape hatch. For a target that is already publicly reachable, Ceryx can stay out of the data path entirely and simply hand the client on.
Because the whole route table is data, a route is a record with a lifecycle rather than a line in a file. That is what makes Ceryx different from running NGINX with a generated config, and it is also what makes the API's security the whole security story.
Configuration is a wall of environment variables
There is no configuration file to edit in the normal path. Ceryx is configured with environment variables, and the README lists them with their defaults.
The API side is three variables plus a debug switch:
- `CERYX_API_HOST`: The host to bind the Ceryx API (default: `127.0.0.1`)
- `CERYX_API_HOSTNAME`: Optional publicly accessible hostname for the Ceryx API (default: None)
- `CERYX_API_PORT`: The port to bind the Ceryx API (default: `5555`)
- `CERYX_DEBUG`: Enable debug logs for Ceryx API (default: `true`)Ceryx logs at info level by default, and setting CERYX_DEBUG to true also emits debug level logs.
The Redis side has a host, a port, an optional password, a key prefix and a timeout, and the timeout is worth reading twice because it covers every Redis operation including the initial connection, in milliseconds, with a default of 100. A Redis connection that is slow will make every proxied request slow, because every request consults Redis.
The remaining variables control the edge behaviour: CERYX_DISABLE_LETS_ENCRYPT turns off automatic certificate generation, CERYX_DNS_RESOLVER sets the DNS resolver IP with the Docker resolver as the default, CERYX_MAX_REQUEST_BODY_SIZE caps incoming request bodies at 100 megabytes by default, CERYX_DOCKERIZE_EXTRA_ARGS passes extra arguments to dockerize, and CERYX_SSL_DEFAULT_CERTIFICATE and CERYX_SSL_DEFAULT_KEY point at the fallback certificate, which is randomly generated at build time.
Containers, Compose and a Helm chart for Kubernetes
Ceryx is designed to run inside a container, and the README is explicit about the consequence: if you are not using the official sourcelair/ceryx image, you have to take care of configuration file generation yourself, with entrypoint.sh as the reference for how that is done.
For Compose, the requirements are a machine reachable from the internet with Docker and Docker Compose, plus at least one domain or subdomain resolving to the machine's public IP address. Starting it is one command:
docker-compose up -dThe compose file in the repository shows the shape of the deployment: a ceryx service from the sourcelair/ceryx image publishing ports 80 and 443, an api service from sourcelair/ceryx-api listening on 5555, and a redis service with a named volume for its data. The API service binds CERYX_API_HOST to 0.0.0.0 inside the compose network, which is a reminder that the API is reachable from anywhere inside that network.
For Kubernetes the README documents a cluster with a public facing IP, kubectl and Helm installed locally, Tiller on the cluster, and a domain or wildcard A record resolving to the cluster address. You edit the values file at .k8s/ceryx/values.yaml and install the chart:
helm install --debug --generate-name --values <path to your value file> ./ceryxThe README suggests adding --dry-run to that command before deploying, to check the generated YAML.
Certificates are handled automatically by default. When a domain is hit over HTTPS and a route exists for it, Ceryx tries to generate a certificate through Let's Encrypt. Setting CERYX_DISABLE_LETS_ENCRYPT to true stops that, in which case requests to unknown hosts fall back to the default certificate generated at build time.
The API is the soft spot, and the README says so
There is one warning in the documentation that deserves to be quoted rather than paraphrased, because it changes how you should deploy the thing.
The README says never to expose the Ceryx API to the public in production, because anyone from the internet will be able to access the API and mess with it, and notes that it is useful for development and testing.
That is the whole access control story. The API is the only writer of the routing table, and if anyone can POST to it they can point a hostname at a service of their choosing, redirect traffic, or remove routes. There is no mention of authentication on the API endpoints, no per-user authorisation, no audit trail of who changed a route, and no role separation between the proxy and the API.
The workflow the README suggests for working with the API locally is to set CERYX_API_HOSTNAME and run a helper inside the container:
docker-compose exec api bin/populate-apiThe companion web interface exists as a community project, the Ceryx Web project, which provides a web UI for the API.
So the operational picture is: keep the API on a private interface or behind your own authentication layer, treat any host that can reach it as fully trusted, and remember that the API hostname setting is what makes the API reachable through the proxy itself, which is convenient for testing and dangerous for production.
The MIT licence lets you build that authentication layer or host the API yourself, but the work is yours, not the project's.
Where Ceryx is the wrong tool
Several constraints make Ceryx a poor fit outside its original use case.
It needs Redis on the request path. Every proxied request consults the backend to decide where to go, with a default Redis timeout of 100 milliseconds across all operations. That is a deliberate trade for a dynamic routing table, and it means Redis availability is a hard dependency of your proxy, not just of your control plane. A plain NGINX configuration has no such dependency.
It assumes you control DNS and own domains. Automatic certificates come from Let's Encrypt, which means a public domain resolving to your address, and the Kubernetes path additionally assumes a wildcard A record is possible. For an internal-only service behind a corporate DNS setup, the certificate story is your problem, and the fallback certificate generated at build time is not a substitute.
It is a proxy for HTTP(S), not a general edge. There is no mention of access control lists per route, of request size policies beyond a global body limit, of header rewriting rules, of load balancing across several targets for one source, or of rate limiting. If you need those, you are looking at a different tool.
It is not built for a bare metal install. The README heads up is that Ceryx is designed to be run inside a container using Docker or similar tools, and that using the official image is what handles configuration generation. Running it outside a container means you take over the entrypoint work.
And the API has no built-in authorisation, which for a shared or multi-tenant environment is disqualifying on its own.
MIT licensed, last pushed in April, newest tag from 2019
The licence is MIT, with a LICENSE file at the root of the repository and an MIT badge in the README. There is no copyleft obligation and no source disclosure requirement, so running the images, forking the proxy or building your own management layer in front of the API are all unremarkable uses.
The maintenance picture needs stating plainly because the two numbers point in different directions. The repository is not archived and the last push was on 2026-04-07, which is more than six months ago. The most recent tagged releases are 0.7.0 from 2019-12-02, 0.6.1 and 0.6.0 from April 2019. So the code has been touched, but there has been no release in a long time, and the newest published artefact is old enough that the compose file's pinned Redis image, redis:3.2.11-alpine, and the Travis CI badge are period-appropriate rather than current.
That combination tells you what kind of dependency Ceryx is. It is infrastructure you can run and read, with a small surface and a permissive licence, but you should not expect a maintained upstream to ship you fixes or upgrade the pinned images for you.
The practical advice is to read the compose file and the entrypoint script before you deploy, and to treat the image tags as something you pin and maintain yourself. The two organisations behind it, SourceLair and the community Ceryx Web project, are the people to look to for how the thing is meant to run.
If your requirement is a small set of stable upstreams with per-route policy, a static NGINX or Traefik configuration will do the same job with fewer moving parts. Ceryx earns its place when the routing table changes as often as the deployments do.
Editorial conclusion
Teams that need to hand out HTTPS endpoints to many internal services without editing a proxy configuration file each time should adopt Ceryx, because the routing table is data in Redis and the API changes it at runtime. It is the wrong tool when the API must not be reachable from the internet, since the README says in plain terms that exposing it publicly lets anyone mess with it, and the wrong tool when you need per-user authorisation or auditing of route changes. Before deploying, keep the API bound to a private interface, decide whether you want the container image to generate your certificates, and note that the last push was on 2026-04-07 while the newest tagged release, 0.7.0, dates from 2019-12-02.
Frequently asked questions
How do I add a route to Ceryx?
Send a POST with a JSON body containing a source and a target to the /api/routes endpoint of the Ceryx API. The proxy then routes requests carrying that Host header or TLS server name to the target, and the route can be updated with PUT or removed with DELETE.
How does Ceryx handle HTTPS certificates?
By default Ceryx tries to generate a certificate through Let's Encrypt when a domain is hit over HTTPS and a route exists for it. Setting CERYX_DISABLE_LETS_ENCRYPT to true disables that behaviour, and requests fall back to the default certificate generated at build time.
Is it safe to expose the Ceryx API publicly?
The README says not to do it in production, because anyone from the internet would be able to access the API and mess with it. The API is the only writer of the routing table, so it should be bound to a private interface or protected by your own authentication.
What does Ceryx need to run?
A machine reachable from the internet with Docker and Docker Compose, at least one domain or subdomain resolving to its public IP address, and a Redis backend. The README notes that Ceryx is designed to run inside a container and that running it outside the official image means handling configuration file generation yourself.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/withlogicco-ceryx)Was this useful?