---
title: "Run with Docker Compose | FoxAuth"
description: "Start MongoDB, provision the schema and serve the authorization server with one command."
canonical: "https://foxauth.dev/docs/get-started/docker-compose/"
lastmod: "2026-10-15T18:51:11+03:00"
---
Run with Docker Compose

For most people the fastest way to see a working authorization server is the Compose file the
repository ships. It brings up three services: MongoDB, a one-shot provisioning step, and the
server. Nothing needs configuring beyond the one value discussed below.

Prerequisites: Docker with Compose v2 (docker compose, not the older docker-compose).

Bring it upSection titled “Bring it up”

Fetch the Compose file:

Terminal window

curl -O https://raw.githubusercontent.com/RedFox-Soft/OAuth-server.ts/main/docker-compose.yml

Decide the ISSUER value now — the warning below explains why. If http://localhost:3000 is
not where a browser will reach this server, edit it in both environment: blocks of
docker-compose.yml, the setup service’s and the oauth service’s. Changing only one leaves
the seeded redirect URI and the advertised issuer disagreeing, and that is the mismatch the
warning below says cannot be repaired in place.

Start everything:

Terminal window

docker compose up

Open the console at http://localhost:3000/admin. The first visit shows a one-time setup screen
that creates the initial super administrator.

What the three services doSection titled “What the three services do”

Service
Image
Role

mongo
mongo:8
The datastore, on a named mongo-data volume, with a mongosh ping healthcheck the other services wait for

setup
ghcr.io/redfox-soft/oauth-server-ts:latest
Runs bun run db:setup and bun run db:migrate, then exits: collections, indexes, the initial RS256 signing key, the admin panel seed, and any schema migrations

oauth
ghcr.io/redfox-soft/oauth-server-ts:latest
The server itself on port 3000, started only after setup completes successfully

The ordering matters. Without the reserved administrators’ project and admin-panel client that
setup seeds, the console’s sign-in redirects to a client no Client document matches. The
first-run setup page still works in that state, which can make it look like a login bug. The server
also refuses to start against a database whose migrations have not run, which is why setup runs
db:migrate after db:setup. Both are safe to repeat, so re-running docker compose up after
pulling a newer image is also the upgrade path; take a backup first when the release notes name a
migration that cannot be undone.

Set ISSUER before the first docker compose up

ISSUER must be the URL a browser reaches the server at, and it must be final before the first
up. The seeded admin client’s redirect URI is derived from it once, with $setOnInsert, and a
later change is not repaired by re-running db:setup.
If you have already started with the wrong value, the workaround is to delete the datastore and
start again:

Terminal window

docker compose down -v # removes the mongo-data volume

# edit ISSUER in docker-compose.yml

docker compose up

Note that this destroys every account, client and signing key in that volume, so it is a fix for
the first day only. On a deployment that already has data there is no repair from the console: the
reserved admin client is the one client the console will not edit, which is why ISSUER has to be
right before the first start.

Where to go nextSection titled “Where to go next”

The console at http://localhost:3000/admin, where you create the first administrator.

The discovery document, which is the authoritative list of endpoint URLs for a client library:
http://localhost:3000/.well-known/openid-configuration.

The key set: http://localhost:3000/jwks.

A liveness probe that is never rate-limited: http://localhost:3000/health, and its readiness
counterpart http://localhost:3000/ready, which also reaches the database.

This file runs MongoDB. docker-compose.postgres.yml beside it is the same three services on
PostgreSQL, started with docker compose -f docker-compose.postgres.yml up. The two are
alternatives and are never combined. See PostgreSQL for which variable
selects which.

For a production-leaning Compose file, with pinned tags, an external database and a TLS proxy in
front, see Deploy with Docker Compose.

NextRun from source
