
Ory Kratos is an open-source identity and user management system designed for cloud-native environments. It handles user registration, login, account recovery, email verification, and profile management through a headless Application Programming Interface (API)-first architecture. Unlike traditional identity platforms that bundle a built-in user interface, Kratos exposes RESTful APIs that you connect to your own frontend. This separation gives you full control over the user experience while Kratos manages the underlying identity logic and security.
This article explains how to deploy an Ory Kratos instance on a Linux server using Docker Compose, configure Traefik for automatic HTTPS with Let's Encrypt, and verify the deployment by registering and authenticating a test user.
Before you begin, you need to:
kratos.example.com).Ory Kratos requires a project directory containing configuration files for the identity schema and server settings. Environment variables store sensitive credentials separately from configuration files.
Create the project directory with all required subdirectories.
This command creates the following directory structure:
config/: Stores Kratos configuration files and identity schemas.data/postgres/: Persists PostgreSQL database files across container restarts.Navigate to the project directory.
Create the identity schema file. This JSON schema defines which fields are available on user accounts and how those fields map to authentication credentials.
Add the following content.
Save and close the file.
This schema defines an identity with an email address that serves as the login identifier, along with optional first and last name fields. The ory.sh/kratos annotations configure the email field for password-based authentication, account recovery, and email verification.
Generate two random secrets for cookie and cipher encryption.
Run this command twice and copy both output strings. You use these values in the configuration file.
Create the Kratos configuration file.
Add the following content. Replace kratos.example.com with your domain name, YOUR_GENERATED_SECRET and YOUR_GENERATED_CIPHER_SECRET with the random strings from the previous command, and update the SMTP section with your email provider's credentials.
Save and close the file.
The configuration file controls how Kratos operates. The serve.public section sets the public API base URL and Cross-Origin Resource Sharing (CORS) settings. The serve.admin section binds the admin API to the loopback address, restricting it from external access. The selfservice section enables password-based authentication with a minimum password length of 12 characters, breach database checking via HaveIBeenPwned, and automatic session creation after registration.
The admin API base_url uses http://127.0.0.1:4434/ intentionally. The admin API provides unrestricted access to all identities and sessions, and should never be exposed through the public reverse proxy.
Create the environment variables file.
Add the following content. Replace EXAMPLE_DB_PASSWORD with a strong, unique database password and admin@example.com with your email address for Let's Encrypt notifications.
Save and close the file.
Docker Compose orchestrates the Kratos server, PostgreSQL database, self-service UI, and Traefik reverse proxy as a single deployment. Traefik automatically provisions TLS certificates from Let's Encrypt.
Create the Docker Compose file.
Add the following content. Replace kratos.example.com with your domain name, and replace yourCookieSecret1234 and yourCsrfSecret1234 with strong random values generated using openssl rand -hex 16.
Save and close the file.
In the above manifest:
services: Launches five containers managed by Docker Compose:traefik: Serves as the reverse proxy and TLS termination point with automatic Let's Encrypt certificate provisioning.postgres: Stores Kratos identity data in a persistent PostgreSQL 16 database.kratos-migrate: Runs database migrations on startup and exits after completion.kratos: Runs the main Ory Kratos identity server.kratos-selfservice-ui-node: Provides the browser-based UI for registration, login, and account management.ports (kratos): Binds the admin API to 127.0.0.1:4434 for local access only, preventing external exposure.labels (kratos): Routes requests matching /.ory/kratos/public/* to port 4433 via Traefik.labels (kratos-selfservice-ui-node): Routes all other requests to port 4455. The priority=1 ensures this acts as the catch-all route.depends_on: Ensures services start in the correct order with health checks.volumes: Provides persistent storage for TLS certificates.restart: unless-stopped: Enables automatic recovery after failures or server reboots. The PostgreSQL Data Source Name (DSN) uses sslmode=disable because the database connection travels over the internal Docker network. If you move PostgreSQL to a separate host, change sslmode=disable to sslmode=require.
Build and start all services in detached mode.
Verify all services are running.
The output displays four running containers and one completed migration container. All containers should show Up except kratos-migrate, which shows Exited (0) after completing database migrations.
View the logs for the services.
For more information on managing Docker Compose stack, see the How To Use Docker Compose article.
Health check endpoints confirm the Kratos server is running correctly and Traefik routes requests properly.
Test the Kratos admin API health endpoint from the server.
Output:
Test the public API through the Traefik HTTPS reverse proxy.
Output:
Verify that the self-service UI is accessible through HTTPS. Replace kratos.example.com with your domain.
A 303 status code confirms the UI is accessible. The self-service UI redirects unauthenticated requests to /login. Open https://kratos.example.com in a web browser to access the UI.
The Kratos API provides self-service flows for user registration and authentication. Testing these flows confirms the deployment handles the complete identity lifecycle correctly.
Initiate a registration flow.
The response contains a JSON flow object with an id field. Locate and copy the id value.
Submit the registration form using test user credentials.
Replace:
FLOW_ID: The flow ID from the previous step's response.YOUR-EMAIL: Your test email address.YOUR-PASSWORD: A password that meets the minimum 12-character requirement.FIRST-NAME and LAST-NAME: Your test user's first and last name. A successful registration returns a JSON response containing a session object with a session_token.
Verify the user was created by querying the admin API.
The response contains the registered identity with the email address and name provided during registration.
Start a login flow.
Locate and copy the flow id from the response. Submit the login credentials by replacing FLOW_ID with the login flow ID.
Replace YOUR-EMAIL and YOUR-PASSWORD with the credentials used during registration.
A successful login returns a JSON response containing a session object with a session_token.
Copy the session_token value from the response and verify the session. Replace SESSION_TOKEN with the token value.
The response contains the authenticated user's identity details, confirming the session is valid.
You have deployed Ory Kratos on a Linux server using Docker Compose with PostgreSQL for persistent storage, Traefik for automatic HTTPS, and the official self-service UI for user-facing flows. The configuration enforces production security settings including password policies, CORS rules, and secure session handling. For advanced configuration, social login providers, and API integration, refer to the official Ory Kratos documentation.
0 Comments
Be the first to comment and share your perspective with the community.