tbcsec/Flagpost
GitHub: tbcsec/Flagpost
Flagpost 是一个开箱即用、支持自托管和全程实时更新的开源 CTF 竞赛运行平台,帮助组织者高效管理从挑战发布到计分排名的完整赛事流程。
Stars: 3 | Forks: 0

**一个现代的、开源的 Capture the Flag 竞赛运行平台 ——
支持自托管、实时更新,且功能完备。**
[](LICENSE)
[](https://github.com/tbcsec/flagpost/actions/workflows/ci.yml)
[](CONTRIBUTING.md)


[亮点](#-highlights) · [功能](#-features) · [快速开始](#-quick-start) · [部署](#-deploying-to-production) · [文档](#-documentation)
Flagpost 是一款为 CTF 组织者打造的完整竞赛平台:发布挑战、
在提交瞬间完成评分、支持参赛者,并实现整个赛事的自动化
—— 所有这些都集于一个可自托管的应用中。它从根本上支持多租户(一次
安装即可运行多场赛事),全程实时更新(使用 WebSockets,而非
轮询),并以一条命令的生产级技术栈开箱即用。
目前仅支持密码身份验证;SSO/LDAP 和 AI 助手已列入路线图,但
特意暂未开发。
## ✨ 亮点
让 Flagpost 脱颖而出的特性 —— 每一项都**已在当下构建并正常运行**:
- **⚡ 全程实时。** 计分板、“谁正在查看此挑战”
在线状态、通知和支持工单线程,所有这些均通过
WebSockets 实时更新。无需刷新,无需轮询。
- **🤖 可视化自动化引擎。** 零代码的 **When → If → Then** 规则构建器:
针对任意事件,执行操作 —— 发送通知、调用(经过 SSRF 加固的) webhook、发送电子邮件、
发布提示、解锁附加挑战、打开问卷、调整分数、颁发
奖项、冻结榜单或发布公告。包括基于时间的触发器,
例如*“在结束前一小时,打开反馈问卷。”*
- **📝 实时协作笔记。** 真正的 CRDT (Y.js) 共同编辑:每个团队的每个挑战都有一个共享的草稿本,
每张工单上都有私密的内部人员笔记 —— 所有人都可以同时
输入,互不冲突。
- **🛡️ 权限即数据。** 非硬编码的 RBAC:可视化的角色编辑器
允许你克隆内置角色,并精细地创建具有每个赛事范围或全站范围的自定义角色。
- **🧩 真正深度的挑战模型。** 支持静态、正则表达式和多项选择题的 flag;
动态(衰减)计分;前置解锁链;定时/分批发布;
标签和难度;以及每个赛事的猜测限制。
- **🏆 完善的计分板。** 带有“一血”(first-blood)的实时排名,并行的
**分组/赛区**,最后阶段的**冻结**,公开的**观战
板**,以及 **CTFtime feed**,让评级赛事完美运行。
- **🔁 兼容 CTFd 且完全可移植。** 以
**ctfcli YAML** 格式批量导入/导出挑战,以及一键、高保真的**平台备份**
(导出/导入你安装的任何部分)。
- **🔒 默认安全。** argon2 哈希,每次安装时自动派生的 JWT 密钥
(不含任何内置凭据 —— 首次运行的设置向导将创建你的所有者账户),
经过 SSRF 加固的 webhook,受 ReDoS 约束的正则表达式 flag,以及时间安全的身份验证。
- **🚀 一条命令投入生产。** `docker compose up` 会在单个源上通过
Caddy 反向代理拉起整个技术栈 —— 当你将其
指向一个域名时,会自动配置 HTTPS。
## 📸 截图

Live scoreboard — real-time standings, first blood, brackets & freeze
|

Challenges — cards, hints, live solves & flag submission
|

Automation builder — visual When → If → Then rules
|

Operational dashboard — drag-and-drop widgets for organisers
|
## 🧩 功能
|
**赛事**
- 每场赛事支持团队**或**个人模式
- 公开/私有可见性 & 自助加入或通过邀请码加入
- 排期、**暂停**、归档以及一键**克隆**
- 每个赛事的模块开关(开启/关闭功能)
**挑战**
- 分类、静态 / 正则表达式 / **多项选择**的 flag
- **动态(衰减)**或静态计分
- 提示、文件附件 (S3/MinIO)
- **前置解锁链**、定时发布
- 受管理的**标签与难度**词表
- 批量 **ctfcli YAML** 导入/导出
- 手动重置多项选择的猜测限制
**计分与计分板**
- 通过 WebSocket 实时更新、**一血**标记
- **动态价值收敛**(对所有解题者保持公平)
- **分组 / 赛区**、计分板**冻结**
- 公开的**观战板** + **CTFtime feed**
- 人工判定奖项与分数调整
|
**团队与参赛者**
- 邀请码、可选的**队长审批**、人数上限
- 团队主页;个人模式下的名单及排名
**沟通与协作**
- **支持工单**,带有实时的内部处理队列与提示音
- **公告**(实时横幅)
- **在线状态** —— “N 人正在查看”、“裁判正在查看”
- 关于挑战和工单的**CRDT 协作笔记**
**自动化、反馈与洞察**
- 可视化**自动化**规则构建器(§ 亮点)
- **反馈问卷** + 解题后的**挑战评分**
- **挑战与团队分析**
- 带有拖拽小部件的运营**仪表板**
**管理**
- **用户**目录 + 软封禁 / 生命周期管理
- 数据驱动的**角色与权限**编辑器
- 全站**主题与品牌**(自定义 logo、调色板)
- SMTP、注册策略、跨赛事**审计日志**
- 完整的**导出 / 导入**备份(包括密钥)
|
## 🚀 快速开始
需要安装带有 Compose 的 [Docker](https://docs.docker.com/get-docker/)。默认的
技术栈适用于**生产环境**:在 Caddy 反向代理后运行构建好的镜像,并集成了 Postgres、
Redis 和 MinIO。
```
git clone https://github.com/tbcsec/flagpost.git
cd flagpost
docker compose up --build
```
打开 **http://localhost:8080** 并完成一次性的**设置向导**,以
创建你的所有者账户。就这样 —— 应用本身、其 API 以及其实时的 WebSocket
更新,都通过 Caddy 在同源下提供服务,因此在本地运行时无需再进行其他
配置。
## 🌅 部署到生产环境
默认的 compose *即*生产技术栈,因此上线主要就是
在 `.env` 中进行配置(复制 `.env.example`):
| 变量 | 作用 |
|---|---|
| `SITE_ADDRESS` | 你的域名,例如 `ctf.example.com`。Caddy 会**自动获取并续期 TLS**。映射端口 `80` + `443`。 |
| `PUBLIC_ORIGIN` | 面向浏览器的源,例如 `https://ctf.example.com`。会在构建时嵌入到前端 —— 请在 `docker compose build` 之前设置好。 |
| `JWT_SECRET` | 一串较长的随机值(多主机部署时必填;否则应用会自动派生并持久化一个)。 |
| `POSTGRES_PASSWORD`, `MINIO_ROOT_USER/PASSWORD` | 真实的凭据。 |
| `MINIO_PUBLIC_ENDPOINT` | 浏览器可访问的 MinIO 主机,用于带签名的附件下载。 |
后端在设计上以**单进程运行**(WebSocket 层
处于进程内)。要在**不使用 Docker** 的情况下运行:构建并托管前端,运行
`npm run build && npm run start`,并在你自己的 TLS 终结代理后,通过 `alembic upgrade head`
然后运行 `uvicorn main:app`(不要加 `--reload`)来运行后端。
### 📌 带版本号的镜像(直接拉取而非构建)
每次发布标签都会向 GHCR 发布**锁定的、可复现的镜像**:
```
ghcr.io/tbcsec/flagpost-backend:v1.1.0 (also :latest)
ghcr.io/tbcsec/flagpost-frontend:v1.1.0 (also :latest)
```
已发布的前端是在**同源模式**下构建的 —— API 调用和
WebSockets 会自动解析为提供页面服务的任意源 —— 因此只需一个镜像,即可在任何同源代理后
运行,无需内置域名,也无需因为 `PUBLIC_ORIGIN`
而重新构建。将 compose 中的 `frontend`/`backend` 服务指向这些镜像
(只需两行覆盖配置),即可通过标签进行升级,而无需从源代码重新构建。
## 🛠️ 本地开发
开发技术栈会挂载源代码并运行支持热重载的开发服务器:
```
docker compose -f docker-compose.dev.yml up --build
# frontend → http://localhost:3000 · backend → http://localhost:8000/docs
```
或者直接运行各端(后端需要 Python 3.12+ 和 venv;前端需要
Node 20+ —— 随包提供的镜像运行的是 3.14 和 26 版本,这也是 CI 测试的环境):
```
# 后端
cd backend && python3 -m venv .venv
.venv/bin/pip install -r requirements-dev.txt
.venv/bin/alembic upgrade head # against a reachable Postgres
.venv/bin/uvicorn main:app --reload
# 前端
cd frontend && npm install && npm run dev
```
在提交 PR 之前,运行一下 CI 所执行的检查:
```
cd backend && .venv/bin/pytest # SQLite-backed, no infra needed
cd frontend && npm run test # vitest
cd frontend && npx tsc --noEmit && npx eslint .
```
## 🧱 技术栈
**后端** —— Python · FastAPI · SQLAlchemy 2 (异步) · Alembic · PostgreSQL ·
Redis · MinIO/S3 · JWT + argon2 · 一流的异步事件总线。
**前端** —— TypeScript · Next.js 15 (App Router) · React 19 · TanStack Query ·
Zustand · Tailwind v4 · TipTap + Y.js (CRDT)。
**实时通信** —— 全面采用 WebSockets。**部署** —— Docker Compose + Caddy。
## 📚 文档
| 文档 | 内容 |
|---|---|
| [`docs/VISION.md`](docs/VISION.md) | Flagpost 是什么及其存在的原因 |
| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | 绑定的技术设计 |
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | 构建顺序及后续规划 |
| [`docs/adr/`](docs/adr/) | 架构决策记录 —— 解释事物*为什么*是现在的样子 |
## 📄 许可证
Copyright © 2026 **Tom Collier**.
Flagpost 采用 **[GNU Affero General Public License v3.0](LICENSE)** 授权。
你可以自由使用、修改和自托管它;如果你将**修改后**的版本作为
网络服务运行,AGPL 的 §13 条款要求你向用户提供其源代码。内置的“Powered by Flagpost”页脚会将每个页面链接到本仓库,这
正是 Flagpost 向远程用户展示其源代码的方式。
为 CTF 社区而生。展起你的旗帜。 🚩
标签:AV绕过, CTF平台, FastAPI, WebSockets, 搜索引擎查询, 测试用例, 版权保护, 网络调试, 自动化, 逆向工具