Skip to main content

Installation Guide

This guide will walk you through deploying your own GZCTF instance. GZCTF is designed to be deployed using containers for optimal portability and scalability.
Important: Before upgrading or migrating:
  1. Database migrations run automatically on startup
  2. Downgrade operations are NOT supported
  3. Always backup your data before upgrading
  4. Large version jumps may cause data incompatibility
  5. Review release notes for breaking changes

System Requirements

Minimum Requirements

CPU

2 cores (x64 or ARM64 architecture)

Memory

4 GB RAM minimum8 GB+ recommended for production

Storage

20 GB minimumScales with challenges and logs

Network

Stable internet connectionPublic IP for external access

Production Requirements

For production deployments with significant load:
  • CPU: 8+ cores for handling concurrent container operations
  • Memory: 16GB+ RAM (GZCTF tested with 16c90g handling 1.34M requests in 3 minutes)
  • Storage: SSD recommended for database performance
  • Network: Low latency, high bandwidth for container traffic

Software Prerequisites

  • Docker Engine 20.10+
  • Docker Compose V2 (recommended)
  • PostgreSQL 12+ (can be containerized)
  • Redis 6+ (can be containerized)

Architecture Overview

A typical GZCTF deployment consists of:

Docker Deployment

The recommended deployment method uses Docker containers for all services.
1

Install Docker

If you don’t have Docker installed:
# Update package index
sudo apt-get update

# Install dependencies
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Set up stable repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker Engine
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Verify installation
sudo docker --version
2

Create Project Directory

Create a directory structure for your GZCTF deployment:
mkdir -p ~/gzctf/{data,logs,files}
cd ~/gzctf
Directory purposes:
  • data/: PostgreSQL database files
  • logs/: Application logs
  • files/: Challenge files and uploads (if not using object storage)
3

Create Docker Compose File

Create a docker-compose.yml file with the following configuration:
docker-compose.yml
version: '3.8'

services:
  gzctf:
    image: gztime/gzctf:latest
    container_name: gzctf
    restart: always
    ports:
      - "80:8080"  # HTTP port
    environment:
      # Database Configuration
      - CONNECTIONSTRINGS__DATABASE=Host=db:5432;Database=gzctf;Username=postgres;Password=<your-db-password>
      
      # Redis Configuration
      - CONNECTIONSTRINGS__REDIS=cache:6379,password=<your-redis-password>
      
      # Email Configuration (Optional)
      - [email protected]
      - EMAILCONFIG__SMTP__HOST=smtp.example.com
      - EMAILCONFIG__SMTP__PORT=587
      - EMAILCONFIG__SMTP__CREDENTIALS__USERNAME=<smtp-username>
      - EMAILCONFIG__SMTP__CREDENTIALS__PASSWORD=<smtp-password>
      
      # Container Provider (docker or kubernetes)
      - CONTAINERPROVIDER__TYPE=docker
      - CONTAINERPROVIDER__PUBLICENTRY=<your-public-ip-or-domain>
      
      # Storage Configuration
      - STORAGE__TYPE=local  # or minio, s3
      
      # Misc Settings
      - ASPNETCORE_URLS=http://0.0.0.0:8080
      - LOGGING__LOGLEVEL__DEFAULT=Information
    volumes:
      - ./files:/app/files
      - ./logs:/app/log
      - /var/run/docker.sock:/var/run/docker.sock  # For Docker container management
    depends_on:
      - db
      - cache
    networks:
      - gzctf-network
  
  db:
    image: postgres:16-alpine
    container_name: gzctf-db
    restart: always
    environment:
      - POSTGRES_PASSWORD=<your-db-password>
      - POSTGRES_USER=postgres
      - POSTGRES_DB=gzctf
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    networks:
      - gzctf-network
  
  cache:
    image: redis:7-alpine
    container_name: gzctf-cache
    restart: always
    command: redis-server --requirepass <your-redis-password>
    volumes:
      - ./data/redis:/data
    networks:
      - gzctf-network

networks:
  gzctf-network:
    driver: bridge
Security: Replace all <your-*-password> placeholders with strong, unique passwords. Never commit these files with real credentials to version control.
4

Configure Environment Variables

For better security, create a .env file instead of hardcoding passwords:
.env
# Database
POSTGRES_PASSWORD=your_secure_db_password_here

# Redis
REDIS_PASSWORD=your_secure_redis_password_here

# SMTP (if using email)
SMTP_USERNAME=your_smtp_username
SMTP_PASSWORD=your_smtp_password

# Public Entry
PUBLIC_ENTRY=your.domain.com
Then reference in docker-compose.yml using ${VARIABLE_NAME} syntax.
5

Start Services

Launch all services:
# Pull latest images
docker compose pull

# Start services in detached mode
docker compose up -d

# View logs
docker compose logs -f gzctf
First startup may take 1-2 minutes as the database is initialized and migrations are applied.
6

Verify Installation

Check that all services are running:
# Check container status
docker compose ps

# Expected output:
# NAME         IMAGE                  STATUS
# gzctf        gztime/gzctf:latest   Up
# gzctf-db     postgres:16-alpine    Up
# gzctf-cache  redis:7-alpine        Up

# Test health endpoint
curl http://localhost/healthz
Navigate to http://localhost (or your server IP) in a browser. You should see the GZCTF interface.

Understanding the Dockerfile

GZCTF uses a multi-stage build optimized for Alpine Linux:
Dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS build
ARG TARGETPLATFORM
COPY publish /build
RUN cp -r /build/${TARGETPLATFORM} /publish

FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final

# Globalization support for multi-language
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false \
    LC_ALL=en_US.UTF-8

WORKDIR /app

# Install runtime dependencies
RUN apk add --update --no-cache \
    wget \
    libpcap \
    icu-data-full \
    icu-libs \
    ca-certificates \
    libgdiplus \
    tzdata \
    krb5-libs && \
    update-ca-certificates

COPY --from=build --chown=$APP_UID:$APP_UID /publish .

# Expose application port
EXPOSE 8080

# Health check configuration
HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=1 \
    CMD wget --no-verbose --tries=1 --spider http://localhost:3000/healthz || exit 1

ENTRYPOINT ["dotnet", "GZCTF.dll"]
Key features:
  • Based on .NET 10.0 Alpine for minimal size
  • Multi-platform support (x64, ARM64)
  • Includes ICU for internationalization
  • Health check endpoint at /healthz
  • Runs on port 8080 internally

First-Time Configuration

After installation, configure your GZCTF instance:
1

Access Admin Panel

  1. Navigate to your GZCTF URL
  2. Click “Register” and create the first user account
  3. The first registered user is automatically granted admin privileges
2

Configure Global Settings

Navigate to Admin Panel → Settings and configure:
  • Platform Title: Your CTF platform name
  • Platform Description: Brief description for SEO
  • Platform Logo/Favicon: Upload custom branding
  • Footer Content: Custom footer HTML
  • Allow Registration: Enable/disable public registration
  • Email Confirmation: Require email verification
  • Active on Register: Auto-activate accounts
  • Email Domain List: Restrict to specific domains
  • Use Captcha: Enable Cloudflare Turnstile
  • Provider Type: Docker or Kubernetes
  • Public Entry: Your public IP or domain
  • Port Range: Range for dynamic container ports
  • Registry: Container image registry URL
  • Auto Destroy: Container lifetime settings
  • Storage Type: Local, MinIO, or S3
  • Bucket Name: For object storage
  • Access Key/Secret: Object storage credentials
  • Region: For AWS S3
3

Test Configuration

  • Send a test email to verify SMTP settings
  • Create a test challenge with container to verify orchestration
  • Upload a test file to verify storage backend
  • Check health metrics and logs

Advanced Configuration

Using Object Storage (MinIO/S3)

For scalable deployments, use object storage instead of local files:
environment:
  - STORAGE__TYPE=minio
  - STORAGE__MINIO__ENDPOINT=minio:9000
  - STORAGE__MINIO__ACCESSKEY=minioadmin
  - STORAGE__MINIO__SECRETKEY=minioadmin
  - STORAGE__MINIO__SECURE=false
  - STORAGE__MINIO__BUCKETNAME=gzctf

Kubernetes Deployment

For Kubernetes deployments:
  1. Configure container provider: CONTAINERPROVIDER__TYPE=kubernetes
  2. Create appropriate RBAC roles for pod management
  3. Use Kubernetes secrets for sensitive configuration
  4. Configure persistent volumes for database
  5. Set up ingress for external access
Detailed Kubernetes manifests and Helm charts are available in the official documentation.

Reverse Proxy Setup

For production, use a reverse proxy (nginx, Caddy, Traefik):
server {
    listen 80;
    server_name ctf.example.com;
    
    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ctf.example.com;
    
    ssl_certificate /etc/ssl/certs/cert.pem;
    ssl_certificate_key /etc/ssl/private/key.pem;
    
    client_max_body_size 256M;
    
    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Monitoring & Maintenance

Health Checks

GZCTF exposes health endpoints:
# Basic health check
curl http://localhost:8080/healthz

# Detailed health information (admin only)
curl http://localhost:8080/api/health

Viewing Logs

# Follow application logs
docker compose logs -f gzctf

# View specific time range
docker compose logs --since 30m gzctf

# Save logs to file
docker compose logs gzctf > logs.txt

Backup Strategy

Regular backups are CRITICAL. GZCTF does not support downgrades, and data loss can be unrecoverable.
1

Database Backup

# Automated PostgreSQL backup
docker exec gzctf-db pg_dump -U postgres gzctf > backup_$(date +%Y%m%d).sql

# Restore from backup
docker exec -i gzctf-db psql -U postgres gzctf < backup_20260301.sql
2

Files Backup

# Backup files directory
tar -czf files_backup_$(date +%Y%m%d).tar.gz -C ~/gzctf files/

# Restore files
tar -xzf files_backup_20260301.tar.gz -C ~/gzctf
3

Configuration Backup

# Backup entire configuration
tar -czf gzctf_full_backup_$(date +%Y%m%d).tar.gz \
  ~/gzctf/docker-compose.yml \
  ~/gzctf/.env \
  ~/gzctf/data/ \
  ~/gzctf/files/

Upgrading GZCTF

1

Backup Everything

Create a complete backup before upgrading (see Backup Strategy above).
2

Pull Latest Image

cd ~/gzctf
docker compose pull gzctf
3

Restart Services

docker compose up -d gzctf
Database migrations run automatically on startup.
4

Verify Upgrade

# Check logs for successful migration
docker compose logs gzctf | grep -i migration

# Verify application is running
curl http://localhost/healthz

Troubleshooting

Symptoms: Application fails to start, connection refused errorsSolutions:
  • Verify PostgreSQL container is running: docker compose ps
  • Check database password matches in both services
  • Ensure network connectivity: docker compose exec gzctf ping db
  • Review PostgreSQL logs: docker compose logs db
Symptoms: “Failed to create container” errorsSolutions:
  • Verify Docker socket is mounted: -v /var/run/docker.sock:/var/run/docker.sock
  • Check Docker permissions: GZCTF needs access to Docker API
  • Verify network configuration and port ranges
  • Check available system resources (CPU, memory, disk)
  • Review container provider settings in admin panel
Symptoms: Users don’t receive verification emailsSolutions:
  • Test SMTP settings from admin panel
  • Check SMTP credentials are correct
  • Verify firewall allows outbound SMTP traffic
  • Check spam folders
  • Review email logs: docker compose logs gzctf | grep -i email
Symptoms: System slowness, OOM errorsSolutions:
  • Limit Redis memory: add maxmemory 2gb to Redis config
  • Configure container auto-destroy to clean up unused instances
  • Increase system resources
  • Monitor with docker stats
  • Check for memory leaks in logs
Symptoms: Slow page loads, timeoutsSolutions:
  • Ensure PostgreSQL has adequate resources
  • Check database indexes are created (automatic)
  • Monitor query performance: docker exec gzctf-db psql -U postgres -d gzctf -c "SELECT * FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;"
  • Consider increasing PostgreSQL shared_buffers
  • Use SSD storage for database

Performance Tuning

For high-load scenarios:
Add to PostgreSQL configuration:
shared_buffers = 2GB
effective_cache_size = 6GB
maintenance_work_mem = 512MB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
random_page_cost = 1.1
effective_io_concurrency = 200
work_mem = 20MB
min_wal_size = 1GB
max_wal_size = 4GB

Security Best Practices

Network Security

  • Use HTTPS with valid certificates
  • Configure firewall rules
  • Limit database access to localhost
  • Use VPN for admin access

Access Control

  • Strong passwords for all services
  • Regular password rotation
  • Enable 2FA for admin accounts (if available)
  • Audit user permissions regularly

Data Protection

  • Encrypt database backups
  • Secure backup storage
  • Regular backup testing
  • GDPR compliance for user data

Container Security

  • Keep images updated
  • Scan for vulnerabilities
  • Limit container resources
  • Use security profiles

Next Steps

Admin Guide

Learn how to configure and manage your GZCTF platform.

Create Your First Game

Set up your first CTF competition.

Challenge Configuration

Create and configure challenges for your competitions.

Monitoring & Metrics

Set up monitoring and observability for your instance.

Community & Support

Need help with installation?

Build docs developers (and LLMs) love