Skip to content


Folders and files

Last commit message
Last commit date

Latest commit



39 Commits

Repository files navigation


Dynamic routing / virtual hosts with nginx, Lua, and Redis.

Simon allows you to very quickly point domains to specific hosts and ports by defining proxy_pass directives in Redis. Largely inspired by hipache, a standalone proxy that does the same thing.



For every request(!), Simon looks up the Redis Set simon:[hostname] to find one or more destinations. To define a route, add a destination (ip or ip:port or even hostname/path) to a Redis set simon:[route]:

> redis-cli sadd
> redis-cli sadd
> redis-cli sadd

Wait, for every request? Isn't that slow? Not at all, we're talking Nginx and Redis here.

Basic example

Point to local port 8080:

> redis-cli sadd

> curl
<h1>Welcome to</h1>

Load balancing example

Distribute requests for to ports 5566 and 5577:

> redis-cli sadd

> curl
{"success": "definitely"}

If Simon finds multiple destinations, new visitors will be randomly directed to one of them as a rough form of load balancing. If a session ID is present Simon will direct all further visits to the same destination. The session ID is read from the cookie "cookie_connect.sid" by default, see options below for how to change this.


These instructions are specific to the OpenResty distribution on Ubuntu:

  • Download and compile nginx with Lua support
# probably as sudo
apt-get update
apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev perl make build-essential
curl -LO
tar -xzvf openresty-
cd openresty-
./configure  --with-luajit --prefix=/opt/openresty
make && make install
  • Clone Simon into /opt/openresty/lualib/
# still as sudo
cd /opt/openresty/lualib/
git clone
  • Edit /opt/openresty/nginx/conf/nginx.conf to add lua_package_path (outside the server block) and the Simon configuration (inside the server location block):
http {

    # ...
    lua_package_path "/opt/openresty/lualib/resty/?.lua"; # Include Lua libraries

    server {
        # Pass all requests through Simon
        location / {
            set $proxy_to "";
            set $proxy_host "";
            access_by_lua_file "/opt/openresty/lualib/simon/simon.lua";
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $proxy_host;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://$proxy_to$request_uri;
        # ...

The above config first initializes Nginx variables $proxy_to and $proxy_host (to make them available in the Lua scope) then runs Simon, then uses those (now defined) variables to set up the proxy_pass directive.

Other features

Wildcard domains

You can use an asterisk "*" to define a catch-all / fallback for a single level of subdomain. For example, "*" will match "" but not "":

> redis-cli sadd simon:*

> curl
<h1>Welcome to</h1>

Wildcard domains are only used if an exact match is not found.

Setting a specific hostname

Some proxied-to servers require a specific hostname to understand the request (maybe you're proxying to a S3 bucket, Wordpress instance, or another Simon instance). By default Simon copies the hostname of the original request (so if the request is to, that will be carried along in the proxied request). To send a specific hostname, you can define a ":hostname" key:

SET simon:[route]:hostname [hostname]

Example: Proxying to a S3 website

Set up "Static website hosting" on your S3 bucket to get public access and loading index.html for / requests.

> redis-cli sadd
> redis-cli set

Removing a route

To remove a destination, remove it from the Redis set with SREM:

> redis-cli srem

To delete an entire route (all destinations) use the Redis DEL command:

> redis-cli del

simon-says helper script

Instead of using the Redis CLI directly, you can use the provided simon-says bash script for a slightly nicer experience, such as

  • Prefixing if not supplied
  • Deleting routes with -
  • Listing other destinations after adding/deleting
# Add a destination
> simon-says :5557
Pointing to
1) ""
2) ""

# Delete a destination
> simon-says -:5557
Not pointing to
1) ""

# List destinations for a route
> simon-says
1) ""


  • Non-proxy routes e.g. /var/nginx/html/static
  • Custom error pages (currently shows a generic Nginx error if no hostname matches)


Dynamic routing/vhosts with nginx + Lua + Redis






No releases published


No packages published