SSL/TLS configuration
Encrypt all API and Dashboard traffic, with your own certificate or a generated one.
Every part of a Zato environment that takes traffic has a TLS port next to its plain-text one - the API load balancer listens on 11224 next to 11223, the Dashboard on 8184 next to 8183, and the OpenAPI console on 8186 next to 8185, with the console's two ports changeable through Zato_Port_OpenAPI_Console and Zato_Port_OpenAPI_Console_SSL. All the TLS ports serve the same certificate: your own zato.pem if you mount one, or a certificate that the container generates on startup.
Publish 8184 and 11224, do not publish 8183 and 11223 - see Disable the plain-text ports.
Use your own SSL certificate
Create a PEM file called zato.pem whose contents are the concatenation of the server's certificate, any intermediate CA certificates and the private key, in that order. If your CA has no intermediate certificates, concatenate only the server's certificate and the private key:
-----BEGIN CERTIFICATE-----
MIIFeTCCA2GgAwIBAgIUd/cKqWLuUNvn1
...
19f67nsJo8Cd6ESCTPFjQ/eX91jl+y7==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIJQgIBADANBgkqhkiG9w0BAQEFAA3gk
...
JScexp8NvHy850wldVG01wtYNdg37rg==
-----END PRIVATE KEY-----
Mount the file at /opt/hot-deploy/ssl/zato.pem in your startup scripts:
Make sure that the mounted file is owned by the user zato inside the container, not by root. Zato picks the certificate up automatically and port 11224 serves it with no further steps. To reach the Dashboard on port 8184 under a custom domain, additionally set the CSRF trusted origins.
Set CSRF trusted origins for the Dashboard
With your own certificate and a custom domain name, set the Zato_Dashboard_CSRF_Trusted_Origins environment variable so that the Dashboard accepts SSL requests for that domain. Without the variable, the Dashboard replies with "CSRF verification failed. Request aborted." when you access it over HTTPS on port 8184.
For instance, if your certificate uses CN=my.dashboard and the Dashboard's address is https://my.dashboard:8184, export:
docker run \
-e Zato_Dashboard_CSRF_Trusted_Origins="https://my.dashboard:8184" \
--mount type=bind,source=/path/to/zato.pem,target=/opt/hot-deploy/ssl/zato.pem \
zatosource/zato-4.1
Require client certificates
Port 11224 can also verify the certificates that API clients present - this is the transport behind the mTLS security definitions that channels use.
Mount the CA that signs your clients' certificates as client-ca.pem:
When the file is present, port 11224 requests a client certificate during the handshake and verifies it against that CA. The certificate is optional by default - clients without one still connect, and each channel enforces its own mTLS definition.
To reject any client without a valid certificate at the handshake itself, set Zato_SSL_Client_Verify=required and do not publish 11223:
docker run \
-e Zato_SSL_Client_Verify=required \
--mount type=bind,source=/path/to/client-ca.pem,target=/opt/hot-deploy/ssl/client-ca.pem \
zatosource/zato-4.1
Which client may call which channel is then decided by the channels' mTLS security definitions.
To accept certificates from more than one CA, concatenate the CA certificates into the one client-ca.pem file.
While client-ca.pem is mounted, port 11554 - the TLS port for HL7 MLLP - verifies the certificates of connecting senders against the same CA. Plain MLLP on port 11553 is unaffected.
The client CA file does not change the main server certificate - zato.pem or the generated certificate keeps serving the server side of the handshake, and the client CA file only adds the verification of clients.
Trust custom Certificate Authorities
If your backend APIs use certificates signed by a private Certificate Authority, Zato needs to trust that CA before it can call them - a common setup in enterprises with internal PKI.
Place the CA certificate in PEM format, for example my-ca.crt, on your host system and mount it under /usr/local/share/ca-certificates/ inside the container:
Then set the Zato_Update_CA_Certificates environment variable to True:
To trust more than one CA, mount each certificate under /usr/local/share/ca-certificates/ with a different filename - the container adds every certificate from that directory to the system trust store when Zato_Update_CA_Certificates=True.
Disable the plain-text ports
Publish 8184 and 11224, do not publish 8183 and 11223:
docker run \
-p 8183:8183 \ # Remove this line
-p 8184:8184 \
-p 11223:11223 \ # Remove this line
-p 11224:11224 \
zatosource/zato-4.1
With only 8184 and 11224 published, the Dashboard and your APIs accept SSL connections alone.
Generated certificates and SSL variables
Without a zato.pem file, Zato generates a self-signed certificate on startup and saves it to /opt/hot-deploy/ssl/auto.pem inside the container - each container generates its own certificate and private key on each start.
The following variables configure SSL behavior. Variables marked "Yes" in the "Auto-gen only" column apply only to generated certificates - Zato ignores them when you mount your own zato.pem. The other variables apply to all SSL connections regardless of where the certificate comes from.
| Variable | Default | Auto-gen only | Description |
|---|---|---|---|
| Zato_SSL_Subject | /C=US/ST=State/L=City/O=Organization/CN=localhost | Yes | Certificate subject - the server's DNS name or IP |
| Zato_SSL_Subject_Alt_Name | subjectAltName=DNS:localhost,IP:127.0.0.1 | Yes | Extra DNS names and IPs on the certificate |
| Zato_SSL_Cert_Days | 3650 | Yes | Validity period in days |
| Zato_SSL_Key_Algorithm | ecdsa | Yes | Key algorithm, ecdsa or rsa |
| Zato_SSL_Key_Size | 4096 | Yes | Key size when the algorithm is RSA |
| Zato_SSL_Protocols | (empty) | --- | Minimum protocol, TLSv1.2 or TLSv1.3 |
| Zato_SSL_Ciphers | (empty) | --- | Allowed cipher suites |
| Zato_SSL_DH_Params | (empty) | --- | Path to Diffie-Hellman parameters file |
| Zato_SSL_Extra_Options | (empty) | --- | Extra HAProxy SSL options, such as ALPN |
| Zato_SSL_Client_Verify | optional | --- | Set to required to reject clients without a valid certificate at the handshake - applies when client-ca.pem is mounted |
| Zato_Update_CA_Certificates | False | --- | Set to True to add the certificates from /usr/local/share/ca-certificates/ to the system trust store |
A generated certificate with a custom subject, extra names and a one-year lifetime:
docker run \
-e Zato_SSL_Subject="/C=GB/ST=London/L=London/O=MyCompany/CN=api.mycompany.com" \
-e Zato_SSL_Subject_Alt_Name="subjectAltName=DNS:api.example.com,IP:192.168.1.100" \
-e Zato_SSL_Cert_Days=365 \
zatosource/zato-4.1
Verify and rotate certificates
Before trusting a configuration, look at what the port really presents:
Three parts of the output are worth reading:
- The certificate chain, and whether the CA that issued it is one that your clients trust
Verify return code: 0 (ok), or the reason it is not- The negotiated protocol and cipher
To see the expiry date alone:
openssl s_client -connect api.example.com:11224 </dev/null 2>/dev/null | openssl x509 -noout -dates
A certificate that expires stops the environment's TLS traffic, and the expiry date is known in advance - rotate the certificate before that date arrives:
- Obtain the new certificate and key, and concatenate them into a new
zato.pem, in the same order as in the original file. - Replace the mounted
zato.pemwith the new file. - Restart the container - see starting and stopping servers.
- Confirm with
openssl s_clientthat the port serves the new dates.
See also
| Page | What it covers |
|---|---|
| Ports and network | Publish 8184 and 11224, do not publish 8183 and 11223 |
| Environment variables | The Zato_SSL_* family in the full reference |
| mTLS | Per-channel enforcement of the client certificates that port 11224 verifies |