Server TLS Certificate
Athena serves the web console and API directly over HTTPS — no separate web server is required. On first start it issues its own certificate from its built-in Root CA, so browsers that don't trust that CA show a certificate warning. This page explains how to install your own CA-issued certificate to remove that warning, and how the certificate is used when Athena runs behind a reverse proxy or load balancer.
Two certificates, two ports#
Athena listens on two TLS ports, and they use certificates for different reasons. It is important to understand the split before changing anything:
| Port | Used by | Certificate |
|---|---|---|
8443 — web console & REST API | Browsers, the REST API, the PowerShell module | Replaceable. Serves your own certificate when one is configured; otherwise falls back to the auto-generated Athena CA certificate. |
8444 — agent gateway (gRPC over HTTP/2) | Enrolled agents only | Always the Athena CA certificate. Agents trust this CA and authenticate with mutual TLS, so this port is not replaceable. |
Only the web port (8443) certificate is meant to be swapped. Leave the agent gateway (8444) on the Athena CA certificate — agents receive and pin that CA during enrollment, and changing it would break agent connectivity. See Certificates & PKI for the agent-side trust model.
The default self-signed certificate#
When you don't supply your own certificate, Athena generates a web certificate signed by its
own Root CA on first start and serves it on port 8443. It is a fully valid
certificate — traffic is encrypted with TLS 1.2 or 1.3 — but because public browsers and
operating systems don't trust the Athena Root CA out of the box, they display a
“not secure” / “certificate not trusted” warning. You have two ways to
remove that warning:
- Distribute the Athena Root CA to the machines that use the console (for
example, add it to the Windows Trusted Root store via Group Policy). Once the CA is trusted,
the self-signed web certificate is accepted with no warning. The CA certificate is available
from
GET api/pki/ca/download— see Certificates & PKI. - Install your own certificate from a CA the clients already trust (an internal enterprise CA, or a public CA such as Let's Encrypt). This is described below and is the better choice when the console is reached by browsers you don't fully manage.
Naming the self-signed certificate#
Even if you keep the self-signed certificate, set Server:Hostnames so the
certificate matches the address people actually type. Its value is a comma-separated list of
DNS names; the first name becomes the certificate subject and every name is added as a Subject
Alternative Name (SAN). If you leave it empty, the certificate is issued for the server's
machine name only, which usually won't match a browser URL and can still trigger a name-mismatch
warning.
# Names the auto-generated web certificate answers to
Server__Hostnames=athena.contoso.com,athena
Installing your own certificate#
To serve the web port with your own certificate, provide it as a PFX/PKCS#12
file (.pfx) and point Athena at it:
| Setting | Environment variable | Purpose |
|---|---|---|
Server:WebCertPath | Server__WebCertPath | Full path to your PFX certificate file, inside the container. |
Server:WebCertPassword | Server__WebCertPassword | Password that protects the PFX. Supply as an environment variable, not in appsettings.json. |
The certificate must be reachable inside the container, so mount it in from the host and use the
container path in Server__WebCertPath. A typical run:
# Mount your PFX read-only and point the web port at it
docker run -d --name athena \
-p 8443:8443 -p 8444:8444 \
-v /etc/athena/certs:/app/certs:ro \
-e Server__WebCertPath=/app/certs/athena.pfx \
-e Server__WebCertPassword=<pfx-password> \
-e Server__PublicUrl=https://athena.contoso.com:8443 \
sealgrid/athena:latest
The change takes effect when the server starts, so restart the container after adding or replacing the certificate. On start-up the server log records whether the web port is serving your external certificate or the Athena CA fallback.
If Server:WebCertPath is empty or the file it points to can't be found,
Athena silently falls back to the auto-generated Athena CA certificate on the web port. If
your certificate isn't taking effect, first confirm the path is correct inside the
container (check your volume mount) and that the container can read the file.
Preparing the PFX#
If your CA gave you a separate certificate and private key (for example a PEM
fullchain.pem and privkey.pem from Let's Encrypt), bundle them into
a single PFX first. Include the full chain so clients can build a path to the trusted root:
# Combine a PEM certificate chain + key into a PFX
openssl pkcs12 -export \
-inkey privkey.pem \
-in fullchain.pem \
-out athena.pfx
Use the export password you set here as Server__WebCertPassword. Make sure the
certificate's subject or SAN includes the exact hostname clients use to reach the console.
TLS version & HSTS#
Both ports negotiate TLS 1.2 or TLS 1.3 only. The legacy TLS 1.0 and 1.1 protocols are permanently disabled and cannot be re-enabled, so very old clients will simply fail to connect. This applies whether you use the built-in certificate or your own.
Athena also sends an HTTP Strict-Transport-Security (HSTS) response header with a one-year max-age, instructing browsers to only ever reach the console over HTTPS. The header does not include subdomains and is not submitted to the browser preload list, which suits an internal deployment reached by IP or a specific hostname. HSTS is one of several hardening headers Athena sends on every response — see HTTP Security Headers & Content Security Policy for the full set and how a reverse proxy can affect them.
Behind a reverse proxy or load balancer#
Athena terminates TLS itself and needs no reverse proxy, but you can place one in front — for TLS offload, a shared virtual IP, or a corporate load balancer. When you do, tell Athena which front-end addresses it should trust, otherwise it ignores forwarded client information and records the proxy's address for every request.
Athena honors the X-Forwarded-For (original client IP) and
X-Forwarded-Proto (original scheme) headers, but only when the
connection comes from an address on your trusted-proxy allowlist. If the allowlist is empty
(the default), these headers are ignored and the direct connection address is used as-is. This
protects per-IP rate limiting and the audit trail from spoofed headers. Configure the allowlist
with either or both of:
| Setting | Environment variable | Value |
|---|---|---|
Security:TrustedProxies | Security__TrustedProxies__0, __1, … | Individual proxy IP addresses, e.g. 10.0.0.5. |
Security:TrustedProxyNetworks | Security__TrustedProxyNetworks__0, … | Proxy subnets in CIDR notation, e.g. 10.0.0.0/24. |
In JSON these are arrays; as environment variables, each list element is indexed with a numeric suffix:
# appsettings.json
"Security": {
"TrustedProxies": ["10.0.0.5"],
"TrustedProxyNetworks": ["10.0.0.0/24"]
}
# or as environment variables
Security__TrustedProxies__0=10.0.0.5
Security__TrustedProxyNetworks__0=10.0.0.0/24
When a proxy handles the public TLS, also set Server:PublicUrl to the externally
reachable base URL so links the server generates point at the front-end address rather than the
internal host:
Server__PublicUrl=https://athena.contoso.com
The agent gateway on 8444 speaks gRPC over HTTP/2 with mutual TLS and should be exposed end-to-end, not TLS-terminated at a generic HTTPS proxy. Front only the web port (8443) with your proxy, and pass the agent port straight through.
Verifying the certificate#
After restarting, confirm the web port is presenting the certificate you expect. From a client that trusts the issuing CA, the console should load with no browser warning. You can also read the presented certificate directly:
# Show the certificate the web port presents (subject, issuer, validity)
openssl s_client -connect athena.contoso.com:8443 -servername athena.contoso.com </dev/null \
| openssl x509 -noout -subject -issuer -dates
The issuer line should name your CA (not Athena Root CA), and the
subject/SAN should match the hostname you connect with. The server also reports its
TLS posture and which web certificate is in use in the start-up log — see
Server Logging.
Troubleshooting#
| Symptom | Likely cause & fix |
|---|---|
| Browser still warns after installing a certificate | The web port fell back to the Athena CA certificate. Check that Server__WebCertPath points to a path that exists inside the container and that the volume is mounted, then restart. |
| “Name mismatch” warning | The certificate subject/SAN doesn't include the hostname clients use. Re-issue with the correct name, or (for the self-signed certificate) set Server:Hostnames. |
| Certificate loads but chain is “incomplete” | The PFX is missing intermediate CA certificates. Rebuild it from the full chain (e.g. fullchain.pem). |
| Old client can't connect at all | It only supports TLS 1.0/1.1, which are disabled. Update the client — these protocols cannot be re-enabled. |
| Audit trail / rate limiting shows the proxy IP for everyone | The proxy isn't on the trusted-proxy allowlist. Add it to Security:TrustedProxies or Security:TrustedProxyNetworks. |
Related#
- Configuration — Server & ports — the full
Serversettings table. - Certificates & PKI — the Athena Root CA, agent certificates, and downloading the CA to distribute trust.
- Installation — first-run setup, ports, and data volumes.
- Server Logging — where start-up and TLS messages are written.