Skip to content

Getting Started

Quick start (copy-paste)

Create a folder, add two files, then run Docker.

1. Save as docker-compose.yml:

services:
  postgres:
    image: postgres:16-alpine
    container_name: matchzy-postgres
    restart: unless-stopped
    environment:
      - POSTGRES_USER=${DB_USER:-postgres}
      - POSTGRES_PASSWORD=${DB_PASSWORD:-postgres}
      - POSTGRES_DB=${DB_NAME:-matchzy_tournament}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U ${DB_USER:-postgres}']
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - matchzy-network

  matchzy-tournament:
    image: sivertio/matchzy-auto-tournament:latest
    container_name: matchzy-tournament-api
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    env_file:
      - .env
    ports:
      - '${HOST_PORT:-3069}:3069'
    environment:
      # Container-specific settings
      - NODE_ENV=production
      - PORT=3000
      # Docker service name for DB connection
      - DB_HOST=postgres
      # Computed DATABASE_URL (uses DB_* vars from .env or defaults)
      - DATABASE_URL=postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@postgres:5432/${DB_NAME:-matchzy_tournament}
      # All other variables (SERVER_TOKEN, STEAM_API_KEY, FRONTEND_BASE_URL, LOG_LEVEL, etc.)
      # are loaded from .env via env_file directive above
    volumes:
      - ./data:/app/data
    healthcheck:
      test: ['CMD', 'wget', '--no-verbose', '--tries=1', '--spider', 'http://localhost:3069/health']
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 10s
    networks:
      - matchzy-network

networks:
  matchzy-network:
    driver: bridge

volumes:
  postgres-data:
    driver: local

Note: This docker-compose.yml automatically reads variables from a .env file in the same directory. Values like ${DB_USER:-postgres} mean "use DB_USER from .env, or default to 'postgres' if not set".

2. Save as .env (optional, for production):

# Database credentials (optional - defaults to postgres/postgres/matchzy_tournament)
DB_USER=postgres
DB_PASSWORD=postgres
DB_NAME=matchzy_tournament

# Session secret (required for session persistence - generate with: openssl rand -base64 32)
SESSION_SECRET=your-session-secret-here

# CS2 server authentication token (required for servers to connect)
SERVER_TOKEN=your-secure-token-here

# Steam API key (required for Steam login - get from https://steamcommunity.com/dev/apikey)
STEAM_API_KEY=your-steam-api-key

# Frontend base URL (for auth redirects)
# Use http:// for local development, https:// for production
FRONTEND_BASE_URL=http://localhost:3069

# Logging (optional - defaults to info)
LOG_LEVEL=info

# Auth settings (optional)
AUTH_STEAM_ENABLED=true

Note: - The env_file: - .env directive in docker-compose.yml automatically loads all variables from your .env file into the container - Important: Set SESSION_SECRET in .env for session persistence (sessions won't survive restarts without it) - Set FRONTEND_BASE_URL to https://your-domain.com in production for secure cookies

3. Start the stack:

docker compose up -d

4. Open in browser: http://localhost:3069

Note: - The docker-compose.yml works without a .env file for quick testing (uses defaults) - For production, create a .env file with SERVER_TOKEN, STEAM_API_KEY, and optionally custom DB_* values - The env_file: - .env directive explicitly loads variables from .env into the container - You can also configure SERVER_TOKEN and STEAM_API_KEY in Settings after first login


Install from repository

If you prefer to clone and use the project’s compose files:

git clone https://github.com/sivert-io/matchzy-auto-tournament.git
cd matchzy-auto-tournament

# Optional: create .env for SERVER_TOKEN, FRONTEND_BASE_URL, etc.
cp example.env .env

# Start (uses pre-built image from Docker Hub)
docker compose -f docker/docker-compose.yml up -d

# Open browser
open http://localhost:3069

To build from source instead:

docker compose -f docker/docker-compose.local.yml up -d --build

Configure Webhook URL

  1. Go to SettingsWebhook URL
  2. Enter your public URL (e.g. https://tournaments.example.com)
  3. CS2 servers use this to send match events to the platform

Local / same machine? Use http://your-local-ip:3069 (not localhost) so servers can reach the app.


Add CS2 Server

Option A: Automated (recommended)

Use the CS2 Server Manager — it configures everything with one command.

Option B: Manual

  1. Install CounterStrikeSharp on your CS2 server
  2. Install MatchZy Enhanced v1.3.0+
  3. In server.cfg set:
    rcon_password "your-secure-password"
    hostport 27015
    
  4. In the platform: ServersAdd Server → enter Name, Host, Port, RCON password → Test ConnectionSave

The server should show 🟢 Online.


Your First Tournament

1. Create teams

ServersTeamsCreate Team

Name: Team Astralis
Tag: AST
Players: Add 5+ players with Steam IDs

Create at least 2 teams.

2. Create tournament

DashboardCreate Tournament

Name: Weekend Cup
Type: Single Elimination (or Double, Swiss, etc.)
Format: BO3
Teams: Select your teams
Maps: Active Duty or custom pool

Click Create Tournament.

3. Start tournament

  1. Click Start Tournament
  2. Matches are created and wait for servers
  3. Players use team pages: https://your-url.com/team/team-name
  4. Veto runs in the browser
  5. Match loads on the server
  6. Bracket updates live

The system handles server allocation, match loading, veto, score updates, and bracket progression.


Next steps

For tournament admins

For players

Share team pages:

https://your-domain.com/team/team-name

Players can view upcoming matches, take part in veto, get server connect info, and see live scores. No login required.

For developers