← База знаний

Безопасность веб-сервера на Banana Pi: от фаервола до PHP

Как только домен начинает указывать на ваш IP, сервер перестаёт быть личным делом: сканеры и боты приходят в первые же часы. Для слабой платы вроде Banana Pi это вдвойне серьёзно — её можно не только взломать, но и просто положить нагрузкой. Разберём полный контур защиты домашнего веб-сервера на одноплатнике: Apache + PHP, наружу смотрят только 80 и 443.

Главный принцип для слабого железа: защита строится на малой поверхности атаки, а не на тяжёлых инспектирующих системах. Антивирусы и полновесные WAF съедят ресурсы платы быстрее любого бота — наш путь другой: закрыть всё лишнее, ограничить всё оставшееся, обновляться автоматически.

Шаг 1. Аудит открытых портов

Каждый слушающий сервис — дверь в систему. Смотрим, что открыто:

bash
sudo ss -tlnp

Правильная картина для веб-сервера: 80 и 443 на всех интерфейсах, SSH (22) — есть, но наружу не пробрасывается, всё служебное — только на 127.0.0.1. Всё незнакомое на 0.0.0.0 выясняем и закрываем.

Частый лишний жилец — LLMNR (порт 5355, systemd-resolved): протокол разрешения имён для локальных сетей, серверу не нужен, а истории уязвимостей имеет. Выключаем:

bash
sudo sed -i 's/^#\?LLMNR=.*/LLMNR=no/' /etc/systemd/resolved.conf
sudo systemctl restart systemd-resolved

Шаг 2. Фаервол ufw

Политика простая: всё входящее запрещено, открыты только веб-порты, SSH — только из домашней сети:

bash
sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 192.168.1.0/24 to any port 22
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Важный нюанс сборок Armbian: фаерволу нужен netfilter в ядре. Если ufw enable падает с ошибкой «Could not fetch rule set generation id» или «Table does not exist» — в ядре вашей сборки нет сетевой фильтрации. Лечится установкой legacy-ядра (linux-image-legacy-sunxi), у которого конфиг традиционно самый полный.

Проброс портов на роутере — только 80 и 443. SSH наружу не пробрасывается никогда: администрирование из своей сети, для удалённого доступа — VPN до роутера.

Шаг 3. fail2ban — автоматический бан по логам

fail2ban читает логи, замечает перебор паролей и сканирование, банит IP через фаервол:

bash
sudo apt install fail2ban -y
sudo tee /etc/fail2ban/jail.local >/dev/null << 'EOF'
[DEFAULT]
bantime  = 12h
findtime = 10m
maxretry = 5
bantime.increment = true
bantime.maxtime   = 1w
ignoreip = 127.0.0.1/8 192.168.1.0/24

[sshd]
enabled = true
backend = systemd

[apache-auth]
enabled = true

[apache-badbots]
enabled = true

[apache-noscript]
enabled = true

[apache-overflows]
enabled = true
EOF
sudo systemctl enable --now fail2ban
sudo fail2ban-client status

Строка ignoreip с вашей подсетью — защита от самобана: что бы вы ни натворили с паролями со своего компьютера, себя сервер не заблокирует. Рецидивистов система банит по нарастающей — каждый повторный бан вдвое длиннее.

Через несколько дней после выхода в интернет загляните в статистику — sudo fail2ban-client status sshd покажет, что защита работала не зря.

Шаг 4. SSH: ключи вместо паролей

Даже непроброшенный наружу SSH стоит перевести на ключи — это закрывает сценарий движения атакующего внутри системы. На своём компьютере:

bash
ssh-keygen -t ed25519
ssh-copy-id user@192.168.1.17

После проверки входа без пароля — на сервере в /etc/ssh/sshd_config:

code

PasswordAuthentication no
PermitRootLogin no

И sudo systemctl restart ssh. Золотое правило: старую сессию не закрывать, пока в новом окне не убедились, что вход по ключу работает.

Шаг 5. Автообновления безопасности

Дыры в Apache и PHP должны латать себя сами, не дожидаясь, пока вы вспомните про сервер:

bash
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure -plow unattended-upgrades

Шаг 6. Apache: не представляться и держать удар

Сканеры ищут конкретные версии с известными дырами — не сообщаем им ничего лишнего:

bash
sudo tee /etc/apache2/conf-available/hardening.conf >/dev/null << 'EOF'
ServerTokens Prod
ServerSignature Off
TraceEnable Off
EOF
sudo a2enconf hardening

Проверьте также /etc/apache2/conf-available/security.conf — если там прописан ServerTokens OS, он перекроет вашу настройку, поменяйте на Prod там же.

Специфика слабой платы — защита от перегрузки: даже безобидный агрессивный краулер способен занять все ядра. Ставим mod_evasive (временный отказ IP, задавшему слишком много запросов) и ограничиваем аппетиты воркеров:

bash
sudo apt install libapache2-mod-evasive -y

В конфигурации Apache для платы с 1 ГБ RAM разумны MaxRequestWorkers около 50 и KeepAliveTimeout 3 — чтобы толпа висящих соединений не выела память.

Применяем всё разом: sudo systemctl reload apache2.

Шаг 7. PHP в жёстких рамках

Настройки кладём отдельным файлом в conf.d — обновления PHP перезаписывают php.ini, а drop-in переживает всё:

bash
PHPV=$(ls /etc/php/ | sort -V | tail -1)
sudo tee /etc/php/$PHPV/fpm/conf.d/99-hardening.ini >/dev/null << 'EOF'
memory_limit = 128M
max_execution_time = 15
upload_max_filesize = 10M
post_max_size = 12M
expose_php = Off
display_errors = Off
log_errors = On
disable_functions = exec,shell_exec,system,passthru,popen,proc_open,pcntl_exec
allow_url_include = Off
session.cookie_httponly = 1
session.use_strict_mode = 1
opcache.enable = 1
opcache.memory_consumption = 64
EOF
sudo systemctl restart php$PHPV-fpm

Ключевая строка — disable_functions: даже если через дырявый скрипт зальют веб-шелл, командовать системой он не сможет — 90% шеллов без exec мертвы. А display_errors = Off прячет от посетителей стектрейсы с путями к файлам; сами ошибки ищите в логах: sudo tail /var/log/apache2/*error.log.

Права на файлы сайта — по принципу «веб-серверу только чтение»: файлы принадлежат отдельному пользователю (например, SFTP-пользователю для заливки), Apache их лишь читает. Пробитый PHP при такой схеме не сможет даже переписать сайт.

Шаг 8. HTTPS

После настройки DNS сертификаты Let's Encrypt ставятся одной командой:

bash
sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache

Certbot найдёт домены по вашим виртуальным хостам, выпустит сертификаты, настроит редирект с HTTP и автопродление. После включения HTTPS добавьте в PHP-конфиг строку session.cookie_secure = 1.

Шаг 9. Бэкап — последний эшелон

Единственная стопроцентная защита. Минимум: свежий образ SD-карты и регулярная копия /var/www и /etc куда-то кроме самой платы. Взлом, умерший носитель, кривое обновление — всё лечится одинаково, если есть вчерашняя копия.

Чего не делать на слабой плате

ClamAV и другие резидентные антивирусы съедят половину памяти ради сомнительной пользы. mod_security с полным набором правил поставит процессор Cortex-A7 на колени. Redis «для ускорения» статике не нужен — page cache ядра Linux уже кэширует горячие файлы бесплатно. Философия остаётся прежней: меньше сервисов — меньше дверей и больше свободных ресурсов.

Итоговый чек-лист

Перед выходом в интернет пройдитесь по списку: ss -tlnp показывает только 22/80/443; ufw активен; fail2ban с джейлами sshd и apache работает; SSH на ключах; unattended-upgrades установлен; Apache не выдаёт версию; PHP с disable_functions и display_errors = Off; тестовые phpinfo-файлы удалены; HTTPS с редиректом; бэкап снят. Десять пунктов — и ваш одноплатник защищён лучше многих «взрослых» серверов.

Корпус Eruscus Blade 19" 1U Стоечный корпус на 4 платы Raspberry Pi с активным охлаждением.
Смотреть корпус →