A simple, hobby reverse proxy + asset server built with Rust.
- Lightweight
- Reverse proxy
- Gzip support
-
Range
header / File streaming - Directory index UI
- Static asset serving
- ETag / Conditional Get / Not Modified
Check out the examples folder.
RUST_LOG="prox" cargo run --example file_server
Download the latest executable: https://github.com/danneu/prox/releases/latest.
Or compile it yourself with Rust.
git clone [email protected]:danneu/prox.git
cd prox
cargo build --release
A prox executable is now available at ./target/release/prox
.
Whenever you run prox
, prox will look for a Prox.toml
config file in the current directory.
Here's the minimal config:
[server]
bind = "localhost:3000"
Prox will listen on :3000 but will just respond with 404s because no sites have been configured.
Here's a server that listens on :3000 and serves a directory of static assets on that port. It also gzips responses, logs each request to stdout, and renders a directory explorer for browsing the filesystem:
[server]
bind = "localhost:3000"
[[site]]
host = "localhost:3000"
serve = { root = "./public" }
browse = {}
gzip = {}
log = {}
Notice how site.host
matches server.bind
.
Here's a more advanced config with multiple sites.
Requests that have headers "Host: foo.com" or "Host: locahost:4001" are proxied to another server listening on port 4001. Those requests are also protected by CORS and have whitelisted the catdog.com origin.
Requests that have the header "Host: example.com" are proxied to another server listening on port 4002. Those requests have CORS enabled but have whitelisted all origins.
[server]
bind = "localhost:3000"
[[site]]
host = ["foo.com", "localhost:4001"]
url = "https://localhost:4001"
serve = { root = "foo/public" }
[site.cors]
origin = ["https://catdog.com"]
[[site]]
host = "example.com"
url = "https://localhost:4002"
[site.cors]
origin = "*"
[server]
bind = "localhost:3000"
timeouts
(object): Set I/O timeouts when connecting/reading/writing to origins. So far only connection timeout is supported.-
connect
(milliseconds): Amount of time to wait if origin is not sending initial data. Default = 5000.[server] # Wait up to 5 seconds for 3rd party to start responding to our request. timeouts = { connect = 5000 }
-
A config can specify any number of virtual hosts.
[[site]]
host = "localhost:3000"
[[site]]
host = "localhost:4000"
[[site]]
host = "localhost:5000"
Required:
host
(string or array or strings): If an incoming request has aHost
header that matches one of a site's hosts, then that site block will specify how to handle the request.
Optional:
-
url
(url string): Requests to this site will be proxied to thisurl
where another server will handle it. -
serve
(object): Serve requests from a directory of static files. If no file matched, then pass the request down the middleware chain.-
root
(file path string): Path to the directory of files to serve. -
dotfiles
(optional bool): If true, then show and serve files that start with a dot ".". Default:false
. -
browse
(optional bool): If true, then render a folder explorer UI that lets users click to navigate around your root folder. Default:false
.
-
-
gzip
(object): Apply the default gzip handler to responses. Prox will negotiate an encoding.-
threshold
(optional int): The minimum byte length for prox to gzip. Default = 1400.[[site]] host = "..." gzip = {} # Default gzip middleware
[[site]] host = "..." [site.gzip] threshold = 16000 # Only gzip files larger than 16kb
-
-
log
(object): Log request/response to stdout.[[site]] # ... log = {}
-
cors
(object): Apply CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS response headers to a site.-
origin
(array of strings or "*" for wildcard). Ex:["https://example.com]
. -
methods
(optional array of strings). Default:["GET", "HEAD", "OPTIONS"]
. -
allowed_headers
(optional array of strings). Default:[]
. Ex:["X-Foo", "X-Bar"]
. -
exposed_headers
(optional array of strings). Default:[]
. Ex:["X-Exposed"]
. -
allow_credentials
(optional bool). Default:false
. (If true, then origin must not be "*" wildcard) -
max_age
(optional int) seconds[site.cors] origin = "*" methods = ["GET"]
[[site]] # Lets foo.com and bar.com send with-credentials cross domain requests # thus they will be able to access cookies. [site.cors] origin = ["foo.com", "bar.com"] allow_credentials = true
-
git clone https://github.com/danneu/prox.git
cd prox
cargo install cargo-watch
CARGO_INCREMENTAL=1 RUST_LOG="prox" cargo watch -x 'run --bin prox'
Crafting requests:
echo -ne 'GET https://localhost:3000/a HTTP/1.1\r\nHost: example.com\r\nContent-Length: 5\r\n\r\nHello' | nc localhost 3000
Docs:
cargo doc --open
cargo watch -x 'doc'