Quick Start
Hosting your own CTF can be quite tricky, but we want to change that!
Below you will find all the necessary steps to get your own instance of CTF-Citadel up and running in no time!
Web-App Initial Setup
We can start off by cloning the main WebApp Repository
# clone the repogit clone https://github.com/CTF-Citadel/webapp# change into the examples foldercd webapp/examples/
Great, now we have everything we need to get started!
The examples subdirectory contains config files for NGINX, as well as a dedicated subfolder for SSL-Certificates, which is nginx/ssl/
.
You may put two files in here named server.crt
and server.key
respectably, which is you Public Certificate and Private Key.
Self-signed certificates are not recommended, you should of course have some valid domain to register officially signed SSL-Certificates. Although when deploying the platform locally, inaccessible to the outside world, self-signed Certificates may be sufficient.
Deploy Using Docker
We made hosting your own instance of CTF-Citadel really easy to accoplish using the power of Docker.
Fresh Images of our WebApp are built on every push to master
and can be pulled from here:
docker pull ghcr.io/ctf-citadel/webapp:main
An way easier method is to use our docker-compose.yaml
file already present in the repo.
This automatically pulls prebuilt images from their respective container registries and should get you up and running in no time.
Before that, it may be a good thing to customize some things for your needs, which is described below.
What to change
The file might look a bit overwhelming at first so here is a walkthrough on what you will need to change.
Bind Mounts
./nginx/nginx.conf:/etc/nginx/nginx.conf
: This is a bind mount to the configuration files for the NGINX reverse proxy. This path should not need changing as long as you do not change the file location of thedocker-compose.yaml
. You can navigate toproxy/
from the repo root and examine the provided config file. If desired you can use a different proxy or integrate it into an already exisiting one../nginx/ssl:/etc/ssl/private
: This is the bind mount to your SSL Certificates that NGINX will use to secure your traffic over HTTPS. If you examined the config file you might have noticed that it will always look forserver.crt
andserver.key
. You should either name your certfiles accordingly or modify the paths in the config file mentioned above../data/postgres:/var/lib/mysql
: This is where your database stores data, which is user data, challenges, ongoing events and more. Choose this path wisely as it is where your data will reside!
General Variables
DB_*
: These are database parameters and should match the ones that you define for the PostgreSQL container itself. We won’t got into more detail on each of them as they are pretty self-explanatoryCONFIG_DIR
: The folder where the configuration fileconfig.yaml
resides in.
Configuration File
The newest version of CTF-Citadel is configured via a unified configuration file. An example configuration is provided in the examples/
folder of the Repository which can be modified according to your needs. Every configuration entry is documented right in the file itself and most are self explanatory.
[webapp]# Name of the instancename = 'testCTF'# Flag prefixprefix = 'CTD'# Dynamic scoring valuesdynamic_k = 24dynamic_p = 1.2# Absolute path to the platform data storagedata = '/data'# Official Discord server URLdiscord = ''
[email]# Email service nameservice = 'hotmail'# Username and password for the email accountusername = 'someone@example.com'password = 'CHANGEME'# Disable email verification requirement on Signupdisable_verify = false# Enable certificate mailing integrationenable_certificate_mailing = false# Enforce a specific email domainenable_enforce_domain = falseenforce_domain = ''
[infra]enable = false# Hostname or IP of the inegrationhost = 'remote.example.com'# Access port of the inegrationport = 443# PSK of the servicepsk = 'CHANGEME'
[m0n1t0r]enable = false# Hostname or IP of the inegrationhost = 'm0n1t0r'# Access port of the inegrationport = 9999# PSK of the servicepsk = 'CHANGEME'
[f1rstbl00d]enable = false# Hostname or IP of the inegrationhost = 'f1rstbl00d'# Access port of the inegrationport = 80# PSK of the servicepsk = 'CHANGEME'
Starting the Containers
Once you are happy with your changes, there is only one thing left to do:
docker-compose --profile full up -d
This will pull and start all containers and if you go to https://localhost:443/
, you should see the Login Page show up.
Understanding Profiles
The docker-compose.yaml
file in examples is structured and managed using docker profiles. This allows you to omit certain components of the whole Citadel stack, if desired.
There are currently three profiles available.
full
: Deploy the stack using all components, including Anti-Cheat, Discord Bot and WebAppstandalone
: Deploy only the WebApp component, excluding Anti-Cheat and Discord Botanticheat
: Deploy the WebApp, including only the Anti-Cheat Componentfirstblood
: Deploy the WebApp, including only the Discord Bot Component
To start a different profile, just switch the command already shown above, for example to use standalone
mode you can run the following.
docker-compose --profile standalone up -d
By utilizing different profiles, different environment variables will come into effect, so be sure you configured them correctly.
Manual Building of the WebApp
If you want to test the latest bleeding-edge changes directly from main
or maybe incorporate some changes of your own, you will need to build a new Docker images locally.
Doing that is pretty easy and can be done by modifying the docker-compose.yaml
in the examples folder.
version: '3'services: # ... # You can leave the nginx and postgres containers identical # ... webapp: build: # <- changing from image to build context: ${PWD}/../ # <- specify our project root dockerfile: Dockerfile # <- name of the Dockerfile to build from # ... # Rest is the same # ...
If you did the above correctly you should now be able to build your own image, telling Docker to do so.
docker-compose up -d --build
This should build the Astro WebApp directly from source and start the other containers automatically.
Infra-Backend Setup
Start by copying the tophack-stack.yml
file from the sample folder in the infra-middleware Repository to your server.
Setup Docker Swarm Production Environment
This setup requires a Linux machine with Docker installed.
Initialize Cluster:
docker swarm init --advertise-addr <MANAGER-IP>
This will return something like:
docker swarm init --advertise-addr 192.168.99.100Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join \ --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \ 192.168.99.100:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
As the output suggests, you need to run the docker swarm join --token <TOKEN>
command on each node.
Setup Traefik in Newly Created Swarm
docker network create --driver=overlay --subnet=10.1.0.0/16 traefik-public
export NODE_ID=$(docker info -f '{{.Swarm.NodeID}}')
docker node update --label-add traefik-public.traefik-public-certificates=true $NODE_ID
# Environment variables for the entire CTF Citadel backend, excluding the webappexport EMAIL=admin@tophack.org # Email for certbotexport DOMAIN=traefik.cluster.tophack.org # Domain for Traefikexport CONTROLLER_DOMAIN=cluster.tophack.org # Domain for controller containersexport USERNAME=admin # Username for Portainerexport PASSWORD=super_secret_portainer_password # Password for Portainerexport HASHED_PASSWORD=$(openssl passwd -apr1 $PASSWORD) # Hashed password for Portainerexport CF_API_EMAIL=mymail@cloudflare.com # Email of Cloudflare account owning the domain for DNS challengeexport CF_API_KEY=my-cf-api-key # API key of Cloudflare account owning the domain for DNS challengeexport GITHUB_USERNAME=ctf-citadel # Username of the GitHub account owning the challenge repositoryexport GITHUB_TOKEN=ghp_supersecret # Personal access token of the GitHub account owning the challenge repositoryexport DOCKERHUB_USERNAME=dockerhubuser # Username for Dockerhub, used to push images during the eventexport DOCKERHUB_TOKEN=dckr_pat_supersecret # Personal access token for Dockerhub, used to push images during the eventexport PSK=super_secret_key # Pre-shared key to authenticate web-backendexport CONTROLLER_REPLICACOUNT=1 # Count of replicas for controller container. This also specifies the number of images that can be built simultaneously.
docker login -u $GITHUB_USERNAME -p $GITHUB_TOKEN ghcr.io
Login to ghcr.io for the controller image:
docker stack deploy -c tophack-stack.yml tophack-stack
This deploys Traefik and the infra-middleware controller to the Swarm cluster with your environment variables.
Authors: Fabian T. & Felix S.