Skip to content

Installation

Self-host OpenTraderWorld on your own machine or server. Takes about 5 minutes.

Containerized only (for now)

OpenTraderWorld runs as a Docker Compose stack, the only supported deployment. A native install is possible but not recommended: Docker keeps the install non-intrusive (everything lives in containers and volumes) and quick to rebuild. See Get Docker for why, and for per-OS install steps.

Requirements

  • Docker with Docker Compose. Don't have it? Get Docker covers macOS, Windows and Linux in a few commands.
  • Linux, macOS, or Windows.
  • A free port (5454 by default; ports 80 + 443 for the HTTPS modes). You can change it during setup.

Check Docker is ready:

bash
docker --version
docker compose version
bash
curl -fsSL https://raw.githubusercontent.com/G-OTW/OpenTraderWorld/master/install.sh | bash

The installer checks Docker is ready, downloads the deploy files (only the deploy/ directory, no source code, no toolchain) into ./opentraderworld, then hands off to the guided setup below, which pulls the prebuilt images from Docker Hub.

Options go after bash -s --:

bash
curl -fsSL https://raw.githubusercontent.com/G-OTW/OpenTraderWorld/master/install.sh | bash -s -- --dir ~/otw
OptionDefaultNotes
--dir <path>./opentraderworldInstall directory. Refuses a non-empty directory or an existing install.
--ref <ref>masterBranch or tag to install.
--buildoffClone the full source and build the images locally instead of pulling (needs git and the toolchain).

From a git clone (alternative)

bash
git clone https://github.com/G-OTW/OpenTraderWorld.git
cd OpenTraderWorld/deploy
./setup.sh

The guided setup

Both paths above run deploy/setup.sh. It asks a few questions, generates strong secrets, writes the config, and starts everything.

It prompts for:

QuestionDefaultNotes
Network mode1 (localhost)1 this machine only · 2 LAN over plain HTTP · 3 LAN over HTTPS with a real certificate · 4 public internet at your own domain. Changeable later, see Network & remote access.
Admin usernameadminThe admin account is created for you; a strong password is generated and shown once.
HTTP port5454Modes 1–2 only; modes 3 and 4 use 80 + 443.
DuckDNS domain / token / LAN IPnoneMode 3 only.
Public domainnoneMode 4 only, and it must already resolve to this server.
Log levelinfotrace / debug / info / warn / error.

Database and session secrets are generated automatically, so you never type them. They are written to deploy/.env (file permissions 600, never committed to git).

At the end, let the script start the stack: it waits for the API, creates your admin account, and prints the generated password once, so copy it before closing the terminal.

By default the setup pulls the prebuilt images from Docker Hub: no Rust or Node toolchain, first start in a couple of minutes. Run ./setup.sh --build to build the three services from source instead (development, local changes).

Headless servers

The admin is created by core itself on first boot (from deploy/.env), so you don't need a browser on the server. Note the printed password and sign in from any machine that can reach the app.

Reinstalling over previous data

If Docker volumes from a previous install exist, the setup offers to wipe them. The default is No everywhere: wiping (and losing the previous database) only happens on an explicit y. Fresh secrets over an old database volume can't work, so declining aborts the setup rather than starting a broken stack.

Manual install (alternative)

If you prefer to configure by hand:

bash
cd deploy
cp .env.example .env

Edit .env and set at least:

  • POSTGRES_PASSWORD: a strong password
  • DATABASE_URL: must contain the same password, e.g. postgres://otw:YOUR_PASSWORD@postgres:5432/opentraderworld
  • SESSION_SECRET: a long random string

Then start the stack. By default this pulls the prebuilt images from Docker Hub (no Rust or Node toolchain required):

bash
docker compose -f docker-compose.yml -f docker-compose.images.yml \
  --env-file .env --env-file network.env up -d
Build from source instead

For development, or to run local changes, omit the images override and build the three services yourself (needs the toolchain; the Rust build is slow):

bash
docker compose --env-file .env --env-file network.env up --build -d

Create the admin (manual installs only)

If you used ./setup.sh and let it start the stack, your admin already exists, so skip ahead.

Otherwise, open the app in your browser (http://localhost:5454 by default). On the first visit, OpenTraderWorld detects there is no admin yet and shows the setup wizard: choose a username and password (min 8 characters), submit, and you land on the dashboard. Passwords are stored hashed with argon2.

Create the admin from the CLI (headless, no browser)

Hit the first-run endpoint from inside the stack: it works regardless of your bind interface or TLS mode, and refuses (HTTP 409) if an admin already exists:

bash
cd deploy
docker compose --env-file .env --env-file network.env exec -T caddy \
  wget -qO- --header=Content-Type:application/json \
  --post-data='{"username":"admin","password":"CHOOSE-A-STRONG-ONE"}' \
  http://core:8080/api/setup

Verify it's running

  • App: http://localhost:5454 (or your chosen port/domain)
  • Health check: http://localhost:5454/api/health{"status":"ok","service":"otw-core",...}
bash
cd deploy
docker compose ps            # container status
docker compose logs -f core  # follow core logs

Everyday operations

Run these from deploy/:

ActionCommand
Startdocker compose up -d
Stopdocker compose down
View logsdocker compose logs -f
Pull newer imagesdocker compose -f docker-compose.yml -f docker-compose.images.yml pull && docker compose up -d
Rebuild after changing code (source build)docker compose up --build -d
Stop and wipe all datadocker compose down -v

Your data lives in Docker named volumes and persists across up/down. It is only deleted with down -v.

Next steps