
Мультихостовый дашборд для межсетевого экрана UFW — объясняет правила простым языком, выявляет пробелы в безопасности и предоставляет диагностику подключений
Многохостовый дашборд для брандмауэра UFW. Подключается к Linux-хостам через SSH, анализирует правила брандмауэра и прослушиваемые порты, объясняет всё понятным языком и указывает на пробелы в безопасности.

| Route | Description |
|---|---|
/ | Обзорная панель с карточками хостов, индикаторами служб и счётчиками пробелов |
Browser --> Cloudflare Tunnel --> Reverse Proxy --> FencePost (:8890)
FastAPI container
|-- SSH --> Host 1 (ufw status, ss -tlnp)
|-- SSH --> Host 2
|-- SSH --> Host N
'-- POST --> Notification webhook
FencePost работает в режиме только для чтения -- он никогда не изменяет правила брандмауэра, а только сообщает о них.
<user> ALL=(ALL) NOPASSWD: /usr/sbin/ufw status verbose, /usr/sbin/ufw status numbered, /usr/bin/ss -tlnp
git clone <repo-url> && cd fencepost
# Add your SSH key
cp ~/.ssh/your_key ssh/id_ed25519
chmod 600 ssh/id_ed25519
# Create your environment file from the template
cp .env.example .env
# Edit .env with real credentials
timezone: Australia/Melbourne
hosts:
- name: My Server
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
# Load env vars (bash/zsh)
export $(grep -v '^#' .env | xargs)
uvicorn app.main:app --reload --port 8890
Откройте http://localhost:8890.
Примечание: локальный режим использует SSH-ключ по пути, указанному в config.yaml (ssh.key_path). Для локальной разработки вы можете переопределить его, указав ваш локальный ssh/id_ed25519:
ssh:
key_path: ssh/id_ed25519
timeout: 10
docker compose up -d --build
Откройте http://localhost:8890. Контейнер автоматически читает учётные данные из .env через compose.yaml.
Учётные данные хранятся в .env (внесён в .gitignore) и используются через compose.yaml. Никогда не коммитьте секреты в репозиторий.
app/
main.py # FastAPI routes and auth
models.py # HostFirewallState, UFWRule, ListeningPort dataclasses
parser.py # Parses ufw status and ss output
explainer.py # Translates rules to plain English
diagnose.py # Connection diagnostic engine
gap_detector.py # Finds uncovered listening ports
ssh_client.py # Paramiko wrapper, parallel host fetching
eventfeed.py # Change detection and webhook posting
templates/
base.html # Layout, CSS, navigation
overview.html # Host dashboard grid
host_detail.html # Per-host tabbed detail view
diagnose.html # Connection diagnostic form and results
login.html # Authentication page
config.yaml # Host definitions, VLANs, devices, timezone
compose.yaml # Docker Compose service definition
Dockerfile # Python 3.12 slim image
.env.example # Template for environment variables
ssh/ # SSH key directory (key not committed)
data/ # Runtime state (last_state.json, not committed)
config.yaml в раздел hosts:ssh-copy-id -i ssh/id_ed25519.pub user@host/etc/sudoers.d/fencepost с необходимыми правилами NOPASSWDdocker compose up -d --buildПри настройке в config.yaml с переменной окружения NOTIFICATIONS_API_KEY FencePost отправляет события об изменениях при каждом обновлении дашборда:
События содержат ключи идемпотентности для предотвращения дубликатов.
MIT
/host/{name} | Детальная информация о хосте с вкладками: объяснённые правила, непокрытые порты, прослушиваемые порты, необработанный вывод |
/diagnose | Инструмент диагностики подключений с визуализацией трассировки по каждому правилу |
/login | Аутентификация на основе сессий |
| Section | Purpose |
|---|
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 | Необязательный вебхук: url, channel (API-ключ задаётся через переменную окружения) |
| Variable | Default | Description |
|---|
FENCEPOST_USERNAME | admin | Имя пользователя для входа |
FENCEPOST_PASSWORD | fencepost | Пароль для входа |
FENCEPOST_SECRET_KEY | change-me | Ключ подписи сессионных cookie |
FENCEPOST_CONFIG | config.yaml | Путь к файлу конфигурации |
NOTIFICATIONS_API_KEY | Bearer-токен для вебхука уведомлений |