A very simple web server providing an HTTP interface to Redis. It uses [hiredis](https://github.com/antirez/hiredis), [jansson](https://github.com/akheron/jansson), [libevent](https://monkey.org/~provos/libevent/), and [http-parser](https://github.com/ry/http-parser/).
Webdis depends on libevent-dev. You can install it on Ubuntu by typing `sudo apt-get install libevent-dev` or on macOS by typing `brew install libevent`.
Starting from release `0.1.12` and including `latest`, Docker Hub images are signed ([download public key](nicolasff.pub)). You should see the following key ID if you verify the trust:
The same documentation page details how to [verify the signatures of multi-architecture images](docs/webdis-docker-content-trust.md), and the tree of manifests used to build them.
**A note on ECR and trust:** [AWS does not support Notary v2](https://github.com/aws/containers-roadmap/issues/43) at the time of this writing, although [a security talk from 2020](https://d2908q01vomqb2.cloudfront.net/fe2ef495a1152561572949784c16bf23abb28057/2020/08/21/C3-ECR-Security-Best-Practices_072020_v3-no-notes.pdf#page=19) mentions that the feature could be available in 2021.
The consequence is that [Webdis images on ECR](https://gallery.ecr.aws/nicolas/webdis) are not signed at this time.
They can still be verified, since the images uploaded there use the exact same hash as the ones on Docker Hub, which _are_ signed. This means that you can verify the signature using the `docker trust inspect` command described above, as long as you **also** make sure that the image hash associated with the image on ECR matches the one shown on Docker Hub.
For more details about Content Trust validation with ECR images, refer to the article titled [Webdis and Docker Content Trust](docs/webdis-docker-content-trust.md) in the [Webdis documentation](docs/README.md).
Starting with [release 0.1.19](https://github.com/nicolasff/webdis/releases/tag/0.1.19), Docker images for Webdis are published as [manifest lists](https://docs.docker.com/registry/spec/manifest-v2-2/#media-types) supporting [multiple architectures](https://docs.docker.com/desktop/multi-arch/). Each release points to an x86-64 image and an ARM64v8 image:
By default `docker pull` will download only the relevant image for your architecture, but you can [specify the platform](https://docs.docker.com/engine/reference/commandline/pull/) to download the image for a specific architecture, e.g.
:information_source: The Docker images [provided on Docker Hub](https://hub.docker.com/r/nicolas/webdis) under `nicolas/webdis` contain both Webdis and an embedded Redis server. They were built this way to make it easy to [try Webdis](#try-in-docker) without having to configure a Docker deployment with two containers, but this is likely not the best way to run Webdis in production.
The following documentation pages cover various such use cases:
- [Running Webdis in Docker with an external Redis instance](docs/webdis-docker-external-redis.md)
- [Running Webdis and Redis in Docker Compose](docs/webdis-redis-docker-compose.md)
- [Running Webdis and Redis in Docker Compose with SSL connections](docs/webdis-redis-docker-compose-ssl.md)
More articles are available in the [Webdis documentation](docs/README.md).
Webdis needs libraries that provide TLS support to encrypt its connections to Redis:
* On Alpine Linux, install `openssl-dev` with `apk-add openssl-dev`.
* On Ubuntu, install `libssl-dev` with `apt-get install libssl-dev`.
* On macOS with HomeBrew, install OpenSSL with `brew install openssl@1.1`.
Then, build Webdis with SSL support enabled:
```sh
$ make SSL=1
```
# Configuring Webdis with SSL
Once Redis is configured with SSL support (see [this guide](https://nishanths.svbtle.com/setting-up-redis-with-tls) for step-by-step instructions), you can configure Webdis to connect to Redis over encrypted connections.
Add a block to `webdis.json` under a key named `"ssl"` placed at the root level, containing the following object:
```json
{
"enabled": true,
"ca_cert_bundle": "/path/to/ca.crt",
"path_to_certs": "/path/to/trusted/certs",
"client_cert": "/path/to/redis.crt",
"client_key": "/path/to/redis.key",
"redis_sni": "redis.mydomain.tld"
}
```
This means that `"ssl"` should be at the same level as `"redis_host"`, `"redis_port"`, etc.
**Important:** the presence of the `"ssl"` configuration block alone does not necessarily enable secure connections to Redis. The key `"enabled"` inside this block **must** also be set to `true`, otherwise Webdis will keep using unencrypted connections.
Use the following table to match the Redis configuration keys to the fields under `"ssl"` in `webdis.json`:
| `tls-ca-cert-file` | `ca_cert_bundle` | CA certificate bundle |
Two other keys have no equivalent in `redis.conf`:
-`path_to_certs` is an optional directory path where trusted CA certificate files are stored in an OpenSSL-compatible format.
-`redis_sni` is an optional Redis server name, used as a server name indication (SNI) TLS extension.
See also the [Hiredis docs](https://github.com/redis/hiredis/blob/v1.0.2/README.md#hiredis-openssl-wrappers) and [Hiredis source code](https://github.com/redis/hiredis/blob/v1.0.2/hiredis_ssl.h#L77-L96) for more information.
For a full tutorial showing how to configure and run Redis and Webdis under Docker Compose with SSL connections between the two services, head to the `docs` folder and open [Running Webdis & Redis in Docker Compose with SSL connections](docs/webdis-redis-docker-compose-ssl.md).
Follow this table to diagnose issues with SSL connections to Redis.
| Error message or issue | Cause | Solution |
| ---------------------- | ----- | -------- |
| Unexpected key or incorrect value in `webdis.json`: 'ssl' | Webdis is not compiled with SSL support | Build webdis with `make SSL=1` |
| Unexpected key or incorrect value under 'ssl' | Invalid configuration | One or more keys in the `ssl` object in was not recognized, make sure they are all valid |
| Failed to load client certificate | Invalid client certificate | Verify the file that `client_cert` points to |
| Failed to load private key | Invalid client key | Verify the file that `client_key` points to |
| Failed to load CA Certificate or CA Path | Invalid CA certificate bundle | Verify the file that `ca_cert_bundle` points to |
| All requests fail with HTTP 503, logs show "Error disconnecting: Connection reset by peer" | SSL disabled in config but Webdis connected to an SSL port | Make sure `enabled` is set to `true` and that Webdis connects to the SSL port for Redis |
| Logs show "Server closed the connection" at start-up | SSL connection failed | The client key and/or client certificate was missing. Make sure the configuration is valid. |
| No error but all requests hang | Webdis connected to the non-SSL port | Make sure Webdis is connecting to the port set under `tls-port` in `redis.conf` |
* Support for "Keep-Alive" connections to Redis: add `"hiredis": { "keep_alive_sec": 15 }` to `webdis.json` to enable it with the default value. See the [Hiredis documentation](https://github.com/redis/hiredis/tree/e07ae7d3b6248be8be842eca3e1e97595a17aa1a#other-configuration-using-socket-options) for details, the value configured in `webdis.json` is the `interval` passed to `redisEnableKeepAliveWithInterval`. Important: note how it is used to set the value for `TCP_KEEPALIVE` (the same value) _and_ to compute the value for `TCP_KEEPINTVL` (integer, set to 1/3 ×`interval`).
* Support for Redis authentication in the config file: set `redis_auth` to a single string to use a password value, or to an array of two strings to use username+password auth ([new in Redis 6.0](https://redis.io/commands/auth)).
* This could be done using a “strict mode” with a table of commands and the verbs that can/must be used with each command. Strict mode would be optional, configurable. How would webdis know of new commands remains to be determined.
`.ext` is an optional extension; it is not read as part of the last argument but only represents the output format. Several formats are available (see below).
Special characters: `/` and `.` have special meanings, `/` separates arguments and `.` changes the Content-Type. They can be replaced by `%2f` and `%2e`, respectively.
Redis 6.0 introduces a more granular [access control system](https://redis.io/topics/acl) and switches from a single password to a pair of username and password. To use these two values with Webdis, set `"redis_auth"` to an array containing the two strings, e.g.
Each ACL contains two lists of commands, `enabled` and `disabled`. All commands being enabled by default, it is up to the administrator to disable or re-enable them on a per-profile basis.
The `http_status` code is an indicator of how Webdis would have responded if the client had used HTTP instead of a WebSocket connection, since WebSocket messages do not inherently have a status code.
For raw Redis protocol WebSocket clients, a rejected command will produce this error (sent as a string in a binary frame):
Environment variables can be used in `webdis.json` to read values from the environment instead of using constant values.
For this, the value must be a string starting with a dollar symbol and written in all caps. For example, to make the redis host and port configurable via environment variables, use the following:
Webdis supports file upload using HTTP PUT. The command URI is slightly different, as the last argument is taken from the HTTP body.
For example: instead of `/SET/key/value`, the URI becomes `/SET/key` and the value is the entirety of the body. This works for other commands such as LPUSH, etc.
**Important:** WebSocket support is currently _disabled by default_. To enable WebSocket support, set the key named `"websockets"` to value `true` in `webdis.json`, e.g.
```json
{
"daemonize": false,
"websockets": true,
}
```
(start and end of file omitted).
WebSockets are supported with the following formats, selected by the connection URL:
Webdis exposes Redis PUB/SUB channels to HTTP clients, forwarding messages in the channel as they are published by Redis. This is done using chunked transfer encoding.