- Docker (Docker Desktop on Windows/Mac, or Docker Engine + Docker Compose v2 on Linux)
- Ports 80 (and 443 for HTTPS) open on your server
1. Get the code
git clone https://github.com/PeterLombaers/petlom.git
cd petlom2. Create your configuration file
cp .env.example .envOpen .env and fill in JWT_SECRET_KEY with a randomly generated secret:
python -c "import secrets; print(secrets.token_hex(32))"Paste the output as the value. The other settings have safe defaults for Docker deployments.
3. Start the application
docker compose up -d --buildThe first run downloads base images and builds the containers — this takes a few minutes.
4. Create your moderator account (do this once)
docker compose exec backend uv run python -m backend.create_account <username> <password>Replace <username> and <password> with your chosen credentials.
To hand someone result entry and nothing else, add --role result_keeper. They can fill
in the results of a round, but cannot change pairings, players or competitions. See
scripts/README.md.
5. Open the app
Go to http://localhost (or http://<your-server-ip> if running on a remote server).
Player search against the FIDE and KNSB rating lists, and the rating import that goes with it,
are disabled unless a chess_player_db instance
is reachable. Without one those features answer 503 and the rest of the app is unaffected.
The rating database is never contacted by the browser — petlom's backend proxies the requests — so it does not need to be exposed to the internet. Run it on the same host and let the two containers talk over its compose network:
1. Start chess_player_db first (its network has to exist before petlom starts):
cd /path/to/chess_player_db
docker compose up -d2. In petlom's .env, uncomment:
COMPOSE_FILE=docker-compose.yml:docker-compose.chessdb.yml
3. Start petlom as usual:
docker compose up -d --buildWithout the COMPOSE_FILE line, pass the overlay by hand instead:
docker compose -f docker-compose.yml -f docker-compose.chessdb.yml up -d --buildVerify the connection:
docker compose exec backend uv run -c "import httpx; print(httpx.get('http://chess-player-db:8000/federations/').json())"External search is moderator-only, so log in before the search field appears in the create-player dialog.
Caddy automatically obtains and renews a TLS certificate from Let's Encrypt. No further configuration is needed. You only need to set the environment variable CADDY_HOST so that it knows for which domain to obtain the certificate.
Update ALLOWED_ORIGINS in .env if you use the development workflow against your production server.
On the server:
git pull
docker compose build
docker compose up -dOr, from a machine that can reach the server over SSH, with scripts/.env configured
(see scripts/README.md):
scripts/deploy.sh --backupThat backs the database up first, then pulls, rebuilds, restarts, and checks the containers came back.
Note: Database schema changes are applied automatically when new tables are added, but existing tables are not altered. If a release adds columns to an existing table, a migration step will be documented in the release notes.
Copy the SQLite file out of the Docker volume without stopping the application. SQLite's online backup API gives a consistent snapshot even while the app is writing:
mkdir -p backups
docker compose exec -T backend uv run python -c "
import sqlite3
src = sqlite3.connect('/data/petlom.db')
dst = sqlite3.connect('/data/_backup.db')
with dst:
src.backup(dst)
dst.close(); src.close()
"
docker compose exec -T backend cat /data/_backup.db > "backups/petlom-$(date +%Y%m%d-%H%M%S).db"
docker compose exec -T backend rm -f /data/_backup.dbFrom a machine with SSH access to the server, scripts/backup.sh does all of that and
downloads the result — see scripts/README.md.
To restore, stop the stack, copy a backup back into the petlom_db volume as
petlom.db, and start it again.
docker compose logs -f
docker compose logs -f backend
docker compose logs -f caddy- Start the backend server:
uv run fastapi dev backend/main.py - Start the frontend server:
cd frontend && npm install && npm run dev - (Optional) Fill the database with fake data:
uv run python fill_db.py
The frontend dev server proxies all /api/* requests to the backend at http://localhost:8000, so
both servers can run simultaneously without CORS issues.
There is a VSCode tasks file at https://gist.github.com/PeterLombaers/0f896b05ecdaba6ff718f815b323ce71 that you can use to run these commands. Simply add it to your .vscode folder, use Ctrl+Shift+p and select Tasks: Run Task.
The TypeScript API client is generated using openapi-typescript. It uses the OpenAPI definition
that FastAPI outputs to generate TypeScript types for the backend API. These types are located at
frontend/src/client/schema.d.ts. You never need to manually edit this file — instead run
npm run generate-client from the frontend directory, or use the corresponding VSCode Task.