legion
is a small reverse proxy plus web server for serving static content.
legion
can serve static files from local filesystem and reverse proxy requests
based on path, virtual host or both. It requires minimal configuration, which
makes it ideal for simple everyday use cases like serving content from current
directory or acting as a simple development server for a frontend + backend
application.
In addition legion
acts as a showcase for several nifty features of Go's
standard HTTP library.
If you have go
installed:
go install github.com/akojo/legion@latest
Otherwise you can grab a binary for your architecture from Releases page.
To serve files from current directory on port 8000:
legion
As an another example, to
- Start a server on port 3000, restricting access to local connections
- Serve files from
static/
under current directory - Route requests to
/api/*
to a backend application over HTTP on localhost port 3001
legion -listen localhost:3000 -route /=static -route /api=http://localhost:3001
legion
accepts configuration both from a configuration
file and via command-line
options. If both are specified, command-line options
override simple values and append values to lists. For example, if you provide
routes both in a configuration file and via command-line, command-line routes
will be appended to the routes in configuration file.
Most of legion
configuration revolves around routes. Every route has two
parts: a source and a target. Together they define where incoming requests
will be routed.
Route source can be either
- A plain path, e.g.
/api
or/
- A path prefixed by a hostname, e.g.
www.example.com/api
orwww.example.com/
Paths are prefix-matched to incoming request paths; longer paths always take
precedence over shorter ones. Prefixing a path with a hostname restricts a route
to match only when incoming request's Host
header matches the given hostname.
Source paths are always absolute; omitting the leading slash will result in an error.
Route target can be either
- A local filesystem path, e.g.
/var/www/html
. Paths can be relative, in which case they are interpreted relative tolegion
's current working directory. - An HTTP/HTTPS URL, e.g.
https://www.example.com/api/v1
Given a local path legion
serves files from the specified directory. If
incoming request specifies a directory and the target directory contains a file
named index.html
, contents of index.html
are returned instead. Otherwise
directory contents are served as an HTML page.
If requested filename is index.html
and the file exists, request will be
redirected to its parent directory.
Given an HTTP/HTTPS URL legion
acts as a reverse proxy, forwarding requests to
the specified address. legion
adds usual forwarding
headers to outgoing requests.
legion
always performs path rewriting, stripping source path from incoming
requests and then appending the remainder to target path.
For example, given routes (see configuration file syntax below)
static:
- source: /
target: /var/www/html
proxy:
- source: /api
target: http://localhost:3000/v1
incoming requests map to targets as follows:
/favicon.ico
: first route is selected and contents of file/var/www/html/favicon.ico
are returned/api/pets/1
: second route is selected and request is forwarded tohttp://localhost:3000/v1/pets/1
NB. in this case, according to legion
's routing rules, if file
/var/www/html/index.html
exists request to /
will return its contents.
When started with an empty configuration legion
serves files from current
directory on port 8000
and writes access logs to stdout.
Configuration file is written in YAML and allows specifying following settings
listen: <addr>
loglevel: <info|warn|error>
tls:
certificates:
- <certificate1>
- <certificate2>
...
routes:
static:
- <route1>
- <route2>
...
proxy:
- <route1>
- <route2>
...
Name | Description | Values | Default |
---|---|---|---|
listen |
Listen on given address (i.e. network interface) and port. Omitting address will listen on all interfaces | host:port , ip:port or :port |
:8000 |
loglevel |
Set log minimum level. Request logs are suppressed when level is above info |
info|warn|error |
info |
TLS section is optional. If defined it will contain a list of X.509 certificate key pair files. If multiple certificates are defined, an appropriate one is selected based on incoming request.
TLS:
certificates:
- certfile: <file>
keyfile: <file>
Name | Description |
---|---|
certfile |
Certificate public key file in X.509 format |
keyfile |
Certificate private key file in X.509 format |
Routes define either static routes, serving files from local filesystem, or proxy routes, relaying request to an upstream server.
routes:
static:
- source: <path>|<hostname/path>
target: <path>
...
proxy:
- source: <path>|<hostname/path>
target: <url>
See Routing for more information on specifying routes.
In addition to configuration file, legion
understands following command-line
flags. Command-line flags override values in configuration file.
-
-config <file>
Read configuration from specified file. Configuration file format is documented above
-
-listen <address>
Listen on given address. Can be
hostname:port
,ip:port
or just:port
. -
-loglevel info|warn|error
Set log level. Request logs are written with level "info" and can thus be suppressed by setting level to either "warn" or "error".
-
-route <source>=<target>
Route requests from
source
totarget
. See Routing for specifying sources and targets.
When acting as a reverse proxy legion
always adds forwarding headers
(X-Forwarded-For
, X-Forwarded-Proto
) to outgoing requests.
If an existing X-Forwarded-For
is found in inbound request it is retained and
client IP is appended to its value. Otherwise new X-Forwarded-For
is added
with inbound request client IP.
Existing X-Forwarded-Proto
in inbound request is copied to outbound request.
Otherwise new X-Forwaded-Proto
is added based on whether inbound request used
TLS.
legion
never adds X-Forwarded-Host
header to outboud requests. If an
X-Forwarded-Host
header is present in an inbound request, its value is used as
Host
header in outboud request. Otherwise Host
of inbound request is used.
legion
prints access logs in structured format using logfmt-compatible output.
An example request log line is
time=2006-01-02T15:04:05Z07:00 level=INFO msg="200 GET /" method=GET proto=HTTP/1.1 path=/ address=localhost:8000 status=200 duration=591.8µs user_agent=curl/8.0.1