Certificates and TLS

Does the DataMind Installer terminate TLS?

No. The DataMind Installer owns no certificates and terminates no TLS. It publishes plain HTTP on its configured port and expects to be reached over a management network or a tunnel, not over the public internet.

There is no certificate variable in the Installer's environment, no certificate path constant in its code, no ACME or renewal logic, and no HTTPS listener. Its content-security policy deliberately does not force an insecure request upgrade, which confirms the interface is served as plain HTTP. Its container healthcheck is a plain http://localhost:<port>/api/health.

My certificate expired and I need to replace it — what do I run?

There is no Installer command for this, because the certificate is not the Installer's. Replace the certificate files at the paths your deployment configuration points to, then recreate the service that serves TLS. That service belongs to the DataMind OS stack, not to the Installer, and the Installer participates only in holding the two path values and in recreating the service for you.

The honest procedure is three steps, and none of them is an Installer command:

  1. Obtain the new certificate and key from your CA or issuing process, and place the files on the host at the paths the deployment already points to.
  2. Verify the replacement before you switch to it — chain, expiry, key match and the served name. See the verification questions below.
  3. Recreate the service that terminates TLS, so it picks up the new files. In the interface this is Apply changes; the Installer will list the service as stale if you also changed a configuration value.
Important

Do not look for a renewal or reload command in the Installer. None exists. If a page in this documentation appears to give you one, it is wrong — report it.

Which component terminates TLS in a DataMind OS deployment?

The deployment's own edge service — not the Installer. The DataMind OS stack includes an OpenResty edge that serves the interface and checks request origins against the configured platform origin.

You will not find its definition in the Installer's repository, because the Installer downloads the deployment's compose file at install time rather than shipping it. That file is the authority on which service mounts the certificate and which ports it publishes:

bash
grep -n -i -E 'cert|ssl|443' deployment/docker-compose.yml
grep -n -E 'SSL_(CERT|KEY)_PATH' deployment/.env

Where do SSL_CERT_PATH and SSL_KEY_PATH live?

They are ordinary configuration values in the DataMind OS deployment's environment schema. The Installation wizard offers them as optional fields during a migration, and they are stored, written and versioned exactly like every other configuration code:

LayerWhere
Installer's databaseA row in configurations with code SSL_CERT_PATH or SSL_KEY_PATH
Rendered environmentdeployment/.env, as SSL_CERT_PATH=…
Consumed byThe deployment service that terminates TLS, which reads the value from its environment

The values are paths — typically absolute host paths — not certificate contents.

Note

The Installer stores the path and writes it into the environment. It does not create the bind mount that makes the file visible inside the container. That mount is declared in the deployment's compose file. Setting a path the service cannot see is the most common cause of "the certificate is not loading".

How do I change the certificate paths?

Edit the two values in Advanced configuration, then apply the change. They are written with the same call as any other configuration value:

bash
curl -X PATCH http://localhost:8000/api/configs/values \
  -H "Authorization: Bearer <access-token>" \
  -H "Content-Type: application/json" \
  -d '[{"code":"SSL_CERT_PATH","value":"/etc/ssl/portal/fullchain.pem"},
       {"code":"SSL_KEY_PATH","value":"/etc/ssl/portal/privkey.pem"}]'

Saving rewrites deployment/.env and marks the services that reference these codes as stale. The interface then offers Apply changes, which recreates exactly those services.

Tip

Point SSL_CERT_PATH at a file that contains the full chain — leaf certificate first, then the intermediates. A certificate file with only the leaf works in browsers that cache the intermediate and fails on everything that does not.

What do I run after replacing the certificate files?

Apply changes — no restart, and no Installer-side certificate command. If you replaced the file contents without changing the paths, the environment did not change, so the Installer has nothing to recreate on its own. Recreate the TLS-terminating service so the process re-reads the files:

Read the service name from the deployment, then target the recreate at it:

bash
curl -X POST http://localhost:8000/api/deployment/apply-config \
  -H "Authorization: Bearer <access-token>" \
  -H "Content-Type: application/json" \
  -d '{"services":["openresty"]}'

If that service is not one the Installer will target, run the recreate in the deployment's own project on the host. Note that the audit trail will then not show the action — a reason to prefer the Installer's path.

How do I verify a replacement certificate before switching?

Use openssl on the host — this is general PKI practice, not a product feature. Four checks cover almost every failure: it is the right name, it is in date, its key matches, and its chain is complete.

Start with the identity and validity window:

bash
openssl x509 -in fullchain.pem -noout -subject -issuer -dates -ext subjectAltName

Check that the dates are what your CA said they would be, and that the SAN contains the exact hostname users type.

How do I check that the private key matches the certificate?

Compare the public key derived from each file; they must be identical.

bash
diff <(openssl x509 -in fullchain.pem -noout -pubkey | openssl sha256) \
     <(openssl pkey -in privkey.pem -pubout | openssl sha256)

No output and exit code 0 means the key matches. This is the check that catches "I renewed the certificate and copied the wrong key file" — which otherwise produces a TLS handshake failure with a message that does not mention the key at all.

Note

You will also see the older RSA-only method, openssl x509 -noout -modulus | openssl sha256 compared with openssl rsa -noout -modulus | openssl sha256. It is fine for RSA keys but does not work for ECDSA, which is why the public-key comparison above is the better habit.

How do I check that the chain is complete?

Verify the leaf against your CA bundle, and inspect what the certificate file actually contains.

First, does the leaf verify against the CA you trust?

bash
openssl verify -CAfile ca-bundle.pem fullchain.pem

If the file holds the leaf plus its intermediates, verify including them:

bash
openssl verify -untrusted fullchain.pem -CAfile ca-bundle.pem leaf.pem

And count how many certificates you actually put in the file:

bash
grep -c 'BEGIN CERTIFICATE' fullchain.pem

A 3 from the count means leaf plus two intermediates; a 1 means you saved only the leaf. The first verify fails with unable to get local issuer certificate when the CA bundle is wrong, and the second fails with a signature or expiry message when an intermediate is missing or expired.

How do I check what is actually being served right now?

Ask the server, not the file on disk — they are different questions.

bash
openssl s_client -connect portal.example.com:443 -servername portal.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates -ext subjectAltName

This shows the certificate a client actually receives, including the case where you replaced the file but the service is still holding the old one in memory. To also see the chain the server presents:

bash
openssl s_client -connect portal.example.com:443 -servername portal.example.com -showcerts </dev/null
Important

Always pass -servername. Without it the server may hand you a default certificate for a different name, and you will "verify" the wrong certificate — a false pass that hides the problem you are investigating.

How do I check a certificate's expiry from a script?

Parse notAfter from the served certificate and compare it to now.

bash
expiry=$(openssl s_client -connect portal.example.com:443 -servername portal.example.com \
  </dev/null 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
echo "expires: $expiry"
date -d "$expiry" +%s        # seconds since epoch, for comparison

Checking the certificate as served, rather than the file, is what makes a monitoring check meaningful — it catches a replaced file that was never reloaded.

How do I renew a certificate?

With whatever issued it. Renewal is not an Installer responsibility and the Installer neither schedules nor performs it. If your organisation issues certificates from an internal CA, follow that CA's process. If the host runs an ACME client, that client renews with its own command, and nothing about the Installer changes.

General practice for an ACME client, and only if that is what you run:

bash
certbot renew --dry-run

Whichever route you use, the sequence that makes a renewal take effect in this deployment is always the same one described above: get the files into place, verify them, then recreate the TLS-terminating service.

Note

An ACME client can also be configured to run a deploy hook that reloads the service automatically after a successful renewal. That is a host-side convenience you own; the Installer does not install or manage it.

Can I use a self-signed certificate?

For a deployment reached over a management network, yes — with two consequences. Users will get a trust warning unless the issuing CA is installed on their machines, and any client that verifies certificates strictly will refuse the connection.

That second point matters more than it looks. PLATFORM_URL drives CORS origins and derived service URLs, and a scheme-less real domain name is turned into https:// automatically. A self-signed certificate that a browser will not trust turns a working deployment into one that appears broken.

Warning

Do not switch PLATFORM_URL to https:// for a name whose certificate users' browsers will reject. Either install your CA on the clients, or keep the deployment on http:// inside the trusted network.

Does the Installer serve its own interface over HTTPS?

No. The Installer's interface and API are served over plain HTTP on its own port. If you want TLS in front of the Installer, terminate it in your own proxy or tunnel.

One thing does adapt automatically: the session cookies' Secure flag is derived from the incoming request — a direct TLS connection, or a proxy that forwards the original protocol — rather than being hardcoded. So a correctly configured front end produces correctly protected cookies without any Installer configuration.

Warning

Verify that your proxy forwards the original protocol. If it does not, the cookies are issued without Secure, the interface keeps working, and nothing tells you the protection is missing.

What changes if the deployment sits behind a load balancer?

Three things need attention. The TLS-terminating layer may move out of the deployment entirely; the forwarded protocol must reach the services so their cookies and redirects are correct; and the platform URL must be the name clients actually use, not an internal one.

Set PLATFORM_URL to the externally visible origin. It is the root of the CORS origin the edge compares against, so an internal hostname there produces a deployment that authorizes nothing.

Does an expired certificate break the Installer?

No. The Installer does not use the deployment's certificate and does not check it. An expired certificate breaks users' access to the DataMind OS interface, not the Installer, and not the administrator's ability to fix it.

That separation is worth remembering during an incident: you can diagnose and repair the certificate entirely from the Installer while the platform itself is inaccessible in a browser.

For the deployment-side procedure, see Certificates and TLS and Network exposure.