Alpine Linux на VPS
linux PHP Caddy rclone fail2ban FTP VDS/VPS Alpine Linux веб-сервер
Крайне минималистичная система, что может пригодиться на слабых конфигурациях. Подходит в случае KVM-виртуализации и при наличии возможности подгружать/подключать ISO.
Решил воспользоваться “виртуальным” вариантом x86_64 (внизу на странице). Для установки в консоли сервера (где-то в ЛК хостинга) загружаемся с подключенного образа. В принципе далее по инструкции - предлагаю воспользоваться “более медленным” вариантом.
Установка
Входим под root (без пароля), setup-alpine
.
- Keyboard layout:
us
- Variant:
us
- Hostname:
vm876632
(номер виртуальной машины) - Сетевой интерфейс - по умолчанию (eth0)
- IP-адрес - в моем случае DHCP нет, настраиваем вручную по данным из ЛК (ниже пример с локальным адресом):
- 192.168.56.101
- Маска 255.255.255.0 (/24)
- Шлюз: 192.168.56.1
- IPv6 не будем настраивать*
- Не хотим настраивать сеть вручную (n)
- Домен DNS - пусто
- DNS nameserver - например Яндекс:
77.88.8.8 77.88.8.1
- Пароль root: предлагаю сразу ввести сложный (или по крайней мере длинный), чтобы хоть как-то защитить SSH
- Временная зона:
Europe/Moscow
(у меня) - Proxy - по умолчанию (none)
- Зеркало APK - сначала включить “общественный” репозиторий
c
, потомf
(найти самое быстрое) - Не хотим настраивать пользователя - no (по умолчанию)
- SSH-сервер - по умолчанию (openssh)
- Разрешить вход root по ssh -
yes
- Ключ SSH мы пока не можем ввести - значение по умолчанию (none) (хотя если вдруг можете - обычно на этом этапе буфер обмена не работает - то стоит ввести, тогда на предыдущем надо было бы оставить prohibit-password)
- Диск:
vda
(скорректировать по факту) - Как хотим использовать -
sys
- Диск будет стерт -
y
Установка завершена. Теоретически можно переделать установку, вызвав setup-disk с параметрами, например поменять размер раздела подкачки. Если посмотреть fdisk -l
, то увидим, что в моем случае объем раздела подкачки составил 940 мегабайт (2x объем оперативки).
* Примечание. На моем хостинге IPv6 как бы есть, но работает он почему-то только с предустанавливаемыми Дебианами/Убунтами и RHEL'ами. Что не так с альтернативными системами, я, к сожалению, не разобрался, так что рассматривать настройку IPv6 не будем.
Перезагружаемся - reboot
. На всякий случай стоит принудительно выбрать жесткий диск при загрузке - может вновь загрузиться образ. Проверим подключение по SSH - должно работать.
Обновим систему:
apk update apk upgrade
Я также устанавливаю Midnight Commander:
apk add mc
Хотя именно в Alpine Linux он как-то не очень хорошо себя проявляет, в частности засоряет историю команд.
Посмотрим свободную память и место на диске:
vm876632:~# free -m total used free shared buff/cache available Mem: 470 38 376 0 57 419 Swap: 940 0 940
vm876632:~# df -H Filesystem Size Used Available Use% Mounted on devtmpfs 10.0M 0 10.0M 0% /dev shm 235.0M 0 235.0M 0% /dev/shm /dev/vda3 4.6G 68.7M 4.3G 2% / tmpfs 94.0M 104.0K 93.9M 0% /run /dev/vda1 271.1M 23.9M 228.2M 9% /boot tmpfs 235.0M 0 235.0M 0% /tmp
Как видим, занято всего ничего: 24 мегабайта в разделе загрузки и 69 - в основном разделе. Не то, что эти ваши Rocky с Debian, которым нужно 2-3 гига.
Выключаем - poweroff
- размонтируем/отключаем/… ISO в ЛК и включаем машину обратно.
Fail2ban
Все по инструкции. Установка:
apk add fail2ban
Совсем не по инструкции у меня посыпались ошибки package mentioned in index not found (try 'apk update'). Так что да, apk update
и потом еще раз apk add fail2ban
. Со второй попытки вроде удачно.
Добавляем в “автозагрузку”:
rc-update add fail2ban
На всякий случай проверить, что сервис добавился:
rc-status
Запуск:
rc-service fail2ban start
Должна создаться конфигурация по умолчанию /etc/fail2ban/jail.d/alpine-ssh.conf. На мой взгляд, в ней многовато количество попыток (maxretry) - поставлю 3, да и bantime по умолчанию маловат - установлю скажем 12 часов
[sshd] enabled = true filter = alpine-sshd port = ssh logpath = /var/log/messages maxretry = 3 bantime = 12h [sshd-ddos] enabled = true filter = alpine-sshd-ddos port = ssh logpath = /var/log/messages maxretry = 3 bantime = 12h
Перезапуск сервиса:
rc-service fail2ban restart
Или можно вместо этого fail2ban-client reload
.
Посмотреть статистику:
fail2ban-client stats
Посмотреть, что там с iptables:
iptables -S iptables -L -v -n | more
PHP
В apk на данный момент есть PHP 8.2 и 8.3. Опять же, на данный момент, это устраивает. Если нет - можно пойти по стопам авторов официальных образов Docker и собрать PHP из исходников.
Установим PHP-FPM 8.3 и некий минимальный набор расширений:
apk add php83 php83-fpm php83-curl php83-gd php83-intl php83-mbstring php83-opcache php83-xml
Выдано предупреждение:
If you need ICU with non-English locales and legacy charset support, install package icu-data-full.
Определенно это нам нужно, так что устанавливаем:
apk add icu-data-full
Вообще что касается расширений, скорее всего их понадобится довольно много доустанавливать - в аналогичных ситуациях тот же remi (в RHEL'ах) как будто больше расширений включает в основу. Например (в смысле “понадобится доустановить”) - допустим, сайт использует БД SQLite (помимо прочего):
apk add php83-dom php83-fileinfo php83-pcntl php83-pdo_sqlite php83-session
Проверка, что PHP как-то установился:
php -i
Вывод длинный, но зато вся конфигурация.
Корректируем при необходимости основной /etc/php83/php.ini, дополнительные в /etc/php83/conf.d/ (например 00_opcache.ini может потребоваться), а также настройки PHP-FPM в /etc/php83/php-fpm.d/www.conf. В частности, PHP-FPM по умолчанию слушает порт (а не сокет), а пользователь и группа nobody
. Давайте-ка наверное сразу сделаем более “канонично” с www-data, да и я как-то больше сокет предпочитаю.
На всякий случай проверим наличие пользователя:
cat /etc/passwd | grep x:82 cat /etc/passwd | grep www-data
Обе команды не должны что-то показать. Создаем прямо как авторы образа Docker (в свою очередь, они ссылаются на установку веб-серверов из пакетов):
adduser -u 82 -D -S -G www-data www-data
В Alpine Linux (точнее в Busybox) нестандартная команда создания пользователя.
-u UID
id пользователя-D
не устанавливать пароль-S
создать системного пользователя-G GRP
группа
Правим /etc/php83/php-fpm.d/www.conf (фрагменты):
user = www-data group = www-data listen = /run/php-fpm83/www.sock
Добавляем в “автозапуск”:
rc-update add php-fpm83
На всякий случай reboot
, после чего ищем php-fpm например в top
.
PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 2365 2334 www-data S 202m 43% 0 0% {php-fpm83} php-fpm: pool www 2366 2334 www-data S 173m 37% 0 0% {php-fpm83} php-fpm: pool www 2334 1 root S 173m 37% 0 0% {php-fpm83} php-fpm: master proces
Вроде есть контакт. Убедимся, что мы не открыли лишние порты:
netstat -tulpn | grep LISTEN
В выводе должны быть только 22-е порты (SSH).
Caddy
https://wiki.alpinelinux.org/wiki/Caddy
Внезапно тоже есть в apk.
apk update apk add caddy caddy-openrc
Или, как авторы образа Docker, скачать бинарник с GitHub. Правда в этом случае видимо надо будет “вручную” делать сервис, а это довольно здоровый скрипт.
Пакет поставляется с пустым /etc/caddy/Caddyfile, так что придется все делать самим. Создадим файл /var/www/html/index.php:
<?php phpinfo(); ?>
Поменяем владельца каталога:
chown -R www-data:www-data /var/www/html
Предварительно сконфигурируем сервер (добавим в /etc/caddy/Caddyfile):
http:// { root * /var/www/html encode zstd gzip file_server php_fastcgi unix//run/php-fpm83/www.sock }
Директива (file_server
) пока фактически не нужна (поскольку иных файлов и нет), но на перспективу пусть будет.
Веб-сервер запускается под пользователем caddy. Необходимо разрешить этому пользователю взаимодействовать с сокетом PHP-FPM. Правим /etc/php83/php-fpm.d/www.conf:
listen.acl_users = www-data,caddy
Перезапускаем php-fpm и запускаем Caddy:
rc-service php-fpm83 restart rc-service caddy start
Заходим на сервер “по IP” - должны увидеть страницу сведений о PHP.
По желанию можно убрать заголовки Server и X-Powered-By. Возвращаемся обратно в Alpine и в /etc/caddy/Caddyfile добавляем директиву:
header -Server
А в /etc/php83/php.ini исправляем:
expose_php = Off
Перезапускаем сервисы php-fpm83 и caddy. “Лишние” заголовки должны исчезнуть.
Добавляем веб-сервер в “автозапуск”:
rc-update add caddy
Git и composer
В принципе и то, и другое есть в apk. Так что на всякий случай обновляем и затем устанавливаем:
apk update apk add git composer
Основное неудобство скорее всего будет заключаться в пользователе - переключиться в www-data нельзя, так что git может ругаться:
fatal: detected dubious ownership in repository at '/var/www/html' To add an exception for this directory, call: git config --global --add safe.directory /var/www/html
Вероятно так и стоит поступить. Либо заводить пользователя и менять на него php-fpm83 и Caddy.
vsftpd
Возможно, по FTP заливать “исходники” будет удобнее. В Wiki для этого предлагают воспользоваться vsftpd.
Установка
Как всегда, из пакетов:
apk add vsftpd vsftpd-openrc
В /etc/vsftpd/vsftpd.conf правим/раскомментируем:
anonymous_enable=NO local_enable=YES write_enable=YES local_umask=022
По желанию - включить текстовый режим передачи (управление переводами строк):
ascii_upload_enable=YES ascii_download_enable=YES
Убрать ошибку 500 OOPS: child died или т.п. - добавить:
seccomp_sandbox=NO
Разрешение входа только www-data (пользователям, перечисленным в списке) - добавить:
userlist_enable=YES userlist_deny=NO userlist_file=/etc/vsftpd/user_list
Соответственно список - файл /etc/vsftpd/user_list:
www-data
Установить пароль пользователю www-data:
passwd www-data
Запуск и добавление в “автозагрузку”:
rc-service vsftpd start rc-update add vsftpd
Ограничение корневой директории
Небольшая проблема в такой конфигурации - по FTP можно обозревать всю файловую систему (доступную пользователю www-data). Можно или не обращать на это внимание, или поменять домашнюю директорию системному пользователю и добавить (раскомментировать) настройку в /etc/vsftpd/vsftpd.conf chroot_local_user=YES
, или разбираться с виртуальными пользователями, что делается, по видимому, через PAM и наверное не особо-то и надо.
Чтобы поменять домашнюю директорию, наверное, не стоит непосредственно редактировать /etc/passwd. Установим пакет shadow, чтобы воспользоваться более-менее привычным usermod:
apk add shadow
Однако прежде чем менять настройки пользователя, придется остановить сервисы, его использующие. В частности PHP:
rc-service php-fpm83 stop
И только затем выполнить:
usermod --home /var/www www-data
Соответственно запускаем PHP обратно и перезапускаем vsftpd для применения настроек.
fail2ban
Фильтр для vsftpd входит в комплект поставки, поэтому есть смысл добавить ловушку и для FTP. Сначала убедимся, что логирование vsftpd включено (в /etc/vsftpd/vsftpd.conf):
xferlog_enable=YES
По всей видимости, отдельно именно входы-выходы не логируются, т.е. либо только вместе с фиксацией передачи файлов, либо вообще никак. Файл логов по умолчанию: /var/log/vsftpd.log
Соответственно создаем “клетку” /etc/fail2ban/jail.d/vsftpd.conf:
[ftp] enabled = true filter = vsftpd port = ftp logpath = /var/log/vsftpd.log maxretry = 3 bantime = 12h
Перезагружаем конфигурацию fail2ban:
fail2ban-client reload
“Неправильно” входим по FTP 3 раза (получаем ошибку 530 Login incorrect), а на 4-й уже “Соединение прервано после 20 секунд неактивности”. Также по желанию можно перепроверить вывод iptables -S | grep f2b-ftp
- должна быть запись с нашим IP и правилом недоступности порта. Кстати по умолчанию vsftpd работает по IPv4.
Облачная синхронизация
В этом смысле я предпочитаю rclone, который опять же есть в apk.
apk add rclone
Настраиваем подключение:
rclone config
Я как-то традиционно пользуюсь mega.nz. “Из коробки” поддерживается еще довольно много облаков, а также универсальные протоколы FTP, sFTP и WebDAV. Для определенности создаю подключение к Меге под названием meganz
.
Проверка (именно с двоеточием в конце):
rclone lsd meganz:
Должно отобразиться содержимое корневой директории.
Теперь можно использовать синхронизацию в скриптах и/или crontab. Например, забегая вперед, в последнем случае:
0 4 * * * /usr/bin/rclone sync /var/www/html/public/images meganz:/backups/images
Тем самым в 4 часа утра синхронизируем с облаком каталог изображений.
Заключение
Собственно, осталось вместо заглушки разместить настоящий сайт и отполировать настройки Caddy, PHP и rclone. С чем, я надеюсь, вы справитесь и без меня.
В целом, все необходимое в Alpine Linux есть, что делает ее достаточно перспективной для использования в качестве ОС для веб-сервера, особенно какого-нибудь "статического", особенно на начальных тарифах VDS/VPS. Хотя вот разработчики FrankenPHP утверждают, что с musl PHP якобы медленно работает. Имейте в виду, если что.
Категория: Программирование, веб | Опубликовано 11.12.2024 | Редакция от 13.12.2024
Похожие материалы
Настройка Ubuntu Server 18.04 на домашнем сервере
Или, если угодно, настройка 14.04 часть 2 - кое-какие моменты за прошедшее время не претерпели особых изменений. Статья все же будет носить более технический характер: затронем настройку Samba из консоли, веб-сервера, облачной синхронизации и др.