3 releases (breaking)
Uses new Rust 2024
| 0.9.0 | Apr 28, 2026 |
|---|---|
| 0.8.0 | Apr 15, 2026 |
| 0.1.0 | Apr 14, 2026 |
#1579 in HTTP server
1,378 downloads per month
75KB
1K
SLoC
tower-proxy
Purpose
tower-proxy is tower Services that allows it to reverse proxy requests.
These Services are implemented to be used in axum, but can also be used in a more general situation.
See the documentation.
This crate was forked from https://github.com/manorom/reverse-proxy-service, & the name was changed so a new crate could be published
License
MIT OR Apache-2.0, see LICENSE-MIT OR LICENSE-Apache-2.0
SPDX-License-Identifier: MIT OR Apache-2.0
lib.rs:
tower-proxy is tower Services that performs "reverse
proxy" with various rewriting rules.
Internally these services use hyper_util::client::legacy::Client to send an incoming request to another
server. The connector for a client can be
or any ones whichever you want.
Examples
There are two types of services, OneshotService and ReusedService. The
OneshotService owns the Client, while the ReusedService shares the Client
via Arc.
General usage
use tower_proxy::ReusedServiceBuilder;
use tower_proxy::{ReplaceAll, ReplaceN};
use hyper::body::Bytes;
use http_body_util::Full;
use http::Request;
use tower_service::Service as _;
let svc_builder = tower_proxy::builder_http("example.com:1234").unwrap();
let req1 = Request::builder()
.method("GET")
.uri("https://myserver.com/foo/bar/foo")
.body(Full::new(Bytes::new()))
.unwrap();
// Clones Arc<Client>
let mut svc1 = svc_builder.build(ReplaceAll("foo", "baz"));
// http://example.com:1234/baz/bar/baz
let _res = svc1.call(req1).await.unwrap();
let req2 = Request::builder()
.method("POST")
.uri("https://myserver.com/foo/bar/foo")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(Full::new(Bytes::from("key=value")))
.unwrap();
let mut svc2 = svc_builder.build(ReplaceN("foo", "baz", 1));
// http://example.com:1234/baz/bar/foo
let _res = svc2.call(req2).await.unwrap();
In this example, the svc1 and svc2 shares the same Client, holding the Arc<Client>s
inside them.
For more information of rewriting rules (ReplaceAll, ReplaceN etc.), see the
documentations of rewrite.
With axum
use tower_proxy::ReusedServiceBuilder;
use tower_proxy::{TrimPrefix, AppendSuffix, Static};
use axum::Router;
#[tokio::main]
async fn main() {
let host1 = tower_proxy::builder_http("example.com").unwrap();
let host2 = tower_proxy::builder_http("example.net:1234").unwrap();
let app = Router::new()
.route_service("/healthcheck", host1.build(Static("/")))
.route_service("/users/{*path}", host1.build(TrimPrefix("/users")))
.route_service("/posts", host2.build(AppendSuffix("/")));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000")
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
Return Types
The return type (std::future::Future::Output) of ReusedService and
OneshotService is Result<Result<Response<Incoming>, ProxyError>, Infallible>.
Features
By default only http1 is enabled.
http1: useshyper/http1http2: useshyper/http2https: alias tonativetlsnativetls: uses thehyper-tlscraterustls: alias torustls-webpki-rootsrustls-webpki-roots: uses thehyper-rustlscrate, with the featurewebpki-rootsrustls-native-roots: uses thehyper-rustlscrate, with the featurerustls-native-certsrustls-http2:http2plusrustls, andrustls/http2is enabled You must turn on eitherhttp1orhttp2. You cannot use the services if, for example, only thehttpsfeature is on.
Through this document, we use rustls to mean any of rustls* features unless otherwise
specified.
Dependencies
~10–38MB
~605K SLoC