gdritter repos melvil / master

Tree @master (Download .tar.gz) @masterview markup · raw · history · blame



Melvil is the HTTP server interface I think I'd want to use. It's very slow at present, and still quite early, but it's at least a proof-of-concept of something I think should exist.

Basic Use

The Melvil server does nothing but pass HTTP requests and responses between other servers: it is, in effect, a mechanism for establishing reverse proxies.

The server is invoked with a single optional argument, and it continues running in the foreground until it is killed with standard Unix signals. The argument is a directory, and if that directory exists, it switches to that directory before continuing. It then reads configuration from that directory and will continuously forward requests based on that configuration.

The configuration directory contains zero or more subdirectories, each of which describes a given request filter and forwarding mechanism. The subdirectory may contain several specifically named files, whose contents specify a forwarding system:

path:    which request paths to match; defaults to "*"
domain:  which request subdomains to match; defaults to "*"
mode:    how to forward the request; defaults to "http"
host:    which host to forward to; defaults to "localhost"
port:    which port to forward to; defaults to "80"
conf:    which path to forward to; defaults to "/dev/null"
resp:    which HTTP response to issue; defaults to 303

These are interpreted as follows:

  • The path and domain fields tell us which requests to forward: both of them default to accepting anything, and both of them allow their values to have the wildcard character *.

  • The mode field tells us how to forward requests. There are three possible forwarding modes:

    • If the mode is http, then Melvil will forward the HTTP request to the server listening on the host host and the port port.
    • If the mode is melvil, then Melvil will recursively check the configuration directory at conf.
    • If the mode is redir, then Melvil will respond with an HTTP response code as indicated in resp and redirect to the host as indicated in host.

In the future, there might be more modes, such as a fastcgi mode which points to a Unix socket or a static mode which serves static files, but this is enough to test the idea.

Example Setups

A simple-but-interesting configuration, which forwards requests for to localhost:5001, redirects to, forwards requests for to, and redirects everything else to localhost:5000.

$ # create the config, which forwards to a
$ # local HTTP server listening on port 5001
$ mkdir 00-base
$ echo         >00-base/domain
$ echo 5001                >00-base/port
$ # redirect to
$ mkdir 00-www
$ echo     >00-www/domain
$ echo redir               >00-www/mode
$ echo         >00-www/host
$ # create the configuration for the blog subdomain
$ mkdir 00-blog
$ echo    >00-blog/domain
$ echo  >00-blog/host
$ # and now create the fallthrough case
$ mkdir 99-default
$ echo mode                >99-default
$ echo 5000                >99-default/port

Notice that we only need to specify a few pieces of information for each case, because we can often use the defaults for various fields, so each "configuration" is usually a directory with two or maybe three files.

Because configuration is specified as a directory, rather than as a single file, we can use properties of the Unix file system as a simple ACL-like mechanism. For example, a system administrator can set up a user-owned configuration directory for each user, and then use a global configuration directory to forward requests to that user on a per-subdomain basis:

$ mkdir -p /etc/melvil
$ for U in $USERS; do
>     # find the user's home directory
>     HOMEDIR=`cat /etc/passwd | grep ${U} | cut -d ':' -f 6`
>     # add a configuration directory to each user
>     mkdir -p ${HOMEDIR}/melvil
>     chown ${U} ${HOMEDIR}/melvil
>     # add a new forwarding rule for each user
>     mkdir -p /etc/melvil/${U}-local
>     # make ${U} forward to the user's melvil configuration
>     echo "${U}"   >/melvil/user-${U}/domain
>     echo "melvil"             >/melvil/user-${U}/mode
>     echo "${HOMEDIR}/melvil"  >/melvil/user-${U}/conf
> done
$ melvil /etc/melvil

Now, if a given user wants to set up a local HTTP server that produces dynamic content, they can add the appropriate forwarding configuration to their own directory, but they cannot modify other users' configurations or the global configuration.

Even if you're running a single server, but want to have multiple services on it, this can be a convenient way to set up reverse proxy servers without needing root access.