
Knocker, сервис контроля доступа на основе стука для вашего домашнего сервера

Knocker — это самоуправляемый сервис, предоставляющий HTTP-шлюз для одноразовой авторизации (SPA) по принципу «тук-тук» для вашей домашней лаборатории. Имеет веб-, CLI + GNOME и Android-клиенты. Он может использоваться как аутентификация для вашего обратного прокси, например Caddy, или даже на уровне межсетевого экрана с помощью интеграции FirewallD. Он позволяет держать ваши сервисы полностью приватными, открывая их по запросу только для авторизованных IP-адресов.
Это идеально подходит для сред домашних лабораторий, где вы хотите выставлять сервисы в интернет без постоянного VPN-соединения, минимизируя свою публичную поверхность атаки.
Knocker-Web Статическое PWA-веб-приложение, поддерживающее стук (внесение в белый список) при перезагрузке.
Knocker-CLI CLI, написанный на Go, с поддержкой фоновых стуков, опционально запускаемых при изменении IP.
Knocker-gnome — расширение для GNOME, построенное поверх Knocker-cli.
Knocker-EXPO Экспериментальное Android-приложение, написанное на React EXPO, с поддержкой фоновых запросов стука.
sequenceDiagram
participant User
participant Caddy as Reverse Proxy (Caddy)
participant Knocker
participant Service as Protected Service
User->>Caddy: HTTP request to protected service
Caddy->>Knocker: GET /verify (copies X-Forwarded-For)
Knocker-->>Knocker: check always_allowed_ips / excluded_paths / whitelist
alt IP whitelisted
Knocker-->>Caddy: 200 OK (empty body)
Caddy->>Service: forward request
Service-->>Caddy: 200 OK
Caddy-->>User: 200 OK
else IP not whitelisted
Knocker-->>Caddy: 401 Unauthorized (empty body)
Caddy-->>User: 401 Unauthorized
end
Note over User,Knocker: Performing a "knock" (to add whitelist entry)
User->>Knocker: POST /knock (X-Api-Key, optional ip_address, ttl)
Knocker->>Knocker: validate API key, determine client IP
Knocker->>Knocker: update whitelist.json with expiry
Knocker-->>User: 200 OK (whitelisted_entry, expires_at, expires_in_seconds)
Этот проект предназначен для развёртывания в Docker-контейнере с помощью предоставленного файла docker-compose.yml. Используются предварительно собранные образы Docker с поддержкой AMD64, ARMv8 и ARMv7.
Knocker предоставляет разные теги образов для разных случаев использования:
latest — последний стабильный релиз (рекомендуется для продакшена)v1.2.3 — теги конкретных версий (фиксированные версии)main — ветка разработки (содержит последние обновления, может быть нестабильной)Конфигурация:
knocker.example.yaml в knocker.yaml.knocker.yaml на свои собственные безопасные случайные строки.trusted_proxies в knocker.yaml; они должны соответствовать подсети сети обратного прокси (docker network inspect xxx).whitelist.storage_path в рабочей директории приложения, /data или /tmp.firewalld.enabled: true и настроив соответствующие параметры. Примечание: Для этого требуется запускать контейнер от root.Запуск сервиса:
docker compose up -d
Это загрузит предварительно собранный образ knocker и запустит сервисы knocker и caddy.
Knocker работает как шлюз аутентификации для вашего обратного прокси. Он предоставляет конечную точку verify для проверки, находится ли IP-адрес запроса в белом списке; если нет, он отвечает 401, и обратный прокси отклоняет соединение.
У Caddy есть директива forward_auth для проверки соединений через конечную точку аутентификации.
Определите переиспользуемый фрагмент: Лучшая практика — определить фрагмент в вашем Caddyfile для проверки аутентификации.
Защитите свои сервисы: Импортируйте фрагмент для любого сервиса, который хотите защитить.
Пример Caddyfile:
# Caddyfile
# Define a reusable snippet for the knock-knock check.
# It points to the knocker service using Docker's internal DNS.
(knocker_auth) {
forward_auth knocker:8000 {
uri /verify
}
}
# The public endpoint for performing the knock.
# Make sure this domain points to your Caddy server's IP.
knock.your-domain.com {
reverse_proxy knocker:8000
}
# An example protected service.
jellyfin.your-domain.com {
import knocker_auth # Apply the forward_auth check
reverse_proxy jellyfin_service_name:8096
}
Когда пользователь не находится в белом списке, директива Caddy forward_auth возвращает ответ 401 Unauthorized с пустым телом.
Важное замечание: Директива Caddy handle_errors не работает с ответами forward_auth. Ответ об ошибке приходит непосредственно от сервиса аутентификации (knocker), а не от самого Caddy, поэтому handle_errors не может перехватывать или изменять эти ответы.
Knocker предоставляет расширенную интеграцию с межсетевым экраном через firewalld, создавая динамические временные правила межсетевого экрана, которые автоматически истекают на основе TTL, указанного в запросах стука. Эта функция работает на уровне сети, позволяя использовать knocker для не-HTTP сервисов, таких как ssh или игровые серверы.
sequenceDiagram
participant Client as User
participant Firewall as Firewalld (knocker zone)
participant Knocker
participant Service as Protected Service (port 22)
Note over Client,Firewall: Initial state — monitored port is blocked by default
Client->>Firewall: TCP SYN to Service:22
Firewall-->>Client: DROP (no response)
Note over Client,Knocker: User performs a knock to whitelist their IP
Client->>Knocker: POST /knock (X-Api-Key, optional ip_address, ttl)
Knocker->>Knocker: validate API key & determine client IP
Knocker->>Firewall: add rich accept rule for client IP on port 22 with timeout
Firewall-->>Knocker: success