本地部署 ARTEX:Docker Compose 全流程与关停后的重启方法
ARTEX 是一套 AI 多 agent 驱动的自主渗透测试系统,Go 单体后端 + 内嵌 Next.js 前端 + PostgreSQL。
这篇文章只讲两件事:怎么装起来,以及关掉之后怎么再开起来。第二件事看起来傻,但踩过一次坑就知道值得单独写——因为「关」有四种关法,对应的「开」是不一样的。
一、部署过程
1. 前置条件
只需要 Docker。macOS 上装 Docker Desktop:
brew install --cask docker装完打开一次 Docker Desktop,等鲸鱼图标变绿,确认命令能用:
docker versiondocker compose versiondocker compose(带空格)是 v2 插件,现在默认就是这个。不要再装 docker-compose(v1,已经废弃)。
2. 拉源码
git clone https://github.com/mhtsec/ARTEX.git ~/tools/ARTEXcd ~/tools/ARTEX放在 ~/tools/ 下是我自己的习惯,路径随意,后面所有命令按这个路径写。
顺便说一句镜像的事:原镜像源 autumn27/artex 已经从 Docker Hub 删了,现在由作者维护成 mianhuatang11/artex。如果拉取失败,可以直接从纯源码本地构建(多阶段构建,无外部预编译依赖):
docker compose build代价是慢,前端 npm ci + Go 编译,第一次十几分钟很正常。
3. 写 .env
cp .env.example .env必须改的只有一行:
POSTGRES_PASSWORD=change-me-please不想手敲就生成一个:
openssl rand -base64 18其余的 LLM 相关(ANTHROPIC_API_KEY / OPENAI_API_KEY / ARTEX_LLM_*)都可以先留空,进 UI 里配。
⚠️ 这个密码一旦用于初始化数据库卷就改不动了(后面「常见问题」会讲为什么),第一次就定好。
4. 启动
docker compose up -d第一次要拉两个镜像,ARTEX 本体 2.37 GB,postgres:16-alpine 411 MB,看网速,国内建议先配好镜像加速。
启动顺序是 compose 文件里写死的:
depends_on: postgres: condition: service_healthy也就是 postgres 的 healthcheck 通过之后才起 artex,不是简单的”先启动后启动”。所以 docker compose ps 里会先看到 postgres 变成 (healthy),artex 才开始 Up。
5. 确认起来了
docker compose ps正常状态长这样:
NAME IMAGE STATUS PORTSartex-artex-1 mianhuatang11/artex:latest Up 2 hours 0.0.0.0:8787->8787/tcp, 127.0.0.1:8788->8788/tcpartex-postgres-1 postgres:16-alpine Up 2 hours (healthy) 5432/tcp再用 HTTP 确认一次,比 ps 更可信:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8787/# 200curl -s http://127.0.0.1:8787/api/health# 200注意 /api/version 这种接口不带登录态会返回 {"error":"未授权"},这是鉴权正常的表现,不是服务挂了。
6. 首次进入
浏览器打开 **http://localhost:8787**,会自动跳到 /setup 设置管理员密码。
- 登录用户名固定是
ARTEX - 密码以 bcrypt 哈希存进数据库
settings表的auth.password_hash
设完再去「LLM 配置」页填模型和 Key,否则 agent 能启动但不会思考。
二、部署完之后必须搞懂的三件事
这三件事决定了你后面「关」和「开」时会不会慌。
1. 两个端口,不是一个
compose 里是这么发布的:
ports: - "8787:8787" - "127.0.0.1:8788:8788"8787 是前端 + API + SSE 实时活动流,绑 0.0.0.0,也就是同局域网的其他设备能访问。
8788 是流量录制代理(MITM,带 CA 存证),只绑 127.0.0.1,故意只让本机访问。
看到 8788 没对外开放不要以为是配错了,那是设计。也别为了”方便远程调试”把它改成 0.0.0.0——那等于把一台能解密 HTTPS 的代理挂到局域网上。
2. 数据存在三个地方
关服务不会丢数据,前提是别碰这三个地方:
pgdata卷(Docker 命名卷artex_pgdata,约 238 MB):任务、资产图、探索图、设置、密码哈希。是最核心的一份。./data目录(bind mount 到容器的/app/data,实测 2.2 GB):会话记录、transcripts、流量包、证据文件。会随着使用快速膨胀,主要是data/tasks和data/traffic。./skills目录:技能提示词,挂载进来是为了改完不用重建镜像。
容器本身是”用完就扔”的,这三处才是真实的资产。
3. 容器里跑的是 start.sh,不是 artex 本体
镜像的入口是 start.sh,它是个守护脚本:
- 子进程退出码
0→ 用户正常停止,脚本退出 - 退出码
75→ 程序请求重启(页面上的”一键更新”靠这个换装) - 其他 → 崩溃,退避 1/2/4…最多 60 秒后重拉
它还会把 SIGTERM 转发给 artex。因为 docker stop 只把信号发给 PID 1,也就是这个脚本,不转发的话 artex 收不到、做不了优雅关闭,10 秒后被 SIGKILL 硬杀,正在跑的任务直接断在半路。
这解释了后面实测里那个 Exited (0):不是意外退出,是优雅关闭。
三、怎么关(四种关法,对应四种后果)
有好几次”关掉之后打不开”,原因就是关的方式和开的方式不匹配。
方式一:docker compose stop(推荐日常用)
cd ~/tools/ARTEXdocker compose stop实测耗时 0.9 秒,两个容器都是 Exited (0):
Container artex-artex-1 StoppedContainer artex-postgres-1 Stopped容器还在(docker compose ps -a 能看到),数据全留,重新开最快。
方式二:docker compose down
docker compose down删掉容器和网络,但保留 pgdata 卷和 ./data、./skills 这两个 bind mount。
什么时候用它:改了 docker-compose.yml(比如加减环境变量、改端口),需要让 compose 重新按新配置建容器。stop 之后再 up 用的是旧容器,新配置不生效。
方式三:docker compose down -v
docker compose down -v多了一个 -v,连 pgdata 卷一起删。
任务、资产、漏洞、账号密码,全都没了。只剩 ./data 里的现场文件,而数据库没了那些文件也读不出来。
这条命令唯一合适的场景是”我想彻底重来一遍”。手滑按到的代价是几天的工作量,建议打完 down 就停手,-v 单独敲。
方式四:直接退出 Docker Desktop 或关机
关掉 Docker Desktop(菜单里 Quit),或者直接合盖关机。
效果上接近方式一:Docker 会先把运行中的容器停掉。区别是它不那么可控,正在跑的任务可能被打断。如果手上有任务在跑,先停任务,再 docker compose stop,最后退出 Docker。
四、怎么重新开(核心)
第一步:确认 Docker 守护进程在跑
这是很容易漏掉的一步。容器停着的时候执行 docker compose up -d,会得到:
Cannot connect to the Docker daemon at unix:///var/run/docker.sock.Is the docker daemon running?macOS 上 Docker 跑在一个轻量虚拟机里,必须先把 Docker Desktop 打开:
open -a Docker然后等它就绪(不是立刻可用,一般十几秒):
until docker info >/dev/null 2>&1; do sleep 1; done; echo "docker ready"第二步:进入项目目录,拉起来
cd ~/tools/ARTEXdocker compose up -d输出会体现依赖顺序:
Container artex-postgres-1 StartingContainer artex-postgres-1 StartedContainer artex-postgres-1 WaitingContainer artex-postgres-1 HealthyContainer artex-artex-1 StartingContainer artex-artex-1 Started实测从执行命令到 HTTP 返回 200,2 秒:
for i in $(seq 1 20); do code=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8787/) [ "$code" = "200" ] && echo "第 ${i} 秒就绪" && break sleep 1done第三步:三连确认
docker compose ps # 两个 Up,postgres 带 (healthy)curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8787/api/healthdocker compose logs --tail 20 artexps 看进程、curl 看端口、logs 看有没有报错。三个都对上才算真起来了。
说明:start / restart / up -d 的区别
三个命令都能”起来”,但语义不同,别混用:
docker compose start:只启动已存在的容器。如果之前是down删掉的,会报no containers to start。docker compose restart:重启已有容器,不处理依赖顺序,也不会应用 compose 配置变更。docker compose up -d:最稳。容器在就启动,不在就按配置创建,还会检查依赖健康状态。
日常就用 up -d,它是幂等的。
五、restart: unless-stopped 到底是什么意思
compose 里给两个服务都写了:
restart: unless-stopped很多人以为这等于”开机自动启动”,实际上它是条件式的:
- 电脑重启 / Docker Desktop 重启,容器会自动拉起(这是 unless-stopped 的部分)
- 但如果容器是被手动 stop 过的,那它不会自动起来(这是 unless 的部分)
- 如果容器已经被
down删掉了,没有容器可拉,更不会起来
所以「昨天还好好的,今天打开浏览器 502」大概率是这两种情况之一:
- 上次是
docker compose stop关的 → 手动状态,Docker 重启也不会拉起 → 需要up -d - 上次是
down关的 → 容器没了 → 需要up -d
判断方法就一句:
docker compose ps -aExited 说明容器在但没跑,up -d 即可;如果连记录都没有,说明被删了,也是 up -d。
Docker Desktop 本身的开机自启在 Settings → General → Start Docker Desktop when you sign in 里勾选。勾了之后,只要上次不是手动 stop,开机就不用管它。
六、常见问题
8787 端口被占用
lsof -iTCP:8787 -sTCP:LISTENdocker compose up -d 报 bind: address already in use 就是它。要么杀掉占用的进程,要么改 compose 的映射(比如 "8080:8787",注意只改宿主机那半边)。
postgres 一直 unhealthy
docker compose logs postgres | tail -30最常见的原因是:卷已经用旧密码初始化过了,但 .env 里的 POSTGRES_PASSWORD 改了。
PostgreSQL 镜像只在数据目录为空时才读 POSTGRES_PASSWORD 建用户,卷里已经有数据的话,这个环境变量会被忽略。结果是 artex 拿新密码去连,认证失败,启动就崩。
三条路,按代价从低到高:
- 把
.env改回原密码(最快,数据不动) - 进容器改数据库密码:
docker compose exec postgres psql -U artex -c "ALTER USER artex PASSWORD '新密码';",再同步改.env docker compose down -v推平重来(数据全丢)
忘记管理员密码
不用重装,仓库里带脚本:
cd ~/tools/ARTEX./reset-password.sh -m docker它会在 postgres 容器里用 pgcrypto 生成 bcrypt 哈希,写回 settings 表的 auth.password_hash,和后端登录校验完全兼容。-m docker 表示走容器内 psql(compose 默认不对宿主机暴露 5432)。
页面能打开,但活动流一直转圈
不是服务挂了,是 SSE 长连接被缓冲。如果前面套了 Nginx 反代,四个头必须加:
proxy_buffering off;proxy_cache off;proxy_read_timeout 3600s;proxy_http_version 1.1;本地直连 localhost:8787 不会有这个问题。
容器在,但日志一直重启
docker compose logs -f artex如果看到反复的启动失败,说明 start.sh 的守护逻辑在工作——它不是死循环,是在按退出码退避重拉。先解决根本错误,别急着 restart。
七、备份与更新
备份
两份东西,缺一不可:
# 数据库docker compose exec -T postgres pg_dump -U artex artex | gzip > artex-db-$(date +%F).sql.gz
# 现场文件(会比较大,实测 2.2G)tar -czf artex-data-$(date +%F).tgz -C ~/tools/ARTEX data./skills 是源码里的东西,跟着 git 走,不用单独备份。
更新
cd ~/tools/ARTEXdocker compose pull artexdocker compose up -d artexdocker image prune -f数据库迁移不用手动跑,ARTEX 每次启动会幂等重跑 schema.sql(ADD COLUMN / CREATE INDEX IF NOT EXISTS),重启即迁移。
想锁版本就在 .env 里写 ARTEX_TAG=v0.3.3,别一直用 latest——某天上游推了个不兼容的版本,只是重启一下就把自己搞崩了。
八、小结
- 装:
cp .env.example .env改密码 →docker compose up -d→ 访问 8787 走/setup - 关:日常
docker compose stop;改了配置用down;down -v是删库,别手滑 - 开:先确认 Docker Desktop 在跑 →
cd ~/tools/ARTEX && docker compose up -d→ps+curl三连确认 - 关掉后打不开,九成是「手动 stop 过」或「down 删过」,
up -d一把解决 - 数据只在三处:
pgdata卷、./data、./skills,容器随便删
最后再提一次边界:这套东西是攻击工具,README 里明确禁止对任何线上系统使用。真要练,就在 Docker 里起自己的靶场,或者用它测本地复现的漏洞环境。工具本身不违法,用在哪里才算。
九、我自己的使用体验
使用一周以来会发现,这个工具效率确实很高,上手很容易,只需要几句话就可以自动化挖洞,但是确实很烧token。它可以自己完成资产探测等操作,也可以自动注入,但对漏洞的等级划分以及挖洞的准度有很大欠缺,对有些漏洞只是有风险不验证就直接说是高危,我自己都蔡好几次坑了补天那边说我有几个漏洞不过审就是因为只说了风险没有验证,以及会把本来就开放的网页说成是未授权访问。所以ai挖洞一定要人来验证,通过这一周的经历,可以发现以后就算ai如何发展,也是始终要人的,我也没那么对未来恐慌了。
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!