Skip to main content

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.

info

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:

ServiceEndpointConfiguration keyDefault address
Ory HydraPublicserve.public0.0.0.0:4444
Ory HydraAdminserve.admin0.0.0.0:4445
Ory KratosPublicserve.public0.0.0.0:4433
Ory KratosAdminserve.admin0.0.0.0:4434
Ory KetoReadserve.read:4466
Ory KetoWriteserve.write:4467
Ory KetoMetricsserve.metrics:4468
Ory KetoOPL syntaxserve.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.public and urls.self.admin instead. It reads serve.<endpoint>.base_url only 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/letsencrypt for certbot, or the cert-manager volume mount). The rule covers every inode underneath, so the symlink (typically in live/<domain>/) and the renewed target (in archive/<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_PATH and 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 with EPERM. Restart kratos serve after 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.