Recommended Apache Configuration
This page describes the recommended OS-provided Apache reverse proxy configuration for MTG services, with TLS 1.3 support and one public hostname per service group. For the package replacement procedure, see Migrating from MTG-Apache2 to the OS Apache Package.
|
The customer is responsible for configuring and operating the reverse proxy, including its security, maintenance, updates and monitoring. Moving to the OS-provided Apache package places responsibility for this layer with the customer rather than MTG. The configuration on this page is a recommended baseline covering the reverse proxy requirements of the MTG services described here, including TLS 1.3 and client certificate authentication where needed. It is not a universal configuration or a prescribed solution for every deployment. The best setup depends on your use case, deployed services, network architecture and security requirements. Adapt and validate the recommendations for your environment before putting them into operation. |
See Supported Platforms for the supported operating system releases. Verify the configuration against the Apache/OpenSSL packages and crypto policy shipped with your supported OS release.
| The CARA configuration and authentication model on this page apply exclusively to CARA 3.x. |
Virtual Host Configuration Changes with TLS 1.3
Some legacy configurations publish several services under one hostname and change SSLVerifyClient inside <Location>
blocks.
For example, the legacy virtual host requested client certificates optionally, /clm-ui/ disabled client certificate
authentication and /cara-admin/secure required it.
Changes to client certificate requirements after the initial handshake can trigger another certificate exchange.
With TLS 1.2, Apache can use handshake renegotiation to do this after reading the requested HTTP path.
TLS 1.3 removes handshake renegotiation.
Its alternative, post-handshake authentication (PHA), requires client support and cannot be assumed to work across
browsers, enrollment clients and other TLS stacks.
With a per-location certificate request, clients that do not offer PHA can receive HTTP 403 with Apache error AH10158
, even on a path intended to allow anonymous access.
HTTP/2 prohibits TLS 1.3 post-handshake authentication altogether, as specified by
RFC 8740.
Set SSLVerifyClient at virtual host level so Apache requests the certificate during the initial TLS handshake.
Separate services with different certificate request policies by hostname, allowing SNI to select the policy before the
HTTP path is available.
For details on the directive’s scope, see the
Apache mod_ssl documentation.
|
If mTLS client authentication is not used, no additional virtual hosts are required for TLS 1.3.
You can retain the existing hostnames and path-based proxy layout with |
Clients must connect to the mTLS hostname directly.
A redirect from an old hostname happens after its TLS handshake and does not repair a failed certificate exchange.
Use distinct names rather than creating multiple virtual hosts with the same ServerName for different paths.
Service-per-Host Baseline
The example uses node01.example.com as the node name and the following service names.
All names may resolve to the same Apache instance or load balancer.
| These configuration examples cover the ERS suite. Configure only the components used in your deployment. |
| Public hostname | Services and paths | Client certificate policy |
|---|---|---|
|
CLM API |
Always |
|
Keycloak |
|
|
EST |
|
|
CARA 3.x web services |
Always |
|
KMS |
Always |
CLM, CARA 3.x and KMS always use SSLVerifyClient none on their Apache virtual hosts.
Authentication for these services is handled by Keycloak, including X.509 login through the authentication hostname
when configured.
Their Apache virtual hosts do not request client certificates.
EST is the exception: the standard supports both HTTP Basic authentication and mTLS client authentication.
Its Apache virtual host uses SSLVerifyClient optional so clients can authenticate with HTTP Basic credentials
without presenting a certificate, or present a client certificate for mTLS.
Authentication for EST is handled by mtg-est-server, not Keycloak.
Anonymous operations such as retrieving CA certificates remain available where permitted by the EST server.
optional requests a certificate from every connection to that hostname.
It permits a client to send no certificate, but rejects a presented certificate that cannot be validated against the
configured client CA trust.
The application still decides whether a particular operation requires an authenticated identity.
Do not use optional_no_ca as a substitute for verified client authentication.
Do not set SSLVerifyClient require on the EST virtual host: doing so would prevent HTTP Basic authentication
without a client certificate and block anonymous operations.
|
DNS, Certificates and Application URLs
Create DNS records for the chosen public service names. The server certificate must cover every name it serves through its subject alternative names (SANs). The examples use a shared full-chain certificate named after the node, containing all five service names as SANs; separate certificates per service are also possible.
Update application public URLs, Keycloak frontend and issuer settings, allowed redirect URIs, browser integrations and enrollment client endpoints to match the chosen names. Check the URLs returned by discovery endpoints and redirects after the change. Retain old HTTP revocation URLs already embedded in certificates, even when other services move to new names.
OS-Specific Paths and Modules
| Setting | RHEL | Ubuntu | SUSE |
|---|---|---|---|
Service |
|
|
|
Main configuration |
|
|
|
Virtual host files |
|
|
|
Server certificates and client CA bundle |
|
|
|
Private keys |
|
|
|
Logs |
|
|
|
Stapling cache directory |
|
|
|
Enable ssl, socache_shmcb, headers, proxy, proxy_http, rewrite and alias.
Enable http2 for HTTP/2 support and proxy_ajp if deploying the KMS AJP example.
Keep authz_core loaded for the access rules.
Load modules before deploying configuration that uses their directives.
On Ubuntu:
a2enmod ssl socache_shmcb headers proxy proxy_http rewrite alias http2
# Only for the KMS AJP configuration:
a2enmod proxy_ajp
Enable each deployed file with a2ensite, for example a2ensite clm.node01.example.com.conf.
Enable 000-default.conf and 10-mtg_ssl_hardening.conf in the same way when using the configuration examples.
On RHEL, install mod_ssl and mod_http2 alongside httpd and check module loading under
/etc/httpd/conf.modules.d/.
On SUSE, enable the same required modules with a2enmod, select the event MPM in /etc/sysconfig/apache2
(APACHE_MPM="event") and enable HTTPS with a2enflag SSL.
Use the distribution’s module binaries and listener configuration.
Do not copy the legacy LoadModule paths, ServerRoot, PID settings or /opt/apache2 paths into the new main
configuration.
Replace legacy Order and Deny access rules with Apache 2.4 Require rules while preserving their intended access
restrictions.
Listeners and Default Virtual Host
Configure ports 80 and 443 once per Apache instance.
Do not copy Listen 443 into every service file.
On RHEL, the example ssl.conf retains the server-wide SSL directives and listener while removing the stock
default:443 virtual host.
On Ubuntu and SUSE, retain the distribution’s listener configuration and disable unused stock sites.
Load 000-default.conf before the service virtual hosts.
It returns HTTP 421 for unconfigured names, including the bare node name, while still serving HTTP-01 challenges on
port 80.
A TLS handshake must complete before an HTTPS error response can be returned, so it also needs a valid server
certificate.
Remove or disable stock welcome pages and directory listings that would otherwise remain accessible.
TLS Policy
The server-wide configuration enables TLS 1.3 and TLS 1.2, disables TLS 1.0 and TLS 1.1 and configures
separate cipher lists for TLS 1.2 and TLS 1.3.
Remove conflicting per-virtual-host legacy settings such as SSLProtocol TLSv1.2 so the shared policy takes effect.
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-CCM:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
Protocols h2 http/1.1
The TLS 1.3 Brainpool groups in the configuration require OpenSSL 3.2 or newer. On OpenSSL versions older than 3.2, including OpenSSL 3.0 shipped with Ubuntu 24.04, remove the TLS 1.3 Brainpool names and use the following variant:
SSLOpenSSLConfCmd Groups secp256r1:secp384r1:secp521r1:brainpoolP256r1:brainpoolP384r1:brainpoolP512r1
Unknown group names can prevent Apache from starting.
Verify support in the Apache-linked OpenSSL library and test actual negotiated protocols and ciphers against the OS
crypto policy.
The examples leave handshake signature algorithms at OpenSSL’s defaults.
Do not carry over restrictive legacy SignatureAlgorithms settings without testing server and client certificates,
including RSA clients' ability to produce TLS 1.3 RSA-PSS handshake signatures.
The configuration enables server certificate OCSP stapling.
Adapt SSLStaplingCache to the OS-specific runtime directory and ensure the server certificate has a usable OCSP
responder and Apache can reach it.
Client certificate OCSP validation (SSLOCSPEnable) is a separate setting.
Preserve the installation’s existing client revocation policy; the example virtual hosts do not enable that policy
automatically.
Client Certificate Forwarding and Backend Trust
The EST and authentication virtual hosts configure the following at virtual host level:
SSLVerifyClient optional
SSLVerifyDepth 2
SSLCACertificateFile /etc/pki/tls/certs/trusted-ca.pem
RequestHeader unset X-SSL-Client-Verify
RequestHeader unset X-SSL-Client-S-DN
RequestHeader unset x-ssl-client-cert
RequestHeader set X-SSL-Client-Verify "%{SSL_CLIENT_VERIFY}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set X-SSL-Client-S-DN "%{SSL_CLIENT_S_DN}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set x-ssl-client-cert "%{SSL_CLIENT_CERT}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
Adapt the CA bundle path and verification depth to the deployed client certificate hierarchy. The client CA bundle must trust the issuers of the client certificates, which may differ from the server certificate’s issuers.
Unset incoming certificate headers before setting them from a successfully verified TLS certificate.
The examples consistently use x-ssl-client-cert, matching the header name expected by the MTG applications.
HTTP header names are case-insensitive, as specified by
RFC 9110, Section 5.1.
Apache’s RequestHeader directive also matches header names without regard to case, so the unset rule removes
client-supplied variants of this header before the verified certificate is forwarded.
Strip any additional identity or certificate-chain headers trusted by your backend.
On hosts using SSLVerifyClient none, remove these headers too if the backend could interpret them as an
authenticated identity.
Use the conditional RequestHeader expressions shown above rather than wrapping the forwarding rules in <If> blocks
based on SSL_CLIENT_VERIFY.
Combining per-location authentication with such blocks can cause the certificate headers to be omitted on the first
request of a connection.
For EST over HTTP proxying, enable tomcat.ssl-valve.enabled=true and ensure tomcat.ssl-valve.ssl-client-cert-header
matches the forwarded header.
See MTG EST Configuration.
For Keycloak X.509 login, configure its certificate lookup and authentication flow for the trusted proxy headers.
The example sanitizes incoming forwarding headers and sets X-Forwarded-Proto: https and X-Forwarded-Port: 443;
Keycloak must use the corresponding xforwarded proxy header mode.
Bind backend listeners to loopback when Apache and the applications share a node, or restrict access to the trusted
proxy on separate nodes.
Clients must not be able to bypass Apache and submit trusted certificate headers directly to the backend.
Where SELinux enforces network restrictions, permit the required proxy connections through the applicable policy.
Use setsebool -P httpd_can_network_connect on to permit proxy connections, or configure a local policy that restricts
this permission more narrowly.
Apply the correct file labels to copied certificate material and account for any AppArmor restrictions on SUSE or
Ubuntu.
HTTP Exceptions and Proxy Targets
Every example port-80 virtual host serves ACME HTTP-01 files from /var/www/html/.well-known/acme-challenge/ before
redirecting other traffic to HTTPS.
Create that directory if using this challenge method and update the renewal client’s webroot setting.
The CLM HTTP virtual host also proxies /rev-info to the CARA revocation information service on port 8906 without
redirecting it to HTTPS.
Clients fetching revocation information must not depend on successfully validating the same TLS service first.
The examples use the following backend listeners and context paths:
| Public path | Backend |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Keep more specific proxy mappings before broader ones, such as /auth/health before /auth.
Preserve matching path and trailing slash semantics in ProxyPass and ProxyPassReverse.
Decide whether the Keycloak management health endpoint should be publicly reachable or restricted to monitoring
systems.
For KMS, replace <KMS_AJP_SECRET> and <CRYPTO_API_AJP_SECRET> with the secrets configured on the corresponding AJP
connectors and protect the configuration files.
Keep the KMS UI base URL aligned with /kms-ui.
The PKCS#11 server terminates its own TLS and KMIP uses its own TCP listener; neither is published by these HTTP
virtual hosts.
Backend paths depend on the application version. The CARA examples apply exclusively to CARA 3.x.
A legacy EST deployment may serve /.well-known/est without the /est context prefix. Preserve working backend paths
during a package-only migration, even when moving their public hostname.
|
Configuration Examples
Expand each configuration below to view and copy it. The examples use placeholder names and Red Hat paths. Adapt them using the OS path table and TLS compatibility notes above before enabling them. They are configuration examples, not a complete deployment for every MTG version.
Default virtual host: 000-default.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
<VirtualHost *:80>
ServerName default.invalid
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^ - [R=421,L]
</VirtualHost>
<VirtualHost *:443>
ServerName default.invalid
CustomLog /var/log/httpd/default-access.log combined
ErrorLog /var/log/httpd/default-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient none
RewriteEngine On
RewriteRule ^ - [R=421,L]
</VirtualHost>
Server-wide TLS and HTTP settings: 10-mtg_ssl_hardening.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite TLSv1.3 TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_SHA256
SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES128-CCM:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256
SSLOpenSSLConfCmd Groups secp256r1:secp384r1:secp521r1:brainpoolP256r1tls13:brainpoolP384r1tls13:brainpoolP512r1tls13:brainpoolP256r1:brainpoolP384r1:brainpoolP512r1
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
SSLUseStapling on
SSLStaplingCache "shmcb:/run/httpd/ssl_stapling(32768)"
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
Protocols h2 http/1.1
ServerTokens Prod
ServerSignature Off
TraceEnable Off
<Directory "/var/www/html">
Options -Indexes
</Directory>
Header always set X-Content-Type-Options "nosniff" "expr=-z resp('X-Content-Type-Options')"
Header always set Referrer-Policy "strict-origin-when-cross-origin" "expr=-z resp('Referrer-Policy')"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=()" "expr=-z resp('Permissions-Policy')"
RHEL server-wide SSL settings: ssl.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
Listen 443 https
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout 300
SSLCryptoDevice builtin
CLM and enrollment protocol virtual host: clm.node01.example.com.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
<VirtualHost *:80>
ServerName clm.node01.example.com
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
<Directory "/var/www/html">
Options -Indexes -FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteCond %{REQUEST_URI} !^/rev-info
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
ProxyPreserveHost On
ProxyPass /rev-info http://127.0.0.1:8906/rev-info
ProxyPassReverse /rev-info http://127.0.0.1:8906/rev-info
</VirtualHost>
<VirtualHost *:443>
ServerName clm.node01.example.com
CustomLog /var/log/httpd/clm.node01.example.com-access.log combined
ErrorLog /var/log/httpd/clm.node01.example.com-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient none
RewriteEngine On
RewriteRule ^/?$ https://%{HTTP_HOST}/clm-ui [R=301,L]
ProxyPreserveHost On
ProxyPass /clm-api http://127.0.0.1:8501/clm-api
ProxyPassReverse /clm-api http://127.0.0.1:8501/clm-api
ProxyPass /clm-ui http://127.0.0.1:3000/clm-ui
ProxyPassReverse /clm-ui http://127.0.0.1:3000/clm-ui
ProxyPass /acme http://127.0.0.1:8502/acme
ProxyPassReverse /acme http://127.0.0.1:8502/acme
ProxyPass /cmp http://127.0.0.1:8504/cmp
ProxyPassReverse /cmp http://127.0.0.1:8504/cmp
ProxyPass /aec http://127.0.0.1:8506/aec
ProxyPassReverse /aec http://127.0.0.1:8506/aec
ProxyPass /scep http://127.0.0.1:8507/scep
ProxyPassReverse /scep http://127.0.0.1:8507/scep
</VirtualHost>
Keycloak virtual host: auth.node01.example.com.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
<VirtualHost *:80>
ServerName auth.node01.example.com
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
<Directory "/var/www/html">
Options -Indexes -FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName auth.node01.example.com
CustomLog /var/log/httpd/auth.node01.example.com-access.log combined
ErrorLog /var/log/httpd/auth.node01.example.com-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient optional
SSLVerifyDepth 2
SSLCACertificateFile /etc/pki/tls/certs/trusted-ca.pem
RequestHeader unset X-SSL-Client-Verify
RequestHeader unset X-SSL-Client-S-DN
RequestHeader unset x-ssl-client-cert
RequestHeader set X-SSL-Client-Verify "%{SSL_CLIENT_VERIFY}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set X-SSL-Client-S-DN "%{SSL_CLIENT_S_DN}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set x-ssl-client-cert "%{SSL_CLIENT_CERT}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RewriteEngine On
RewriteRule ^/?$ https://%{HTTP_HOST}/auth [R=301,L]
ProxyPreserveHost On
RequestHeader unset X-Forwarded-For
RequestHeader unset X-Forwarded-Host
RequestHeader unset X-Forwarded-Server
RequestHeader unset Forwarded
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyPass /auth/health http://127.0.0.1:9000/auth/health
ProxyPassReverse /auth/health http://127.0.0.1:9000/auth/health
ProxyPass /auth http://127.0.0.1:8505/auth
ProxyPassReverse /auth http://127.0.0.1:8505/auth
</VirtualHost>
EST virtual host: est.node01.example.com.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
<VirtualHost *:80>
ServerName est.node01.example.com
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
<Directory "/var/www/html">
Options -Indexes -FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName est.node01.example.com
CustomLog /var/log/httpd/est.node01.example.com-access.log combined
ErrorLog /var/log/httpd/est.node01.example.com-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient optional
SSLVerifyDepth 2
SSLCACertificateFile /etc/pki/tls/certs/trusted-ca.pem
RequestHeader unset X-SSL-Client-Verify
RequestHeader unset X-SSL-Client-S-DN
RequestHeader unset x-ssl-client-cert
RequestHeader set X-SSL-Client-Verify "%{SSL_CLIENT_VERIFY}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set X-SSL-Client-S-DN "%{SSL_CLIENT_S_DN}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
RequestHeader set x-ssl-client-cert "%{SSL_CLIENT_CERT}s" "expr=%{SSL_CLIENT_VERIFY} == 'SUCCESS'"
ProxyPreserveHost On
ProxyPass /.well-known/est http://127.0.0.1:8503/est/.well-known/est
ProxyPassReverse /.well-known/est http://127.0.0.1:8503/est/.well-known/est
ProxyPass /est http://127.0.0.1:8503/est
ProxyPassReverse /est http://127.0.0.1:8503/est
</VirtualHost>
CARA 3.x virtual host: cara.node01.example.com.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
# This virtual host applies exclusively to CARA 3.x.
<VirtualHost *:80>
ServerName cara.node01.example.com
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
<Directory "/var/www/html">
Options -Indexes -FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName cara.node01.example.com
CustomLog /var/log/httpd/cara.node01.example.com-access.log combined
ErrorLog /var/log/httpd/cara.node01.example.com-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient none
RewriteEngine On
RewriteRule ^/?$ https://%{HTTP_HOST}/cara-admin-ui [R=301,L]
ProxyPreserveHost On
ProxyPass /cara-ws http://127.0.0.1:8902/cara-ws
ProxyPassReverse /cara-ws http://127.0.0.1:8902/cara-ws
ProxyPass /cara-admin-ui http://127.0.0.1:3007/cara-admin-ui
ProxyPassReverse /cara-admin-ui http://127.0.0.1:3007/cara-admin-ui
</VirtualHost>
KMS virtual host: kms.node01.example.com.conf
# Example configuration with placeholder names and Red Hat paths.
# Adapt using the Recommended Apache Configuration guide before deployment.
<VirtualHost *:80>
ServerName kms.node01.example.com
Alias /.well-known/acme-challenge/ /var/www/html/.well-known/acme-challenge/
<Directory /var/www/html/.well-known/acme-challenge/>
Options None
AllowOverride None
Require all granted
ForceType text/plain
</Directory>
<Directory "/var/www/html">
Options -Indexes -FollowSymLinks
AllowOverride None
</Directory>
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName kms.node01.example.com
CustomLog /var/log/httpd/kms.node01.example.com-access.log combined
ErrorLog /var/log/httpd/kms.node01.example.com-error.log
LogLevel ssl:warn
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/node01.example.com_fullchain.pem
SSLCertificateKeyFile /etc/pki/tls/private/node01.example.com_privkey.pem
SSLVerifyClient none
RewriteEngine On
RewriteRule ^/?$ https://%{HTTP_HOST}/kms-ui [R=301,L]
ProxyPreserveHost On
ProxyPass /kms ajp://127.0.0.1:8801/kms secret=<KMS_AJP_SECRET>
ProxyPassReverse /kms ajp://127.0.0.1:8801/kms
ProxyPass /kms-ui http://127.0.0.1:3005/kms-ui
ProxyPassReverse /kms-ui http://127.0.0.1:3005/kms-ui
ProxyPass /kms-crypto-api ajp://127.0.0.1:8807/kms-crypto-api secret=<CRYPTO_API_AJP_SECRET>
ProxyPassReverse /kms-crypto-api ajp://127.0.0.1:8807/kms-crypto-api
</VirtualHost>
Verification
Run the OS-specific syntax, module and virtual host checks described in the migration guide. Then test every deployed hostname with server certificate verification enabled. For example, replace the example names and CA files below with those for your environment:
openssl s_client -connect clm.node01.example.com:443 \
-servername clm.node01.example.com -tls1_3 \
-CAfile server-ca.pem -verify_hostname clm.node01.example.com \
-verify_return_error </dev/null
curl --cacert server-ca.pem --tlsv1.3 --tls-max 1.3 \
https://est.node01.example.com/.well-known/est/cacerts
curl --cacert server-ca.pem --tlsv1.3 --tls-max 1.3 \
--cert client-fullchain.pem --key client-key.pem \
https://est.node01.example.com/.well-known/est/cacerts
Confirm the negotiated TLS version and certificate verification result.
Repeat the connection check with TLS 1.2 and confirm that TLS 1.0 and TLS 1.1 are refused using a client capable of
offering them.
To test a node before changing DNS, use curl’s --resolve hostname:443:node-ip option, preserving the hostname for SNI
and certificate verification.
The cacerts requests check EST reachability with and without a certificate; they do not prove authenticated
enrollment.
Also perform certificate-authenticated reenrollment and HTTP Basic enrollment with the real client workflows and
test Keycloak X.509 login if enabled.
Verify the first request on a new connection and subsequent requests, without relying on PHA support in a particular
test client.
Check these outcomes:
-
Services configured with
nonework without a client certificate or certificate selection prompt. -
Services configured with
optionalpermit anonymous operations allowed by the application and accept trusted client certificates for authenticated operations. -
A presented untrusted or expired client certificate is rejected.
-
EST accepts HTTP Basic authentication without a client certificate and handles authentication in
mtg-est-server. -
Forged certificate and forwarding headers cannot create an authenticated identity or alter the application’s advertised public URLs.
-
Browser login, APIs and deployed enrollment protocols use the intended names and paths.
-
Existing CRL and OCSP URLs remain reachable over HTTP and ACME HTTP-01 challenges are served without redirection.
-
Unknown hostnames reach the default virtual host rather than an application or distribution welcome page.
-
Renewal installs certificates at the new paths and reloads
httpdorapache2successfully.