SSem SecuMon 免⁠费⁠指⁠南

从一台个人服务器起步 · 2026 年 10 月版

准备中安装包的发布正在准备中。

本指南先行公开准备工作、安装步骤以及运维中需要了解的事项。发布开始后,下载地址会写在这里。

1. 准⁠备⁠工⁠作

项目要求
要保护的服务器Linux(systemd)+ fail2ban · nftables · sqlite3。amd64 或 arm64。已在 Ubuntu 22.04 · CentOS 8 上验证。
控制台服务器1 台。JDK 21 · Tomcat 11 · PostgreSQL 17。用 Docker 启动最简单。
网络各服务器需能通过 HTTPS 访问控制台地址。服务器无需开放任何入站端口。建议将控制台置于 VPN 或内网之后。
时钟所有服务器和控制台的时钟都需用 NTP 同步。签名时间偏差超过 60 秒,请求即会被拒绝。
证书控制台使用的 HTTPS 证书(例如 Let's Encrypt)。登录 Cookie 只通过 HTTPS 传输,因此无法通过明文 HTTP 登录。

先在每台要保护的服务器上安装软件包。

# Debian · Ubuntu
apt-get update && apt-get install -y fail2ban nftables sqlite3
# RHEL · Rocky · CentOS
dnf install -y epel-release && dnf install -y fail2ban nftables sqlite
systemctl enable --now fail2ban

2. 启⁠用 fail2ban 指⁠数⁠封⁠禁

设置为同一 IP 再犯次数越多,封禁时间越长。SecuMon 根据这些倍数计算“当前处于第几级”和“下次会被封禁多久”。

# /etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
bantime.increment   = true
bantime.multipliers = 1 2 4 8 16 32 64 168
bantime.maxtime     = 168h
ignoreip = 127.0.0.1/8 ::1 <你的 VPN IP 段>

# /etc/fail2ban/fail2ban.local — 屡犯记录保留 60 天(默认仅 1 天,一天后又会被当作初犯)
[DEFINITION]
dbpurgeage = 60d

按上述设置,封禁时长如下。fail2ban 会加入少量随机时间,因此实际值会略有出入。

累计封禁1 次2 次3 次4 次5 次6 次7 次8 次及以上
封禁时长1 小时2 小时4 小时8 小时16 小时32 小时64 小时7 天

请务必把你自己的访问路径(如 VPN IP 段)加入 ignoreip。这样就不会因为输错几次密码,而被自己的服务器封禁。

3. 安⁠装控⁠制⁠台

3-1. 机密文件

机密值不写在代码或环境变量中,而是作为文件统一放在一个目录里。控制台容器会以只读方式将该目录挂载到 /App/secrets。

mkdir -p /srv/secumon/secrets/tls && chmod 700 /srv/secumon
cd /srv/secumon/secrets
openssl rand -hex 24 > db_password
openssl rand -base64 18 > admin_password      # 首次登录密码(账户名 admin)
openssl genpkey -algorithm ed25519 -out console_ed25519.key
openssl pkey -in console_ed25519.key -pubout -out console_ed25519.key.pub
# 文件设为 644,以便容器账户读取 — 由上级目录的 700 负责保护
chmod 644 db_password admin_password console_ed25519.key console_ed25519.key.pub
文件用途缺少时
db_password数据库连接控制台无法启动
admin_password首个管理员账户 admin 的密码账户不会被创建,因而无法登录
console_ed25519.key · .pub命令签名只能查看,无法执行
abuseipdb.keyAbuseIPDB API 密钥(可选)无法使用举报和信誉查询
telegram.envTelegram 通知(可选)不会发送通知
tls/cert.pem · chain.pem · privkey.pem控制台 HTTPS 证书无法通过 HTTPS 访问

仅凭 console_ed25519.key 这一个文件,就能签发对所有服务器都有效的命令。请勿将此文件放在代码仓库或共享网盘中,务必单独保管。

3-2. 数据库

数据库端口不对外开放。控制台在同一 Docker 网络内通过容器名连接数据库。

docker network create secumon-net
docker run -d --name secumon-db --network secumon-net --restart unless-stopped \
  -e POSTGRES_DB=secumon -e POSTGRES_USER=secumon \
  -e POSTGRES_PASSWORD_FILE=/run/secrets/db_password \
  -v /srv/secumon/secrets/db_password:/run/secrets/db_password:ro \
  -v secumon_pgdata:/var/lib/postgresql/data \
  postgres:17

数据表和初始数据由控制台在首次启动时自动创建,无需另外用 psql 导入表结构。

3-3. 控制台配置

控制台是运行在 Tomcat 11 上的 Web 应用。运行方法将随发布包一同公开,这里先整理需要事先确定的环境变量。

环境变量默认值含义
F2B_DB_URLjdbc:postgresql://…:5432/secumon数据库地址。使用容器名填写。
F2B_CANONICAL_HOST必须改为你自己的值你的控制台域名。通过明文 HTTP 或其他地址访问时,会跳转到该地址的 HTTPS。
F2B_PROTECTED_CIDRS必须改为你自己的值绝不封锁的 IP 段 — 你的 VPN · 内网 · 服务器公网 IP。私有网络和回环地址无论此值如何,始终受保护。
F2B_BLOCK_TTL_DAYS30IP 段封锁的默认期限(天)。0 表示永久。
F2B_AUTO_BLOCK_ENABLEDtrue开启或关闭屡犯 IP 自动封锁。
F2B_AUTO_BLOCK_THRESHOLD3从第几次封禁开始自动封锁。
F2B_AUTO_BLOCK_TTL_DAYS30自动封锁的期限(天)。
F2B_FEED_REFRESH_HOURS24重新下载公开封锁列表和国家列表的周期(小时)。
F2B_BAN_MULTIPLIERS1 2 4 8 16 32 64 168须与 jail 配置中的倍数完全一致。
F2B_ABUSE_DAILY_LIMIT1000AbuseIPDB 每日使用上限。

启动后检查状态。看到 "db":"ok" 即表示正常。

curl -s https://<控制台地址>/api/health

4. 注⁠册服⁠务⁠器 — 代⁠理⁠程⁠序

  1. 以 admin 登录控制台,在目标标签页中输入服务器名称,然后点击注册 + 签发令牌。
  2. 界面上会显示目标 ID 和一次性令牌。令牌只在此时显示一次,15 分钟后过期。
  3. 在要保护的服务器上以 root 身份运行安装脚本。
# 在要保护的服务器上执行(root)
tar xzf agent-amd64.tgz && cd agent
./install-agent.sh --console https://<控制台地址> \
    --target-id <目标 ID> --token <一次性令牌>
journalctl -u secumon-agent -f      # 30 秒内出现下面这样的一行即为正常

正常时会输出类似这样的一行 secumon-agent: 2026/10/06 16:40:12 전송 완료 — jail 2개, 밴 5건

安装脚本只做以下几件事,不会开放任何防火墙端口。

  • 创建一个无法登录的专用账户 f2bagent — 代理程序不以 root 运行。
  • 只允许通过 sudo 调用一个 root 权限包装脚本 /usr/local/sbin/f2b-agent-exec。
  • 代理程序的签名密钥在该服务器上生成,私钥不会经网络传出。
  • 向控制台注册后,以 secumon-agent 服务常驻运行。

控制台地址请勿使用含下划线(_)的主机名。Tomcat 11 会以违反规范为由拒绝。请先用 getent hosts <控制台域名> 确认服务器能否解析控制台域名。

如果注册已完成、但之后的步骤失败了,排除原因后原样重新运行同一条命令即可。已注册的代理程序不会再次使用令牌。

要移除服务器,请在控制台中将其停用(该代理程序的请求会立即被拒绝),然后在服务器上运行 systemctl disable --now secumon-agent。

5. 如⁠何看⁠懂界⁠面

  • 仪表盘 — 所有服务器的当前封禁、累计封禁、屡犯 IP 和趋势。如果服务器卡片上的“最后接收”远超 30 秒,请检查该服务器的代理程序。
  • 封禁列表 — 当前被拦截的 IP,同时显示屡犯等级、剩余时间和国家。国家信息来自控制台内置的查询表。
  • IP 详情 — 该 IP 被封禁的服务器、封禁历史、下次封禁的预计时长、AbuseIPDB 信誉。

“当前封禁”读取自 fail2ban 当前实际生效的封禁列表,“屡犯次数”则单独读取自 fail2ban 的封禁记录。因此,已解除的封禁不会被误显示为当前封禁。

6. 封⁠禁 · 解⁠封 · IP 段⁠封⁠锁

  • 封禁 · 解封需要操作员及以上角色。封禁可针对任意 IP;未选择 jail 时默认为 sshd。
  • IP 段封锁仅限管理员。必须再次输入要封锁的 IP 段才会执行,大于 IPv4 /16 · IPv6 /48 的会被拒绝。默认 30 天后自动解除。
  • 可以一次对多个 IP 段 × 多台服务器下发封锁。只有全部通过检查才会下发任何一条 — 因为只生效一半的状态最危险。
  • 命令必须由服务器上的代理程序在 60 秒内取走才会执行。结果可在执行标签页的命令历史中查看,分为完成、失败、过期。

如果封错了,可在控制台的执行 → 解除封锁中解除。若情况紧急到无法进入控制台,就直接在该服务器上删除。

# 仅删除一个 IP 段
nft delete element inet f2b_console blocklist4 '{ 203.0.113.0/24 }'
# 删除 SecuMon 添加的全部封锁(fail2ban 规则在另一张表中,不受影响)
nft delete table inet f2b_console

7. 自⁠动⁠封⁠锁

屡犯 IP 自动封锁

每 5 分钟挑出累计被封禁 3 次及以上的 IP,在所有服务器上封锁 30 天。这是唯一无需人工批准就会修改防火墙的功能,因此加了多重限制。

  • 只封锁单个 IP(/32 · /128),不封锁 IP 段。
  • 跳过受保护 IP 段。每次最多只下发 20 条。
  • 同一 IP 不会重复升级,所有操作都记录到审计日志并通知到 Telegram。

要关闭此功能,请为控制台设置 F2B_AUTO_BLOCK_ENABLED=false 后重启。被误封的 IP 请先用解除封锁解除,再删除其升级记录,之后才会被重新判定。

docker exec secumon-db psql -U secumon -d secumon -c "DELETE FROM auto_block WHERE ip = '<IP>'"

公开封锁列表

在封锁订阅源标签页中开启。初始时两者均为关闭状态。

  • Spamhaus DROP — 被劫持或专用于犯罪活动的 IP 段。不可能产生正常流量,几乎不必担心误封。
  • FireHOL level1 — 未使用的地址和已确认的恶意 IP 段。其中也包含私有网络,因此控制台会先滤掉与受保护 IP 段重叠的条目再下发。

每天重新下载一次,内容不变则不会重复下发到服务器。从列表中移除的 IP 段会在下次更新时自动解除。

8. 国⁠家⁠封⁠锁 — 启⁠用⁠之⁠前

需要全球访问的服务,不能按国家封锁。

  • 权威 DNS 服务器 — 全球的解析器都要能访问,你的域名才能被解析。SecuMon 始终放行 53 端口。
  • 邮件接收(25)· VPN — 一旦封锁,邮件会中断,你在海外也无法连回自己的服务器。这类服务器请不要启用国家封锁。
  • 搜索引擎爬虫 — 封锁大国时,搜索引擎爬虫也会一并被拦截,网站可能从搜索结果中消失。

在国家封锁标签页中选择国家后,会先显示该国的 IP 段数量。应用后立即下载列表,30 秒内写入所有服务器;关闭时则删除该国的列表。大国的 IP 段可多达数万个。

即使某个国家来的攻击很多,实际上往往也只是该国的少数 IP 段或租用的服务器。封锁之后,攻击者会换到其他国家的服务器。请把国家封锁视为与公开封锁列表、屡犯自动封锁配合使用的辅助手段。

SecuMon 在防火墙规则的最前面放行已建立连接的响应。如果没有这条规则,你的服务器向该国服务(软件包镜像 · 通知 API · 证书签发)发起的连接,其响应也会被拦截。

9. AbuseIPDB · Telegram

AbuseIPDB

将 abuseipdb.key 放入机密目录即可启用。密钥只存在于控制台服务器上,不会出现在界面、数据库或任何服务器上。

  • 只能举报当前正被封禁或最近 30 天内被封禁过的 IP — 不能举报任意 IP。
  • 同一 IP 在 15 分钟内不会重复举报。每日配额由控制台自行计数。
  • 举报类别根据 jail 名称确定 — ssh → 18 · 22,Web(apache · nginx)→ 18 · 21,邮件 → 18 · 11,其他 → 18。

Telegram

# /srv/secumon/secrets/telegram.env
TELEGRAM_TOKEN=<机器人令牌>
TELEGRAM_CHAT_ID=<聊天 ID>

通知屡犯自动封锁和公开列表的变更,完整列表以附件文件发送。没有变化时不发通知 — 如果每天都收到“无变更”,真正重要的通知反而容易被忽略。

10. 账⁠户 · 两⁠步⁠验⁠证

角色可执行的操作
VIEWER 只读查看仪表盘 · 封禁列表 · IP 详情 · 命令历史
OPERATOR 操作员+ 封禁 · 解封 · AbuseIPDB 举报与信誉查询
ADMIN 管理员+ IP 段封锁 · 服务器注册 · 封锁订阅源 · 国家封锁 · 用户 · 审计日志
  • 首次登录使用 admin 和 admin_password 文件中的密码。登录后请在我的账户中修改密码。
  • 在我的账户 → 两步验证中,用身份验证器应用扫描二维码,或手动输入密钥。同一个验证码不能使用两次。
  • 密码输错 5 次将锁定 15 分钟;同一 IP 每分钟最多尝试 10 次。30 分钟无任何操作会自动退出登录。

如果丢失了身份验证器应用,无法在界面上解除,需要由能访问控制台服务器的人直接在数据库中解除。

docker exec secumon-db psql -U secumon -d secumon -c \
  "UPDATE app_user SET totp_enabled=false, totp_secret=NULL, totp_last_counter=0 WHERE username='admin';"

11. 备⁠份 · 密⁠钥⁠管⁠理

# 数据库 — 密码是哈希,注册令牌也只以哈希形式保存
docker exec secumon-db pg_dump -U secumon secumon | gzip > secumon-$(date +%F).sql.gz
# 机密目录 — 这才是真正的机密。与数据库备份分开存放
tar czf secumon-secrets-$(date +%F).tgz -C /srv/secumon secrets
  • 更换控制台签名密钥后,所有代理程序都会拒绝命令。如已更换,请对每台服务器按以下顺序重新注册:停用 → 重新签发令牌 → 删除服务器上的 /etc/secumon/agent.json · agent_ed25519.key → 重新安装。
  • 定期检查:每天查看服务器状态和失败的命令;每周查看审计日志中的拒绝记录,以及未启用两步验证的账户。

12. 故⁠障⁠排⁠查

代理程序和控制台的消息以韩语输出。请在日志中直接搜索下表中以代码样式显示的文字。

现象原因处理方法
代理程序日志 등록되지 않았거나 비활성 상태인 타겟服务器已在控制台中被停用重新获取令牌并重新注册
代理程序日志 요청 시각 편차가 허용치를 넘습니다服务器时钟偏差超过 60 秒用 NTP 同步时钟
代理程序日志 이미 사용된 nonce同一请求被重复发送这是正常的防御。若持续出现,请排查网络重复发送
命令结果 거부: 만료된 명령代理程序未能在 60 秒内取走命令检查服务器上 secumon-agent 的状态后重新执行
命令结果 거부: 서명이 유효하지 않음更换控制台签名密钥后未重新注册按第 11 节的顺序重新注册
服务器卡片的最后接收时间停滞 · 日志中断代理程序卡住systemctl restart secumon-agent
已开启国家封锁,但服务器上未生效代理程序日志中没有这一行: 국가 차단 적용确认代理程序是否为最新版本,并查看日志中的错误
登录状态反复失效通过非 HTTPS 地址访问改用控制台的 HTTPS 地址访问

如有其他疑问,请发送邮件至 halo@levelupsoft.com。