Skip to content

External Databases

By default, Kotauth’s Docker Compose stack starts a bundled PostgreSQL 15 container. For production deployments, you’ll often want to connect to a managed database service instead — RDS, Supabase, Neon, Railway, Render, or your own self-managed PostgreSQL server.

Kotauth connects to PostgreSQL via a standard JDBC URL. All connection configuration is done through environment variables — no code changes required.


There are two ways to specify the database connection. DB_URL always wins when set.

Option A — Full JDBC URL (recommended for external databases)

Set DB_URL directly in .env. All other DB_* connection variables (DB_HOST, DB_PORT, DB_NAME) are ignored.

DB_URL=jdbc:postgresql://your-host:5432/kotauth_db?sslmode=require
DB_USER=kotauth
DB_PASSWORD=your-password

Option B — Component variables (default for the bundled stack)

Let the compose file construct the URL from parts. Useful when using the bundled db service or a simple external server that doesn’t need extra JDBC parameters.

DB_HOST=db # defaults to the Docker service name
DB_PORT=5432
DB_NAME=kotauth_db
DB_USER=kotauth
DB_PASSWORD=your-password

The compose stack resolves these to: jdbc:postgresql://db:5432/kotauth_db


Set DB_URL in your .env file. The bundled db service in the compose file will start but sit idle — you can remove it by hand if you prefer a cleaner stack.

.env
DB_URL=jdbc:postgresql://your-managed-host:5432/kotauth_db?sslmode=require
DB_USER=kotauth
DB_PASSWORD=your-password

Then start normally:

Terminal window
# Local / evaluation
docker compose up -d
# Production with Caddy TLS
docker compose -f docker-compose.prod.yml up -d

Most managed PostgreSQL providers require or recommend SSL. Append parameters as a query string to DB_URL:

ParameterValuesNotes
sslmoderequire, verify-ca, verify-full, disablerequire is the minimum for most managed providers
ssltrueAlternative to sslmode=require for some providers
channel_bindingdisableRequired for Neon with certain client versions
connectTimeoutsecondsMax time to wait for a connection
socketTimeoutsecondsMax time to wait for a response

Example with multiple parameters:

DB_URL=jdbc:postgresql://your-host:5432/kotauth_db?sslmode=require&connectTimeout=10

Find your endpoint in the RDS console under Connectivity & security → Endpoint.

DB_URL=jdbc:postgresql://xxx.yyy.us-east-1.rds.amazonaws.com:5432/kotauth_db?sslmode=require
DB_USER=kotauth
DB_PASSWORD=your-password

IAM authentication is not currently supported — use standard username/password credentials.

For RDS Proxy, use the proxy endpoint instead of the RDS instance endpoint. RDS Proxy uses session pinning for transactions, which is compatible with Flyway.


The database user must have the following permissions. Flyway needs CREATE on first boot to run migrations; subsequent restarts only need DML permissions.

-- Create the database and user
CREATE DATABASE kotauth_db;
CREATE USER kotauth WITH PASSWORD 'your-password';
-- Permissions needed for Flyway migrations (first boot)
GRANT CREATE ON DATABASE kotauth_db TO kotauth;
-- Permissions needed for normal operation
GRANT CONNECT ON DATABASE kotauth_db TO kotauth;
GRANT USAGE ON SCHEMA public TO kotauth;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO kotauth;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO kotauth;
-- Ensure future tables/sequences are also accessible
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO kotauth;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO kotauth;

For the audit log, consider a separate maintenance role with UPDATE/DELETE on audit_log — the app user should only have INSERT and SELECT on that table. See Production Checklist.


If your infrastructure uses PgBouncer in session pooling mode, it works transparently:

DB_URL=jdbc:postgresql://your-pgbouncer-host:6432/kotauth_db?sslmode=require

After setting your environment variables, check that Kotauth can reach the database:

Terminal window
# Check the logs
docker compose logs kotauth | grep -E "migration|Flyway|DB|error"
# Or use the health endpoint
curl -s http://localhost:8080/health/ready
# {"status":"UP"} means migrations completed and DB is reachable

If the database is unreachable, Kotauth will log the JDBC connection error and exit. The container will be restarted by Docker’s restart: unless-stopped policy — check the logs after a few seconds to see the error details.