HTTPS Configuration

It's often useful to be able to start a server with a self-signed cert. The following code starts a web-server on HTTPS port 9443 with a simple handler:

public class HttpsSelfSignedCert {
    public static void main(String[] args) {
        MuServer server = muServer()
            .withHttpsPort(9443)
            .addHandler(Method.GET, "/", (req, resp, pp) -> resp.write("This is HTTPS"))
            .start();
        System.out.println("Server started at " + server.uri());
    }
}
(see full file)

Signed certificates

To use a signed certificate, you need to create an HttpsConfigBuilder and pass it to the withHttpsConfig method on the MuServerBuilder class.

The HttpsConfigBuilder has a number of useful ways to create a context, for example you can load a cert from the file system, classpath, or an InputStream.

You can also specify which TLS protocols and ciphers you would like to use.

public class HttpsWithCert {
    public static void main(String[] args) {

        HttpsConfigBuilder httpsConfig = HttpsConfigBuilder.httpsConfig()
            .withKeystoreType("JKS")
            .withKeystorePassword("Very5ecure")
            .withKeyPassword("ActuallyNotSecure")
            .withKeystore(new File("src/main/java/io/muserver/docs/samples/HttpsCert.jks"))
            .withProtocols("TLSv1.2", "TLSv1.3")
            .withCipherFilter(new SSLCipherFilter() {
                public List<String> selectCiphers(Set<String> supportedCiphers, List<String> defaultCiphers) {
                    return defaultCiphers;
                }
            });

        MuServer server = muServer()
            .withHttpsPort(10443)
            .withHttpsConfig(httpsConfig)
            .addHandler(Method.GET, "/", (req, resp, pp) -> resp.write("This is HTTPS"))
            .start();

        System.out.println("Server started at " + server.uri());

    }
}
(see full file)

Changing certs at runtime

To perform a hot change of an HTTPS certificate, construct a new HttpsConfigBuilder and change it using the MuServer server reference:

server.changeHttpsConfig(httpsConfig);

HSTS Handler

HTTP Strict-Transport-Security instructs browsers to only access your website via HTTPS. This is achieved by setting the Strict-Transport-Security response header.

For convenience, the HttpsRedirectorBuilder class can be used to generate a handler to do this for you. Just tell it the HTTPS port to redirect to, and the amount of time the directive is valid for.

public class HSTSExample {
    public static void main(String[] args) {
        MuServer server = muServer()
            .withHttpPort(20080)
            .withHttpsPort(20443)
            .addHandler(
                HttpsRedirectorBuilder.toHttpsPort(20443)
                    .withHSTSExpireTime(365, TimeUnit.DAYS)
                    .includeSubDomains(true)
            )
            .addHandler(Method.GET, "/", (req, resp, pp) -> resp.write("This is HTTPS"))
            .start();
        System.out.println("Server started at " + server.httpUri());
    }
}
(see full file)

If you omit the HSTS config on this builder, it will redirect to HTTPS without setting HSTS headers.

Let's Encrypt integration

Getting free, automatically renewed certificates with Let's Encrypt and other ACME-based Certificate Authorities is even simpler than providing your own SSL config.

See the Let's Encrypt integration documentation for details.

Better TLS with OpenSSL

Mu Server is based on Netty, and Netty recommends that OpenSSL is used due to it being faster and having JDK-independent ciphers. In order to support OpenSSL, please follow the netty-tcnative wiki page.

If running on a modern Linux distribution, it may be enough to add the following dependency:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-tcnative-boringssl-static</artifactId>
    <version>2.0.65.Final</version>
    <classifier>linux-x86_64</classifier>
    <scope>runtime</scope>
</dependency>

Accessing SSL Settings

The sslInfo() method on the MuServer class returns an SSLInfo object that can be used to get the actual values your server supports. In a handler, this can be accessed with request.server().sslInfo() and the following table shows the settings from this website:

Property Value
sslInfo.providerName() OpenSSL
sslInfo.protocols() SSLv2Hello, TLSv1.2, TLSv1.3
sslInfo.ciphers() TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256
sslInfo.certificates()
  • CN=muserver.io - from Tue Sep 24 13:11:49 UTC 2024 to Mon Dec 23 13:11:48 UTC 2024
  • CN=R10, O=Let's Encrypt, C=US - from Wed Mar 13 00:00:00 UTC 2024 to Fri Mar 12 23:59:59 UTC 2027

To see which TLS versions and ciphers your users are connecting with, you can refer to the connection info exposed by Mu Server.

To see an SSL report for Mu Server using OpenSSL, go to the SSL Labs SSL Report for muserver.io.

Mutual TLS with Client certificates

To allow authentication with client certificates, create a Trust Manager and pass it to withClientCertificateTrustManager(TrustManager) on the HttpsConfigBuilder. You can then access the client cert (if sent and valid) with the MuRequest.connnection().clientCertificate() method from any handler.

See the Mutual TLS documentation for a full example.