The TLS registry is a Quarkus extension centralizing the TLS configuration for the application. You can use the TLS registry to define the configuration in one place and reference it from multiple places in the application.
The TLS extension is automatically added to your project when you use a compatible extension. For example, if your application uses Quarkus REST, gRPC, or reactive routes, the TLS registry is automatically added to your project.
- 1. Using TLS registry
- 2. Referencing a TLS configuration
- 3. Configuring TLS
- 4. The registry API
- 5. Registering a certificate from an extension
- 6. Startup checks
- 7. Reloading certificates
- 8. Using Kubernetes secrets or cert-manager
- 9. Working with OpenShift serving certificates
- 10. Quarkus CLI commands and development CA (Certificate Authority)
- 11. Automatic certificate management with Let’s Encrypt
1. Using TLS registry
To configure a TLS connection, including key and trust stores, use the quarkus.tls.*
properties.
The configuration model always contains a default (unnamed) TLS configuration that is configured by properties directly under quarkus.tls.
.
In addition, it allows you to define separate named configurations; these use quarkus.tls.<name>.
properties.
However, by using the quarkus.tls.<name>.*
properties, you can also have specific configurations for specific connections.
1.1. Configure the HTTP server to use https://
To configure the HTTP server to use HTTPS, you can use the following configuration:
quarkus.tls.key-store.pem.0.cert=server.crt
quarkus.tls.key-store.pem.0.key=server.key
quarkus.http.insecure-requests=disabled # Reject HTTP requests
With a p12
(PKCS12) keystore, use the following configuration:
quarkus.tls.key-store.p12.path=server-keystore.p12
quarkus.tls.key-store.p12.password=secret
quarkus.http.insecure-requests=disabled # Reject HTTP requests
Instead of the default configuration, you can use a named configuration:
quarkus.tls.https.key-store.p12.path=server-keystore.p12
quarkus.tls.https.key-store.p12.password=secret
quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=https
1.2. Configure a client to use https://
As an example to illustrate client configuration, we will use a gRPC client:
quarkus.tls.trust-store.jks.path=grpc-client-truststore.jks
quarkus.tls.trust-store.jks.password=password
quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.use-quarkus-grpc-client=true
1.3. Configuring mTLS
To configure mTLS, set up both the server and the client. Each will require a keystore and a truststore:
-
the server keystore contains the server certificate and private key
-
the client keystore contains the client certificate and private key
-
the server truststore contains the client certificate (to authenticate the client)
-
the client truststore contains the server certificate (to authenticate the server)
quarkus.tls.my-server.key-store.p12.path=target/certs/grpc-keystore.p12
quarkus.tls.my-server.key-store.p12.password=password
quarkus.tls.my-server.trust-store.p12.path=target/certs/grpc-server-truststore.p12
quarkus.tls.my-server.trust-store.p12.password=password
quarkus.tls.my-client.trust-store.p12.path=target/certs/grpc-client-truststore.p12
quarkus.tls.my-client.trust-store.p12.password=password
quarkus.tls.my-client.key-store.p12.path=target/certs/grpc-client-keystore.p12
quarkus.tls.my-client.key-store.p12.password=password
quarkus.grpc.clients.hello.plain-text=false
quarkus.grpc.clients.hello.tls-configuration-name=my-client
quarkus.grpc.clients.hello.use-quarkus-grpc-client=true
quarkus.http.ssl.client-auth=REQUIRED # Enable mTLS
quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=my-server
quarkus.grpc.server.use-separate-server=false
quarkus.grpc.server.plain-text=false
2. Referencing a TLS configuration
After you have configured a named configuration by using quarkus.tls.<name>
, reference it by using the tls-configuration-name
property:
quarkus.tls.https.key-store.p12.path=server-keystore.p12
quarkus.tls.https.key-store.p12.password=secret
quarkus.http.insecure-requests=disabled
quarkus.http.tls-configuration-name=https # Reference the named configuration
3. Configuring TLS
Configuring TLS is mainly about key stores and trust stores.
The configuration depends on the format (pem
, p12
, jks
…).
There are other important properties too.
This section details the various properties you can use to configure TLS.
3.1. Key stores
Key stores are used to store the private key and the certificate. They are mainly used on the server side but can also be used on the client side when mTLS is used.
3.1.1. PEM key stores
Privacy Enhanced Mail (PEM) keystores are composed of a list of pairs of two files: the certificate and the private key.
The certificate file is a .crt
or .pem
file; the private key file is often a .key
file.
To configure a PEM keystore, use the following properties:
quarkus.tls.key-store.pem.a.cert=server.crt
quarkus.tls.key-store.pem.a.key=server.key
quarkus.tls.key-store.pem.b.cert=my-second-cert.crt
quarkus.tls.key-store.pem.b.key=my-second-key.key
In general, you only need a single pair consisting of a certificate and a private key. Even if the certificate is part of a certificate chain, it includes only one private key corresponding to the end-entity certificate.
When multiple pairs are configured, the selection is based on Server Name Indication (SNI). The client sends the server name it wants to connect to, and the server selects the appropriate pair of certificates and private keys. To use this feature, ensure SNI is enabled on both the client and server.
When configuring multiple key or certificate pairs, the order follows the lexicographical order of their names, as demonstrated with a and b in the previous example.
The pair with the lowest lexicographical order is considered the first.
You can define the order by using the quarkus.tls.key-store.pem.order property.
For example, quarkus.tls.key-store.pem.order=b,c,a .
This setting is crucial when using SNI, where the first specified pair is used as the default.
|
3.1.2. PKCS12 key stores
PKCS12 key stores are a single file containing the certificate and the private key.
To configure a PKCS12 keystore, use the following properties:
quarkus.tls.key-store.p12.path=server-keystore.p12
quarkus.tls.key-store.p12.password=secret
.p12
files are password-protected, so you need to provide the password to open the keystore.
These files can include more than one certificate and private key.
If this is the case, take either of the following actions:
-
Provide the alias of the certificate and the private key you want to use.
To configure the alias, use the following properties:
quarkus.tls.key-store.p12.path=server-keystore.p12 quarkus.tls.key-store.p12.password=secret quarkus.tls.key-store.p12.alias=my-alias quarkus.tls.key-store.p12.alias-password=my-alias-password
-
Alternatively, use SNI to select the appropriate certificate and private key. Note that all keys must use the same password.
3.1.3. JKS key stores
JKS key stores are a single file containing the certificate and the private key. Note that the JKS format should be avoided as it is less secure than PKCS12. To configure a JKS keystore, use the following properties:
quarkus.tls.key-store.jks.path=server-keystore.jks
quarkus.tls.key-store.jks.password=secret
.jks
files are password-protected, so you need to provide the password to open the keystore.
Also, they can include more than one certificate and private key.
If this is the case:
-
Provide the alias of the certificate and the private key you want to use.
To configure the alias, use the following properties:
quarkus.tls.key-store.jks.path=server-keystore.jks quarkus.tls.key-store.jks.password=secret quarkus.tls.key-store.jks.alias=my-alias quarkus.tls.key-store.jks.alias-password=my-alias-password
-
Alternatively, use SNI to select the appropriate certificate and private key. Note that all keys must use the same password.
3.1.4. SNI
Server Name Indication (SNI) is a TLS extension allowing a client to specify the hostname it attempts to connect to during the TLS handshake. It enables a server to present different TLS certificates for multiple domains on a single IP address, facilitating secure communication for virtual hosting scenarios.
To enable SNI, use the following property:
quarkus.tls.key-store.sni=true # Disabled by default
With this setting enabled, the client indicates the server name during the TLS handshake, allowing the server to select the appropriate certificate:
-
When configuring the keystore with PEM files, multiple certificate (CRT) and key files must be provided. CRT is a common file extension for X.509 certificate files, typically in PEM (Privacy-Enhanced Mail) format. These files contain the public certificate.
-
When configuring the keystore with a JKS or P12 file, the server selects the appropriate certificate based on the SNI (Server Name Indication) hostname provided by the client during the TLS handshake. The server matches the SNI hostname with the common name (CN) or subject alternative names (SAN) configured in the certificates stored in the keystore. All keystore and alias passwords must be identical, and there is no need to set the alias property.
3.1.5. Credential providers
You can use a credential provider instead of passing the keystore password and alias password in the configuration.
A credential provider offers a way to retrieve the keystore and alias password. Note that the credential provider is only used if the password or alias password is not set in the configuration.
To configure a credential provider, use the following properties:
# The name of the credential bucket in the credentials provider
quarkus.tls.key-store.credentials-provider.name=my-credentials
# The name of the bean providing the credential provider (optional, using the default credential provider if not set)
quarkus.tls.key-store.credentials-provider.bean-name=my-credentials-provider
# The key used to retrieve the keystore password, `password` by default
quarkus.tls.key-store.credentials-provider.password-key=password
# The key used to retrieve the alias password, `alias-password` by default
quarkus.tls.key-store.credentials-provider.alias-password-key=alias-password
The credential provider can only be used with PKCS12 and JKS key stores. |
3.2. Trust stores
Trust stores are used to store the certificates of the trusted parties. In regular TLS, the client uses a truststore to authenticate the server. With mutual TLS (mTLS), both the server and the client use truststores to authenticate each other.
3.2.1. PEM trust stores
PEM trust stores are composed of a list of .crt
or .pem
files.
Each of them contains a certificate.
To configure a PEM truststore, use the following properties:
quarkus.tls.trust-store.pem.certs=ca.crt,ca2.pem
3.2.2. PKCS12 trust stores
PKCS12 trust stores are a single file containing the certificates. You can use the alias to select the appropriate certificate when multiple certificates are included.
To configure a PKCS12 truststore, use the following properties:
quarkus.tls.trust-store.p12.path=client-truststore.p12
quarkus.tls.trust-store.p12.password=password
quarkus.tls.trust-store.p12.alias=my-alias
.p12
files are password-protected, so you need to provide the password to open the truststore.
However, unlike key stores, the alias does not require a password because it contains a public certificate, not a private key.
3.2.3. JKS trust stores
JKS truststores are single files containing multiple certificates. You can use the alias to select the appropriate certificate when multiple certificates are present. However, avoid using the JKS format as it is less secure than PKCS12.
To configure a JKS truststore, use the following properties:
quarkus.tls.trust-store.jks.path=client-truststore.jks
quarkus.tls.trust-store.jks.password=password
quarkus.tls.trust-store.jks.alias=my-alias
.jks
files are password-protected, so you need to provide the password to open the truststore.
However, unlike keystores, the alias does not require a password because it contains a public certificate, not a private key.
3.2.4. Credential providers
Instead of passing the truststore password in the configuration, you can use a credential provider. A credential provider allows you to retrieve passwords and other credentials. Note that the credential provider is used only if the password is not set in the configuration.
To configure a credential provider, use the following properties:
# The name of the credential bucket in the credentials provider
quarkus.tls.trust-store.credentials-provider.name=my-credentials
# The name of the bean providing the credential provider (optional, using the default credential provider if not set)
quarkus.tls.trust-store.credentials-provider.bean-name=my-credentials-provider
# The key used to retrieve the truststore password, `password` by default
quarkus.tls.trust-store.credentials-provider.password-key=password
The credential provider can only be used with PKCS12 and JKS trust stores. |
3.3. Other properties
While key stores and trust stores are the most important properties, there are other properties you can use to configure TLS.
While the following examples use the default configuration, you can use the named configuration by prefixing the properties with the configuration’s name. |
3.3.1. Cipher suites
Cipher suites are the list of ciphers that you can use during the TLS handshake. You can configure the ordered list of enabled cipher suites. If not configured, a reasonable default is selected from the built-in ciphers. However, when specified, your configuration precedes the default suite defined by the SSL engine in use.
To configure the cipher suites, use the following property:
quarkus.tls.cipher-suites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384
3.3.2. TLS protocol versions
The TLS protocol versions are the list of protocols that can be used during the TLS handshake.
Enabled TLS protocol versions are specified as an ordered list separated by commas.
The relevant configuration property is quarkus.tls.protocols
(or quarkus.tls.<name>.protocols
for named TLS configurations).
It defaults to TLSv1.3, TLSv1.2
if not configured.
The supported values are: TLSv1
, TLSv1.1
, TLSv1.2
, TLSv1.3
.
To only enable TLSv1.3
, configure the following property:
quarkus.tls.protocols=TLSv1.3
3.3.3. Handshake timeout
When a TLS connection is established, the handshake phase is the first step. During this phase, the client and server exchange information to establish the connection, typically the cipher suite, the TLS protocol version, the certification validation, and so on.
To configure the timeout for the handshake phase, use the following property:
quarkus.tls.handshake-timeout=10S # Default.
3.3.4. ALPN
Application-Layer Protocol Negotiation (ALPN) is a TLS extension that allows the client and server to negotiate which protocol they will use for communication during the TLS handshake. ALPN enables more efficient communication by allowing the client to indicate its preferred application protocol to the server before establishing the TLS connection.
This helps in scenarios like HTTP/2, where multiple protocols might be available, allowing for faster protocol selection.
ALPN is enabled by default. To disable it, use the following property:
quarkus.tls.alpn=false
3.3.5. Certificate Revocation List (CRL)
A Certificate Revocation List (CRL) is a list of certificates the issuing Certificate Authority (CA) revoked before their scheduled expiration date. When a certificate is compromised, no longer needed, or deemed invalid, the CA adds it to the CRL to inform relying parties not to trust it anymore.
You can configure the CRL with the list of certificate files you do not trust anymore. Two formats are allowed: DER and PKCS#7 (P7B).
-
When using the DER format, you must pass DER-encoded CRLs.
-
When using the PKCS#7 format, you must pass the PKCS#7
SignedData
object, with the only significant field beingcrls
.
To configure the CRL, use the following property:
quarkus.tls.certificate-revocation-list=ca.crl, ca2.crl
3.3.6. Trusting all certificates and hostname verification
These two properties should not be used in production. You can configure your TLS connection to trust all certificates and disable the hostname verification. Note that these are two different processes:
|
To trust all certificates, use the following property:
quarkus.tls.trust-all=true
To disable the hostname verification, use the following property:
quarkus.tls.hostname-verification-algorithm=NONE
3.4. Configuration reference
The following table lists the supported properties:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Configuration property |
Type |
Default |
---|---|---|
boolean |
|
|
list of string |
||
path |
required |
|
string |
||
string |
||
string |
||
string |
||
path |
required |
|
string |
||
string |
||
string |
||
string |
||
Enables Server Name Indication (SNI). Server Name Indication (SNI) is a TLS extension that allows a client to specify the hostname it is attempting to connect to during the TLS handshake. This enables a server to present different SSL certificates for multiple domains on a single IP address, facilitating secure communication for virtual hosting scenarios. With this setting enabled, the client indicate the server name during the TLS handshake, allowing the server to select the right certificate. When configuring the keystore with PEM files, multiple CRT/Key must be given. When configuring the keystore with a JKS or a P12 file, it selects one alias based on the SNI hostname. In this case, all the keystore password and alias password must be the same (configured with the Environment variable: |
boolean |
|
The name of the "credential" bucket (map key → passwords) to retrieve from the A credential provider offers a way to retrieve the key store password as well as alias password. Note that the credential provider is only used if the passwords are not set in the configuration. Environment variable: |
string |
|
The name of the bean providing the credential provider. The name is used to select the credential provider to use. The credential provider must be exposed as a CDI bean and with the If not set, the default credential provider is used. Environment variable: |
string |
|
The key used to retrieve the key store password. If the selected credential provider does not support the key, the password is not retrieved. Otherwise, the retrieved value is used to open the key store. Environment variable: |
string |
|
The key used to retrieve the key store alias password. If the selected credential provider does not contain the key, the alias password is not retrieved. Otherwise, the retrieved value is used to access the alias Environment variable: |
string |
|
list of path |
||
path |
required |
|
string |
||
string |
||
string |
||
path |
required |
|
string |
||
string |
||
string |
||
The name of the "credential" bucket (map key → passwords) to retrieve from the A credential provider offers a way to retrieve the key store password as well as alias password. Note that the credential provider is only used if the passwords are not set in the configuration. Environment variable: |
string |
|
The name of the bean providing the credential provider. The name is used to select the credential provider to use. The credential provider must be exposed as a CDI bean and with the If not set, the default credential provider is used. Environment variable: |
string |
|
The key used to retrieve the trust store password. If the selected credential provider does not contain the configured key, the password is not retrieved. Otherwise, the retrieved value is used to open the trust store. Environment variable: |
string |
|
Sets the ordered list of enabled cipher suites. If none is given, a reasonable default is selected from the built-in ciphers. When suites are set, it takes precedence over the default suite defined by the Environment variable: |
list of string |
|
Sets the ordered list of enabled TLS protocols. If not set, it defaults to Note that setting an empty list, and enabling TLS is invalid. You must at least have one protocol. Also, setting this replaces the default list of protocols. Environment variable: |
list of string |
|
|
||
Enables the Application-Layer Protocol Negotiation (ALPN). Application-Layer Protocol Negotiation is a TLS extension that allows the client and server during the TLS handshake to negotiate which protocol they will use for communication. ALPN enables more efficient communication by allowing the client to indicate its preferred application protocol to the server before the TLS connection is established. This helps in scenarios such as HTTP/2 where multiple protocols may be available, allowing for faster protocol selection. Environment variable: |
boolean |
|
Sets the list of revoked certificates (paths to files). A Certificate Revocation List (CRL) is a list of digital certificates that have been revoked by the issuing Certificate Authority (CA) before their scheduled expiration date. When a certificate is compromised, no longer needed, or deemed invalid for any reason, the CA adds it to the CRL to inform relying parties not to trust the certificate anymore. Two formats are allowed: DER and PKCS#7 (also known as P7B). When using the DER format, you must pass DER-encoded CRLs. When using the PKCS#7 format, you must pass PKCS#7 Environment variable: |
list of path |
|
boolean |
|
|
The hostname verification algorithm to use in case the server’s identity should be checked. Should be If set to If not set, the configured extension decides the default algorithm to use. For example, for HTTP, it will be "HTTPS". For TCP, it can depend on the protocol. Nevertheless, it is recommended to set it to "HTTPS" or "LDAPS". Environment variable: |
string |
|
When configured, the server will reload the certificates (from the file system for example) and fires a This property configures the period to reload the certificates. IF not set, the certificates won’t be reloaded automatically. However, the application can still trigger the reload manually using the The fired event is used to notify the application that the certificates have been updated, and thus proceed with the actual switch of certificates. Environment variable: |
||
path |
required |
|
path |
required |
|
path |
required |
|
path |
required |
|
The order of the key/cert files, based on the names in the By default, Quarkus sorts the key using a lexicographical order. This property allows you to specify the order of the key/cert files. Environment variable: |
list of string |
|
path |
required |
|
string |
||
string |
||
string |
||
string |
||
path |
required |
|
string |
||
string |
||
string |
||
string |
||
Enables Server Name Indication (SNI). Server Name Indication (SNI) is a TLS extension that allows a client to specify the hostname it is attempting to connect to during the TLS handshake. This enables a server to present different SSL certificates for multiple domains on a single IP address, facilitating secure communication for virtual hosting scenarios. With this setting enabled, the client indicate the server name during the TLS handshake, allowing the server to select the right certificate. When configuring the keystore with PEM files, multiple CRT/Key must be given. When configuring the keystore with a JKS or a P12 file, it selects one alias based on the SNI hostname. In this case, all the keystore password and alias password must be the same (configured with the Environment variable: |
boolean |
|
The name of the "credential" bucket (map key → passwords) to retrieve from the A credential provider offers a way to retrieve the key store password as well as alias password. Note that the credential provider is only used if the passwords are not set in the configuration. Environment variable: |
string |
|
The name of the bean providing the credential provider. The name is used to select the credential provider to use. The credential provider must be exposed as a CDI bean and with the If not set, the default credential provider is used. Environment variable: |
string |
|
The key used to retrieve the key store password. If the selected credential provider does not support the key, the password is not retrieved. Otherwise, the retrieved value is used to open the key store. Environment variable: |
string |
|
The key used to retrieve the key store alias password. If the selected credential provider does not contain the key, the alias password is not retrieved. Otherwise, the retrieved value is used to access the alias Environment variable: |
string |
|
list of path |
||
path |
required |
|
string |
||
string |
||
string |
||
path |
required |
|
string |
||
string |
||
string |
||
The name of the "credential" bucket (map key → passwords) to retrieve from the A credential provider offers a way to retrieve the key store password as well as alias password. Note that the credential provider is only used if the passwords are not set in the configuration. Environment variable: |
string |
|
The name of the bean providing the credential provider. The name is used to select the credential provider to use. The credential provider must be exposed as a CDI bean and with the If not set, the default credential provider is used. Environment variable: |
string |
|
The key used to retrieve the trust store password. If the selected credential provider does not contain the configured key, the password is not retrieved. Otherwise, the retrieved value is used to open the trust store. Environment variable: |
string |
|
Sets the ordered list of enabled cipher suites. If none is given, a reasonable default is selected from the built-in ciphers. When suites are set, it takes precedence over the default suite defined by the Environment variable: |
list of string |
|
Sets the ordered list of enabled TLS protocols. If not set, it defaults to Note that setting an empty list, and enabling TLS is invalid. You must at least have one protocol. Also, setting this replaces the default list of protocols. Environment variable: |
list of string |
|
|
||
Enables the Application-Layer Protocol Negotiation (ALPN). Application-Layer Protocol Negotiation is a TLS extension that allows the client and server during the TLS handshake to negotiate which protocol they will use for communication. ALPN enables more efficient communication by allowing the client to indicate its preferred application protocol to the server before the TLS connection is established. This helps in scenarios such as HTTP/2 where multiple protocols may be available, allowing for faster protocol selection. Environment variable: |
boolean |
|
Sets the list of revoked certificates (paths to files). A Certificate Revocation List (CRL) is a list of digital certificates that have been revoked by the issuing Certificate Authority (CA) before their scheduled expiration date. When a certificate is compromised, no longer needed, or deemed invalid for any reason, the CA adds it to the CRL to inform relying parties not to trust the certificate anymore. Two formats are allowed: DER and PKCS#7 (also known as P7B). When using the DER format, you must pass DER-encoded CRLs. When using the PKCS#7 format, you must pass PKCS#7 Environment variable: |
list of path |
|
boolean |
|
|
The hostname verification algorithm to use in case the server’s identity should be checked. Should be If set to If not set, the configured extension decides the default algorithm to use. For example, for HTTP, it will be "HTTPS". For TCP, it can depend on the protocol. Nevertheless, it is recommended to set it to "HTTPS" or "LDAPS". Environment variable: |
string |
|
When configured, the server will reload the certificates (from the file system for example) and fires a This property configures the period to reload the certificates. IF not set, the certificates won’t be reloaded automatically. However, the application can still trigger the reload manually using the The fired event is used to notify the application that the certificates have been updated, and thus proceed with the actual switch of certificates. Environment variable: |
About the Duration format
To write duration values, use the standard You can also use a simplified format, starting with a number:
In other cases, the simplified format is translated to the
|
4. The registry API
While extensions automatically use the TLS registry, you can also access the TLS configuration programmatically through the registry API.
To access the TLS configuration, inject the TlsConfigurationRegistry
bean.
You can retrieve a named TLS configuration by calling get("<NAME>")
or the default configuration by calling getDefault()
.
@Inject
TlsConfigurationRegistry certificates;
// ...
TlsConfiguration def = certificates.getDefault().orElseThrow();
TlsConfiguration named = certificates.get("name").orElseThrow();
//...
The TlsConfiguration
object contains the key stores, trust stores, cipher suites, protocols, and other properties.
It also provides a way to create an SSLContext
from the configuration.
As Vert.x is omnipresent in Quarkus, you can also use the TlsConfiguration
object to configure the Vert.x client or server such as KeyCertOptions
, TrustOptions
, and so on.
5. Registering a certificate from an extension
This section is only for extension developers. An extension can register a certificate in the TLS registry. This is useful when an extension needs to provide a certificate to the application or provides a different format.
To achieve this, the extension processor must produce a TlsCertificateBuildItem
.
A TlsCertificateBuildItem
is composed of a name and a CertificateSupplier
.
TlsCertificateBuildItem item = new TlsCertificateBuildItem("named",
new MyCertificateSupplier());
The certificate supplier is a runtime object generally retrieved by using a recorder method. Here is an example of a certificate supplier:
public class MyCertificateSupplier implements Supplier<TlsConfiguration> {
@Override
public TlsConfiguration get() {
try {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(getClass().getResourceAsStream("target/certs/test-registration-keystore.p12"),
"password".toCharArray());
KeyStore ts = KeyStore.getInstance("PKCS12");
ts.load(getClass().getResourceAsStream("target/certs/test-registration-truststore.p12"),
"password".toCharArray());
return new BaseTlsConfiguration() {
@Override
public KeyStore getKeyStore() {
return ks;
}
@Override
public KeyStore getTrustStore() {
return ts;
}
};
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
6. Startup checks
When the application starts, the TLS registry performs several checks to ensure the configuration is correct:
-
Key stores and trust stores are accessible.
-
Aliases are available and accessible in the key stores and trust stores.
-
Certificates are valid.
-
Cipher suites and protocols are valid.
-
Certificate Revocation Lists (CRLs) are valid.
If any of these checks fail, the application will not start.
7. Reloading certificates
The TlsConfiguration
obtained from the TLSConfigurationRegistry
includes a mechanism for reloading certificates.
The reload
method refreshes the key stores and trust stores, typically by reloading them from the file system.
The reload operation is not automatic and must be triggered manually.
Additionally, the TlsConfiguration implementation must support reloading (which is the case for the configured certificate).
|
The reload
method returns a boolean
indicating whether the reload was successful.
A value of true
means the reload operation was successful, not necessarily that there were updates to the certificates.
After a TlsConfiguration
has been reloaded, servers and clients using this configuration may need to perform specific actions to apply the new certificates.
The recommended approach is to fire a CDI event (CertificateUpdatedEvent
) that servers and clients can listen to and make the necessary changes:
@Inject
TlsConfigurationRegistry registry;
public void reload() {
TlsConfiguration config = registry.get("name").orElseThrow();
if (config.reload()) {
event.fire(new CertificateUpdatedEvent("name", config));
}
}
// In the server or client code
public void onReload(@Observes CertificateUpdatedEvent event) {
if ("name".equals(event.getName())) {
server.updateSSLOptions(event.tlsConfiguration().getSSLOptions());
// Or update the SSLContext.
}
}
These APIs provide a way to implement custom certificate reloading.
7.1. Periodic reloading
The TLS registry includes a built-in mechanism for periodically checking the file system for changes and reloading certificates.
You can configure periodic certificate reloading by using properties.
The reload-period
property specifies the interval for reloading certificates and will emit a CertificateUpdatedEvent
each time certificates are reloaded.
quarkus.tls.reload-period=1h
quarkus.tls.key-store.pem.0.cert=tls.crt
quarkus.tls.key-store.pem.0.key=tls.key
For each named configuration, you can set a specific reload period:
quarkus.tls.http.reload-period=30min
quarkus.tls.http.key-store.pem.0.cert=tls.crt
quarkus.tls.http.key-store.pem.0.key=tls.key
Remember that the impacted server and client may need to listen to the CertificateUpdatedEvent
to apply the new certificates.
This is automatically done for the Quarkus HTTP server, including the management interface if it is enabled.
8. Using Kubernetes secrets or cert-manager
When running in Kubernetes, you can use Kubernetes secrets to store the key stores and trust stores.
8.1. Using Kubernetes secrets
To use Kubernetes secrets, you need to create a secret with the key stores and trust stores. Consider the following secret as an example:
apiVersion: v1
data:
tls.crt: ...
tls.key: ...
kind: Secret
metadata:
name: my-certs
type: kubernetes.io/tls
The easiest way to use these certificates is to mount the secret as a volume in the pod:
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: demo
app.kubernetes.io/version: 1.0.0-SNAPSHOT
app.kubernetes.io/managed-by: quarkus
name: demo
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: demo
app.kubernetes.io/version: 1.0.0-SNAPSHOT
template:
metadata:
labels:
app.kubernetes.io/managed-by: quarkus
app.kubernetes.io/name: demo
app.kubernetes.io/version: 1.0.0-SNAPSHOT
spec:
containers:
- env:
- name: KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
image: ...
imagePullPolicy: IfNotPresent
name: demo
ports:
- containerPort: 8443 # Configure the port to be HTTPS
name: http
protocol: TCP
volumeMounts:
- mountPath: /certs
name: my-volume
volumes:
- name: my-volume
secret:
defaultMode: 0666 # Set the permissions, otherwise the pod may not be able to read the files
optional: false
secretName: my-certs # Reference the secret
Then, you can configure the TLS registry to use the certificates:
# ...
# TLS Registry configuration
%prod.quarkus.tls.http.key-store.pem.0.cert=/certs/tls.crt
%prod.quarkus.tls.http.key-store.pem.0.key=/certs/tls.key
# HTTP server configuration:
%prod.quarkus.http.tls-configuration-name=http
%prod.quarkus.http.insecure-requests=disabled
You can combine this with the periodic reloading to automatically reload the certificates when they change.
8.2. Using cert-manager
When running in Kubernetes, you can use cert-manager to generate and renew certificates automatically. Cert-manager produces a secret containing the keystores and truststores. Configuring the TLS registry is the same as when using Kubernetes secrets. The generated secret includes the following files:
-
tls.crt
for the certificate -
tls.key
for the private key -
ca.crt
for the CA certificate (if needed)
To handle the renewal, you can use the periodic reloading mechanism:
# ...
# TLS Registry configuration
%prod.quarkus.tls.http.key-store.pem.0.cert=/certs/tls.crt
%prod.quarkus.tls.http.key-store.pem.0.key=/certs/tls.key
%prod.quarkus.tls.http.reload-period=24h
# HTTP server configuration:
%prod.quarkus.http.tls-configuration-name=http
%prod.quarkus.http.insecure-requests=disabled
9. Working with OpenShift serving certificates
When running your application in OpenShift, you can leverage the OpenShift serving certificates to generate and renew TLS certificates automatically. The Quarkus TLS registry can use these certificates and Certificate Authority (CA) files to handle HTTPS traffic and validate certificates securely.
9.1. Acquiring a certificate
To have OpenShift generate a certificate, annotate an existing Service object. The generated certificate will be stored in a secret, which you can then mount in your pod.
Consider the following Service example:
---
apiVersion: v1
kind: Service
metadata:
annotations:
service.beta.openshift.io/serving-cert-secret-name: my-tls-secret
labels:
app.kubernetes.io/name: ...
app.kubernetes.io/version: ...
app.kubernetes.io/managed-by: quarkus
name: hero-service
spec:
ports:
- name: http
port: 443
protocol: TCP
targetPort: 8443
selector:
app.kubernetes.io/name: ...
app.kubernetes.io/version: ...
type: ClusterIP
The annotation service.beta.openshift.io/serving-cert-secret-name
instructs OpenShift to generate a certificate and store it in a secret named my-tls-secret
.
To use the stored certificate:
-
Add this annotation to your already running service:
oc annotate service hero-service \ service.beta.openshift.io/serving-cert-secret-name=my-tls-secret
-
Mount the secret as a volume in your pod by updating your Deployment configuration:
apiVersion: apps/v1 kind: Deployment metadata: labels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... name: my-service spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... template: metadata: labels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... spec: volumes: - name: my-tls-secret (1) secret: secretName: my-tls-secret containers: - env: - name: KUBERNETES_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: QUARKUS_TLS_KEY_STORE_PEM_ACME_CERT (2) value: /etc/tls/tls.crt - name: QUARKUS_TLS_KEY_STORE_PEM_ACME_KEY value: /etc/tls/tls.key image: ... imagePullPolicy: Always name: my-service volumeMounts: (3) - name: my-tls-secret mountPath: /etc/tls readOnly: true ports: - containerPort: 8443 (4) name: https protocol: TCP
1 Define a volume to mount the secret. Use the same name as the secret declared above. 2 Set up the keystore with the paths to the certificate and private key. This can be configured using environment variables or configuration files. Here, we use environment variables. OpenShift serving certificates always create the tls.crt
andtls.key
files.3 Mount the secret in the container. Ensure the path matches the one used in the configuration (here /etc/tls
).4 Configure the port to serve HTTPS. By setting the quarkus.tls.key-store.pem.acme.cert
andquarkus.tls.key-store.pem.acme.key
variables (or their environment variable variant as done above), the TLS registry will use the certificate and private key from the secret. This configures the default keystore for the Quarkus HTTP server, allowing it to use the certificate. For information about using this certificate in a named configuration, see Referencing a TLS configuration. -
Deploy your application to use the certificate generated by OpenShift. This will make the service available over HTTPS.
9.2. Trusting the Certificate Authority (CA)
Now that your service uses a certificate issued by OpenShift, configure your client applications to trust this certificate. To do so, create a ConfigMap that holds the CA certificate, and then configure the pod to mount it.
As demonstrated below with a Quarkus REST client, the same principle applies to any client.
-
Start by defining an empty ConfigMap, which will be populated with the CA certificate:
apiVersion: v1 kind: ConfigMap metadata: name: client-tls-config annotations: service.beta.openshift.io/inject-cabundle: "true"
The
service.beta.openshift.io/inject-cabundle
annotation is used to inject the CA certificate into the ConfigMap. Note that the ConfigMap initially has no data — it is empty. During its processing, OpenShift injects the CA certificate into the ConfigMap in theservice-ca.crt
file. -
Mount the ConfigMap by adding a volume and mounting it in your Deployment configuration:
apiVersion: apps/v1 kind: Deployment metadata: name: my-service-client labels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... template: metadata: labels: app.kubernetes.io/name: ... app.kubernetes.io/version: ... spec: containers: - name: my-service-client image: ... ports: - name: http containerPort: 8080 protocol: TCP volumeMounts: (1) - name: my-client-volume mountPath: /deployments/tls volumes: (2) - name: my-client-volume configMap: name: client-tls-config
1 Mount the ConfigMap in the container. Ensure the path matches the one used in the configuration (here /deployments/tls
).2 Define a volume to mount the ConfigMap and reference the ConfigMap that receives the CA certificate. -
Configure the REST client to use this CA certificate.
Consider the following REST client interface:
package org.acme; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; @RegisterRestClient(baseUri = "https://hero-service.cescoffi-dev.svc", configKey = "hero") (1) public interface HeroClient { record Hero (Long id, String name, String otherName, int level, String picture, String powers) { } @GET @Path("/api/heroes/random") Hero getRandomHero(); }
1 Configure the base URI and the configuration key. The name must be in the format <service-name>.<namespace>.svc
; otherwise, the certificate will not be trusted. Ensure that theconfigKey
is also configured. -
Configure the REST client to trust the CA certificate generated by OpenShift:
quarkus.rest-client.hero.tls-configuration-name=my-service-tls (1) quarkus.tls.my-service-tls.trust-store.pem.certs=/deployments/tls/service-ca.crt (2)
1 Configure the hero
REST client with the TLS configuration namedmy-service-tls
.2 Set up the my-service-tls
TLS configuration, specifically the truststore with the CA certificate. Ensure the path matches the one used in the Kubernetes Deployment configuration. The file is always namedservice-ca.crt
.
9.3. Certificate renewal
OpenShift automatically renews the certificates it generates. When the certificate is renewed, the secret is updated with the new certificate and private key.
To ensure your application uses the new certificate, you can leverage the Quarkus TLS registry’s periodic reloading feature.
By setting the reload-period
property, the TLS registry will periodically check the key stores and trust stores for changes and reload them if needed:
quarkus.tls.reload-period=24h
You can also implement a custom mechanism to reload the certificates when the secret is updated. See Reloading certificates for more information.
10. Quarkus CLI commands and development CA (Certificate Authority)
The TLS registry provides CLI commands to generate a development CA and trusted certificates. This avoids having to use self-signed certificates locally.
> quarkus tls
Install and Manage TLS development certificates
Usage: tls [COMMAND]
Commands:
generate-quarkus-ca Generate Quarkus Dev CA certificate and private key.
generate-certificate Generate a TLS certificate with the Quarkus Dev CA if
available.
In most cases, you generate the Quarkus Development CA once and then generate certificates signed by this CA.
The Quarkus Development CA is a Certificate Authority that can be used to sign certificates locally.
It is only valid for development purposes and only trusted on the local machine.
The generated CA is located in $HOME/.quarkus/quarkus-dev-root-ca.pem
, and installed in the system truststore.
10.1. Understanding self-signed versus CA-signed certificates
When developing with TLS, you can use two types of certificates:
-
Self-signed certificate: The certificate is signed by the same entity that uses it. It is not trusted by default. This type of certificate is typically used when a Certificate Authority (CA) is unavailable or you want a simple setup. It is not suitable for production and should only be used for development.
-
CA-signed certificate: The certificate is signed by a Certificate CA, a trusted entity. This certificate is trusted by default and is the standard choice for production environments.
While you can use a self-signed certificate for local development, it has limitations.
Browsers and tools like curl
, wget
, and httpie
typically do not trust self-signed certificates, requiring manual import.
To avoid this issue, you can use a development CA to sign certificates and install the CA in the system truststore. This ensures that the system trusts all certificates signed by the CA.
Quarkus simplifies the generation of a development CA and the certificates that are signed by this CA.
10.2. Generate a development CA
The development CA is a Certificate Authority that can be used to sign certificates locally. Note that the generated CA is only valid for development purposes and can only be trusted on the local machine.
-
Generate a development CA:
quarkus tls generate-ca-certificate --install --renew --truststore (1) (2) (3)
1 --install
installs the CA in the system truststore. Windows, Mac, and Linux (Fedora and Ubuntu) are supported. However, depending on your browser, you might need to import the generated CA manually. Refer to your browser’s documentation for more information. The generated CA is located in$HOME/.quarkus/quarkus-dev-root-ca.pem
.2 --renew
renews the CA if it already exists. When this option is used, the private key is changed, so you need to regenerate the certificates signed by the CA. If the CA expires, it will automatically renew without requiring the--renew
option.3 --truststore
also generates a PKCS12 truststore containing the CA certificate.
When installing the certificate, your system might ask for your password to install the certificate in the system truststore or ask for confirmation in a dialog on Windows. |
On Windows, run as administrator from an elevated terminal to install the CA in the system truststore. |
10.3. Generate a trusted (signed) certificate
After installing the Quarkus Development CA, you can generate a trusted certificate. This certificate will be signed by the Quarkus Development CA and trusted by your system.
quarkus tls generate-certificate --name my-cert
This command generates a certificate signed by the Quarkus Development CA, which your system will trust if properly installed or imported.
The certificate is stored in ./.certs/
.
Two files are generated:
-
$NAME-keystore.p12
: Contains the private key and the certificate. It is password-protected. -
$NAME-truststore.p12
: Contains the CA certificate, which you can use as a truststore, for example, for testing.
Additional options are available:
Usage: tls generate-certificate [-hrV] [-c=<cn>] [-d=<directory>]
-n=<name> [-p=<password>]
Generate a TLS certificate with the Quarkus Dev CA if available.
-c, --cn=<cn> The common name of the certificate. Default is 'localhost'
-d, --directory=<directory>
The directory in which the certificates will be created.
Default is `.certs`
-n, --name=<name> Name of the certificate. It will be used as file name and
alias in the keystore
-p, --password=<password>
The password of the keystore. Default is 'password'
-r, --renew Whether existing certificates will need to be replaced
A .env
file is also generated when generating the certificate, making the Quarkus dev mode aware of these certificates.
So, then, if you run your application in dev mode, it will use these certificates:
./mvnw quarkus:dev
...
INFO [io.quarkus] (Quarkus Main Thread) demo 1.0.0-SNAPSHOT on JVM (powered by Quarkus 999-SNAPSHOT) started in 1.286s. Listening on: http://localhost:8080 and https://localhost:8443
Now, you can open the Dev UI using HTTPS: https://localhost:8443/q/dev
or issue a request using curl
:
curl https://localhost:8443/hello
Hello from Quarkus REST%
A self-signed certificate is generated if the Quarkus Development CA is not installed. |
10.4. Generating a self-signed certificate
Even if the Quarkus Development CA is installed, you can generate a self-signed certificate:
quarkus tls generate-certificate --name my-cert --self-signed
This generates a self-signed certificate that the Quarkus Development CA does not sign.
10.5. Uninstalling the Quarkus Development CA
Uninstalling the Quarkus Development CA from your system depends on your OS.
10.5.1. Deleting the CA certificate on Windows
To delete the CA certificate on Windows, use the following commands from a Powershell terminal with administrator rights:
# First, we need to identify the serial number of the CA certificate
> certutil -store -user Root
root "Trusted Root Certification Authorities"
================ Certificate 0 ================
Serial Number: 019036d564c8
Issuer: O=Quarkus, CN=quarkus-dev-root-ca # <-That's the CA, copy the Serial Number (the line above)
NotBefore: 6/19/2024 11:07 AM
NotAfter: 6/20/2025 11:07 AM
Subject: C=Cloud, S=world, L=home, OU=Quarkus Dev, O=Quarkus Dev, CN=quarkus-dev-root-ca
Signature matches Public Key
Non-root Certificate uses same Public Key as Issuer
Cert Hash(sha1): 3679bc95b613a2112a3d3256fe8321b6eccce720
No key provider information
Cannot find the certificate and private key for decryption.
CertUtil: -store command completed successfully.
> certutil -delstore -user -v Root $Serial_Number
Replace $Serial_Number
with the serial number of the CA certificate.
10.5.2. Deleting the CA certificate on Linux
On Fedora, you can use the following command:
sudo rm /etc/pki/ca-trust/source/anchors/quarkus-dev-root-ca.pem
sudo update-ca-trust
On Ubuntu, you can use the following command:
sudo rm /usr/local/share/ca-certificates/quarkus-dev-root-ca.pem
sudo update-ca-certificates
11. Automatic certificate management with Let’s Encrypt
Let’s Encrypt is a free, automated certificate authority provided by Internet Security Research Group.
Let’s Encrypt uses Automated certificate management environment (ACME) protocol to support automatic certificate issuance and renewal. To learn more about Let’s Encrypt and ACME, see Let’s Encrypt documentation.
The TLS registry extension allows a CLI ACME client to issue and renew Let’s Encrypt certificates. Your application uses this TLS registry extension to resolve ACME protocol challenges.
Follow the steps below to have your Quarkus application prepared and automatically updated with new and renewed Let’s Encrypt certificates.
11.1. Prerequisites
Ensure that a fully resolvable DNS domain name is available that you can use to access your application. You can use this domain name to create a Let’s Encrypt account and support Let’s Encrypt ACME challenges to prove that you own this domain. You can use ngrok to start experimenting with the Quarkus Let’s Encrypt ACME feature; for more information, see the Use ngrok for testing section below.
Your Quarkus HTTPS application must use a build-time property to enable a Let’s Encrypt ACME challenge route:
quarkus.tls.lets-encrypt.enabled=true
The TLS registry can manage the challenge process from either the main HTTP interface or the management interface. Using a management interface is strongly recommended to let Quarkus deal with ACME challenge configuration separately from the main application’s deployment and security requirements:
quarkus.tls.lets-encrypt.enabled=true
quarkus.management.enabled=true
Port 80
The Let’s Encrypt ACME challenge requires that the application is reachable on port We also recommend setting
|
The challenge is served from the primary HTTP interface (accessible from your DNS domain name).
Do not start your application yet. |
11.2. Application preparation
Before you request a Let’s Encrypt certificate, you must run the TLS registry Let’s Encrypt CLI prepare
command to prepare your application:
quarkus tls lets-encrypt prepare --domain=<domain-dns-name>
Make sure you run a prepare command in the root directory of your application. |
The prepare
command does the following:
-
Creates a
.letsencrypt
folder in your application’s root directory -
Creates a self-signed domain certificate and private key for your application configured in the previous Prerequisites step to be able to start and accept HTTPS requests
-
Creates a
.env
configuration file in your application’s root directory and configures the application to use the self-signed domain certificate and private key (until we get the Let’s Encrypt certificate)
The following snippet shows an example of the generated .env
file:
quarkus.tls.key-store.pem.acme.cert=.letsencrypt/lets-encrypt.crt
quarkus.tls.key-store.pem.acme.key=.letsencrypt/lets-encrypt.key
The .env file does not contain the quarkus.tls.lets-encrypt.enabled and quarkus.management.enabled properties as they are build-time properties that require a rebuild of the application.
|
11.3. Start your application
You can start your application:
java -jar quarkus-run.jar
Access your application endpoint by using https://your-domain-name:8443/
; for example, https://your-domain-name:8443/hello
, and accept a self-signed certificate in the browser.
Next, keep the application running and request your first Let’s Encrypt certificate.
11.4. Issue certificate
From the application directory, run the issue-certificate
command to acquire your first Let’s Encrypt certificate:
quarkus tls lets-encrypt issue-certificate \
--domain=<domain-dns-name> \ (1)
--email=<your contact email> \ (2)
--management-url=https://localhost:9000 (3)
1 | Set your domain name. |
2 | Provide your contact email address that Let’s Encrypt can use to contact you in case of any issues with your Let’s Encrypt account. |
3 | Set your application management URL, which you can use to handle ACME challenges.
Use https://localhost:8443/ if you choose not to enable a management router in the Prerequisites step. |
During the processing of the issue-certificate
command, the TLS registry CLI performs the following tasks:
-
Checks if the application is prepared to serve the challenge.
-
Creates and records Let’s Encrypt account information.
-
Issues a Let’s Encrypt certificate request.
-
Interacts with the Quarkus application to resolve ACME challenges.
Once the Let’s Encrypt certificate chain and private key have been successfully acquired, they are converted to PEM format and copied to your application’s .letsencrypt
folder.
The TLS registry is informed that a new certificate and private key are ready and reloads them automatically.
Now, access your application’s endpoint using https://your-domain-name:8443/
again.
Confirm in the browser that the Let’s Encrypt certificate authority is now signing your domain certificate.
Note that currently, the issue-certificate
command implicitly creates a Let’s Encrypt account to make it easy for users to get started with the ACME protocol.
Support for the Let’s Encrypt account management will evolve further.
11.5. Renew certificate
Renewing certificates is similar to issuing the first certificate, but it requires an existing account created during the Issue certificate step.
Run the following command to renew your Let’s Encrypt certificate:
quarkus tls lets-encrypt renew-certificate \
--domain=<domain-dns-name> (1)
1 | Set your domain name. |
During this command, TLS registry CLI reads a Let’s Encrypt account information recorded during the Issue certificate step, issues a Let’s Encrypt certificate request, and communicates with a Quarkus application to have ACME challenges resolved.
Once the Let’s Encrypt certificate chain and private key have been successfully renewed, they are converted to PEM format and copied to your application’s .letsencrypt
folder.
The TLS registry is notified when a new certificate and private key are ready, and it automatically reloads them.
11.6. Use ngrok for testing
ngrok can be used to provide a secure HTTPS tunnel to your application running on localhost, and make it easy to test HTTPS based applications.
ngrok provides a simplified way of getting started with the Quarkus Let’s Encrypt ACME feature.
The first thing you have to do with ngrok is to ask it to reserve a domain. You can use Quarkiverse ngrok in dev mode or reserve it directly in the ngrok dashboard.
Unfortunately, you cannot use your ngrok domain to test the Quarkus Let’s Encrypt ACME feature immediately. This is because ngrok itself uses Let’s Encrypt and intercepts ACME challenges that are meant to be handled by the Quarkus application instead.
Therefore, remove the ngrok Let’s Encrypt certificate policy from your ngrok domain:
ngrok api --api-key <YOUR-API-KEY> reserved-domains delete-certificate-management-policy <YOUR-RESERVED-DOMAIN-ID>
YOUR-RESERVED-DOMAIN-ID
is your reserved domain’s id which starts from rd_
, you can find it in the ngrok dashboard domains section.
Now, because ngrok only forwards ACME challenges over HTTP, start ngrok as follows:
ngrok http --domain <YOUR-NGROK-DOMAIN> 8080 --scheme http (1)
1 | 8080 is the localhost HTTP port your application is listening on.
Note that the application will be accessible from http://YOUR-NGROK-DOMAIN on port 80 but redirected to your local machine on port 8080 . |
You can now test the Quarkus Let’s Encrypt ACME feature from your local machine.