2. Reverse-proxy: basic-auth + IP-allowlist
Перед панелью должен стоять reverse-proxy (Caddy или nginx), который пускает только доверенные IP. Даже зная адрес панели, посторонний упрётся в эту стену.
Caddy (/etc/caddy/Caddyfile):
panel-subdomain.your.domain {
@allowed remote_ip 203.0.113.10 198.51.100.20 # ваши IP
handle @allowed {
basicauth { admin JDJhJDE0... } # хеш пароля
reverse_proxy 127.0.0.1:3000
}
respond 403
}
caddy hash-password --plaintext 'ВАШ_ПАРОЛЬ'
systemctl reload caddy
Аналог на nginx (фрагмент server-блока):
location / {
allow 203.0.113.10;
allow 198.51.100.20;
deny all;
auth_basic "restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:3000;
}
Если у вас динамический IP и allowlist по адресу не подходит, оставьте хотя бы basic-auth с сильным паролем и рассмотрите доступ к панели только через собственный VPN или туннель.
3. Закрыть лишние порты
ufw default deny incoming
ufw allow 22/tcp # SSH
ufw allow 443/tcp # reverse-proxy / панель / ноды
ufw allow from PANEL_IP to any port 2222 proto tcp # порт нод — только с IP панели
ufw --force enable
Сама панель и страница подписки должны слушать только 127.0.0.1 — наружу они выходят исключительно через reverse-proxy. Порт для связи ноды с панелью должен быть открыт только для IP панели, иначе постучаться в ноду напрямую сможет кто угодно.
4. SSH только по ключу
ssh-keygen -t ed25519 -C "vpn-admin"
ssh-copy-id root@SERVER_IP
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
systemctl restart ssh
5. fail2ban против перебора
apt -y install fail2ban
cat >/etc/fail2ban/jail.d/local.conf <<'EOF'
[sshd]
enabled = true
maxretry = 4
bantime = 1h
findtime = 10m
EOF
systemctl enable --now fail2ban
Для попыток перебора basic-auth можно добавить отдельный jail на лог nginx/Caddy, фильтруя по статусам 401/403.
6. Общая гигиена
- API-токены для ботов — минимально необходимые права, хранить в .env, регулярно ротировать: утёкший токен даёт доступ к выдаче подписок.
- Swagger/документация API — выключены в проде (или тоже под allowlist).
- Панель, ноды и система регулярно обновляются, changelog используемой панели стоит читать перед обновлением.
- Резервная копия базы — обязательна перед любыми правками: без неё угон или сбой панели означает потерю всех клиентов разом.
- Двухфакторная аутентификация — везде, где доступна: на почте домена, у хостинг-провайдера, у регистратора. Компрометация почты нередко означает угон домена целиком.
Чек-лист
- Панель на невзрачном поддомене, адрес нигде не публикуется
- Reverse-proxy: basic-auth + IP-allowlist
- Панель и страница подписки слушают только 127.0.0.1
- Порт связи с нодой открыт только для IP панели
- SSH по ключу, парольный вход выключен, fail2ban включён
- Swagger выключен, токены в .env, есть регулярные бэкапы