How to Deploy OTserver With Docker Compose

Prerequisites

Install Docker Engine with Compose. Use long random, URL-safe database credentials and a separate long random OTSERVER_SECRET; keep the environment file out of source control. Put TLS in a reverse proxy in front of OTserver and do not expose MongoDB outside its Docker network.

Local development

Clone the OTserver manager repository, including the pinned Otter contract submodule, and run the following commands from its root:

1
2
git clone --recurse-submodules https://github.com/ruveydac/OTserver.git
cd OTserver

For an existing checkout, run git submodule update --init --recursive before building.

The repository’s docker-compose.yml bind-mounts the source, installs dependencies, runs pnpm dev, and publishes MongoDB on port 27017. Use it only as a local quick start:

1
2
3
cp .env.example .env
# Replace OTSERVER_SECRET in .env with a long random value.
docker compose up

Open http://localhost:3000/admin to create the first administrator account.

Production example with MongoDB

The repository’s multi-stage Dockerfile builds the standalone application and runs it as an unprivileged user. From the repository root, save this as compose.production.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
services:
  mongo:
    image: mongo:8.0
    restart: unless-stopped
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD}
    volumes:
      - mongo-data:/data/db
    healthcheck:
      test: ['CMD-SHELL', 'mongosh --quiet -u "$$MONGO_INITDB_ROOT_USERNAME" -p "$$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --eval "db.adminCommand({ ping: 1 })"']
      interval: 10s
      timeout: 5s
      retries: 10

  otserver:
    build: .
    restart: unless-stopped
    depends_on:
      mongo:
        condition: service_healthy
    environment:
      DATABASE_URL: 'mongodb://${MONGO_ROOT_USERNAME}:${MONGO_ROOT_PASSWORD}@mongo:27017/otserver?authSource=admin'
      OTSERVER_SECRET: ${OTSERVER_SECRET}
    ports:
      - '127.0.0.1:3000:3000'
    volumes:
      - import-files:/app/import-files

volumes:
  # Single MongoDB instance; use a replica set or managed MongoDB when high availability is required.
  mongo-data:
  import-files:

Create .env.production with no quotes and URL-safe values so the MongoDB connection string remains valid:

1
2
3
MONGO_ROOT_USERNAME=otserver
MONGO_ROOT_PASSWORD=replace-with-a-long-random-url-safe-password
OTSERVER_SECRET=replace-with-a-different-long-random-secret

Protect the file and start the stack:

1
2
3
chmod 600 .env.production
docker compose --env-file .env.production -f compose.production.yml up --build -d
docker compose --env-file .env.production -f compose.production.yml ps

This compact example uses the MongoDB bootstrap administrator for the application. Create a dedicated least-privilege MongoDB user and update DATABASE_URL where your security policy requires separate database administration credentials.

Proxy HTTPS traffic to 127.0.0.1:3000. Keep a new instance private until you open /admin and create the first account, which receives the protected Admin role. Then create the site hierarchy that will receive discovery imports.

Back up both the mongo-data and import-files volumes. Pin and test MongoDB and OTserver upgrades rather than changing image versions during an unplanned restart.

Update an existing production deployment

Back up MongoDB and the uploaded import files, then check out the OTserver release tag or commit you have tested. From the same repository directory, update its pinned submodule and rebuild only the application:

1
2
3
4
5
git submodule update --init --recursive
docker compose --env-file .env.production -f compose.production.yml build otserver
docker compose --env-file .env.production -f compose.production.yml up --no-deps -d otserver
docker compose --env-file .env.production -f compose.production.yml ps
docker compose --env-file .env.production -f compose.production.yml logs --tail=100 otserver

Keep the same Compose project name, production environment file, and volumes so the replacement container uses the existing inventory and import files. Do not use down -v during an upgrade: it deletes the named volumes. After restarting, sign in and verify the inventory and a small import. If rollback is needed, rebuild the previous tested revision; restore the matching database and import-file backup if the upgrade changed stored data incompatibly.

Import configuration

Import an authorized scanner export through Imports → Create New, or configure the scanner’s direct upload with the destination URL, site document ID, and a user API key with read/write access to that site.

Verify the result

Sign in at /admin, confirm that the expected site exists, and create a small authorized import before planning a plant-wide rollout. The import result shows created, updated, skipped, unresolved, and warning counts.

Deploy the scanner on Linux or plan a plant rollout.