CTFd + CTFd_Whale 部署

以下内容基于 frankli0324 师傅的这篇 ctfd-whale 使用指南 修改

  • 一切都使用最新的(截止文章发布时)

手动安装部署 CTFd

从零开始 👉 安装配置 Docker

系统环境: 刚初始化安装后的 Ubuntu 20.04 LTS

直接按照 Docker 官方文档操作 👉 https://docs.docker.com/engine/install/ubuntu/

懒得去看文档直接执行这里的命令

  • 这里的内容在以后可能会失效,一些还是以官方文档为准
1
2
3
4
5
6
7
8
9
10
11
sudo apt update 
sudo apt install ca-certificates curl gnupg -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y

安装完成 Docker 后将当前用户加入到 docker 组:

1
sudo usermod -aG docker ${USER}

重新启动一个会话,然后就可以无需 sudo 执行 docker 命令了。接下来初始化一个 swarm 集群, 然后给节点标注名称

1
2
docker swarm init
docker node update --label-add "name=linux-1" $(docker node ls -q)

ctfd-whale 利用 docker swarm 的集群管理能力,能够将题目容器分发到不同的节点上运行。选手每次请求启动题目容器时,ctfd-whale 都将随机选择一个合适的节点运行这个题目容器。

注意,2.5.0+ 版本 CTFd 的 docker-compose.yml 中包含了一个 nginx 反代,占用了 80 端口

部署 CTFd

1
2
git clone https://github.com/CTFd/CTFd --depth=1
cd CTFd # 注: 后续所有操作均在这个 CTFd 目录中

先修改 docker-compose.yml 文件,把第一行的 version: '2' 删掉,然后执行:

1
docker compose up -d

等待启动完毕后访问 8000 端口,对 CTFd 进行初始化配置

配置 frps

修改 docker-compose.yml,往里面添加一个 frp_connect 网络用于 frps 与 frpc 之间的通信,然后添加 frps service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
services:
...
frps:
image: glzjin/frp
restart: always
volumes:
- ./conf/frp:/conf
entrypoint:
- /usr/local/bin/frps
- -c
- /conf/frps.ini
ports:
- 10000-10100:10000-10100 # 映射direct类型题目的端口
- 8001:8001 # 映射http类型题目的端口
networks:
default: # 需要将frps暴露到公网以正常访问题目容器
frp_connect:

networks:
...
frp_connect:
driver: overlay
internal: true
attachable: true
ipam:
config:
- subnet: 172.1.0.0/16

创建 frp 的配置文件目录: ./conf/frp:

1
mkdir ./conf/frp

创建 frpc 配置文件:./conf/frp/frpc.ini, 填写下面的内容(注释中的内容全部删掉, 不然会导致配置文件解析错误无法正常启动 frpc 服务):

1
2
3
4
5
6
[common]
# 下面两个端口注意不要与direct类型题目端口范围重合
bind_port = 7987 # frpc 连接到 frps 的端口
vhost_http_port = 8001 # frps 映射http类型题目的端口
token = your_token # 填写一个随机的字符串即可
subdomain_host = welcome.blue-whale.me # 访问http题目容器的主机名

配置 frpc

同样的操作,再添加一个网络,用于 frpc 与题目容器之间进行通信,并添加 frpc service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
services:
...
frps:
image: glzjin/frp
restart: always
volumes:
- ./conf/frp:/conf
entrypoint:
- /usr/local/bin/frpc
- -c
- /conf/frpc.ini
depends_on:
- frps
networks:
frp_containers:
frp_connect: # 供 frpc 访问 frps

networks:
...
frp_containers:
driver: overlay
internal: true # 如果允许题目容器访问外网,则可以去掉这一行
attachable: true
ipam:
config:
- subnet: 172.2.0.0/16

同样的,创建 frpc 的配置文件: ./conf/frp/frpc.ini

1
2
3
4
5
6
[common]
token = your_token # 与 frps.ini 中一致的token
server_addr = frps
server_port = 7987 # 对应 frps.ini 中的 bind_port
admin_addr = frpc
admin_port = 7400

检查 frp 配置

执行 docker compose up -d 更新 compose 配置

  • 可以通过查看日志检查服务状态:
1
2
3
4
5
6
7
8
ctf@welcome-blue-whale-ctfd:~/CTFd$ docker compose logs frps
ctfd-frps-1 | 2023/08/19 05:19:07 [I] [service.go:146] frps tcp listen on 0.0.0.0:7987
ctfd-frps-1 | 2023/08/19 05:19:07 [I] [service.go:188] http service listen on 0.0.0.0:48100
ctfd-frps-1 | 2023/08/19 05:19:07 [I] [root.go:204] Start frps success
ctfd-frps-1 | 2023/08/19 05:19:08 [I] [service.go:356] client login info: ip [172.1.0.4:39176] version [0.28.2] hostname [] os [linux] arch [amd64]
ctf@welcome-blue-whale-ctfd:~/CTFd$ docker compose logs frpc
ctfd-frpc-1 | 2023/08/19 05:19:08 [I] [service.go:224] login to server success, get run id [e626881d0ed6c1db], server udp port [0]
ctfd-frpc-1 | 2023/08/19 05:19:08 [I] [service.go:109] admin server listen on frpc:7400
  • 如果是类似上面这样的输出那么说明 frpc 和 frps 配置及服务正常

😅遇到的坑

  • 🔴 坑1: 遇到 Cannot start service frpc: attaching to network failed, make sure your network options are correct and check manager logs: context deadline exceeded 报错
    • 先前是固定写死的 frpc 容器的IP地址, 指定了 172.1.0.3, 然后 docker compose up -d 时遇到 attaching to network failed 错误
    • 解决方案: 换了其他的 IP 就可以用了,或者像现在这样删掉指定的 IP,自动分配即可
    • 错误原因: 未知
      • 并没有发现有其他的容器占用了 172.1.0.3 这个 IP 地址

配置 CTFd 👉 安装 ctfd-whale

frp 服务正常工作后,把本机 docker 的访问接口映射到 CTFd 容器中,并将 CTFd 加入到 frpc 所在的 network 中(frpc_connect):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
services:
...
ctfd:
...
volumes:
...
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
...
- frpc
networks:
...
- frp_connect:

将 CTFd-Whale 克隆至 CTFd 的插件目录:

1
git clone https://github.com/frankli0324/CTFd-Whale CTFd/plugins/ctfd-whale --depth=1

重新 build CTFd 的镜像, 更新 compose 配置:

1
2
docker compose build
docker compose up -d

管理员登录 CTFd, 进入后台, 右上角可以看到 Whale 插件的配置入口

  • 首先配置 Docker 配置选项:
    • Auto Connect Network 中填写: ctfd_frp_containers
    • 点击 Submit 保存配置
  • 然后进入 Router 配置选项检查 frp 配置:
    • Http Domain Suffix 与之前 frps.ini 中的 subdomain_host 保持一致
    • External Http Port 与之前 frps.ini 中的 vhost_http_port 保持一致
    • Direct IP Address 填写能够访问到 frps 中指定端口的 IP(以 Direct 方式生成的题目将显示该 IP 和随机使用的端口号)
    • Direct Minimum PortDirect Maximum Port 对应 docker-compose.yml 中 frps 配置的端口范围

到目前为止,CTFd-Whale 已经可以正常使用了

配置 Nginx

TODO