---
title: "Deploy CTFd"
description: "Capture-the-flag platform with MariaDB, Redis, volumes and locked setup"
category: "Other"
url: https://railway.com/deploy/ctfd-1
---

# Deploy CTFd

Capture-the-flag platform with MariaDB, Redis, volumes and locked setup

**[Deploy CTFd on Railway](https://railway.com/template/ctfd-1)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/ctfd-1/manifest.json

- **Creator:** Agaz Self-Host
- **Category:** Other

## Template content

### MariaDB

- **Image:** mariadb:10.11.19@sha256:d769e37960821dfdcf096954f6e7ac89f747e116c1bba98e48edd265dfc7deae
- **Start command:** `/bin/bash -c 'export MARIADB_USER="${MARIADB_USER:-ctfd}" MARIADB_DATABASE="${MARIADB_DATABASE:-ctfd}" MARIADB_AUTO_UPGRADE="${MARIADB_AUTO_UPGRADE:-1}"; exec docker-entrypoint.sh mariadbd --datadir=/var/lib/mysql/data --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --wait_timeout=28800 --log-warnings=0'`

### Redis

- **Image:** redis:8.8.4@sha256:6e61ab45b3e867bacbef2fdd969ec74f4e0f8aaca8cc946cb8ac0c494035e7e7
- **Start command:** `/bin/sh -c 'rm -rf /data/lost+found && exec docker-entrypoint.sh redis-server --requirepass "$REDIS_PASSWORD" --save 60 1 --dir /data'`

### CTFd https://ctfd.io/static/images/Logo.png

- **Image:** ctfd/ctfd:3.8.9@sha256:84aff1e50b6a6f931b5da90c6f5b7c623ba4583217a9b00e9d4c1b7c53b9739f
- **Start command:** `/bin/bash -c 'set -e; cd /opt/CTFd; export UPLOAD_FOLDER="${UPLOAD_FOLDER:-/data/uploads}" LOG_FOLDER="${LOG_FOLDER:-/data/logs}" REVERSE_PROXY="${REVERSE_PROXY:-2,1,1,1,0}" WORKERS="${WORKERS:-3}" WORKER_CLASS="${WORKER_CLASS:-gevent}"; mkdir -p "$UPLOAD_FOLDER" "$LOG_FOLDER" CTFd/plugins/railway_setup_gate; echo IyBSYWlsd2F5IHRlbXBsYXRlOiBvbmx5IHRoZSBob2xkZXIgb2YgU0VUVVBfVE9LRU4gbWF5IHJ1biBDVEZkJ3MgZmlyc3QtcnVuIC9zZXR1cCB3aXphcmQuCmltcG9ydCBobWFjCmltcG9ydCBvcwoKZnJvbSBmbGFzayBpbXBvcnQgcmVkaXJlY3QsIHJlcXVlc3QsIHNlc3Npb24sIHVybF9mb3IKCmZyb20gQ1RGZC51dGlscy5jb25maWcgaW1wb3J0IGlzX3NldHVwCgpQQUdFID0gIiIiPCFkb2N0eXBlIGh0bWw+PGh0bWw+PGhlYWQ+PG1ldGEgY2hhcnNldD0idXRmLTgiPjx0aXRsZT5DVEZkIHNldHVwIGlzIGxvY2tlZDwvdGl0bGU+PC9oZWFkPgo8Ym9keSBzdHlsZT0iZm9udC1mYW1pbHk6c2Fucy1zZXJpZjttYXgtd2lkdGg6NDBlbTttYXJnaW46NGVtIGF1dG87bGluZS1oZWlnaHQ6MS41Ij4KPGgxPkNURmQgaXMgbm90IHNldCB1cCB5ZXQ8L2gxPgo8cD5UbyBydW4gdGhlIHNldHVwIHdpemFyZCwgb3BlbiA8Y29kZT4vc2V0dXA/dG9rZW49Jmx0O1NFVFVQX1RPS0VOJmd0OzwvY29kZT4gb24gdGhpcyBkb21haW4uCjxjb2RlPlNFVFVQX1RPS0VOPC9jb2RlPiBpcyBhIHZhcmlhYmxlIG9uIHRoZSBDVEZkIHNlcnZpY2UgaW4geW91ciBSYWlsd2F5IHByb2plY3QuPC9wPjwvYm9keT48L2h0bWw+IiIiCgoKZGVmIGxvYWQoYXBwKToKICAgIHRva2VuID0gb3MuZW52aXJvbi5nZXQoIlNFVFVQX1RPS0VOIiwgIiIpCiAgICBpZiBub3QgdG9rZW46CiAgICAgICAgcmV0dXJuCgogICAgQGFwcC5iZWZvcmVfcmVxdWVzdAogICAgZGVmIHJhaWx3YXlfc2V0dXBfZ2F0ZSgpOgogICAgICAgIGlmIHJlcXVlc3QuZW5kcG9pbnQgIT0gInZpZXdzLnNldHVwIiBvciBpc19zZXR1cCgpOgogICAgICAgICAgICByZXR1cm4gTm9uZQogICAgICAgIGdpdmVuID0gcmVxdWVzdC5hcmdzLmdldCgidG9rZW4iLCAiIikKICAgICAgICBpZiBnaXZlbiBhbmQgaG1hYy5jb21wYXJlX2RpZ2VzdChnaXZlbi5lbmNvZGUoKSwgdG9rZW4uZW5jb2RlKCkpOgogICAgICAgICAgICBzZXNzaW9uWyJyYWlsd2F5X3NldHVwX29rIl0gPSBUcnVlCiAgICAgICAgICAgIHJldHVybiByZWRpcmVjdCh1cmxfZm9yKCJ2aWV3cy5zZXR1cCIpKQogICAgICAgIGlmIHNlc3Npb24uZ2V0KCJyYWlsd2F5X3NldHVwX29rIik6CiAgICAgICAgICAgIHJldHVybiBOb25lCiAgICAgICAgcmV0dXJuIFBBR0UsIDQwMwo= | base64 -d > CTFd/plugins/railway_setup_gate/__init__.py; if [ "$(id -u)" = 0 ]; then chown -R 1001:1001 "$UPLOAD_FOLDER" "$LOG_FOLDER" CTFd/plugins/railway_setup_gate; exec setpriv --reuid=1001 --regid=1001 --clear-groups /opt/CTFd/docker-entrypoint.sh; fi; exec /opt/CTFd/docker-entrypoint.sh'`
- **Health check:** /healthcheck
- **Public domain:** Yes

## Documentation

# Deploy and Host CTFd on Railway

CTFd is an open-source platform for running capture-the-flag (CTF) competitions. Admins create challenges with flags, hints and downloadable files. Players or teams register, submit flags and climb a live scoreboard. It includes user and team modes, dynamic scoring, an admin panel, plugins and themes, and a REST API.

## About Hosting CTFd

Hosting CTFd means running its Python (gunicorn) web app with a MySQL-compatible database, a Redis cache, and persistent storage for challenge files. This template deploys the official `ctfd/ctfd` 3.8.9 image with MariaDB 10.11 and Redis 8.8, each pinned by digest and on its own volume, so challenges, users, solves and uploads survive redeploys. CTFd runs three gevent workers behind Railway's proxy with the real client IP passed through. It connects to the database and cache over the private network, and generates its secret key at deploy time. The first-run setup wizard is locked behind a generated `SETUP_TOKEN`, so nobody else can claim the admin account before you do.

## Common Use Cases

* Running a public or private CTF competition for a conference, meetup or online event
* Security training and workshops in schools, universities and companies
* Hosting an internal practice range of challenges for a red team or a CTF team

## Dependencies for CTFd Hosting

* MariaDB (database for users, challenges, submissions and settings)
* Redis (cache and session store)

### Deployment Dependencies

* [CTFd on GitHub](https://github.com/CTFd/CTFd) and the [3.8.9 release](https://github.com/CTFd/CTFd/releases/tag/3.8.9)
* [CTFd deployment docs](https://docs.ctfd.io/docs/deployment/installation) and [configuration reference](https://docs.ctfd.io/docs/deployment/configuration)
* Images: [ctfd/ctfd](https://hub.docker.com/r/ctfd/ctfd), [mariadb](https://hub.docker.com/_/mariadb), [redis](https://hub.docker.com/_/redis)

### Implementation Details

After the deploy finishes, open the CTFd service's **Variables** tab in Railway, copy `SETUP_TOKEN`, and visit:

```
https:///setup?token=
```

Complete the wizard to name your event and create the admin account. Until then, every page shows a short "setup is locked" notice. Once setup is done, the token has no further effect.

- Uploads and CTFd's logs live on the CTFd volume at `/data`. MariaDB stores its data on its own volume, and Redis on another.
- Defaults are set in the start command and can be overridden with service variables: `WORKERS` (3), `WORKER_CLASS` (gevent), `REVERSE_PROXY` (`2,1,1,1,0`), `UPLOAD_FOLDER`, `LOG_FOLDER`. Any other [CTFd setting](https://docs.ctfd.io/docs/deployment/configuration), such as `MAIL_SERVER` for email, can be added as a variable.
- The container starts as root only to fix the volume's ownership, then drops to CTFd's own user (uid 1001).

## Why Deploy CTFd on Railway?


Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying CTFd on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.



## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/ctfd-1
