Крайне минималистичная система, что может пригодиться на слабых конфигурациях. Подходит в случае 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 объем оперативки).

изображение.png

* Примечание. На моем хостинге 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. С чем, я надеюсь, вы справитесь и без меня. smile

В целом, все необходимое в Alpine Linux есть, что делает ее достаточно перспективной для использования в качестве ОС для веб-сервера, особенно какого-нибудь "статического", особенно на начальных тарифах VDS/VPS. Хотя вот разработчики FrankenPHP утверждают, что с musl PHP якобы медленно работает. Имейте в виду, если что. smile


Категория: Программирование, веб | Опубликовано 11.12.2024 | Редакция от 13.12.2024

Похожие материалы

Настройка Ubuntu Server 18.04 на домашнем сервере

Или, если угодно, настройка 14.04 часть 2 - кое-какие моменты за прошедшее время не претерпели особых изменений. Статья все же будет носить более технический характер: затронем настройку Samba из консоли, веб-сервера, облачной синхронизации и др.


Комментарии, обсуждение