Get started

Run OpenSourceOM with Docker Compose

docker-compose.yml in the core repository starts two services: Postgres 16 and an API image built from the local Dockerfile. The image entrypoint is om and the command is serve.

cp .env.example .env
docker compose up -d
docker compose ps

Postgres listens on host port 5432 with user, password, and database opensourceom unless you override POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB. The API listens on OM_API_PORT (default 8080) and receives OM_ADMIN_EMAIL and the optional Google, GitHub, and SMTP settings from .env. Open the console and create the admin, or run om admin create --email on the host first. Keep port 8080 private until an admin exists. A volume named postgres-data keeps the database across restarts.

Migrations

om serve applies pending SQL files in migrations/ before it listens. Compose starts the API with that command, so docker compose up -d creates the schema. A later image applies only the files that are not already recorded in schema_migrations. Startup logs applied database migrations or database schema is current.

Set OM_AUTO_MIGRATE=false in .env when a separate step should own the schema. om migrate is also how you migrate when Compose is running Postgres alone:

docker compose up -d postgres
go build -o om ./cmd/om
./om migrate

The CLI’s default database host is localhost, which is the published port. .env.example sets POSTGRES_HOST=postgres, and the API service in the compose file sets that same value on the container. The CLI does not read .env. Do not export POSTGRES_HOST=postgres into the shell that runs om on your machine.

CLI against Compose

Build om on the host (or unpack a release binary) and use it for scans. The container image can also run one-off commands if you point it at the Compose network:

docker compose run --rm api migrate

api migrate works because the image entrypoint is already om. Cloud scans are easier on the host, where your AWS, Azure, and GCP credential files already live. The API container does not mount those credentials. To scan from the container you would pass the credential environment yourself, for example -e AWS_REGION -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY, and the database host inside that network is postgres, which the service already sets.

If the CLI cannot connect

  • POSTGRES_HOST=postgres in the shell is the usual miss. That hostname exists only on the Compose network. Unset it, or set POSTGRES_HOST=localhost, for a CLI on the host.
  • Password, user, and database must match what Compose used to initialize the volume. Changing POSTGRES_PASSWORD in .env after the first start does not alter an existing volume.
  • The API waits until Postgres is healthy, then applies migrations. om migrate on the host does not wait. If it runs before the port is open, retry it.
  • relation "nodes" does not exist means the API has not finished starting, or OM_AUTO_MIGRATE=false and om migrate has not been applied to this database.

GET http://localhost:8080/v1/health returns {"status":"ok","service":"opensourceom-api"} when the API process is up and Postgres answers a ping. om serve applies migrations before it listens, so a healthy API has the current schema when OM_AUTO_MIGRATE is left on. A scan that fails on the database while health is ok means the CLI and the container are not using the same connection settings.

Useful commands

docker compose logs -f api
docker compose down
docker compose down -v

down -v deletes the Postgres volume. The next API start is an empty database and applies migrations again.