Skip to main content

Deploying Challenge Services

Automatic Challenge Deployment Service

Hosted CTFd offers a service that allows you to manage and automatically deploy Capture The Flag challenges in the form of challenge containers. Challenge containers are typical applications packaged using Docker into Docker images and are deployed in our challenge container servers.

Applications that are deployed through this service can be accessed by any user with knowledge of the URL/hostname.

If you are looking for a per-account instance of an application, where it can be deployed by each user, please see Application Target Challenges.


Automatic challenge deployment is only available in Hosted CTFd and Enterprise installations of CTFd


Hosted CTFd currently only supports images built for the linux/amd64 platform. Details on how to build an appropriate image while using an ARM based system (Apple Silicon, ARM, ARM64) can be found on Docker's documentation on Buildx.

Deployment Requirements

Challenge containers/services must meet the following requirements:

  • Challenge containers must EXPOSE a port (e.g. EXPOSE 8000) in their Dockerfile/image
  • Challenge containers should have a network service running that listens on your EXPOSE'ed port that then relays the network connection to your main service (see this page for an example)
  • Challenge containers should be as small as possible
  • Challenge containers should not be comprised of multiple applications
  • Challenge containers are not made with Docker Compose

It's worth noting as well that Hosted CTFd instances are not required to use our challenge deployment infrastructure. If you have very specific requirements, you're free to run your application on seperate servers. For example those provided by DigitalOcean, Amazon Web Services, Google Cloud Platform, or Microsoft Azure.

Deployment Steps

To create a service-based challenge:

  1. Login as an administrator and navigate to the Admin Panel.

  2. Click on the Services link on the top right.

  3. Click the "plus" icon to go to the create service page.

  4. Give your service a title (alphanumeric and dashes only) and click the Create button.

  5. Build your docker image.

  6. After building the docker image, open your terminal and run the commands listed on the service page.

    • Login with your CTFd username as <username>@<> and account password.

      $ docker login -u '[email protected]'
    • Tag the target image[subdomain]/[challenge-name] with the source image [your image name].

      $ docker tag your-image-name[subdomain]/[challenge-name]
    • Push the tagged image to CTFd's service registry.

      $ docker push[subdomain]/[challenge-name]
  7. The service page will then update with the deployed domain name of the challenge (You may need to manually refresh the page). You should receive an email every time the challenge is deployed.


Below is a hypothetical example using the hosted CTFd instance.

$ docker login
Username: [email protected]
Password: password
Login Succeeded

$ docker tag <image><challenge-name>

$ docker push<challenge-name>
The push refers to repository [<challenge-name>]
d331a460b7f1: Pushed
b826215d4ea3: Pushed
0987a4ff6d69: Pushed
d7a1c1d656bd: Pushed
2c77720cf318: Pushed
1f6b6c7dc482: Pushed
c8dbbe73b68c: Pushed
2fb7bfc6145d: Pushed
latest: digest: sha256:... size: 12345

As a reminder, your Docker image must have a port exposed. Most images do, but if you happen to be writing something custom, here's the reference in the Docker documentation.

Common examples are EXPOSE 80 or EXPOSE 8000.

Once the docker image succeeds, the services page should show:

Current Status: deployed

Deployed On:

Internal Port: 8000

This is persistent link that participants can use to access your challenge.

Connecting to Services

Hosted CTFd instances uses an improved customized infrastructure based on SNI multiplexing to host challenge services. Our infrastructure automatically encrypts all communication to a challenge service and all communication happens over a single well known port (443). You can read more about the this design on our blog at

If the underlying application you've deployed is a web server, you can simply open the URL in a browser and it will work seamlessly (e.g.

However, if your underlying application communicates directly over TCP you have a few options:

  1. You may use an SSL/TLS aware client software such as our snicat (sc) tool.

  2. Or you can "Request a TCP port" from our infrastructure and use a tool such as netcat. Keep in mind that this will forego any security or vanity benefits provided by using our encrypted connections.


snicat is designed to be very similar to netcat whilst providing vanity urls and encrypted connections. snicat can also be downloaded for Mac, Linux, and Windows.

For example:

❯ sc
(connected to and reading from stdin)

For Linux and Mac the following commands should download snicat for you:

wget "`uname`_`uname -m`" -O sc
chmod +x sc

For Mac, you may need to remove the quarantine attribute by running:

xattr -d sc

For Windows, you can download the x64 exe here and then run it from the command prompt.

Please refer to for full details and documentation

netcat / Requesting a TCP port

If you'd like users to use netcat, you can, however keep in mind that connections will be unencrypted.

  1. Browse to your deployed service and select the TCP connection tab

  1. Click on "Request TCP Port". Confirm that you'd like to request a port.

  1. Refresh the page if it does not automatically refresh

  2. You should receive a hostname and port as shown below:

Once you've been allocated a hostname and port, share it with your users for them to be able to connect to the service via tools like netcat.

Alternatively you can also leverage our fallback proxy service that allows netcat to connect to challenge services without requesting a port.

For example:

❯ nc 23


If none of the above options work for you, you can take a look at some of the other options here.


If you have any questions or any feedback, please feel free to contact us.