说明:
本教程涉及修改流盾 WAF 的源码文件,构建过程中可能出现无法预测的报错
操作前建议备份代码文件,或出现报错后从 GitHub 的开源仓库拉取源码覆盖
我之做了一个 模仿腾讯 EdgeOne 的流盾 WAF 403 响应页面:
模仿腾讯 EdgeOne 的流盾 WAF 403 响应页面-流盾WAF社区-建站综合交流-zibll子比社区
然后我就想,其他页面(滑块验证、JS挑战、数学验证)能不能改显示效果
所以从 github 上拉取的流盾的源码进行分析,对照响应页面改了一下
个人需要,自用开发,不喜勿喷
效果图例:



这是通过修改 3 个 Lua 源文件得到的效果
如何安装:
首先:你要安装了流盾 WAF,没有安装的话可以走了
我们一个需要上传 3 个文件覆盖,分别是
| 本地文件 | 目标路径 | 影响页面 |
|---|---|---|
upstream_error.lua |
engine/lua/waf/upstream_error.lua |
504 / 502 / 503 源站错误页 |
challenge.lua |
engine/lua/waf/actions/challenge.lua |
JS 挑战、算术验证码、滑动验证码、访问被拒绝页 |
page_render.lua |
engine/lua/waf/page_render.lua |
全局 footer(504/算术/滑动三页共用) |
覆盖完成后,需要重新构建 docker 容器,否则改动不会生效,执行以下指令:
cd /www/wwwroot/flow-shield-waf
// 假设安装路径为 /www/wwwroot/flow-shield-waf
docker compose up -d --build app
文件下载:
可能遇到的问题:
构建结束后终端出现以下报错:
[+] Running 3/3
✔ Container flowshield-waf-clickhouse-1 Healthy
✘ Container flowshield-waf-redis-1 Error
✔ Container flowshield-waf-app Recreated
01:故障显现
- 现象:WAF 后台报
服务器错误:Error -2 connecting to redis:6379. Name does not resolve;app 日志lua tcp socket connect timed out, when connecting to 172.19.0.4:6379与waf traffic: redis connect failed: timeout。 - 本质:redis 连不上,此时它已在 128MB 上限上崩、陷入重启死循环。
02:确认 app 正常、Lua 改动已生效
docker run --rm --entrypoint cat flowshield-waf-app:latest /etc/nginx/lua/waf/upstream_error.lua | grep -c f0f6fe→1(我们改的浅蓝渐变页面已烤进镜像)docker compose ps→ appUp (healthy)、clickhouseUp 8h (healthy)、redisRestarting (137)。- 结论:不是 Lua 页面问题,问题在 redis 容器反复退出 137。
03:锁定 redis 死循环根因
docker inspect ... OOMKilled/Restarting/Status→OOMKilled=false Restarting=true Status=restarting。docker logs --tail 30 flowshield-waf-redis-1→ 空。free -h→ xxGi / 543Mi 可用 / 4Gi swap(宿主机没 OOM)。docker inspect ... ExitCode/MemLimit/RestartCount→ExitCode=137 MemLimit=134217728 RestartCount=13。- 结论:
MemLimit=134217728= 128MB cgroup 上限;redis 加载 47h 累积数据超 128MB 被 SIGKILL(退出 137),OOMKilled在 cgroup v2 下误报 false,日志空是因被杀在启动阶段。根因确认。
05:修复
- 建
docker-compose.override.yml:services.redis.mem_limit: 512m(不动原文件、只覆盖 redis)。 docker compose up -d redis→Container flowshield-waf-redis-1 Started。docker compose ps→ redis 从Restarting (137)变为Up 8 seconds (health: starting)不再崩
06:验证 redis 存活
docker exec flowshield-waf-redis-1 redis-cli ping→NOAUTH Authentication required.(证明 redis 在监听且设了密码,app 自带密码可认证)。docker compose ps→ redisUp 5 minutes (healthy)。docker compose logs --tail 20 app→ 仅旧的(日志记最新)超时错误,无新报错。
07:重建 app 连接
docker compose restart app→ 干净重启,[startup]全流程完成、无 redis 报错 (清掉可能缓存的旧 redis IP / 死连接)。
08:最终确认
docker compose logs --since 1m app | grep -iE 'redis|Name does not resolve' → 无输出 → 最近 1 分钟无 redis 报错,故障闭环。
报错原因:
根因 是 redis 128MB cgroup 上限被累积数据撑爆 → cgroup v2 OOM SIGKILL → 重启死循环 → Docker 内嵌 DNS 无 redis 端点 → Name does not resolve;修复 = mem_limit 提至 512MB(override 文件),全链路恢复,且与我们改的 Lua 页面无关。
终端日志:
以下是我操作过程中的终端日志,可供参考:
Welcome to Alibaba Cloud Elastic Compute Service !
Updates Information Summary: available
84 Security notice(s)
53 Important Security notice(s)
26 Moderate Security notice(s)
5 Low Security notice(s)
Run "dnf upgrade-minimal --security" to apply all updates.More details please refer to:
https://help.aliyun.com/document_detail/416274.html
Last failed login: Sat Aug 15 14:34:40 CST 2026 from [REDACTED_IP_1] on ssh:notty
There were 46 failed login attempts since the last successful login.
Last login: Fri Aug 14 06:22:51 2026 from [REDACTED_IP_2]
[root@[REDACTED_HOSTNAME] ~]# ls -l /www/wwwroot/flow-shield-waf/engine/lua/waf/upstream_error.lua \
> /www/wwwroot/flow-shield-waf/engine/lua/waf/actions/challenge.lua \
> /www/wwwroot/flow-shield-waf/engine/lua/waf/page_render.lua
-rwxr-xr-x 1 root root 29733 Aug 15 21:45 /www/wwwroot/flow-shield-waf/engine/lua/waf/actions/challenge.lua
-rwxr-xr-x 1 root root 4172 Aug 15 21:45 /www/wwwroot/flow-shield-waf/engine/lua/waf/page_render.lua
-rwxr-xr-x 1 root root 4437 Aug 15 21:45 /www/wwwroot/flow-shield-waf/engine/lua/waf/upstream_error.lua
[root@[REDACTED_HOSTNAME] ~]# cd /www/wwwroot/flow-shield-waf
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose up -d --build app
[+] Building 19263.2s (73/73) FINISHED docker:default
=> [app internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 8.41kB 0.1s
=> [app] resolve image config for docker-image://docker.io/docker/dockerfile:1 8.3s
=> CACHED [app] docker-image://docker.io/docker/dockerfile:1@sha256:ecfaec9ed6d810b56388c508f4121597bfbba70d41a6dfeee4d8cad5f295fc32 0.0s
=> [app internal] load build definition from Dockerfile 0.0s
=> [app internal] load metadata for docker.io/library/node:20-alpine 6.6s
=> [app internal] load metadata for docker.io/openresty/openresty:1.25.3.1-2-alpine-fat 10.3s
=> [app internal] load .dockerignore 0.2s
=> => transferring context: 240B 0.1s
=> CACHED [app stage-1 1/53] FROM docker.io/openresty/openresty:1.25.3.1-2-alpine-fat@sha256:5eebac9570d121dcca1f32c8dfec56e799f31f7fc51389831685a3c996305b8b 0.0s
=> [app frontend-build 1/11] FROM docker.io/library/node:20-alpine@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609372293 0.0s
=> [app internal] load build context 0.2s
=> => transferring context: 67.17kB 0.2s
=> CACHED [app frontend-build 2/11] WORKDIR /build 0.0s
=> [app stage-1 2/53] RUN printf '==> [runtime] ALPINE_MIRROR=%s PIP_INDEX_URL=%s NGINX_MIRROR=%s CARGO_REGISTRY=%s\n' "official" "https://pypi.org/simple" "https://nginx.org/download" "crates.io" 1.1s
=> [app frontend-build 3/11] RUN printf '==> [frontend-build] NPM_CONFIG_REGISTRY=%s\n' "https://registry.npmjs.org/" 1.1s
=> [app stage-1 3/53] RUN if [ -n "" ]; then sed -i "s#https\?://dl-cdn.alpinelinux.org/alpine##g" /etc/apk/repositories; fi 0.8s
=> [app frontend-build 4/11] COPY frontend/package.json frontend/package-lock.json ./ 0.1s
=> [app frontend-build 5/11] RUN npm ci --include=dev 44.6s
=> [app stage-1 4/53] RUN if [ -n "" ]; then sed -i "s#https\?://[^/]*/alpine##g" /etc/apk/repositories; fi 1.2s
=> [app stage-1 5/53] RUN apk add --no-cache python3 py3-pip nginx supervisor curl redis libjpeg-turbo tzdata 3062.6s
=> [app frontend-build 6/11] RUN test -f node_modules/.bin/vite 2.0s
=> [app frontend-build 7/11] RUN mv node_modules /tmp/frontend-node_modules 0.5s
=> [app frontend-build 8/11] COPY frontend/ ./ 0.3s
=> [app frontend-build 9/11] RUN rm -rf node_modules 0.7s
=> [app frontend-build 10/11] RUN mv /tmp/frontend-node_modules node_modules 0.5s
=> [app frontend-build 11/11] RUN npm run build 107.1s
=> [app stage-1 6/53] COPY deploy/app/vendor/ngx_http_geoip2_module /tmp/ngx_http_geoip2_module 0.1s
=> [app stage-1 7/53] RUN apk add --no-cache --virtual .geoip2-build build-base pcre-dev zlib-dev openssl-dev linux-headers libmaxminddb-dev curl 575.8s
=> [app stage-1 8/53] RUN /usr/local/openresty/nginx/sbin/nginx -v 2>&1 | sed -n 's/.*openresty\///p' | cut -d' ' -f1 > /tmp/openresty_ver 0.5s
=> [app stage-1 9/53] RUN cut -d. -f1-3 /tmp/openresty_ver > /tmp/nginx_build_version 0.3s
=> [app stage-1 10/53] RUN test -s /tmp/nginx_build_version 0.4s
=> [app stage-1 11/53] RUN nginx_ver="$(cat /tmp/nginx_build_version)"; official="https://nginx.org/download/nginx-${nginx_ver}.tar.gz"; if [ -n "" ]; then curl -fL --retry 2 --retry-delay 1 -o "/tmp/nginx-${nginx_ver}.tar.gz" "/n 2.3s
=> [app stage-1 12/53] RUN tar xzf "/tmp/nginx-$(cat /tmp/nginx_build_version).tar.gz" -C /tmp 0.5s
=> [app stage-1 13/53] RUN cd "/tmp/nginx-$(cat /tmp/nginx_build_version)" && ./configure --with-compat --add-dynamic-module=/tmp/ngx_http_geoip2_module 11.6s
=> [app stage-1 14/53] RUN make -C "/tmp/nginx-$(cat /tmp/nginx_build_version)" -j"$(nproc)" modules 1.7s
=> [app stage-1 15/53] RUN cp "/tmp/nginx-$(cat /tmp/nginx_build_version)/objs/ngx_http_geoip2_module.so" /usr/local/openresty/nginx/modules/ 0.7s
=> [app stage-1 16/53] RUN rm -rf /tmp/nginx-* /tmp/ngx_http_geoip2_module /tmp/openresty_ver /tmp/nginx_build_version 0.6s
=> [app stage-1 17/53] RUN apk del .geoip2-build 0.6s
=> [app stage-1 18/53] RUN apk add --no-cache libmaxminddb 270.0s
=> [app stage-1 19/53] WORKDIR /app/backend 0.1s
=> [app stage-1 20/53] COPY backend/requirements-base.txt backend/requirements-extra.txt ./ 0.1s
=> [app stage-1 21/53] RUN apk add --no-cache --virtual .py-build-deps python3-dev gcc musl-dev jpeg-dev zlib-dev rust cargo 14123.7s
=> [app stage-1 22/53] RUN python3 -m venv /opt/venv 9.3s
=> [app stage-1 23/53] RUN /opt/venv/bin/pip install --upgrade pip 27.1s
=> [app stage-1 24/53] RUN if [ -n "" ]; then mkdir -p /root/.cargo; printf '%s\n' '[source.crates-io]' 'replace-with = "cn"' '[source.cn]' "registry = """ > /root/.cargo/config.toml; fi 0.3s
=> [app stage-1 25/53] RUN --mount=type=cache,target=/root/.cache/pip MAKEFLAGS="-j1" CARGO_BUILD_JOBS=1 /opt/venv/bin/pip install --prefer-binary --quiet -r requirements-base.txt 722.8s
=> [app stage-1 26/53] RUN apk del .py-build-deps 1.3s
=> [app stage-1 27/53] RUN --mount=type=cache,target=/root/.cache/pip MAKEFLAGS="-j1" CARGO_BUILD_JOBS=1 /opt/venv/bin/pip install --prefer-binary --quiet -r requirements-extra.txt 2.7s
=> [app stage-1 28/53] COPY backend/pyproject.toml ./ 0.3s
=> [app stage-1 29/53] COPY backend/app ./app 0.9s
=> [app stage-1 30/53] COPY slide_captcha /opt/flowshield/slide-captcha-defaults 0.1s
=> [app stage-1 31/53] COPY deploy/clickhouse /app/deploy/clickhouse 0.1s
=> [app stage-1 32/53] COPY engine/lua /etc/nginx/lua 0.1s
=> [app stage-1 33/53] COPY engine/snippets /etc/nginx/snippets 0.0s
=> [app stage-1 34/53] COPY deploy/app/engine.nginx.conf /usr/local/openresty/nginx/conf/nginx.conf 0.0s
=> [app stage-1 35/53] RUN mkdir -p /etc/nginx/html /data/engine/conf.d /data/engine/certs /etc/nginx/geoip /usr/local/openresty/nginx/logs 0.3s
=> [app stage-1 36/53] RUN touch /usr/local/openresty/nginx/logs/error.log 0.4s
=> [app stage-1 37/53] RUN chmod 666 /usr/local/openresty/nginx/logs/error.log 0.4s
=> [app stage-1 38/53] RUN rm -rf /etc/nginx/conf.d/* 0.5s
=> [app stage-1 39/53] COPY --from=frontend-build /build/dist /usr/share/nginx/html 0.3s
=> [app stage-1 40/53] COPY deploy/app/frontend.nginx.conf /etc/nginx/http.d/flowshield-panel.conf 0.0s
=> [app stage-1 41/53] COPY deploy/app/panel.nginx.conf /etc/nginx/nginx.conf 0.0s
=> [app stage-1 42/53] RUN rm -f /etc/nginx/http.d/default.conf 0.5s
=> [app stage-1 43/53] COPY deploy/app/supervisord.conf /etc/supervisor/supervisord.conf 0.1s
=> [app stage-1 44/53] COPY deploy/app/entrypoint.sh /entrypoint.sh 0.0s
=> [app stage-1 45/53] COPY deploy/app/wait-for.sh /opt/flowshield/wait-for.sh 0.0s
=> [app stage-1 46/53] COPY deploy/app/wait-for-backend.sh /opt/flowshield/wait-for-backend.sh 0.0s
=> [app stage-1 47/53] COPY deploy/app/startup-log.sh /opt/flowshield/startup-log.sh 0.0s
=> [app stage-1 48/53] COPY deploy/app/startup-ready.sh /opt/flowshield/startup-ready.sh 0.0s
=> [app stage-1 49/53] RUN chmod +x /entrypoint.sh 0.3s
=> [app stage-1 50/53] RUN chmod +x /opt/flowshield/wait-for.sh 0.4s
=> [app stage-1 51/53] RUN chmod +x /opt/flowshield/wait-for-backend.sh 0.4s
=> [app stage-1 52/53] RUN chmod +x /opt/flowshield/startup-log.sh 0.4s
=> [app stage-1 53/53] RUN chmod +x /opt/flowshield/startup-ready.sh 0.4s
=> [app] exporting to image 416.8s
=> => exporting layers 416.4s
=> => writing image sha256:0442986bf68d09a9a77fe965de5fc99622b2cd1613480df71001e7a9c075c768 0.1s
=> => naming to docker.io/library/flowshield-waf-app:latest 0.1s
[+] Running 3/3
✔ Container flowshield-waf-clickhouse-1 Healthy 3.4s
✘ Container flowshield-waf-redis-1 Error 3.4s
✔ Container flowshield-waf-app Recreated 2.9s
dependency failed to start: container flowshield-waf-redis-1 is unhealthy
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose up -d --build app
[+] Building 11.2s (73/73) FINISHED docker:default
=> [app internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 8.41kB 0.0s
=> [app] resolve image config for docker-image://docker.io/docker/dockerfile:1 4.8s
=> CACHED [app] docker-image://docker.io/docker/dockerfile:1@sha256:ecfaec9ed6d810b56388c508f4121597bfbba70d41a6dfeee4d8cad5f295fc32 0.0s
=> [app internal] load build definition from Dockerfile 0.0s
=> [app internal] load metadata for docker.io/library/node:20-alpine 5.2s
=> [app internal] load metadata for docker.io/openresty/openresty:1.25.3.1-2-alpine-fat 5.2s
=> [app internal] load .dockerignore 0.0s
=> => transferring context: 240B 0.0s
=> [app stage-1 1/53] FROM docker.io/openresty/openresty:1.25.3.1-2-alpine-fat@sha256:5eebac9570d121dcca1f32c8dfec56e799f31f7fc51389831685a3c996305b8b 0.0s
=> [app internal] load build context 0.1s
=> => transferring context: 28.78kB 0.1s
=> [app frontend-build 1/11] FROM docker.io/library/node:20-alpine@sha256:fb4cd12c85ee03686f6af5362a0b0d56d50c58a04632e6c0fb8363f609372293 0.0s
=> CACHED [app stage-1 2/53] RUN printf '==> [runtime] ALPINE_MIRROR=%s PIP_INDEX_URL=%s NGINX_MIRROR=%s CARGO_REGISTRY=%s\n' "official" "https://pypi.org/simple" "https://nginx.org/download" "crates.io" 0.0s
=> CACHED [app stage-1 3/53] RUN if [ -n "" ]; then sed -i "s#https\?://dl-cdn.alpinelinux.org/alpine##g" /etc/apk/repositories; fi 0.0s
=> CACHED [app stage-1 4/53] RUN if [ -n "" ]; then sed -i "s#https\?://[^/]*/alpine##g" /etc/apk/repositories; fi 0.0s
=> CACHED [app stage-1 5/53] RUN apk add --no-cache python3 py3-pip nginx supervisor curl redis libjpeg-turbo tzdata 0.0s
=> CACHED [app stage-1 6/53] COPY deploy/app/vendor/ngx_http_geoip2_module /tmp/ngx_http_geoip2_module 0.0s
=> CACHED [app stage-1 7/53] RUN apk add --no-cache --virtual .geoip2-build build-base pcre-dev zlib-dev openssl-dev linux-headers libmaxminddb-dev curl 0.0s
=> CACHED [app stage-1 8/53] RUN /usr/local/openresty/nginx/sbin/nginx -v 2>&1 | sed -n 's/.*openresty\///p' | cut -d' ' -f1 > /tmp/openresty_ver 0.0s
=> CACHED [app stage-1 9/53] RUN cut -d. -f1-3 /tmp/openresty_ver > /tmp/nginx_build_version 0.0s
=> CACHED [app stage-1 10/53] RUN test -s /tmp/nginx_build_version 0.0s
=> CACHED [app stage-1 11/53] RUN nginx_ver="$(cat /tmp/nginx_build_version)"; official="https://nginx.org/download/nginx-${nginx_ver}.tar.gz"; if [ -n "" ]; then curl -fL --retry 2 --retry-delay 1 -o "/tmp/nginx-${nginx_ver}.tar.gz" 0.0s
=> CACHED [app stage-1 12/53] RUN tar xzf "/tmp/nginx-$(cat /tmp/nginx_build_version).tar.gz" -C /tmp 0.0s
=> CACHED [app stage-1 13/53] RUN cd "/tmp/nginx-$(cat /tmp/nginx_build_version)" && ./configure --with-compat --add-dynamic-module=/tmp/ngx_http_geoip2_module 0.0s
=> CACHED [app stage-1 14/53] RUN make -C "/tmp/nginx-$(cat /tmp/nginx_build_version)" -j"$(nproc)" modules 0.0s
=> CACHED [app stage-1 15/53] RUN cp "/tmp/nginx-$(cat /tmp/nginx_build_version)/objs/ngx_http_geoip2_module.so" /usr/local/openresty/nginx/modules/ 0.0s
=> CACHED [app stage-1 16/53] RUN rm -rf /tmp/nginx-* /tmp/ngx_http_geoip2_module /tmp/openresty_ver /tmp/nginx_build_version 0.0s
=> CACHED [app stage-1 17/53] RUN apk del .geoip2-build 0.0s
=> CACHED [app stage-1 18/53] RUN apk add --no-cache libmaxminddb 0.0s
=> CACHED [app stage-1 19/53] WORKDIR /app/backend 0.0s
=> CACHED [app stage-1 20/53] COPY backend/requirements-base.txt backend/requirements-extra.txt ./ 0.0s
=> CACHED [app stage-1 21/53] RUN apk add --no-cache --virtual .py-build-deps python3-dev gcc musl-dev jpeg-dev zlib-dev rust cargo 0.0s
=> CACHED [app stage-1 22/53] RUN python3 -m venv /opt/venv 0.0s
=> CACHED [app stage-1 23/53] RUN /opt/venv/bin/pip install --upgrade pip 0.0s
=> CACHED [app stage-1 24/53] RUN if [ -n "" ]; then mkdir -p /root/.cargo; printf '%s\n' '[source.crates-io]' 'replace-with = "cn"' '[source.cn]' "registry = """ > /root/.cargo/config.toml; fi 0.0s
=> CACHED [app stage-1 25/53] RUN --mount=type=cache,target=/root/.cache/pip MAKEFLAGS="-j1" CARGO_BUILD_JOBS=1 /opt/venv/bin/pip install --prefer-binary --quiet -r requirements-base.txt 0.0s
=> CACHED [app stage-1 26/53] RUN apk del .py-build-deps 0.0s
=> CACHED [app stage-1 27/53] RUN --mount=type=cache,target=/root/.cache/pip MAKEFLAGS="-j1" CARGO_BUILD_JOBS=1 /opt/venv/bin/pip install --prefer-binary --quiet -r requirements-extra.txt 0.0s
=> CACHED [app stage-1 28/53] COPY backend/pyproject.toml ./ 0.0s
=> CACHED [app stage-1 29/53] COPY backend/app ./app 0.0s
=> CACHED [app stage-1 30/53] COPY slide_captcha /opt/flowshield/slide-captcha-defaults 0.0s
=> CACHED [app stage-1 31/53] COPY deploy/clickhouse /app/deploy/clickhouse 0.0s
=> CACHED [app stage-1 32/53] COPY engine/lua /etc/nginx/lua 0.0s
=> CACHED [app stage-1 33/53] COPY engine/snippets /etc/nginx/snippets 0.0s
=> CACHED [app stage-1 34/53] COPY deploy/app/engine.nginx.conf /usr/local/openresty/nginx/conf/nginx.conf 0.0s
=> CACHED [app stage-1 35/53] RUN mkdir -p /etc/nginx/html /data/engine/conf.d /data/engine/certs /etc/nginx/geoip /usr/local/openresty/nginx/logs 0.0s
=> CACHED [app stage-1 36/53] RUN touch /usr/local/openresty/nginx/logs/error.log 0.0s
=> CACHED [app stage-1 37/53] RUN chmod 666 /usr/local/openresty/nginx/logs/error.log 0.0s
=> CACHED [app stage-1 38/53] RUN rm -rf /etc/nginx/conf.d/* 0.0s
=> CACHED [app frontend-build 2/11] WORKDIR /build 0.0s
=> CACHED [app frontend-build 3/11] RUN printf '==> [frontend-build] NPM_CONFIG_REGISTRY=%s\n' "https://registry.npmjs.org/" 0.0s
=> CACHED [app frontend-build 4/11] COPY frontend/package.json frontend/package-lock.json ./ 0.0s
=> CACHED [app frontend-build 5/11] RUN npm ci --include=dev 0.0s
=> CACHED [app frontend-build 6/11] RUN test -f node_modules/.bin/vite 0.0s
=> CACHED [app frontend-build 7/11] RUN mv node_modules /tmp/frontend-node_modules 0.0s
=> CACHED [app frontend-build 8/11] COPY frontend/ ./ 0.0s
=> CACHED [app frontend-build 9/11] RUN rm -rf node_modules 0.0s
=> CACHED [app frontend-build 10/11] RUN mv /tmp/frontend-node_modules node_modules 0.0s
=> CACHED [app frontend-build 11/11] RUN npm run build 0.0s
=> CACHED [app stage-1 39/53] COPY --from=frontend-build /build/dist /usr/share/nginx/html 0.0s
=> CACHED [app stage-1 40/53] COPY deploy/app/frontend.nginx.conf /etc/nginx/http.d/flowshield-panel.conf 0.0s
=> CACHED [app stage-1 41/53] COPY deploy/app/panel.nginx.conf /etc/nginx/nginx.conf 0.0s
=> CACHED [app stage-1 42/53] RUN rm -f /etc/nginx/http.d/default.conf 0.0s
=> CACHED [app stage-1 43/53] COPY deploy/app/supervisord.conf /etc/supervisor/supervisord.conf 0.0s
=> CACHED [app stage-1 44/53] COPY deploy/app/entrypoint.sh /entrypoint.sh 0.0s
=> CACHED [app stage-1 45/53] COPY deploy/app/wait-for.sh /opt/flowshield/wait-for.sh 0.0s
=> CACHED [app stage-1 46/53] COPY deploy/app/wait-for-backend.sh /opt/flowshield/wait-for-backend.sh 0.0s
=> CACHED [app stage-1 47/53] COPY deploy/app/startup-log.sh /opt/flowshield/startup-log.sh 0.0s
=> CACHED [app stage-1 48/53] COPY deploy/app/startup-ready.sh /opt/flowshield/startup-ready.sh 0.0s
=> CACHED [app stage-1 49/53] RUN chmod +x /entrypoint.sh 0.0s
=> CACHED [app stage-1 50/53] RUN chmod +x /opt/flowshield/wait-for.sh 0.0s
=> CACHED [app stage-1 51/53] RUN chmod +x /opt/flowshield/wait-for-backend.sh 0.0s
=> CACHED [app stage-1 52/53] RUN chmod +x /opt/flowshield/startup-log.sh 0.0s
=> CACHED [app stage-1 53/53] RUN chmod +x /opt/flowshield/startup-ready.sh 0.0s
=> [app] exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:0442986bf68d09a9a77fe965de5fc99622b2cd1613480df71001e7a9c075c768 0.0s
=> => naming to docker.io/library/flowshield-waf-app:latest 0.0s
[+] Running 2/2
✔ Container flowshield-waf-clickhouse-1 Healthy 0.5s
✘ Container flowshield-waf-redis-1 Error 0.5s
dependency failed to start: container flowshield-waf-redis-1 is unhealthy
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker ps -a --format 'table {{.Names}}\t{{.Status}}'
NAMES STATUS
flowshield-waf-app Created
flowshield-waf-clickhouse-1 Up 8 hours (healthy)
flowshield-waf-redis-1 Restarting (137) 2 seconds ago
hardcore_cartwright Up 8 hours
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker run --rm --entrypoint cat flowshield-waf-app:latest /etc/nginx/lua/waf/upstream_error.lua | grep -c f0f6fe
1
[root@[REDACTED_HOSTNAME] flow-shield-waf]# cd /www/wwwroot/flow-shield-waf
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
flowshield-waf-app flowshield-waf-app:latest "/entrypoint.sh" app 2 hours ago Up 3 minutes (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp
flowshield-waf-clickhouse-1 clickhouse/clickhouse-server:24-alpine "/entrypoint.sh" clickhouse 47 hours ago Up 8 hours (healthy) 8123/tcp, 9000/tcp, 9009/tcp
flowshield-waf-redis-1 redis:7-alpine "docker-entrypoint.s…" redis 47 hours ago Restarting (137) 57 seconds ago
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker inspect flowshield-waf-redis-1 --format 'OOMKilled={{.State.OOMKilled}} Restarting={{.State.Restarting}} Status={{.State.Status}}'
OOMKilled=false Restarting=true Status=restarting
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker logs --tail 30 flowshield-waf-redis-1
[root@[REDACTED_HOSTNAME] flow-shield-waf]# free -h
total used free shared buff/cache available
Mem: 1.8Gi 1.3Gi 474Mi 3.0Mi 226Mi 543Mi
Swap: 4.0Gi 627Mi 3.4Gi
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker inspect flowshield-waf-redis-1 --format 'ExitCode={{.State.ExitCode}} Error={{.State.Error}} MemLimit={{.HostConfig.Memory}} RestartCount={{.RestartCount}}'
ExitCode=137 Error= MemLimit=134217728 RestartCount=13
[root@[REDACTED_HOSTNAME] flow-shield-waf]# cd /www/wwwroot/flow-shield-waf
[root@[REDACTED_HOSTNAME] flow-shield-waf]# cat > docker-compose.override.yml <<'EOF'
> services:
> redis:
> mem_limit: 512m
> EOF
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose up -d redis
[+] Running 1/1
✔ Container flowshield-waf-redis-1 Started 1.1s
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
flowshield-waf-app flowshield-waf-app:latest "/entrypoint.sh" app 2 hours ago Up 5 minutes (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp
flowshield-waf-clickhouse-1 clickhouse/clickhouse-server:24-alpine "/entrypoint.sh" clickhouse 47 hours ago Up 8 hours (healthy) 8123/tcp, 9000/tcp, 9009/tcp
flowshield-waf-redis-1 redis:7-alpine "docker-entrypoint.s…" redis 10 seconds ago Up 8 seconds (health: starting) 6379/tcp
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker logs --tail 20 flowshield-waf-redis-1
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker exec flowshield-waf-redis-1 redis-cli ping
NOAUTH Authentication required.
[root@[REDACTED_HOSTNAME] flow-shield-waf]# sleep 15
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
flowshield-waf-app flowshield-waf-app:latest "/entrypoint.sh" app 3 hours ago Up 11 minutes (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp, 0.0.0.0:9000->9000/tcp, :::9000->9000/tcp
flowshield-waf-clickhouse-1 clickhouse/clickhouse-server:24-alpine "/entrypoint.sh" clickhouse 47 hours ago Up 8 hours (healthy) 8123/tcp, 9000/tcp, 9009/tcp
flowshield-waf-redis-1 redis:7-alpine "docker-entrypoint.s…" redis 5 minutes ago Up 5 minutes (healthy) 6379/tcp
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose logs --tail 20 app
flowshield-waf-app | 2026/08/15 21:45:43 [error] 210#210: *1706 [lua] traffic_counter.lua:534: tick(): waf traffic: redis connect failed: timeout, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 211#211: *1735 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1738 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1740 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1724 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1730 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1716 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:44 [error] 210#210: *1716 [lua] traffic_counter.lua:534: tick(): waf traffic: redis connect failed: timeout, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 211#211: *1735 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1738 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1748 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1730 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1740 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1724 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:45 [error] 210#210: *1724 [lua] traffic_counter.lua:534: tick(): waf traffic: redis connect failed: timeout, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:46 [error] 210#210: *1754 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:46 [error] 210#210: *1740 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:46 [error] 210#210: *1748 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:46 [error] 210#210: *1730 lua tcp socket connect timed out, when connecting to 172.19.0.4:6379, context: ngx.timer
flowshield-waf-app | 2026/08/15 21:45:46 [error] 210#210: *1730 [lua] traffic_counter.lua:534: tick(): waf traffic: redis connect failed: timeout, context: ngx.timer
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose restart app
[+] Restarting 1/1
✔ Container flowshield-waf-app Started 3.7s
[root@[REDACTED_HOSTNAME] flow-shield-waf]# sleep 10
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose logs --since 2m app
flowshield-waf-app | 2026-08-15 21:52:17,294 WARN received SIGQUIT indicating exit request
flowshield-waf-app | 2026-08-15 21:52:18,415 WARN stopped: worker (terminated by SIGTERM)
flowshield-waf-app | 2026-08-15 21:52:18,558 WARN stopped: backend (terminated by SIGTERM)
flowshield-waf-app | [startup] [1/5] 初始化运行环境
flowshield-waf-app | GeoIP2 enabled: using MaxMind databases from /etc/nginx/geoip
flowshield-waf-app | [startup] GeoIP2 已启用 (/etc/nginx/geoip)
flowshield-waf-app | [startup] [3/5] 启动服务进程 (backend / worker / engine / panel)
flowshield-waf-app | [startup] 启动 API 后端 (127.0.0.1:8000)...
flowshield-waf-app | [startup] 启动管理面板 (Nginx :9000)...
flowshield-waf-app | [startup] 启动后台 Worker...
flowshield-waf-app | [startup] 启动 WAF 引擎 (OpenResty :80/:443)...
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose ps clickhouse
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
flowshield-waf-clickhouse-1 clickhouse/clickhouse-server:24-alpine "/entrypoint.sh" clickhouse 47 hours ago Up 8 hours (healthy) 8123/tcp, 9000/tcp, 9009/tcp
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose logs --since 5m clickhouse
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker compose logs --since 5m app | grep -iE 'clickhouse|module|panel|error|traceback' | head -40
flowshield-waf-app | [startup] [3/5] 启动服务进程 (backend / worker / engine / panel)
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker exec flowshield-waf-clickhouse-1 wget -qO- 'http://localhost:8123/' 2>&1 | head -3
wget: can't connect to remote host: Connection refused
[root@[REDACTED_HOSTNAME] flow-shield-waf]# docker exec flowshield-waf-clickhouse-1 clickhouse-client --query 'SELECT 1' 2>&1
1
[root@[REDACTED_HOSTNAME] flow-shield-waf]#










