Serving the APIs
Ory Hydra, Ory Kratos and Ory Keto share one configuration block for their HTTP APIs. Every endpoint is configured the same way: where it listens, whether it terminates TLS, and how it reports the address it bound.
Ory Oathkeeper has its own serve configuration and isn't covered by this page. It configures serve.api, serve.proxy and
serve.prometheus with host, port and write_listen_file, plus tls and a timeout on the API and proxy endpoints — the
Prometheus endpoint serves plain HTTP only. It has no base_url, no unix sockets and no socket permissions, and it doesn't reload
a certificate that changes on disk, so rotating one needs a restart.
Endpoints
Each service exposes its own endpoints, and each endpoint is configured independently under serve:
| Service | Endpoint | Configuration key | Default address |
|---|---|---|---|
| Ory Hydra | Public | serve.public | 0.0.0.0:4444 |
| Ory Hydra | Admin | serve.admin | 0.0.0.0:4445 |
| Ory Kratos | Public | serve.public | 0.0.0.0:4433 |
| Ory Kratos | Admin | serve.admin | 0.0.0.0:4434 |
| Ory Keto | Read | serve.read | :4466 |
| Ory Keto | Write | serve.write | :4467 |
| Ory Keto | Metrics | serve.metrics | :4468 |
| Ory Keto | OPL syntax | serve.opl | :4469 |
Set every option below as an environment variable by replacing dots with underscores and uppercasing the key. For example,
serve.public.tls.cert.path becomes SERVE_PUBLIC_TLS_CERT_PATH.
Host and port
serve:
public:
host: 0.0.0.0
port: 4433
Ory Keto defaults the host to the empty string, which binds both the IPv4 and the IPv6 wildcard. Ory Hydra and Ory Kratos default
to 0.0.0.0, which binds IPv4 only.
Set port to 0 to let the operating system assign a free port. Combine it with write_listen_file to find out
which port it picked.
Base URL
serve.<endpoint>.base_url is the URL the endpoint is reached at from outside, which differs from the address it binds whenever a
proxy or ingress sits in front of it:
serve:
public:
base_url: https://auth.example.com/
What each service does with it differs:
- Ory Kratos uses it as the public and admin URL, so it ends up in redirects and in the form actions of self-service flows. Set it when a proxy fronts the endpoint.
- Ory Hydra generates redirects from
urls.self.issuer,urls.self.publicandurls.self.admininstead. It readsserve.<endpoint>.base_urlonly to derive the host name it reports in anonymous telemetry. - Ory Keto accepts the option and ignores it.
HTTPS (TLS)
Configuring a certificate and a private key is what makes an endpoint serve HTTPS. None of the services generate a certificate for you.
This example creates a self-signed pair, which browsers and API clients only accept after you add it to their trust store:
openssl genrsa -out key.pem 4096
openssl req -new -x509 -sha256 -key key.pem -out cert.crt -days 365 \
-subj "/CN=auth.example.com" -addext "subjectAltName=DNS:auth.example.com"
Point the endpoint at the files:
serve:
public:
tls:
cert:
path: /etc/ory/tls/tls.crt
key:
path: /etc/ory/tls/tls.key
Or pass their content base64 encoded:
SERVE_PUBLIC_TLS_CERT_BASE64=$(base64 -i cert.crt)
SERVE_PUBLIC_TLS_KEY_BASE64=$(base64 -i key.pem)
If you run Docker locally, pass them as environment variables:
docker run ... \
-e SERVE_PUBLIC_TLS_CERT_BASE64="$SERVE_PUBLIC_TLS_CERT_BASE64" \
-e SERVE_PUBLIC_TLS_KEY_BASE64="$SERVE_PUBLIC_TLS_KEY_BASE64" \
...
or mount the certificate files into the container and point path at them.
Set both the certificate and the key. The service fails to start when only one of the two is configured, so that a typo can't
leave the endpoint serving plain HTTP unnoticed. Each cert and key takes either path or base64, never both.
Endpoints are independent, so one can serve HTTPS while another stays on plain HTTP inside your network.
A certificate configured through path is reloaded when the file changes, so certificate rotation needs no restart. Certificates
passed as base64 are read once at startup.
gRPC and Connect clients keep working over an Ory Keto endpoint that terminates TLS. Configure them with the same trust store you use for the REST API.
Ory Hydra applies serve.tls to both endpoints
Ory Hydra additionally reads a top-level serve.tls, which applies to the public and the admin endpoint at once. Configure
serve.public.tls and serve.admin.tls to give an endpoint its own certificate instead. An endpoint listening on a unix socket
never inherits serve.tls.
Terminate TLS at a proxy
If a load balancer, ingress controller, or service mesh terminates TLS in front of the service, don't configure a certificate. The service then serves HTTP, and the proxy is responsible for HTTPS. Make sure the proxy is the only way to reach the service.
The deprecated tls.enabled flag
serve.<endpoint>.tls.enabled is deprecated and ignored: a configured certificate turns TLS on, and removing the certificate
turns it off. The services still accept the flag so that an existing configuration keeps loading, and log a warning at startup
naming the key to remove.
Certificate renewal with the filesystem sandbox
Ory Network and Ory Enterprise License (OEL) deployments run Ory Kratos with the Landlock filesystem sandbox active. The configured TLS cert and key paths are allow-listed at startup, including any symlinks resolved at that moment. Landlock rules are irrevocable, and they attach to a specific inode.
With cert-manager or certbot, a renewal writes a new file and re-points a symlink at it. Whether that "just works" depends on how the cert path is allow-listed:
-
Containing-directory grant — transparent renewals. Add the cert directory under
security.landlock.allowed_paths(for example/etc/letsencryptfor certbot, or the cert-manager volume mount). The rule covers every inode underneath, so the symlink (typically inlive/<domain>/) and the renewed target (inarchive/<domain>/) both sit inside the sandbox and reads keep working — no restart needed.security:landlock:allowed_paths:- /etc/letsencrypt -
Leaf grant — restart required. If only the cert and key files themselves are allow-listed (the default for
SERVE_PUBLIC_TLS_CERT_PATHand friends), the rule attaches to the original target inode. After a renewal the symlink resolves to a new inode that is not in the allowlist, and the kernel denies reads withEPERM. Restartkratos serveafter every renewal so the rules re-attach. Wire the restart into your renew hook.
Unix sockets
Set the host to a unix: path to listen on a unix socket instead of a TCP port:
serve:
public:
host: unix:/var/run/ory/public.sock
socket:
owner: ory
group: ory
mode: 384 # 0600
Connecting to a unix socket requires write permission on the socket file, so mode is the access control for the endpoint. It
defaults to 493 (0755), which lets only the owner connect. owner and group default to the user running the service and
that user's primary group.
The socket file is removed on shutdown. A socket file that an unclean shutdown left behind is replaced on the next start, so a crashed process doesn't block a restart.
A unix socket endpoint can't terminate TLS, because the socket permissions are the access control and there is no host name for a client to verify. Configuring both is rejected at startup rather than silently serving one of them.
Listen file
serve.<endpoint>.write_listen_file names a file that the service writes once the endpoint is listening. Its content is the
resolved host:port, which is how you discover the port when listening on port: 0:
serve:
public:
port: 0
write_listen_file: file:///var/run/ory/public.addr
The value must use the file:// scheme. The endpoint might not accept connections yet at the moment the file is written.
Request logging
serve.<endpoint>.request_log.disable_for_health keeps the health endpoints out of the request log:
serve:
public:
request_log:
disable_for_health: true
Ory Keto accepts this option but doesn't use it — it never logs requests to its health endpoints.
Configuration reference
The full set of options per service: Ory Hydra, Ory Kratos, Ory Keto.
