⚠️ 提示:本站 AI 助手使用博主个人 API Token,没事别特么瞎用。
运维 · · 约 40 分钟阅读

Scanopy 社区版完全指南:自动发现网络拓扑、四视图文档、Docker 部署与排障

还在用 draw.io 手动画网络拓扑图?机器一变图就过期。Scanopy 是一个用 Rust + Svelte 构建的开源网络文档工具,部署一个 daemon 就能自动扫描全网,通过 SNMP/LLDP/CDP/ARP 发现主机、交换机、容器和服务依赖,生成 L2 物理、L3 逻辑、工作负载、应用依赖四个视图,定期重扫保持最新。社区版 AGPL-3.0 免费自建,一条 docker compose 命令起步。本文覆盖社区版选型、Docker Compose 部署、daemon 配置、扫描调优、四视图解读、导出集成、安全加固和常见排障。

一、为什么需要 Scanopy

网络文档的三种死法

方式初始准确度一周后一个月后根因
Visio / draw.io 手动画100%80%50%人不会主动更新图
IaC 声明文件95%90%70%只记录管道内资源,漂移和手动改不在里面
Excel 资产表90%60%30%没人填、格式乱、多份不同步

Scanopy 的核心思路:不画图、不声明,而是扫描实际运行的网络,从 SNMP/LLDP/CDP/ARP 协议中发现真实的设备、连接和服务,自动生成拓扑图并定期重扫保持最新。

Scanopy 是什么

Scanopy 是一个自动化的网络文档工具,不是监控工具。它不追踪带宽和告警(那是 Zabbix/Prometheus 的活),它只做一件事:把你的网络长什么样变成一份永远最新的文档。

维度说明
定位网络拓扑自动发现 + 文档生成(非监控)
发现协议SNMP、LLDP、CDP、ARP
扫描能力全 65536 端口扫描 + 260+ 服务指纹识别
四视图L2 物理(交换机端口)、L3 逻辑(子网/VLAN)、工作负载(VM/容器)、应用依赖
技术栈Rust(扫描引擎)+ Svelte/TypeScript(UI)+ PostgreSQL(存储)
部署方式Docker Compose 一键部署 / Proxmox LXC / Unraid
社区版AGPL-3.0,免费自建,限 1 个网络 + 1 个席位
商业版解除限制 + 多网络 + 多席位 + 导出 + 集成
云版$11.99/月起,零运维

社区版 vs 商业版 vs 云版

能力社区版(免费)商业版(付费自建)云版(托管)
价格免费联系定价$11.99/月起
许可证AGPL-3.0商业许可SaaS
网络数1 个无限按计划
席位数1 个按计划按计划
自动发现✅ 全部✅✅
四视图✅✅✅
导出(SVG/Mermaid/Confluence)❌✅✅
OIDC/SAML 集成❌✅✅
多 daemon 分布式扫描❌✅✅
支持社区 Discord官方支持官方支持

结论:个人 homelab、小团队单网络文档、学习网络拓扑 → 社区版完全够用。需要多站点扫描、团队协作、导出到 Confluence → 考虑商业版或云版。

跟同类工具的对比

工具自动发现拓扑图L2L3工作负载应用依赖Docker开源
Scanopy CE✅ SNMP/LLDP/CDP/ARP✅ 自动✅✅✅✅✅AGPL-3.0
NetDisco✅ SNMP/CDP/LLDP/ARP✅ 自动✅✅❌❌❌BSD
LibreNMS✅ SNMP/CDP/LLDP基础✅✅❌❌❌GPL-3.0
NetBox手动 + Discovery Agent插件✅✅✅❌❌Apache-2.0
Nmap✅ ICMP/ARP/TCP❌❌❌❌❌❌NPSL
draw.io❌手动❌❌❌❌❌Apache-2.0

Scanopy 的差异化:唯一同时做到「自动发现 + 四视图 + Docker 检测」的开源工具。NetDisco 强在 L2 但不碰容器;LibreNMS 是监控不是文档;NetBox 是数据库不是扫描器;draw.io 是画板不是发现引擎。


二、社区版 Docker Compose 部署

1.1 环境要求

资源最低推荐说明
CPU1 核2 核Rust 扫描引擎单核够用
内存1 GB2 GBPostgreSQL + Server + Daemon
磁盘5 GB20 GB镜像 + DB + 历史扫描数据
OSLinux 任意发行版Ubuntu 22.04+ / Debian 12+也可 macOS/FreeBSD
Docker20.10+24.0+Docker Engine + Compose v2
网络能访问目标网段—daemon 用 host 网络模式扫描

1.2 一键部署

# 1. 下载 docker-compose.yml
curl -O https://raw.githubusercontent.com/scanopy/scanopy/refs/heads/main/docker-compose.yml

# 2. (可选)下载 .env.example 改名配置
curl -O https://raw.githubusercontent.com/scanopy/scanopy/refs/heads/main/.env.example
cp .env.example .env

# 3. 改密码(生产必须改)
sed -i 's/POSTGRES_PASSWORD=password/POSTGRES_PASSWORD=你的强密码/' .env

# 4. 改 Public URL(如果远程访问)
echo 'SCANOPY_PUBLIC_URL=http://你的IP:60072' >> .env

# 5. 启动
docker compose up -d

# 6. 查看状态
docker compose ps

启动后访问 http://<你的IP>:60072,注册第一个账号(自动成为管理员),等待首次扫描完成。

1.3 三容器架构详解

docker-compose.yml 启动三个容器:

flowchart TB
  subgraph HOST["宿主机网络"]
    direction TB
    DAEMON["daemon(扫描引擎)<br/>:60073 · host 网络 · privileged"]
    SERVER["server(Web API + UI)<br/>:60072 · bridge 网络"]
    SOCK["/var/run/docker.sock(只读挂载)<br/>daemon 挂载后用于 Docker 检测"]
    PG[("postgres:17-alpine<br/>数据存储 :5432")]
    DAEMON -->|"扫描结果上报"| SERVER
    DAEMON -. 读取 .-> SOCK
    SERVER --> PG
  end
容器镜像职责端口网络模式
daemonghcr.io/scanopy/scanopy/daemon:latest扫描引擎,用 SNMP/LLDP/ARP 发现设备和拓扑60073host(需要原始网络访问)
serverghcr.io/scanopy/scanopy/server:latestWeb API + 静态 UI,连接 PostgreSQL60072bridge
postgrespostgres:17-alpine存储扫描结果、用户、网络模型5432bridge

daemon 为什么是 privileged + host 网络:扫描需要发送原始 ARP 请求和接收 LLDP/CDP 帧,这些不是普通 TCP/UDP,需要原始套接字权限。host 网络模式让 daemon 直接使用宿主机网卡,能看到真实网络拓扑。

1.4 .env 关键配置项

# ===== Server =====
# 数据库连接(compose 内部网络,不用改)
SCANOPY_DATABASE_URL=postgresql://postgres:你的密码@postgres:5432/scanopy

# 外部访问地址(远程访问时改成你的 IP 或域名)
SCANOPY_PUBLIC_URL=http://192.168.1.100:60072

# 日志级别:debug / info / warn / error
SCANOPY_LOG_LEVEL=info

# 禁止注册(首次创建账号后建议开启)
# SCANOPY_DISABLE_REGISTRATION=true

# 禁止密码登录(配合 OIDC 使用)
# SCANOPY_DISABLE_PASSWORD_LOGIN=true

# ===== HTTPS(反向代理时开启) =====
# SCANOPY_USE_SECURE_SESSION_COOKIES=true

# ===== SMTP(密码重置 + 通知,可选) =====
# SCANOPY_SMTP_RELAY=smtp.gmail.com
# SCANOPY_SMTP_USERNAME=your-email@gmail.com
# SCANOPY_SMTP_PASSWORD=your-app-password
# SCANOPY_SMTP_EMAIL=scanopy@yourdomain.com
# SCANOPY_SMTP_PORT=587

# ===== Prometheus 指标(可选) =====
# SCANOPY_METRICS_TOKEN=your-secure-token
# SCANOPY_EXTERNAL_SERVICE_PROMETHEUS_ALLOWED_IPS=192.168.1.0/24

# ===== Daemon =====
# daemon API Key(自动生成,不用手动设)
# SCANOPY_DAEMON_API_KEY=<autogenerated>

1.5 Proxmox / Unraid / 裸机部署

除了 Docker Compose,Scanopy 社区版还支持:

Proxmox LXC(一行命令):

# 在 Proxmox 宿主机执行
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/scanopy.sh)"

Unraid:在 Unraid Community Apps 搜索 “scanopy” 一键安装。

裸机 daemon(远程扫描器):

# 下载 daemon 二进制
curl -fL https://github.com/scanopy/scanopy/releases/latest/download/scanopy-daemon-linux-amd64 -o scanopy-daemon
chmod +x scanopy-daemon
sudo mv scanopy-daemon /usr/local/bin/

# 注册为 systemd 服务
sudo tee /etc/systemd/system/scanopy-daemon.service << 'EOF'
[Unit]
Description=Scanopy Daemon
After=network.target

[Service]
ExecStart=/usr/local/bin/scanopy-daemon
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now scanopy-daemon

裸机 daemon 适合部署在网络隔离段(如 DMZ 或独立 VLAN),扫描完后把数据回传给中心 Server,实现多段扫描(商业版功能,社区版只能连一个 Server)。


三、首次扫描配置

2.1 在 Web UI 创建网络

  1. 登录 http://<IP>:60072
  2. 进入 Networks → New Network
  3. 填写:
    • Name:Home-Lab 或 Office-Floor-1
    • Scan Range:CIDR 或范围,如 192.168.1.0/24
    • SNMP Community:如果交换机开了 SNMP,填 community string(如 public 或自定义);没有 SNMP 只能做 ARP + 端口扫描
  4. 保存后自动开始首次扫描

2.2 扫描流程(一次扫描做了什么)

1. ARP 扫描
   → 发现 CIDR 范围内所有活跃 IP(包括没开端口的主机)

2. 端口扫描
   → 对响应的主机扫全 65536 端口(或常用端口子集)

3. 服务指纹
   → 对开放端口做 banner grab,匹配 260+ 服务定义
   → 识别 SSH / HTTP / HTTPS / MySQL / Redis / PostgreSQL / Docker Registry...

4. SNMP 查询
   → 对开了 SNMP 的交换机/路由器查 LLDP/CDP 邻居表
   → 构建 L2 物理连接关系(哪个交换机哪个口连哪个设备)

5. Docker 检测
   → 如果 daemon 挂载了 /var/run/docker.sock
   → 读取容器列表、网络、端口映射
   → 构建工作负载视图

6. 拓扑关联
   → 把 ARP 表 + LLDP 邻居 + 端口扫描结果交叉关联
   → 生成 L2/L3/工作负载/应用四个视图

2.3 扫描范围规划

场景CIDR说明
家庭网络192.168.1.0/24一个 /24 覆盖路由器 + 所有设备
小办公室10.0.0.0/16多 VLAN,daemon 放核心交换机旁
机房单机架10.10.10.0/2816 个 IP,扫完秒级
多 VLAN 园区分段填多个 CIDR社区版只能 1 个网络,多 VLAN 填一个大范围或用商业版多 daemon

⚠️ 社区版限制:只能创建 1 个 Network。如果你有多个不连续网段需要扫描,把它们合并成一个大 CIDR(如 10.0.0.0/8 会扫很久,建议拆分或升商业版)。

2.4 SNMP 配置(L2 拓扑的关键)

没有 SNMP,Scanopy 只能做 ARP + 端口扫描(L3 和应用视图),无法生成 L2 物理拓扑(交换机端口连线图)。如果你的网络有可管理交换机,强烈建议开 SNMP。

Cisco/H3C/华为交换机开 SNMP:

# 进入交换机配置模式
configure terminal

# SNMP v2c(简单但不安全,仅内网用)
snmp-server community public RO

# SNMP v3(推荐,加密 + 认证)
snmp-server group SCANOPY v3 priv read SCANOPY-READ
snmp-server user scanopy SCANOPY v3 auth sha YourAuthPass123 priv aes256 YourPrivPass456

# 确保 LLDP 开启
lldp run
cdp run   # Cisco 专用

exit
write memory

Linux 主机开 SNMP(可选):

# RHEL/CentOS
dnf install net-snmp -y
# 编辑 /etc/snmp/snmpd.conf
#   com2sec readonly 192.168.1.0/24 public
#   view systemview included .1.3.6.1
systemctl enable --now snmpd
firewall-cmd --add-service=snmp --permanent && firewall-cmd --reload

# Ubuntu/Debian
apt install snmpd -y
# 编辑 /etc/snmp/snmpd.conf
#   agentaddress udp:161
#   rocommunity public 192.168.1.0/24
systemctl restart snmpd

在 Scanopy Web UI 的 Network 设置里填入 SNMP community 或 v3 凭证,下次扫描就能看到交换机端口级拓扑了。


四、四视图解读

3.1 L2 物理视图(交换机端口连线图)

flowchart TB
  SWC["SW-Core<br/>10.10.10.1 · Cisco 2960"]
  SWA["SW-Access-1<br/>10.10.10.2 · Cisco 2960"]
  SV1["Server-01<br/>10.10.10.11 · esxi host"]
  SV2["Server-02<br/>10.10.10.12 · Docker host"]
  SWC -->|"Gi0/1"| SWA
  SWC -->|"Gi0/2"| SV1
  SWA -->|"Fa0/24"| SV2
  • 数据来源:SNMP 查询交换机的 LLDP/CDP 邻居表 + ARP 表
  • 能看到:每个交换机的每个端口连了什么设备、VLAN 归属、端口状态(up/down)
  • 没 SNMP 看不到:只有 IP 列表,没有物理连线

3.2 L3 逻辑视图(子网 + VLAN)

flowchart TB
  subgraph V10["10.10.10.0/24 · VLAN 10(Servers)"]
    direction LR
    S1["Srv-1"] --- S2["Srv-2"] --- S3["Srv-3"] --- S4["Srv-4"]
  end
  subgraph V20["10.10.20.0/24 · VLAN 20(Clients)"]
    direction LR
    P1["PC-1"] --- P2["PC-2"] --- P3["PC-3"]
  end
  V10 -->|"路由"| V20
  • 数据来源:ARP 表 + 子网掩码推算 + SNMP VLAN 查询
  • 能看到:子网划分、VLAN 分组、跨子网路由路径
  • 用途:排查”为什么 PC-1(VLAN 20)访问不了 Srv-1(VLAN 10)” → 一眼看出是不是路由没配

3.3 工作负载视图(VM + 容器嵌套)

flowchart TB
  subgraph ESXI["esxi-01(10.10.10.11)"]
    subgraph VM1["VM: web-server"]
      C1["Container: nginx"]
      C2["Container: php-fpm"]
    end
    subgraph VM2["VM: db-server"]
      C3["Container: postgres"]
    end
  end
  • 数据来源:Docker socket(容器)+ VMware/Hyper-V API(VM,商业版)
  • 社区版 Docker 检测:daemon 挂载 /var/run/docker.sock,自动读取运行中的容器列表
  • 能看到:宿主机 → VM → 容器的完整嵌套链
  • 用途:知道”postgres 跑在哪台物理机的哪个 VM 里” → 下线物理机前评估影响

3.4 应用依赖视图

flowchart TB
  subgraph APP1["Application: Web-App"]
    direction TB
    NG["nginx<br/>10.10.10.11:443"]
    FP["php-fpm<br/>10.10.10.11:9000"]
    PG2["postgres<br/>10.10.10.12:5432"]
    RD2["redis<br/>10.10.10.11:6379"]
    NG --> FP
    FP --> PG2
    NG --> RD2
  end
  subgraph APP2["Application: Monitoring"]
    direction TB
    GF["grafana<br/>10.10.10.20:3000"]
    PM["prometheus<br/>10.10.10.20:9090"]
    GF --> PM
  end
  • 数据来源:端口扫描 + 服务指纹 + 端口依赖推断(如 443 连 9000 连 5432)
  • 能看到:哪些服务组成一个应用、依赖链是什么
  • 用途:下线一台机器前,看到它上面跑了什么、谁依赖它

五、定时扫描与调优

4.1 扫描计划

在 Web UI 的 Network 设置里配置扫描频率:

频率适用场景理由
每小时频繁变更的测试环境抓住短暂启动的容器
每 6 小时办公网络设备开关机频繁
每天 03:00机房服务器变更少,夜间扫描不影响业务
手动触发网络变更后即时刷新

建议:生产网络每天 1 次足够;如果 Docker 环境容器频繁起停,提高到每 6 小时。

4.2 扫描速度调优

社区版的扫描速度取决于三个因素:

因素影响调优方向
网络规模/24 扫完约 2-5 分钟,/16 可能 30+ 分钟拆小 CIDR 或用 commercial 多 daemon
端口范围全 65536 扫完很慢Web UI 里可配常用端口列表
SNMP 响应交换机 SNMP 慢会拖整体确保交换机 SNMP 超时设为 5s

4.3 Docker 检测开关

daemon 默认挂载 /var/run/docker.sock。如果你的扫描节点上没有 Docker,可以关掉:

# docker-compose.yml daemon 段
  volumes:
    - daemon-config:/root/.config/scanopy/daemon
    # 注释掉下面这行关闭 Docker 检测
    # - /var/run/docker.sock:/var/run/docker.sock:ro

六、安全加固

5.1 生产环境 Checklist

项默认状态改成怎么改
PostgreSQL 密码password强随机密码.env 里 POSTGRES_PASSWORD
注册开放开放关闭.env 里 SCANOPY_DISABLE_REGISTRATION=true
HTTP 明文HTTPHTTPS + 反向代理Nginx/Caddy 反代 + 证书
SNMP communitypublic自定义 + v3交换机配置
端口暴露60072 全网可达仅限内网防火墙规则
Session CookieHTTPSecureSCANOPY_USE_SECURE_SESSION_COOKIES=true

5.2 Nginx 反向代理 + HTTPS

server {
    listen 443 ssl http2;
    server_name scanopy.yourdomain.com;

    ssl_certificate     /etc/ssl/certs/scanopy.pem;
    ssl_certificate_key /etc/ssl/private/scanopy.key;

    location / {
        proxy_pass http://127.0.0.1:60072;
        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-Proto $scheme;
    }
}

# HTTP → HTTPS 跳转
server {
    listen 80;
    server_name scanopy.yourdomain.com;
    return 301 https://$host$request_uri;
}

反代后在 .env 里:

SCANOPY_PUBLIC_URL=https://scanopy.yourdomain.com
SCANOPY_USE_SECURE_SESSION_COOKIES=true

5.3 防火墙规则

# 仅允许内网访问 Web UI
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source=192.168.1.0/24 port=60072/tcp accept'
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source=10.0.0.0/8 port=60072/tcp accept'
firewall-cmd --reload

# daemon 端口不需要对外暴露(只跟 server 通信)
# 如果用 host 网络模式,60073 端口默认只监听 127.0.0.1

七、数据导出与集成

6.1 社区版能做的

社区版虽然不支持 SVG/Mermaid/Confluence 导出(商业版功能),但可以通过以下方式获取数据:

方式说明适用
Web UI 截图浏览器直接截图,粘贴到文档快速分享
API 调用Server 有 REST API,可以 curl 拉数据自动化
PostgreSQL 直查连到 scanopy 库写 SQL自定义报表
Grafana配 PostgreSQL 数据源,在 Grafana 里画监控面板

6.2 直查 PostgreSQL

# 进入 postgres 容器
docker exec -it scanopy-postgres psql -U postgres -d scanopy

# 查所有发现的主机
SELECT ip_address, hostname, os_type, first_seen, last_seen
FROM hosts
ORDER BY last_seen DESC;

# 查所有开放端口
SELECT h.ip_address, p.port, p.protocol, p.service_name
FROM ports p
JOIN hosts h ON p.host_id = h.id
WHERE p.state = 'open'
ORDER BY h.ip_address, p.port;

# 查交换机端口连接
SELECT s.name AS switch, p.port_id, p.port_name, p.connected_device, p.vlan
FROM switch_ports p
JOIN switches s ON p.switch_id = s.id
ORDER BY s.name, p.port_id;

# 查发现的容器
SELECT c.name, c.image, h.ip_address AS host, c.status
FROM containers c
JOIN hosts h ON c.host_id = h.id
WHERE c.status = 'running'
ORDER BY h.ip_address;

6.3 REST API 示例

# 获取 API Token(Web UI → Settings → API Tokens → Generate)

# 列出所有网络
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:60072/api/v1/networks

# 列出某网络下所有主机
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:60072/api/v1/networks/1/hosts

# 触发手动扫描
curl -X POST -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:60072/api/v1/networks/1/scan

6.4 Prometheus 指标

在 .env 里开启:

SCANOPY_METRICS_TOKEN=your-secure-token
SCANOPY_EXTERNAL_SERVICE_PROMETHEUS_ALLOWED_IPS=192.168.1.0/24

Prometheus scrape_config:

scrape_configs:
  - job_name: 'scanopy'
    metrics_path: /metrics
    bearer_token: 'your-secure-token'
    static_configs:
      - targets: ['scanopy-server:60072']

八、运维常用操作

7.1 日常运维命令

# 查看容器状态
docker compose ps

# 查看实时日志
docker compose logs -f

# 只看 daemon 扫描日志
docker compose logs -f daemon

# 只看 server 日志
docker compose logs -f server

# 重启所有服务
docker compose restart

# 只重启 daemon(扫描异常时常用)
docker compose restart daemon

# 停止全部
docker compose down

# 更新到最新版
docker compose pull && docker compose up -d

# 备份数据库
docker exec scanopy-postgres pg_dump -U postgres scanopy > scanopy-backup-$(date +%Y%m%d).sql

# 恢复数据库
cat scanopy-backup-20260828.sql | docker exec -i scanopy-postgres psql -U postgres -d scanopy

7.2 升级流程

# 1. 备份
docker exec scanopy-postgres pg_dump -U postgres scanopy > pre-update-backup.sql

# 2. 拉新镜像
docker compose pull

# 3. 重启(自动迁移数据库)
docker compose up -d

# 4. 检查日志有没有迁移报错
docker compose logs server | grep -i error

# 5. 验证 Web UI 能打开
curl -I http://localhost:60072

7.3 数据清理

社区版没有自动清理策略,历史扫描数据会累积。定期清理:

-- 进入 psql
docker exec -it scanopy-postgres psql -U postgres -d scanopy

-- 删除 90 天前的扫描历史
DELETE FROM scan_results WHERE created_at < NOW() - INTERVAL '90 days';

-- 清理后执行 VACUUM 回收空间
VACUUM FULL;

九、常见排障

排障 1:扫描完成但看不到任何主机

现象:扫描状态显示 Complete,但主机列表为空。

排查顺序:

# 1. 确认 daemon 网络模式是 host
docker inspect scanopy-daemon | grep NetworkMode
# 期望输出: "NetworkMode": "host"

# 2. 确认扫描范围正确
docker compose logs daemon | grep "scan range"
# 看看实际扫描的 CIDR 是不是你期望的

# 3. 手动 ARP 测试
docker exec scanopy-daemon arp-scan 192.168.1.0/24
# 如果这个也没输出,说明 daemon 容器看不到目标网络

# 4. 检查防火墙是否拦了 ICMP/ARP
firewall-cmd --list-all
iptables -L -n | grep -E 'DROP|REJECT'

最常见原因:daemon 不在目标网段(比如 daemon 跑在云服务器上,扫描的是家庭网络,ARP 过不去)。daemon 必须和目标网络在同一个二层广播域。

排障 2:L2 拓扑图空白(没有交换机连线)

现象:能看到主机 IP 列表,但 L2 视图没有交换机和物理连线。

根因:没有配置 SNMP,或交换机不支持 LLDP/CDP。

排查:

# 1. 确认交换机开了 SNMP
snmpwalk -v 2c -c public 192.168.1.1
# 有输出说明 SNMP 通

# 2. 确认 LLDP 开了
snmpwalk -v 2c -c public 192.168.1.1 1.0.8802.1.1.2.1.4.1
# 有输出说明 LLDP 邻居表可查

# 3. 在 Scanopy Web UI 的 Network 设置里确认 SNMP community 填了

排障 3:Docker 容器不显示

现象:工作负载视图看不到容器。

排查:

# 1. 确认 daemon 挂载了 docker.sock
docker inspect scanopy-daemon | grep docker.sock
# 期望: "/var/run/docker.sock:/var/run/docker.sock:ro"

# 2. 确认目标机器上 Docker 在跑
docker ps

# 3. 如果 daemon 和 Docker 不在同一台机器
# → 社区版只能检测 daemon 所在机器的 Docker
# → 远程 Docker 需要商业版多 daemon 或在目标机器上单独跑 daemon

排障 4:扫描太慢

现象:一次扫描超过 30 分钟。

排查:

# 1. 看是哪个阶段慢
docker compose logs daemon | grep -E 'phase|duration'

# 2. 如果是端口扫描慢 → 缩小端口范围
# Web UI → Network Settings → Port Scan Profile
# 从 "Full (65536)" 改成 "Common" 或自定义

# 3. 如果是 SNMP 慢 → 交换机 SNMP 超时设太长
# 登录交换机把 SNMP 超时改成 3-5 秒

# 4. 如果是网络太大 → 拆 CIDR
# 10.0.0.0/8 会扫几小时,拆成 10.0.0.0/24 + 10.0.1.0/24

排障 5:Web UI 打不开(502 / Connection Refused)

# 1. server 容器活着没
docker compose ps server
# 如果是 Exited → docker compose logs server 看报错

# 2. 端口绑定对不对
docker compose ps --format '{{.Name}} {{.Ports}}'
# 期望: 0.0.0.0:60072->60072/tcp

# 3. PostgreSQL 起来了没
docker compose ps postgres
# server 依赖 postgres,postgres 没起 server 会退出

# 4. 磁盘满了没
df -h
# PostgreSQL 磁盘满了会挂

排障 6:PostgreSQL 密码改了连不上

# .env 改了 POSTGRES_PASSWORD 但 postgres 容器还用旧密码
# 因为 PostgreSQL 首次初始化时写死了密码,后续改 .env 不会更新

# 解决:删掉 postgres 数据卷重新初始化(会丢数据!先备份!)
docker compose down
docker volume rm scanopy_postgres_data
docker compose up -d
# 然后重新注册账号、重新扫描

排障 7:升级后 Web UI 报错 500

# 大概率是数据库迁移没跑成功
docker compose logs server | grep -i migrat

# 手动触发迁移
docker compose run --rm server migrate

# 如果迁移报错 → 恢复备份
cat pre-update-backup.sql | docker exec -i scanopy-postgres psql -U postgres -d scanopy

排障 8:daemon 连不上 server

# daemon 日志报 "connection refused"
docker compose logs daemon | grep -i connect

# 1. server 起来了没
docker compose ps server

# 2. SCANOPY_SERVER_URL 配的对不对
# docker-compose.yml 里 daemon 段:
#   SCANOPY_SERVER_URL: http://127.0.0.1:60072
# 如果 daemon 用 host 网络,127.0.0.1 指向宿主机 → server 必须监听 0.0.0.0:60072

# 3. server 监听地址
ss -tlnp | grep 60072

十、社区版落地实践建议

9.1 适合社区版的场景

场景适配度说明
家庭网络文档⭐⭐⭐⭐⭐1 个网络足够,Docker 检测 + 主机发现
个人 homelab⭐⭐⭐⭐⭐完美匹配,社区版就是为此设计的
小型办公室(单网段)⭐⭐⭐⭐50 台以内单 VLAN,够用
小型办公室(多 VLAN)⭐⭐⭐填一个大 CIDR,但扫描会慢
中型机房(多机架)⭐⭐单 daemon 覆盖不够,考虑商业版
大型企业园区⭐社区版单网络限制,需要商业版多 daemon

9.2 落地 Checklist

  • 1 台 Linux 机器(2C2G 起),能访问目标网络
  • Docker Engine + Compose v2 已安装
  • 交换机已开启 SNMP + LLDP(用于 L2 拓扑)
  • docker-compose.yml 已下载,.env 已配置(密码 + Public URL)
  • 防火墙放行 60072 端口(或配置 Nginx 反代)
  • 首次扫描完成,四视图都能看到数据
  • 设置定时扫描频率
  • 关闭注册(SCANOPY_DISABLE_REGISTRATION=true)
  • 配置 PostgreSQL 备份 cron
  • 如果有 Nginx/Grafana,集成 API 或直查 DB

十一、延伸:什么时候该升级商业版

信号说明
需要扫描多个不连续网段社区版 1 个网络限制 → 多 daemon
团队需要多人同时看社区版 1 个席位 → 多 RBAC
需要导出 SVG/Mermaid 到文档系统社区版无导出 → 商业版
需要 OIDC/SAML 集成社区版只有密码登录 → 商业版
合规要求不用 AGPL社区版 AGPL → 商业许可
需要官方支持社区版只有 Discord → 商业版工单

商业版和社区版用的是同一套代码,只是 License 不同。社区版数据可以无缝迁移到商业版:换 License Key + 重启即可。


官方资源:

问问 AI