本文介绍在 Linux 主机上使用 systemd 直接运行回归终端平台服务和基础组件的部署方式。该方案不依赖 Docker Compose 或 Helm 管理平台服务,适合希望明确控制二进制、配置文件、数据目录和 systemd 单元的环境。
动态题目容器仍然依赖 Kubernetes。Kubernetes 控制节点、工作节点、Pod CIDR、节点标签和镜像源等准备工作请先阅读 环境准备。本页只说明平台主机如何通过 kubeconfig 接入已经准备好的 Kubernetes 集群。
生产边界
裸机 / systemd 部署可以用于生产环境。它把平台服务、数据库、缓存、队列、registry 和日志组件都交给宿主机 systemd 管理,排障路径直接,备份边界清晰。它的限制与 Docker Compose 类似:这些基础组件不由 Kubernetes 调度,无法使用 Kubernetes 统一安排 Pod 调度、PVC 绑定、滚动发布和节点故障迁移。Kubernetes 只负责运行 challenge pods。
目录规划
推荐遵循 Linux FHS 风格,把程序、配置、动态数据和日志分开:
| 路径 | 内容 | 权限建议 |
|---|---|---|
/usr/local/bin/r2s-server | 回归终端平台服务二进制。 | root:root,0755。 |
/usr/local/bin/nats-server | 可选,本地 NATS JetStream 二进制。 | root:root,0755。 |
/usr/local/bin/registry | 可选,本地 Docker Distribution registry 二进制。 | root:root,0755。 |
/usr/local/bin/victoria-logs | 可选,本地 VictoriaLogs 二进制。 | root:root,0755。 |
/usr/local/share/ret2shell/web | 前端静态文件。 | root:root,0755。 |
/etc/ret2shell/config.toml | 平台主配置文件。 | root:ret2shell,0640。 |
/etc/ret2shell/kubeconfig.yaml | 外置 Kubernetes kubeconfig。 | root:ret2shell,0640。 |
/etc/ret2shell/sensitive_word_list.txt | 敏感词文件。 | root:ret2shell,0640。 |
/etc/ret2shell/registry/config.yml | 可选,本地 registry 配置。 | root:ret2shell,0640。 |
/var/lib/ret2shell/bucket | 题目仓库、附件、checker、环境配置。 | ret2shell:ret2shell。 |
/var/lib/ret2shell/media | 用户上传媒体文件。 | ret2shell:ret2shell。 |
/var/lib/ret2shell/captures | 动态题目交互捕获数据。 | ret2shell:ret2shell。 |
/var/lib/ret2shell/nats | 可选,NATS JetStream 数据。 | ret2shell:ret2shell。 |
/var/lib/ret2shell/registry | 可选,题目镜像仓库数据。 | ret2shell:ret2shell。 |
/var/lib/ret2shell/victoria-logs | 可选,VictoriaLogs 数据。 | ret2shell:ret2shell。 |
/var/log/ret2shell | 平台本地日志。 | ret2shell:ret2shell。 |
PostgreSQL 和 Valkey 使用发行版软件包安装时,建议先使用发行版默认数据目录,例如 Debian/Fedora 的 PostgreSQL、Arch Linux 的 /var/lib/postgres/data,以及发行版为 Valkey 配置的默认目录。它们的备份和迁移按对应发行版服务处理。使用专用数据盘时,可以把数据库默认数据目录和 /var/lib/ret2shell 放到同一块可靠 SSD 或独立卷上。
创建系统用户和目录:
NOLOGIN="$(command -v nologin || echo /bin/false)"
sudo useradd --system \
--home-dir /var/lib/ret2shell \
--shell "$NOLOGIN" \
ret2shell
sudo install -d -o root -g ret2shell -m 0750 /etc/ret2shell
sudo install -d -o root -g ret2shell -m 0750 /etc/ret2shell/registry
sudo install -d -o root -g root -m 0755 /usr/local/share/ret2shell/web
sudo install -d -o ret2shell -g ret2shell -m 0750 \
/var/lib/ret2shell \
/var/lib/ret2shell/bucket \
/var/lib/ret2shell/media \
/var/lib/ret2shell/captures \
/var/lib/ret2shell/nats \
/var/lib/ret2shell/registry \
/var/lib/ret2shell/victoria-logs \
/var/log/ret2shell如果系统已经存在 ret2shell 用户,可以跳过 useradd,但要确认它可以读 /etc/ret2shell,并能写 /var/lib/ret2shell 与 /var/log/ret2shell。
安装发行版组件
平台主机至少需要 PostgreSQL、Valkey/Redis 协议缓存、Nginx、Git 和 skopeo。skopeo 用于平台把上传的题目镜像归档推送到 registry。
Debian / Ubuntu
sudo apt update
sudo apt install -y \
curl ca-certificates git openssl rsync skopeo nginx \
postgresql postgresql-client \
valkey-server
sudo systemctl enable --now postgresql
sudo systemctl enable --now valkey-server
sudo systemctl enable --now nginx旧版 Debian 或 Ubuntu 可能只提供 redis-server。此时可以先安装 redis-server 并在 config.toml 中继续使用 redis:// URL;生产环境建议优先使用 Valkey 8+。
Fedora
sudo dnf install -y \
curl ca-certificates git openssl rsync skopeo nginx \
postgresql-server postgresql \
valkey
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
sudo systemctl enable --now valkey
sudo systemctl enable --now nginx如果 postgresql-setup --initdb 提示数据库已经初始化,可以忽略该提示,继续启动服务。
Arch Linux
sudo pacman -Syu --needed \
curl git openssl rsync skopeo nginx \
postgresql valkey
sudo -iu postgres initdb -D /var/lib/postgres/data
sudo systemctl enable --now postgresql
sudo systemctl enable --now valkey
sudo systemctl enable --now nginx如果 PostgreSQL 已经初始化,initdb 会提示目录非空。确认不是新机器后可以跳过该步骤。
初始化 PostgreSQL
为平台创建独立数据库和用户。下面的密码要和后续 /etc/ret2shell/config.toml 中的 [database].password 保持一致。
sudo -iu postgres psql <<'SQL'
CREATE USER ret2shell WITH PASSWORD '<replace-with-random-postgres-password>';
CREATE DATABASE ret2shell OWNER ret2shell;
SQL检查连接:
psql 'postgresql://ret2shell:<replace-with-random-postgres-password>@127.0.0.1:5432/ret2shell?sslmode=disable' \
-c 'select current_user, current_database();'r2s-server 启动时会自动执行数据库迁移。部署前只需要保证数据库、用户和密码可用。连接失败时,检查 PostgreSQL 是否监听 127.0.0.1:5432,以及 pg_hba.conf 是否允许本机 TCP 密码认证。
配置 Valkey
建议开启本地监听、密码和 AOF 持久化。不同发行版配置路径可能不同,先确认实际文件:
ls /etc/valkey/valkey.conf /etc/redis/redis.conf 2>/dev/null把以下配置写入对应配置文件:
bind 127.0.0.1 ::1
protected-mode yes
requirepass <replace-with-random-valkey-password>
appendonly yes重启服务:
sudo systemctl restart valkey || sudo systemctl restart valkey-server || sudo systemctl restart redis-server检查连接:
valkey-cli -a '<replace-with-random-valkey-password>' ping \
|| redis-cli -a '<replace-with-random-valkey-password>' ping后续 config.toml 中的缓存 URL 使用:
redis://:<replace-with-random-valkey-password>@127.0.0.1:6379可选纯裸机组件
NATS、Docker Distribution registry 和 VictoriaLogs 都是 Go 程序。需要纯裸机部署时,可以从官方 Docker image 中把二进制拆出来放入 /usr/local/bin,然后用 systemd 运行。Docker 只用于提取文件,不需要在生产主机常驻;也可以在构建机上提取后用 scp 分发到平台主机。
提取二进制
docker pull nats:2-alpine
cid="$(docker create nats:2-alpine)"
sudo docker cp "$cid:/nats-server" /usr/local/bin/nats-server
docker rm "$cid"
docker pull registry:3
cid="$(docker create registry:3)"
sudo docker cp "$cid:/bin/registry" /usr/local/bin/registry
docker rm "$cid"
docker pull victoriametrics/victoria-logs:v1.43.1
cid="$(docker create victoriametrics/victoria-logs:v1.43.1)"
sudo docker cp "$cid:/victoria-logs-prod" /usr/local/bin/victoria-logs
docker rm "$cid"
sudo chmod 0755 /usr/local/bin/nats-server /usr/local/bin/registry /usr/local/bin/victoria-logs如果某个镜像版本的二进制路径发生变化,先查看镜像入口:
docker image inspect nats:2-alpine --format '{{json .Config.Entrypoint}}'
docker image inspect registry:3 --format '{{json .Config.Entrypoint}}'
docker image inspect victoriametrics/victoria-logs:v1.43.1 --format '{{json .Config.Entrypoint}}'NATS JetStream
创建 /etc/ret2shell/nats.env:
sudo tee /etc/ret2shell/nats.env >/dev/null <<'EOF'
NATS_TOKEN=<replace-with-random-nats-token>
EOF
sudo chown root:ret2shell /etc/ret2shell/nats.env
sudo chmod 0640 /etc/ret2shell/nats.env创建 /etc/systemd/system/nats.service:
[Unit]
Description=NATS JetStream for Ret2Shell
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ret2shell
Group=ret2shell
EnvironmentFile=/etc/ret2shell/nats.env
ExecStart=/usr/local/bin/nats-server -js -sd /var/lib/ret2shell/nats --auth ${NATS_TOKEN}
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/var/lib/ret2shell/nats
[Install]
WantedBy=multi-user.target启动并检查:
sudo systemctl daemon-reload
sudo systemctl enable --now nats
sudo systemctl status natsVictoriaLogs
创建 /etc/systemd/system/victoria-logs.service:
[Unit]
Description=VictoriaLogs for Ret2Shell
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ret2shell
Group=ret2shell
ExecStart=/usr/local/bin/victoria-logs --storageDataPath=/var/lib/ret2shell/victoria-logs --httpListenAddr=127.0.0.1:9428
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/var/lib/ret2shell/victoria-logs
[Install]
WantedBy=multi-user.target启动并检查:
sudo systemctl daemon-reload
sudo systemctl enable --now victoria-logs
curl -fsS http://127.0.0.1:9428/Docker Distribution registry
本地 registry 用于保存平台上传的题目镜像。Kubernetes 节点必须能访问 [cluster.registry].external 中填写的地址。
创建 /etc/ret2shell/registry/config.yml:
version: 0.1
log:
fields:
service: ret2shell-registry
storage:
delete:
enabled: true
filesystem:
rootdirectory: /var/lib/ret2shell/registry
http:
addr: 0.0.0.0:5000设置权限:
sudo chown root:ret2shell /etc/ret2shell/registry/config.yml
sudo chmod 0640 /etc/ret2shell/registry/config.yml创建 /etc/systemd/system/ret2shell-registry.service:
[Unit]
Description=Docker Distribution Registry for Ret2Shell
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=ret2shell
Group=ret2shell
ExecStart=/usr/local/bin/registry serve /etc/ret2shell/registry/config.yml
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/var/lib/ret2shell/registry
[Install]
WantedBy=multi-user.target启动并检查:
sudo systemctl daemon-reload
sudo systemctl enable --now ret2shell-registry
curl -fsS http://127.0.0.1:5000/v2/如果 registry 通过 HTTP 暴露给 Kubernetes 节点,需要在 k3s 或容器运行时中配置 insecure registry。k3s 配置示例见 Docker Compose 部署中的 registry 拉取地址说明。公网环境建议给 registry 配置 TLS 或仅通过内网访问,并用防火墙限制来源。
安装 r2s-server
推荐把 r2s-server 放入 /usr/local/bin。如果有已经构建好的 release 二进制,可以直接安装:
sudo install -m 0755 r2s-server /usr/local/bin/r2s-server需要从源码构建时,在构建机执行:
git clone https://github.com/ret2shell/ret2shell.git
cd ret2shell
git checkout <release-version>
rustup target add x86_64-unknown-linux-musl
cargo build --locked --release --bin r2s-server --target x86_64-unknown-linux-musl
sudo install -m 0755 target/x86_64-unknown-linux-musl/release/r2s-server /usr/local/bin/r2s-server构建机需要 Rust 1.94+、Node.js、Corepack 和 pnpm。生产主机只需要接收构建产物时,可以在构建机完成上述步骤,再把 r2s-server 和前端 dist 目录复制到生产主机。
前端静态文件可以由平台内置静态服务提供。构建并安装前端:
cd ret2shell/web
corepack enable
pnpm install --frozen-lockfile
pnpm build
sudo rsync -a --delete dist/ /usr/local/share/ret2shell/web/平台需要 Git 身份来维护题目仓库:
sudo -u ret2shell git config --global user.email platform@ret.sh.cn
sudo -u ret2shell git config --global user.name Ret2Shell配置平台
创建敏感词文件,可以先为空:
sudo touch /etc/ret2shell/sensitive_word_list.txt
sudo chown root:ret2shell /etc/ret2shell/sensitive_word_list.txt
sudo chmod 0640 /etc/ret2shell/sensitive_word_list.txt把外置 Kubernetes kubeconfig 放到 /etc/ret2shell/kubeconfig.yaml:
sudo install -m 0640 -o root -g ret2shell kubeconfig.yaml /etc/ret2shell/kubeconfig.yamlkubeconfig 的生成方式和 RBAC 可以参考 Docker Compose 部署中的 kubeconfig 注入说明。集群本身的安装与节点规划请回到 环境准备。
创建 /etc/ret2shell/config.toml:
[auditor]
sensitive_word_list = '/etc/ret2shell/sensitive_word_list.txt'
[auth]
buffer_time = 21600
expires_time = 86400
signing_key = '<replace-with-random-signing-key>'
[bucket]
path = '/var/lib/ret2shell/bucket'
[cache]
url = 'redis://:<replace-with-valkey-password>@127.0.0.1:6379'
[captcha]
enabled = true
difficulty = 4
validator = 'pow'
[cluster]
enabled = true
auto_infer = false
try_default = false
kube_config_path = '/etc/ret2shell/kubeconfig.yaml'
node_selector = 'challenge'
enable_capture = true
capture_directory = '/var/lib/ret2shell/captures'
[cluster.registry]
enabled = true
server = '127.0.0.1:5000'
external = 'registry.internal.example.com:5000'
insecure = true
[database]
host = '127.0.0.1'
port = 5432
ssl_mode = 'disable'
user = 'ret2shell'
password = '<replace-with-postgres-password>'
db = 'ret2shell'
[email]
enabled = false
host = 'smtp.example.com'
password = ''
port = 587
sender = 'Ret2Shell'
tls = 'starttls'
username = ''
[logging]
compress = true
directory = '/var/log/ret2shell'
files_kept = 3
level = 'info,tower_http=info,sqlx=warn'
victoria = 'http://127.0.0.1:9428'
[media]
anti_theft = true
limit = 100
path = '/var/lib/ret2shell/media'
[queue]
host = '127.0.0.1'
port = 4222
token = '<replace-with-nats-token>'
[server]
host = '127.0.0.1'
port = 8080
api_base_path = '/api'
cors_origins = 'https://ctf.example.com'
external_domain = 'ctf.example.com'
external_https = true
[server.rate_limit]
burst_limit = 32
burst_restore_rate = 500
[server.frontend]
serve_type = 'static'
path = '/usr/local/share/ret2shell/web'设置权限:
sudo chown root:ret2shell /etc/ret2shell/config.toml
sudo chmod 0640 /etc/ret2shell/config.toml如果不使用动态题目容器,把 [cluster].enabled 改为 false,并删除或禁用 [cluster.registry]。如果不使用 VictoriaLogs,删除 [logging].victoria,后台集中日志查询功能会不可用,但平台仍会写 /var/log/ret2shell。
配置 systemd
创建 /etc/systemd/system/ret2shell.service:
[Unit]
Description=Ret2Shell Platform
After=network-online.target postgresql.service nats.service valkey.service valkey-server.service redis-server.service
Wants=network-online.target
Requires=postgresql.service nats.service
[Service]
Type=simple
User=ret2shell
Group=ret2shell
WorkingDirectory=/var/lib/ret2shell
Environment=HOME=/var/lib/ret2shell
Environment=RUST_BACKTRACE=1
ExecStart=/usr/local/bin/r2s-server up
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=full
ReadWritePaths=/var/lib/ret2shell /var/log/ret2shell
[Install]
WantedBy=multi-user.target如果你的 Valkey 或 PostgreSQL service 名称不同,可以用下面的命令查看后调整 After= 和 Requires=:
systemctl list-unit-files 'postgresql*' 'valkey*' 'redis*'启动平台:
sudo systemctl daemon-reload
sudo systemctl enable --now ret2shell
sudo systemctl status ret2shell查看日志:
journalctl -u ret2shell -f
tail -f /var/log/ret2shell/*.log配置 Nginx 入口
示例使用 Nginx 处理 80/443 和真实客户端地址,平台只监听 127.0.0.1:8080。创建 /etc/nginx/conf.d/ret2shell.conf:
server {
listen 80;
server_name ctf.example.com;
client_max_body_size 1024m;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
location / {
proxy_pass http://127.0.0.1:8080;
}
}检查并重载:
sudo nginx -t
sudo systemctl reload nginx生产环境应配置 HTTPS,并把 config.toml 中的 external_https 和 cors_origins 与真实访问地址保持一致。
检查服务
检查本机依赖:
systemctl status postgresql
systemctl status valkey || systemctl status valkey-server || systemctl status redis-server
systemctl status nats
systemctl status victoria-logs
systemctl status ret2shell-registry
systemctl status ret2shell检查平台健康状态:
curl -fsS http://127.0.0.1:8080/api/ping
curl -fsS http://ctf.example.com/api/ping检查 Kubernetes kubeconfig:
KUBECONFIG=/etc/ret2shell/kubeconfig.yaml kubectl get nodes -o wide
KUBECONFIG=/etc/ret2shell/kubeconfig.yaml kubectl -n ret2shell-challenge get pods,svc检查 registry:
curl -fsS http://127.0.0.1:5000/v2/
curl -fsS http://registry.internal.example.com:5000/v2/第二条命令应在 Kubernetes 节点上也能成功。否则题目镜像上传到 registry 后,challenge pods 仍然无法拉取镜像。
备份和升级
至少备份以下内容:
| 内容 | 推荐方式 |
|---|---|
| PostgreSQL | 使用 pg_dump 或物理备份。 |
/etc/ret2shell | 纳入配置备份,注意密钥和 kubeconfig 权限。 |
/var/lib/ret2shell/bucket | 题目仓库、附件和 checker。 |
/var/lib/ret2shell/media | 用户上传媒体。 |
/var/lib/ret2shell/captures | 可选,题目交互捕获数据。 |
/var/lib/ret2shell/registry | 使用本地 registry 时备份。 |
/var/lib/ret2shell/nats | 使用本地 NATS JetStream 时备份。 |
/var/lib/ret2shell/victoria-logs | 需要保留集中日志时备份。 |
数据库备份示例:
sudo install -d -m 0750 -o ret2shell -g ret2shell /var/lib/ret2shell/backups
sudo -iu postgres pg_dump ret2shell > "/var/lib/ret2shell/backups/ret2shell.$(date +%F).sql"升级平台时:
- 备份 PostgreSQL、
/etc/ret2shell和/var/lib/ret2shell中的重要目录。 - 停止平台服务:
sudo systemctl stop ret2shell。 - 替换
/usr/local/bin/r2s-server和/usr/local/share/ret2shell/web。 - 检查
config.toml是否需要新增字段。 - 启动平台:
sudo systemctl start ret2shell。 - 观察日志,确认数据库迁移完成且
/api/ping返回正常。
不要在没有备份的情况下跨大版本升级 PostgreSQL、Valkey、NATS、registry 或 VictoriaLogs。基础组件升级失败通常比平台二进制回滚更难恢复。
