From e94829381fae2843bfe6ebc25d96a800bbff7e4f Mon Sep 17 00:00:00 2001 From: okxlin Date: Mon, 31 Jul 2023 23:29:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E9=95=BF=E4=BA=AD?= =?UTF-8?q?=E9=9B=B7=E6=B1=A0=E5=88=B0=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/safeline/2.4.0/.env.sample | 12 ++ apps/safeline/2.4.0/data.yml | 88 +++++++++++++ apps/safeline/2.4.0/docker-compose.yml | 98 +++++++++++++++ apps/safeline/README.md | 118 ++++++++++++++++++ apps/safeline/data.yml | 20 +++ .../latest-1p-network-bug/.env.sample | 12 ++ apps/safeline/latest-1p-network-bug/data.yml | 88 +++++++++++++ .../latest-1p-network-bug/docker-compose.yml | 90 +++++++++++++ apps/safeline/latest/.env.sample | 12 ++ apps/safeline/latest/data.yml | 88 +++++++++++++ apps/safeline/latest/docker-compose.yml | 98 +++++++++++++++ apps/safeline/logo.png | Bin 0 -> 13169 bytes 12 files changed, 724 insertions(+) create mode 100644 apps/safeline/2.4.0/.env.sample create mode 100644 apps/safeline/2.4.0/data.yml create mode 100644 apps/safeline/2.4.0/docker-compose.yml create mode 100644 apps/safeline/README.md create mode 100644 apps/safeline/data.yml create mode 100644 apps/safeline/latest-1p-network-bug/.env.sample create mode 100644 apps/safeline/latest-1p-network-bug/data.yml create mode 100644 apps/safeline/latest-1p-network-bug/docker-compose.yml create mode 100644 apps/safeline/latest/.env.sample create mode 100644 apps/safeline/latest/data.yml create mode 100644 apps/safeline/latest/docker-compose.yml create mode 100644 apps/safeline/logo.png diff --git a/apps/safeline/2.4.0/.env.sample b/apps/safeline/2.4.0/.env.sample new file mode 100644 index 00000000..8e6b293b --- /dev/null +++ b/apps/safeline/2.4.0/.env.sample @@ -0,0 +1,12 @@ +CONTAINER_NAME="safeline" +MGT_PORT="40080" +POSTGRES_DB="safeline" +POSTGRES_HOST="postgres" +POSTGRES_PASSWORD="password_xxJdZD" +POSTGRES_PORT="5432" +POSTGRES_USER="postgresql" +REDIS_HOST="redis" +REDIS_PASSWORD="" +REDIS_PORT="6379" +SAFELINE_DIR="./data" +SUBNET_PREFIX="169.254.0" diff --git a/apps/safeline/2.4.0/data.yml b/apps/safeline/2.4.0/data.yml new file mode 100644 index 00000000..29ec2c05 --- /dev/null +++ b/apps/safeline/2.4.0/data.yml @@ -0,0 +1,88 @@ +additionalProperties: + formFields: + - default: "" + edit: true + envKey: REDIS_HOST + key: redis + labelEn: Redis Service + labelZh: Redis服务 + required: true + type: service + - default: "6379" + edit: true + envKey: REDIS_PORT + labelEn: Redis Service Port + labelZh: Redis服务端口 + required: true + rule: paramPort + type: number + - default: "" + edit: true + envKey: REDIS_PASSWORD + labelEn: Redis Service Password + labelZh: Redis服务密码 + required: true + rule: paramCommon + type: password + - default: "" + edit: true + envKey: POSTGRES_HOST + key: postgresql + labelEn: Postgres database Service + labelZh: Postgres数据库服务 + required: true + type: service + - default: "5432" + edit: true + envKey: POSTGRES_PORT + labelEn: Postgres database Service Port + labelZh: Postgres数据库服务端口 + required: true + rule: paramPort + type: number + - default: safeline + edit: true + envKey: POSTGRES_DB + labelEn: Postgres database Name + labelZh: Postgres数据库名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_USER + labelEn: Postgres database User Name + labelZh: Postgres数据库用户名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_PASSWORD + labelEn: Postgres database User Password + labelZh: Postgres数据库密码 + required: true + rule: paramCommon + type: password + - default: 40080 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: SAFELINE_DIR + labelEn: Data storage folder + labelZh: 数据存放文件夹 + required: true + type: text + - default: 169.254.0 + edit: true + envKey: SUBNET_PREFIX + labelEn: Subnet prefix + labelZh: 子网前缀 + required: true + type: text diff --git a/apps/safeline/2.4.0/docker-compose.yml b/apps/safeline/2.4.0/docker-compose.yml new file mode 100644 index 00000000..2927e156 --- /dev/null +++ b/apps/safeline/2.4.0/docker-compose.yml @@ -0,0 +1,98 @@ +version: '3' +services: + safeline-management: + container_name: ${CONTAINER_NAME}-mgt-api + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.4 + image: chaitin/safeline-mgt-api:2.4.0 + volumes: + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/nginx:/resources/nginx + - ${SAFELINE_DIR}/logs:/logs + - /etc/localtime:/etc/localtime:ro + ports: + - ${PANEL_APP_PORT_HTTP:-9443}:1443 + environment: + - MANAGEMENT_RESOURCES_DIR=/resources/management + - NGINX_RESOURCES_DIR=/resources/nginx + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - MARIO_URL=http://safeline-mario:3335 + - DETECTOR_URL=http://safeline-detector:8001 + - MANAGEMENT_LOGS_DIR=/logs/management + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-detector: + container_name: ${CONTAINER_NAME}-detector + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.5 + image: chaitin/safeline-detector:2.4.0 + volumes: + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/detector:/logs/detector + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/detector + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-mario: + container_name: ${CONTAINER_NAME}-mario + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.6 + image: chaitin/safeline-mario:2.4.0 + volumes: + - ${SAFELINE_DIR}/resources/mario:/resources/mario + - ${SAFELINE_DIR}/logs/mario:/logs/mario + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/mario + - GOGC=100 + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - REDIS_URL=redis://:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT}/0 + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-tengine: + container_name: ${CONTAINER_NAME}-tengine + restart: always + image: chaitin/safeline-tengine:2.4.0 + volumes: + - ${SAFELINE_DIR}/resources/nginx:/etc/nginx + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx + - /etc/localtime:/etc/localtime:ro + - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache + - /etc/resolv.conf:/etc/resolv.conf + environment: + - MGT_ADDR=${SUBNET_PREFIX}.4:9002 + ulimits: + nofile: 131072 + network_mode: host + labels: + createdBy: Apps + +networks: + safeline-ce: + name: safeline-ce + driver: bridge + ipam: + driver: default + config: + - gateway: ${SUBNET_PREFIX:?SUBNET_PREFIX required}.1 + subnet: ${SUBNET_PREFIX}.0/24 + driver_opts: + com.docker.network.bridge.name: safeline-ce \ No newline at end of file diff --git a/apps/safeline/README.md b/apps/safeline/README.md new file mode 100644 index 00000000..e0a8e156 --- /dev/null +++ b/apps/safeline/README.md @@ -0,0 +1,118 @@ +

+ +

+

雷池 - 广受好评的社区 WAF

+
+

+ + + + + +

+ +

+ 官方网站 | + 在线 Demo | + 技术文档 | + For English +

+ +一款足够简单、足够好用、足够强的免费 WAF。基于业界领先的语义引擎检测技术,作为反向代理接入,保护你的网站不受黑客攻击。 + +核心检测能力由智能语义分析算法驱动,专为社区而生,不让黑客越雷池半步。 + + + +

相关源码仓库

+

+ 语义分析自动机引擎 | + 流量分析插件 | + T1K 协议 | + 测试工具 +

+ +## 相关特性 + +#### 便捷性 + +采用容器化部署,一条命令即可完成安装,0 成本上手。安全配置开箱即用,无需人工维护,可实现安全躺平式管理。 + +#### 安全性 + +首创业内领先的智能语义分析算法,精准检测、低误报、难绕过。语义分析算法无规则,面对未知特征的 0day 攻击不再手足无措。 + +#### 高性能 + +无规则引擎,线性安全检测算法,平均请求检测延迟在 1 毫秒级别。并发能力强,单核轻松检测 2000+ TPS,只要硬件足够强,可支撑的流量规模无上限。 + +#### 高可用 + +流量处理引擎基于 Nginx 开发,性能与稳定性均可得到保障。内置完善的健康检查机制,服务可用性高达 99.99%。 + +## 🚀 安装 + +### 配置需求 + +- 操作系统:Linux +- 指令架构:x86_64 +- 软件依赖:Docker 20.10.6 版本以上 +- 软件依赖:Docker Compose 2.0.0 版本以上 +- 最小化环境:1 核 CPU / 1 GB 内存 / 10 GB 磁盘 + + +### 一键安装 + +``` +bash -c "$(curl -fsSLk https://waf-ce.chaitin.cn/release/latest/setup.sh)" +``` + +> 更多安装方式请参考 安装雷池 + +## 🕹️ 快速使用 + +### 登录 + +浏览器打开后台管理页面 `https://:9443`。根据界面提示,使用 **支持 TOTP 的认证软件** 扫描二维码,然后输入动态口令登录: + +![login.gif](https://waf-ce.chaitin.cn/images/gif/login.gif) + +### 配置防护站点 + +雷池以反向代理方式接入,优先于网站服务器接收流量,对流量中的攻击行为进行检测和清洗,将清洗过后的流量转发给网站服务器。 + +![config.gif](https://waf-ce.chaitin.cn/images/gif/config_site.gif) + +💡 TIPS: 添加后,执行 `curl -H "Host: <域名>" http://:<端口>` 应能获取到业务网站的响应。 + +### 测试效果 + +使用以下方式尝试模拟黑客攻击,看看雷池的防护效果如何 + +- 浏览器访问 `http://:<端口>/?id=1%20AND%201=1` +- 浏览器访问 `http://:<端口>/?a=` + +![log.gif](https://waf-ce.chaitin.cn/images/gif/detect_log.gif) + +> 如果你需要进行深度测试,请参考 测试防护效果 + +### FAQ + +- [安装问题](https://waf-ce.chaitin.cn/posts/faq_install) +- [登录问题](https://waf-ce.chaitin.cn/posts/faq_login) +- [网站无法访问](https://waf-ce.chaitin.cn/posts/faq_access) +- [配置问题](https://waf-ce.chaitin.cn/posts/faq_config) +- [其他问题](https://waf-ce.chaitin.cn/posts/faq_other) + +## 🏘️ 联系我们 + +1. 可以通过 GitHub Issue 直接进行 Bug 反馈和功能建议 +2. 可以扫描下方二维码加入雷池社区版用户讨论群 + + + +## Star History + + + Star History Chart + diff --git a/apps/safeline/data.yml b/apps/safeline/data.yml new file mode 100644 index 00000000..13dd5d37 --- /dev/null +++ b/apps/safeline/data.yml @@ -0,0 +1,20 @@ +name: 雷池 +tags: + - 工具 +title: 一款足够简单、足够好用、足够强的免费 WAF +type: 工具 +description: 一款足够简单、足够好用、足够强的免费 WAF +additionalProperties: + key: safeline + name: 雷池 + tags: + - Tool + shortDescZh: 一款足够简单、足够好用、足够强的免费 WAF + shortDescEn: A simple and easy to use WAF tool + type: tool + crossVersionUpdate: true + limit: 1 + recommend: 0 + website: https://waf-ce.chaitin.cn/ + github: https://github.com/chaitin/safeline + document: https://waf-ce.chaitin.cn/posts/guide_introduction diff --git a/apps/safeline/latest-1p-network-bug/.env.sample b/apps/safeline/latest-1p-network-bug/.env.sample new file mode 100644 index 00000000..baa2be42 --- /dev/null +++ b/apps/safeline/latest-1p-network-bug/.env.sample @@ -0,0 +1,12 @@ +CONTAINER_NAME="safeline" +MGT_PORT="40080" +POSTGRES_DB="safeline" +POSTGRES_HOST="postgres" +POSTGRES_PASSWORD="password_xxJdZD" +POSTGRES_PORT="5432" +POSTGRES_USER="postgresql" +REDIS_HOST="redis" +REDIS_PASSWORD="" +REDIS_PORT="6379" +SAFELINE_DIR="./data" +SUBNET_PREFIX="172.18.0" diff --git a/apps/safeline/latest-1p-network-bug/data.yml b/apps/safeline/latest-1p-network-bug/data.yml new file mode 100644 index 00000000..aadbb33f --- /dev/null +++ b/apps/safeline/latest-1p-network-bug/data.yml @@ -0,0 +1,88 @@ +additionalProperties: + formFields: + - default: "" + edit: true + envKey: REDIS_HOST + key: redis + labelEn: Redis Service + labelZh: Redis服务 + required: true + type: service + - default: "6379" + edit: true + envKey: REDIS_PORT + labelEn: Redis Service Port + labelZh: Redis服务端口 + required: true + rule: paramPort + type: number + - default: "" + edit: true + envKey: REDIS_PASSWORD + labelEn: Redis Service Password + labelZh: Redis服务密码 + required: true + rule: paramCommon + type: password + - default: "" + edit: true + envKey: POSTGRES_HOST + key: postgresql + labelEn: Postgres database Service + labelZh: Postgres数据库服务 + required: true + type: service + - default: "5432" + edit: true + envKey: POSTGRES_PORT + labelEn: Postgres database Service Port + labelZh: Postgres数据库服务端口 + required: true + rule: paramPort + type: number + - default: safeline + edit: true + envKey: POSTGRES_DB + labelEn: Postgres database Name + labelZh: Postgres数据库名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_USER + labelEn: Postgres database User Name + labelZh: Postgres数据库用户名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_PASSWORD + labelEn: Postgres database User Password + labelZh: Postgres数据库密码 + required: true + rule: paramCommon + type: password + - default: 40080 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: SAFELINE_DIR + labelEn: Data storage folder + labelZh: 数据存放文件夹 + required: true + type: text + - default: 172.18.0 + edit: false + envKey: SUBNET_PREFIX + labelEn: Subnet prefix + labelZh: 子网前缀 + required: true + type: text diff --git a/apps/safeline/latest-1p-network-bug/docker-compose.yml b/apps/safeline/latest-1p-network-bug/docker-compose.yml new file mode 100644 index 00000000..169c01f6 --- /dev/null +++ b/apps/safeline/latest-1p-network-bug/docker-compose.yml @@ -0,0 +1,90 @@ +version: '3' +services: + safeline-management: + container_name: ${CONTAINER_NAME}-mgt-api + restart: always + networks: + 1panel-network: + ipv4_address: ${SUBNET_PREFIX}.234 + image: chaitin/safeline-mgt-api:latest + volumes: + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/nginx:/resources/nginx + - ${SAFELINE_DIR}/logs:/logs + - /etc/localtime:/etc/localtime:ro + ports: + - ${PANEL_APP_PORT_HTTP:-9443}:1443 + environment: + - MANAGEMENT_RESOURCES_DIR=/resources/management + - NGINX_RESOURCES_DIR=/resources/nginx + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - MARIO_URL=http://safeline-mario:3335 + - DETECTOR_URL=http://safeline-detector:8001 + - MANAGEMENT_LOGS_DIR=/logs/management + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-detector: + container_name: ${CONTAINER_NAME}-detector + restart: always + networks: + 1panel-network: + ipv4_address: ${SUBNET_PREFIX}.235 + image: chaitin/safeline-detector:latest + volumes: + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/detector:/logs/detector + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/detector + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-mario: + container_name: ${CONTAINER_NAME}-mario + restart: always + networks: + 1panel-network: + ipv4_address: ${SUBNET_PREFIX}.236 + image: chaitin/safeline-mario:latest + volumes: + - ${SAFELINE_DIR}/resources/mario:/resources/mario + - ${SAFELINE_DIR}/logs/mario:/logs/mario + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/mario + - GOGC=100 + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - REDIS_URL=redis://:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT}/0 + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-tengine: + container_name: ${CONTAINER_NAME}-tengine + restart: always + image: chaitin/safeline-tengine:latest + volumes: + - ${SAFELINE_DIR}/resources/nginx:/etc/nginx + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx + - /etc/localtime:/etc/localtime:ro + - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache + - /etc/resolv.conf:/etc/resolv.conf + environment: + - MGT_ADDR=${SUBNET_PREFIX}.234:9002 + ulimits: + nofile: 131072 + network_mode: host + labels: + createdBy: Apps + +networks: + 1panel-network: + external: true \ No newline at end of file diff --git a/apps/safeline/latest/.env.sample b/apps/safeline/latest/.env.sample new file mode 100644 index 00000000..8e6b293b --- /dev/null +++ b/apps/safeline/latest/.env.sample @@ -0,0 +1,12 @@ +CONTAINER_NAME="safeline" +MGT_PORT="40080" +POSTGRES_DB="safeline" +POSTGRES_HOST="postgres" +POSTGRES_PASSWORD="password_xxJdZD" +POSTGRES_PORT="5432" +POSTGRES_USER="postgresql" +REDIS_HOST="redis" +REDIS_PASSWORD="" +REDIS_PORT="6379" +SAFELINE_DIR="./data" +SUBNET_PREFIX="169.254.0" diff --git a/apps/safeline/latest/data.yml b/apps/safeline/latest/data.yml new file mode 100644 index 00000000..29ec2c05 --- /dev/null +++ b/apps/safeline/latest/data.yml @@ -0,0 +1,88 @@ +additionalProperties: + formFields: + - default: "" + edit: true + envKey: REDIS_HOST + key: redis + labelEn: Redis Service + labelZh: Redis服务 + required: true + type: service + - default: "6379" + edit: true + envKey: REDIS_PORT + labelEn: Redis Service Port + labelZh: Redis服务端口 + required: true + rule: paramPort + type: number + - default: "" + edit: true + envKey: REDIS_PASSWORD + labelEn: Redis Service Password + labelZh: Redis服务密码 + required: true + rule: paramCommon + type: password + - default: "" + edit: true + envKey: POSTGRES_HOST + key: postgresql + labelEn: Postgres database Service + labelZh: Postgres数据库服务 + required: true + type: service + - default: "5432" + edit: true + envKey: POSTGRES_PORT + labelEn: Postgres database Service Port + labelZh: Postgres数据库服务端口 + required: true + rule: paramPort + type: number + - default: safeline + edit: true + envKey: POSTGRES_DB + labelEn: Postgres database Name + labelZh: Postgres数据库名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_USER + labelEn: Postgres database User Name + labelZh: Postgres数据库用户名 + required: true + rule: paramCommon + type: text + - default: "" + edit: true + envKey: POSTGRES_PASSWORD + labelEn: Postgres database User Password + labelZh: Postgres数据库密码 + required: true + rule: paramCommon + type: password + - default: 40080 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Port + labelZh: 端口 + required: true + rule: paramPort + type: number + - default: ./data + edit: true + envKey: SAFELINE_DIR + labelEn: Data storage folder + labelZh: 数据存放文件夹 + required: true + type: text + - default: 169.254.0 + edit: true + envKey: SUBNET_PREFIX + labelEn: Subnet prefix + labelZh: 子网前缀 + required: true + type: text diff --git a/apps/safeline/latest/docker-compose.yml b/apps/safeline/latest/docker-compose.yml new file mode 100644 index 00000000..437fae37 --- /dev/null +++ b/apps/safeline/latest/docker-compose.yml @@ -0,0 +1,98 @@ +version: '3' +services: + safeline-management: + container_name: ${CONTAINER_NAME}-mgt-api + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.4 + image: chaitin/safeline-mgt-api:latest + volumes: + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/nginx:/resources/nginx + - ${SAFELINE_DIR}/logs:/logs + - /etc/localtime:/etc/localtime:ro + ports: + - ${PANEL_APP_PORT_HTTP:-9443}:1443 + environment: + - MANAGEMENT_RESOURCES_DIR=/resources/management + - NGINX_RESOURCES_DIR=/resources/nginx + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - MARIO_URL=http://safeline-mario:3335 + - DETECTOR_URL=http://safeline-detector:8001 + - MANAGEMENT_LOGS_DIR=/logs/management + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-detector: + container_name: ${CONTAINER_NAME}-detector + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.5 + image: chaitin/safeline-detector:latest + volumes: + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/detector:/logs/detector + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/detector + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-mario: + container_name: ${CONTAINER_NAME}-mario + restart: always + networks: + safeline-ce: + ipv4_address: ${SUBNET_PREFIX}.6 + image: chaitin/safeline-mario:latest + volumes: + - ${SAFELINE_DIR}/resources/mario:/resources/mario + - ${SAFELINE_DIR}/logs/mario:/logs/mario + - /etc/localtime:/etc/localtime:ro + environment: + - LOG_DIR=/logs/mario + - GOGC=100 + - DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} + - REDIS_URL=redis://:${REDIS_PASSWORD}@${REDIS_HOST}:${REDIS_PORT}/0 + cap_drop: + - net_raw + labels: + createdBy: Apps + + safeline-tengine: + container_name: ${CONTAINER_NAME}-tengine + restart: always + image: chaitin/safeline-tengine:latest + volumes: + - ${SAFELINE_DIR}/resources/nginx:/etc/nginx + - ${SAFELINE_DIR}/resources/management:/resources/management + - ${SAFELINE_DIR}/resources/detector:/resources/detector + - ${SAFELINE_DIR}/logs/nginx:/var/log/nginx + - /etc/localtime:/etc/localtime:ro + - ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache + - /etc/resolv.conf:/etc/resolv.conf + environment: + - MGT_ADDR=${SUBNET_PREFIX}.4:9002 + ulimits: + nofile: 131072 + network_mode: host + labels: + createdBy: Apps + +networks: + safeline-ce: + name: safeline-ce + driver: bridge + ipam: + driver: default + config: + - gateway: ${SUBNET_PREFIX:?SUBNET_PREFIX required}.1 + subnet: ${SUBNET_PREFIX}.0/24 + driver_opts: + com.docker.network.bridge.name: safeline-ce \ No newline at end of file diff --git a/apps/safeline/logo.png b/apps/safeline/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b58a7ce9d4748de445803f5f5fc27804a133d4db GIT binary patch literal 13169 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 literal 0 HcmV?d00001