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:
**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.
**Example: validating the signature of ECR images via Docker Hub**
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.
## SSL troubleshooting
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 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)).
* Add better support for PUT, DELETE, HEAD, OPTIONS? How? For which commands?
* 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.
Webdis can connect to a Redis server that requires credentials.
For Redis versions before 6.0, provide the password as a single string in `webdis.json` using the key `"redis_auth"`. For example:
```json
"redis_auth": "enter-password-here"
```
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.
```json
"redis_auth": ["my-username", "my-password"]
```
This new authentication system is only supported in Webdis 0.1.13 and above.
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.
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.