Skip to content

Conversation

@juhaku
Copy link

@juhaku juhaku commented Nov 25, 2025

This commit adds native TLS support using tokio-rustls. The feature is gated behind a feature flag and can be optionally enabled.

Since axum already had all the necessary connection handling logic in place but was missing TLS acceptor functionality, this PR adds that support by implementing a TlsListener wrapper for TcpListener that first accepts TCP connections and then performs TLS handshakes.

Example

Wrap TcpListener with TlsListener to allow axum to serve HTTPS connections.

let cert = CertificateDer::from_slice(&[0]);
let key = PrivateKeyDer::from_pem_slice(&[0]).unwrap();
let config = ServerConfig::builder()
    .with_no_client_auth()
    .with_single_cert(vec![cert], key).unwrap();

let tcp = TcpListener::bind(("0.0.0.0", 8443)).await.unwrap();
let tls_listener = TlsListener::new(tcp, config);
let app = Router::new().route("/", routing::get(|| async { "Hello" }));

let _ = axum::serve(tls_listener, app.into_make_service());

Motivation

Axum has all necessary plumbing in place for handling connections but lacks the ability to serve TLS connections directly. While there are multiple examples on repository how to achieve this, I feel it should be something that is part of the library for completeness and simplified usage.

With having this functionality in axum directly there is no need for users to duplicate the loop logic to their codebase just for few lines of code.

No goals

While this commit adds support for tokio-rustls uses of openssl was not considered, but could be something to consider in future.

Solution

In it's simplicity this functionality integrates to existing axum::serve functionality with one single line addition as shown below:

let tcp = TcpListener::bind(("0.0.0.0", 8443)).await.unwrap();
+let tls_listener = TlsListener::new(tcp, config);
let app = Router::new().route("/", routing::get(|| async { "Hello" }));

let _ = axum::serve(tls_listener, app.into_make_service());

This commit adds native TLS support using tokio-rustls. The feature
is gated behind a feature flag and can be optionally enabled.

Since axum already had all the necessary connection handling logic
in place but was missing TLS acceptor functionality, this PR adds
that support by implementing a `TlsListener` wrapper for `TcpListener`
that first accepts TCP connections and then performs TLS handshakes.

 # Example

Wrap `TcpListener` with `TlsListener` to allow axum to serve HTTPS
connections.
```rust
let cert = CertificateDer::from_slice(&[0]);
let key = PrivateKeyDer::from_pem_slice(&[0]).unwrap();
let config = ServerConfig::builder()
    .with_no_client_auth()
    .with_single_cert(vec![cert], key).unwrap();

let tcp = TcpListener::bind(("0.0.0.0", 8443)).await.unwrap();
let tls_listener = TlsListener::new(tcp, config);
let app = Router::new().route("/", routing::get(|| async { "Hello" }));

let _ = axum::serve(tls_listener, app.into_make_service());
```
@juhaku
Copy link
Author

juhaku commented Nov 25, 2025

As far for tests, there are doc tests, but I did not yet write any unit tests for the change. I'd like some pointers for direction whether it is useful to test the server TLS somehow? Should set the server up using TLS, (self signed cert & key needed ), and then fire some requests to see whether they come through.

This comes with an example as well which can be found from examples folder.

@juhaku
Copy link
Author

juhaku commented Nov 25, 2025

But I guess there is noway around this deny, since rustls has ISC license becuase of the webpki 🤦‍♂️

@juhaku
Copy link
Author

juhaku commented Nov 25, 2025

However, should that be allowed? The ISC license is comparable to MIT and is non-copyleft permissive license.

Example of ISC license

Copyright (c) <year> <copyright holders>

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

@jplatte
Copy link
Member

jplatte commented Nov 25, 2025

We've always been intentionally avoiding the complexity that comes with supporting TLS, and I don't think anything has changed.

This can just be a third-party crate (just like axum-server is), no?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants