多主机 UFW 防火墙仪表板。通过 SSH 连接 Linux 主机,解析防火墙规则和监听端口,以通俗易懂的语言进行解释,并标记安全缺口。

| 路由 | 描述 |
|---|---|
/ | 概览仪表板,含主机卡片、服务标签、缺口计数 |
/host/{name} | 主机详情,带标签页视图:解释的规则、未覆盖端口、监听端口、原始输出 |
/diagnose | 连接诊断工具,带逐规则追踪可视化 |
浏览器 --> Cloudflare Tunnel --> 反向代理 --> FencePost (:8890)
FastAPI 容器
|-- SSH --> 主机 1 (ufw status, ss -tlnp)
|-- SSH --> 主机 2
|-- SSH --> 主机 N
'-- POST --> 通知 webhook
FencePost 是只读的 —— 它从不修改防火墙规则,仅做报告。
<user> ALL=(ALL) NOPASSWD: /usr/sbin/ufw status verbose, /usr/sbin/ufw status numbered, /usr/bin/ss -tlnp
git clone <仓库-url> && cd fencepost
# 添加你的 SSH 密钥
cp ~/.ssh/your_key ssh/id_ed25519
chmod 600 ssh/id_ed25519
# 从模板创建环境文件
cp .env.example .env
# 编辑 .env 填入真实凭据
timezone: Australia/Melbourne
hosts:
- name: 我的服务器
hostname: 192.168.1.10
ssh_user: deploy
ssh_port: 22
is_docker_host: false
networks:
"192.168.1.0/24": "LAN"
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# 加载环境变量(bash/zsh)
export $(grep -v '^#' .env | xargs)
uvicorn app.main:app --reload --port 8890
打开 http://localhost:8890。
注意:本地模式使用 config.yaml 中指定的 SSH 密钥路径(ssh.key_path)。本地开发时你可能想覆盖此路径,使其指向本地的 ssh/id_ed25519:
ssh:
key_path: ssh/id_ed25519
timeout: 10
docker compose up -d --build
打开 http://localhost:8890。容器通过 compose.yaml 自动从 .env 读取凭据。
凭据存储在 .env(已加入 .gitignore)中,由 compose.yaml 引用。切勿将密钥提交到仓库。
app/
main.py # FastAPI 路由和认证
models.py # HostFirewallState、UFWRule、ListeningPort 数据类
parser.py # 解析 ufw status 和 ss 输出
explainer.py # 将规则翻译成通俗易懂的中文
diagnose.py # 连接诊断引擎
gap_detector.py # 查找未覆盖的监听端口
ssh_client.py # Paramiko 封装,并行获取主机信息
eventfeed.py # 变更检测和 webhook 发布
templates/
base.html # 布局、CSS、导航
overview.html # 主机仪表板网格
host_detail.html # 每个主机的标签页详情视图
diagnose.html # 连接诊断表单及结果
login.html # 认证页面
config.yaml # 主机定义、VLAN、设备、时区
compose.yaml # Docker Compose 服务定义
Dockerfile # Python 3.12 slim 镜像
.env.example # 环境变量模板
ssh/ # SSH 密钥目录(密钥不提交)
data/ # 运行时状态(last_state.json,不提交)
config.yaml 的 hosts: 下添加条目ssh-copy-id -i ssh/id_ed25519.pub user@host/etc/sudoers.d/fencepost,包含所需的 NOPASSWD 规则docker compose up -d --build当在 config.yaml 中配置且设置 NOTIFICATIONS_API_KEY 环境变量时,FencePost 会在每次仪表板刷新时发布变更事件:
事件包含幂等键以防止重复。
MIT
/login | 基于会话的身份认证 |
| 部分 | 用途 |
|---|
timezone | 显示时间戳所用的 IANA 时区(例如 Australia/Melbourne、UTC) |
hosts | SSH 目标数组:name、hostname、ssh_user、ssh_port、is_docker_host |
ssh | key_path(私钥路径)和 timeout(超时秒数) |
networks | CIDR 到名称的映射(用于 VLAN)—— 在规则解释和诊断中使用 |
devices | 已命名的 IP 地址,用于诊断页面的快速选择按钮 |
notifications | 可选的 webhook:url、channel(API 密钥通过环境变量设置) |
| 变量 | 默认值 | 描述 |
|---|
FENCEPOST_USERNAME | admin | 登录用户名 |
FENCEPOST_PASSWORD | fencepost | 登录密码 |
FENCEPOST_SECRET_KEY | change-me | 会话 Cookie 签名密钥 |
FENCEPOST_CONFIG | config.yaml | 配置文件路径 |
NOTIFICATIONS_API_KEY | 通知 webhook 的 Bearer 令牌 |