Running the server in Docker
The server comes as a container image, ghcr.io/burningstormstudios/odyssey-server, for anywhere Docker runs: a server of your own, a rented one, a NAS, or Docker Desktop on Windows or a Mac. It is the same server as the download, and it keeps everything it writes, the world, its settings, its art and its logs, in one folder you give it.
The image comes for 64-bit Intel and AMD processors and for 64-bit ARM ones, such as an Apple Silicon Mac. Docker picks the right one by itself.
Which image#
| Tag | What it is |
|---|---|
latest | The newest stable release. |
beta | The newest test release, or a stable one if it is newer. |
13, 13.0 | The newest stable release of 13, or of 13.0. |
13.0.0 | That release exactly, and never anything else. |
latest is the usual choice. Pin an exact version if you would rather choose when to update.
Running it#
Make a folder for the server's data, and start it there:
mkdir odyssey && cd odyssey
mkdir data
docker run -d --name odyssey \
--user "$(id -u):$(id -g)" \
-v "$PWD/data:/data" \
-p 2597-2599:2597-2599/udp \
--restart unless-stopped \
--stop-timeout 60 \
ghcr.io/burningstormstudios/odyssey-server:latest
--userruns the server as you, so the files indataare yours to open and edit.-vputs the server's data in thedatafolder.-popens the three game ports. They are UDP; see ports, routers and firewalls.--stop-timeout 60gives the server time to save when the container is stopped.
The first start makes a new, empty world and a server.yaml in data. docker logs odyssey shows what the server is doing.
To run a world you already have, such as one converted from the original Odyssey, put its .db file and its assets folder in data before the first start, and a server.yaml that names the file:
database:
provider: sqlite
file: discordia.db
Everything else in server.yaml is filled in on the first start. Settings in server.yaml has the rest.
On a Mac#
Docker on a Mac runs Linux in a virtual machine, and the server runs inside that. A port opened with -p is opened on the virtual machine, not on the Mac, and whether players reach it depends on how the Docker app passes ports from the Mac across. These steps are for Colima.
--user is your own user and group, as anywhere else. On a Mac id -u is usually 501 and id -g is 20, not the 1000:1000 in the examples here.
Out of the box, Colima passes TCP across and not UDP, and the game's ports are UDP. The server starts and says it is listening, but the game cannot reach it, even from the same Mac: connecting fails with "No route to host".
Give the virtual machine its own address on your network instead. Stop Colima with colima stop, and in ~/.colima/default/colima.yaml, under network, set:
network:
address: true
mode: bridged
interface: en0
interface is the Mac's connection to your network: route get default names it, after interface:. Then colima start. It may ask for your password, to install what this mode needs.
The virtual machine is now a machine of its own on your network, and colima list shows its address. That address is the server's:
- In the game, connect to that address, not to
localhost. - In Odyssey Server Admin, give that address too.
- On the router, forward the game's ports to that address, not to the Mac's. Give it a fixed address in the router's settings, as for any server; see ports, routers and firewalls.
Managing it#
Odyssey Server Admin manages a server in a container from your own computer, over the network, as it would any server somewhere else:
- Stop the container:
docker stop odyssey. - In
data/server.yaml, underadminApi, setenableNetwork: true. - Start it again with the admin port too. Add
-p 5297:5297to thedocker runabove, or toportsin a Compose file. - Read the setup code from
docker logs odyssey, and in Odyssey Server Admin choose Somewhere else, give the server's address and port 5297, and Claim this server. See staff, roles and rights.
With Docker Compose#
A compose.yaml holds the same settings, and is easier to keep. In the odyssey folder:
services:
server:
image: ghcr.io/burningstormstudios/odyssey-server:latest
# Your own user and group: run "id -u" and "id -g".
user: "1000:1000"
restart: unless-stopped
stop_grace_period: 1m
ports:
- "2597-2599:2597-2599/udp"
# - "5297:5297" # for Odyssey Server Admin, once enableNetwork is on
volumes:
- ./data:/data
Then docker compose up -d starts it, and docker compose logs -f server follows its log.
With a database#
The world can be kept in PostgreSQL, MySQL or MariaDB instead of a file. Compose can run the database beside the server. Before the first start, put a server.yaml in data that points at it:
database:
provider: postgres
host: db
name: odyssey
user: odyssey
For MySQL or MariaDB, the provider is mysql. The password is given to the server in ODYSSEY_DB_PASSWORD, so server.yaml holds nothing secret.
PostgreSQL:
services:
server:
image: ghcr.io/burningstormstudios/odyssey-server:latest
user: "1000:1000"
restart: unless-stopped
stop_grace_period: 1m
depends_on:
db:
condition: service_healthy
environment:
ODYSSEY_DB_PASSWORD: choose-a-password
ports:
- "2597-2599:2597-2599/udp"
volumes:
- ./data:/data
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: odyssey
POSTGRES_PASSWORD: choose-a-password
POSTGRES_DB: odyssey
healthcheck:
test: ["CMD-SHELL", "pg_isready -U odyssey -d odyssey"]
interval: 5s
retries: 10
volumes:
- db:/var/lib/postgresql/data
volumes:
db:
MySQL: the same server service, with this db:
db:
image: mysql:8.4
restart: unless-stopped
environment:
MYSQL_DATABASE: odyssey
MYSQL_USER: odyssey
MYSQL_PASSWORD: choose-a-password
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 20
volumes:
- db:/var/lib/mysql
MariaDB: the same, with this db:
db:
image: mariadb:11
restart: unless-stopped
environment:
MARIADB_DATABASE: odyssey
MARIADB_USER: odyssey
MARIADB_PASSWORD: choose-a-password
MARIADB_RANDOM_ROOT_PASSWORD: "yes"
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 5s
retries: 20
volumes:
- db:/var/lib/mysql
Choose your own password, the same in both places. The database's port is not opened to the outside: only the server reaches it.
depends_on holds the server back until the database answers. A world already kept in a file can be moved into the database with import-world: see putting a world in, running the command with docker compose run --rm server import-world /data/discordia.db.
Updating#
The server in a container does not update itself, and Odyssey Server Admin says so. A new version upgrades the world when it first starts, so back it up first: Back up now on the Database page of Odyssey Server Admin, or, with the server stopped, a copy of the data folder (and of the database, if the world is kept in one). Then pull the new image and start a new container from it:
docker compose pull
docker compose up -d
Or, without Compose, docker pull the image, then docker stop odyssey, docker rm odyssey, and the same docker run as before. The world is in data, so a new container carries on where the old one stopped.
Checking an image is ours#
Every image is signed by the workflow that builds it. With cosign:
cosign verify ghcr.io/burningstormstudios/odyssey-server:latest \
--certificate-identity-regexp '^https://github.com/BurningstormStudios/Odyssey/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
It prints the signature's details if the image came from us, and fails if it did not.