Using HTTPS

This chapter explains how we can access our Humphrey application using HTTPS, improving the security of the application and allowing our client-side code access to more advanced browser features.

Note: While Humphrey's core features are dependency-free, using TLS requires the rustls crate to ensure that the cryptography used is secure.

Enabling the TLS Feature

To use HTTPS with Humphrey, you must first enable the tls feature in your Cargo.toml file:

[dependencies]
humphrey = { version = "*", features = ["tls"] }

Setting up the TLS Certificate

TLS requires a certificate and a private key, which must be supplied to the Humphrey app. In production, these would be generated by a certificate authority like Let's Encrypt, but when developing an HTTPS application, it's often easier to use a self-signed certificate.

The mkcert command-line tool can be used to generate a trusted certificate for local development.

Installing mkcert

mkcert can be installed as follows (or downloaded from the aforementioned link):

Windows:

$ choco install mkcert

MacOS:

$ brew install mkcert

Linux:

$ sudo apt install libnss3-tools
$ brew install mkcert

Generating the Certificate

Once installed, the mkcert certificate authority must be trusted by the operating system, which can be done by running the following command.

$ mkcert -install

Finally, to generate a certificate for local development, run this command, which will create two files, localhost.pem and localhost-key.pem.

$ mkcert localhost

Using the Certificate with Humphrey

When creating your Humphrey application, the certificate and key must be provided to the App using the with_cert method, which is only available when the tls feature is enabled. A very simple example using TLS is shown below. Notice that we use run_tls instead of run to start the application.

use humphrey::http::{Request, Response, StatusCode};
use humphrey::App;
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    let app: App<()> = App::new()
        .with_stateless_route("/", home)
        .with_cert("path/to/localhost.pem", "path/to/localhost-key.pem");

    app.run_tls("0.0.0.0:443")?;

    Ok(())
}

fn home(_: Request) -> Response {
    Response::new(
        StatusCode::OK,
        "<html><body><h1>This is served over HTTPS!</h1></body></html>",
    )
}

Forcing HTTPS

By default, when you call app.run_tls("0.0.0.0:443"), the application will only accept connections on the HTTPS port (443). Typically, web applications will automatically redirect requests the HTTP port 80 to the HTTPS endpoint. To enable this in Humphrey, you can use the with_forced_https method on the App struct, as follows:

// --snip--
let app: App<()> = App::new()
    .with_stateless_route("/", home)
    .with_cert("path/to/localhost.pem", "path/to/localhost-key.pem")
    .with_forced_https(true);
// --snip--

This starts a background thread which simply redirects HTTP requests to the corresponding HTTPS URL.

Conclusion

In this section, we've covered how to use the TLS feature of Humphrey, and how to use it to serve HTTPS applications. Next, we'll learn how to monitor internal events in the application.