ServerAdmin.ru
28.9K subscribers
304 photos
35 videos
13 files
2.63K links
Авторская информация о системном администрировании.

Информация о рекламе: @srv_admin_reklama_bot
Автор: @zeroxzed

Второй канал: @srv_admin_live
Сайт: serveradmin.ru
Download Telegram
​​Я уже много раз упоминал про использование простейшего http сервера на базе python:

# python3 -m http.server 8000

Я его постоянно использую, когда надо быстро откуда-то забрать файлы без лишних телодвижений. Просто перехожу в нужную директорию, запускаю веб сервер, скачиваю файлы, открыв их по ip адресу сервера и завершаю работу веб сервера.

Мне понадобилось для проверки одного приложения запустить https сервер, так как по http оно не работает. Было лень настраивать для этого Nginx. Подумал, что наверное его так же можно быстро поднять с помощью python. Быстро нашёл решение.

Генерируем самоподписный ключ и сертификат в один файл:

# openssl req -new -x509 -keyout localhost.pem -out localhost.pem -days 365 -nodes

Создаём файл webserver.py следующего содержания:

import http.server, ssl

server_address = ('172.20.0.210', 8000)
httpd = http.server.HTTPServer(server_address, http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket,server_side=True,certfile='localhost.pem',ssl_version=ssl.PROTOCOL_TLSv1_2)
httpd.serve_forever()

Запускаем веб сервер:

# python3 webserver.py

Идём по адресу https://172.20.0.210:8000 и видим содержимое директории или какой-то сайт, если в ней лежит index.html.

В принципе, можно сохранить этот файл и использовать для передачи файлов, если вам важно передавать по https. Я люблю такие простые и быстрые решения. Так что обязательно сохраню и буду использовать.

#webserver #python
​​Обращаю ваше внимание на сервис по генерации конфигов для Nginx. Я когда-то давно уже о нём рассказывал, но с тех пор прошло много лет.

https://www.digitalocean.com/community/tools/nginx

Сам я на постоянку не пользуюсь такими сервисами, потому что у меня уже на все случаи жизни есть свои конфигурации. Но время от времени их имеет смысл проверять и актуализировать. Вот и в этот раз я решил этим заняться.

Указанный сервис очень удобен. Видно, что развивается. Раньше немного не так работал. Через форму на сайте указываете все нужные параметры и на выходе получается готовый набор конфигурационных файлов, разбитых по смыслу на части: отдельно общий конфиг, конфиг по безопасности, конфиг для специфических настроек wordpress, если укажите, что делаете конфигурацию для этой cms, отдельно настройки для letsencrypt и так далее.

В конце вам предложат скачать весь набор правил и покажут последовательность действий, для того, чтобы всё заработало. В зависимости от настроек, это будут команды для:

генерации файла dhparam.pem, нужного для работы https с параметром ssl_dhparam:
создания каталога letsencrypt для подтверждения сертификатов;
инструкции по настройке certbot.

Я создал типовой для меня конфиг и сверился со своим. Увидел некоторые опции, которые раньше не использовал. Например:

log_not_found - разрешает или запрещает записывать в error_log ошибки о том, что файл не найден. По умолчанию в nginx параметр включён и в error_log пишутся эти ошибки, сервис предлагает по умолчанию отключать. В принципе, смысл в этом есть. На практике error_log реально забивается этими записями, хотя чаще всего они не нужны, так как на работающий сайт постоянно кто-то стучится по несуществующим урлам. К себе тоже добавил этот параметр глобальноlog_not_found off; Раньше отключал только по месту для отдельных location, типа /favicon.ico или /robots.txt

ssl_ciphers - обновил себе набор шифров. Я не вникаю в подробности набора, так как не особо в этом разбираюсь, да и не вижу большого смысла. Только учтите, что этот набор должен согласовываться с параметром ssl_protocols, где вы указываете список поддерживаемых версий TLS. Сейчас считается, что ниже TLSv1.2 использовать небезопасно.

отдельно глобально вынесена блокировка всего, что начинается с точки, кроме директории .well-known, которую использует letsencrypt, и подключается ко всем виртуальным хостам:
location ~ /\.(?!well-known) {
  deny all;
Я обычно в каждом виртуальном хосте сначала разрешал .well-known, а потом блокировал всё, что начинается с точки:
location ~ /\.well-known\/acme-challenge {
  allow all;
}
location ~ /\. {
deny all;
  return 404;
}
То, как предлагает сервис, сделано удобнее. Тоже забрал себе.

Ну и так далее. Не буду всё расписывать, так как у каждого свои шаблоны. В общем, сервис удобный и полезный. Рекомендую не просто забрать в закладки, но и провести аудит своих конфигов на предмет улучшения. А если настраиваете nginx редко, то просто пользуйтесь этим сервисов. Он рисует абсолютно адекватные и качественные конфиги.

#nginx #webserver
​​Для получения бесплатных TLS сертификатов от Let's Encrypt существуют два набора скриптов: certbot и acme.sh. Может ещё какие-то есть, но эти самые популярные. Certbot написан на python, acme.sh полностью на bash.

Я всегда использовал certbot. Просто привычка. Начал с него и всегда пользуюсь именно им. Много раз слышал, что acme.sh более удобен и функционален. Плюс, не привязан к версии python. Он вообще не нужен, хотя для базовых систем это не принципиально. Python обычно есть на всех полноценных системах Linux.

Решил я посмотреть на acme.sh и сравнить с certbot. Устанавливается он просто:

# curl https://get.acme.sh | sh -s email=my@example.com

Обязательно измените email. С указанным доменом example потом ничего выпустить не получится. Установщик делает 3 вещи:

1️⃣ Копирует скрипт acme.sh и некоторые конфиги в домашнюю директорию ~/.acme.sh/
2️⃣ Подключает в .bashrc окружение из ~/.acme.sh/acme.sh.env. По сути просто делает алиас alias acme.sh="/root/.acme.sh/acme.sh".
3️⃣ Добавляет в cron пользователя задачу на ежедневную попытку обновления сертификатов.

После этого можно сразу пробовать получить сертификат. Acme.sh поддерживает разные CA, поэтому надо явно указать letsencrypt:

# acme.sh --issue --server letsencrypt -d 329415.simplecloud.ru -w /var/www/html

Если всё прошло без ошибок, то в директории ~/.acme.sh появится папка с именем домена, где будет лежать сертификат, ключ и некоторые настройки для этого домена. Теперь можно куда-то скопировать этот сертификат с ключом и перезапустить веб сервер. Например, в директорию /etc/nginx/certs/. Можно это сделать вручную, а можно через тот же acme.sh:

acme.sh --install-cert -d 329415.simplecloud.ru \
--key-file    /etc/nginx/certs/key.pem \
--fullchain-file /etc/nginx/certs/cert.pem \
--reloadcmd   "service nginx force-reload"

Если ранее Nginx был настроен на использование сертификата и ключа для этого домена из указанной директории, то он перечитает свой конфиг и автоматически подхватит новые файлы.

В целом, по использованию плюс-минус то же самое, что и в certbot. Какого-то явного удобства не увидел. Плюс только один - простая установка, так как это обычный bash скрипт без зависимостей. Но я по-прежнему буду использовать certbot, потому что мне больше нравится делать вот так:

# apt install certbot
а не так:
# curl https://get.acme.sh | sh -

Если кто-то пользуется acme.sh и знает его явные преимущества, прошу поделиться информацией.

Исходники

#webserver
​​Как быстро и малыми усилиями попытаться выяснить, почему что-то тормозит в php коде сайта? Расскажу, с чего уместнее всего начать расследование, если вы используете php-fpm. Если нет каких-то особых требований, то лично я всегда исользую именно его.

У него есть две простые настройки, которые можно применить в нужном пуле, когда проводите расследование:

slowlog = /var/log/php-fpm/site01.ru.slow.log
request_slowlog_timeout = 1s

Таймаут выставляете под свои требования. Если сайт в целом тормозной (bitrix, админка wordpress), то 1 секунда слишком малый интервал, но в идеале хочется, чтобы весь код выполнялся быстрее этого времени.

Далее необходимо перезаустить php-fpm и идти смотреть лог:

# systemctl restart php8.0-fpm

В логе запросов будет не только информация о скрипте, который долго выполняется, но и его трассировака. Она будет включать в себя все инклюды и функции. То, что было вызвано сначала, будет внизу трейса, последняя функция - в самом верху. Причём верхней функцией будет та, что выполнялась в момент наступления времени, указанного в request_slowlog_timeout. Часто именно она и причина тормозов.

Разобраться во всём этом не такая простая задача, но в целом выполнимая даже админом. Самое главное, что иногда можно сразу получить подсказку, которая ответит на ворос о том, что именно томозит. Бывает не понятно, какой именно запрос приводит к выполнению того или иного скрипта. Нужно сопоставить по времени запрос в access.log веб сервера и slowlog php-fpm. 

Очень часто тормозят какие-то заросы к внешним сервисам. Они могут делаться, к примеру, через curl_exec. И вы это сразу увидите в slowlog в самом верху трейса. Нужно будет только пройтись по функуциям и зависимостям, и найти то место, откуда функция с curl вызывается. Также часто в самом верху трейса можно увидеть функцию mysqli_query или что-то в этом роде. Тогда понятно, что тормозят запросы к базе.

По факту это самый простой инструмент, который имеет смысл использовать в самом начале разборов. Зачастую с его помощью можно сразу найти проблему. Ну а если нет, то можно подключать strace и смотреть более детально, что там внутри происходит. Но это уже сложнее, хотя какие-то простые вещи тоже можно сразу отловить. Тот же внешний тормозящий запрос тоже будет виден сразу.

#php #webserver #perfomance
У сайтов на Bitrix существует одна особенность. Специально выделил жирным, потому что это такая особенность, что всем особенностям особенность. В админке можно править исходники сайта прямо наживую, в том числе и служебные файлы .htaccess. Любой, кто имеет доступ к админке, может грохнуть сайт. И это время от времени случается.

Вчера грохнули сайт по похожей схеме. Сеошник добавлял редиректы правкой .htaccess через админку. Редиректов там сотни. Сайт очень старый. Его развивали и поддерживали за последние лет 10 несколько разных компаний и программистов. Правку файлов тоже на постоянной основе делают несколько человек - как минимум сеошник и контент менеджер.

Из-за ошибки в .htaccess апач на каждый запрос отдавал 500-ю ошибку. Это я уже потом узнал. Сначала зашёл на сервер, сразу посмотрел изменения за последние сутки:

# find /home/bitrix/ext_www/site01 -mtime -1 -ls

Когда увидел в списке файлов .htaccess сразу на него подумал. Сходил на бэкап сервер, забрал оттуда предыдущую версию файла. Он очень большой, так что глазами разницу не видно. Сравнил так:

# sdiff /root/restored/.htaccess /home/bitrix/ext_www/site01/.htaccess

Увидел много изменений. Сразу вернул прошлую версию файла. Сайт ожил. Я посмотрел на внесённые изменения. Сходил, проверил синтаксис через публичный сервис:

http://www.htaccesscheck.com (полезный, стоит сохранить)

Забавное вступительное слово у сервиса:

"Sick of one silly typo in a .htaccess file causing your entire site to be broken?" - "Устали, что банальная опечатка в .htaccess, роняет весь сайт?"

Это такая фишка Апача. И плюс, и минус одновременно.

Сервис показал ошибку. Один url, куда был направлен 301 редирект, был некорректный по формату. Из-за этого Apache на все запросы возвращал 500-ю ошибку. Я удивился от этого. Не припоминаю, что сталкивался с этим раньше. Как-то нелогично. Одно дело давать ошибку на конкретный редирект, а другое руинить всю свою работу из-за него.

В общем, файл починил, сеошнику отправил ссылку на сервис, чтобы проверял свои редиректы, прежде чем добавлять их в .htaccess. Как защититься от этого, не знаю. Это уже не первый раз, когда прямой правкой сайта через админку ломают его работу. Теоретически, я конечно знаю, как это можно исправить. Но для масштаба текущего бизнеса это будет неоправданно большой бюджет. Простой даже в несколько часов некритичен и проблем не создаёт. Напрягает это только меня, что приходится вручную решать проблемы. Но, собственно, я для этого туда и нанят.

#bitrix #webserver #apache
​​Один подписчик поделился со мной информацией о необычном и полезном программном продукте. Изначально он обратился ко мне с просьбой подсказать, какой веб сервер под Windows можно использовать для быстрого запуска локально с флешки размещённого там небольшого проекта. Первое, что мне пришло в голову - Caddy. Это максимально простой веб сервер, состоящий из одного бинарника на Go, который всю конфигурацию хранит в едином конфиге. Версия под Windows тоже есть.

Он в итоге нашёл для себя вариант ещё проще и лучше - Small HTTP server. Пошёл, посмотрел, что это такое. Очень заинтересовала программа. Раньше про неё не слышал. Она из далёкого прошлого. Написана изначально была под Windows 95 и NT, но развивается до сих пор. Свежий релиз от 24.03.24. Код, как я понял, написан на С++ и очень хорошо оптимизирован. Установщик занимает примерно 1 мегабайт (❗️). При этом программа имеет следующие возможности:

HTTP сервер. Поддерживает CGI и FastCGI интерфейсы для скриптов (запуск исполняемых файлов; Perl, PHP, и других внешних интерпретаторов), ISAPI (Internet Server API — API для веб-сервера IIS) интерфейс, виртуальные хосты и каталоги.

Почтовый сервер POP3 и SMTP. Анти-спам фильтры. Белый, чёрный, и серый списки общие для всех и персональные для каждого пользователя. Переотправка и возможности запускать скрипты для входящих сообщений. Запуск внешнего антивируса.

FTP сервер с виртуальными каталогами.

HTTP proxy сервер. Поддерживаются HTTP, FTP, HTTPS запросы
Сохранение большого объема трафика, быстрый доступ. Внутренняя докачка при разрывах соединения. Сервер может запрашивать сжатый контент и распаковывать ответ на лету (с использованием внешней Zlib библиотеке).

DNS сервер. 🔥Опция динамической проверки сервиса на удаленном хосту и если сервис не работает, автоматическая замена одного IP адреса на другой во всех запросах. Рекурсивный поиск имен от корневых DNS серверов или от DNS серверов провайдера. Кеширование. Опция автоматического ответа на запросы IPv6 адреса. (для сетей, не использующих Internet по IPv6). DNSBL сервер (работает совместно с SMTP). DNS через HTTP(S) известный как DoH (RFC8484).

DHCP сервер.

HTTP TLS VPN сервер и клиент! Используется OpenVPN Windows TAP драйвер. Описание, как это работает и для чего.

Всё это собрано под Windows и Linux, в том числе ARM. Для Debian есть готовый пакет. Хорошее решение для маломощных одноплатников.

По работе всех служб есть статистика в веб интерфейсе. Я попробовал работу на Windows. Всё работает чётко, запустил без каких-либо проблем. Конфигурация хранится в текстовом файле. Управлять можно как в нём, так и через интерфейс программы. Для запуска достаточно запустить экзешник. По умолчанию веб сервер работает в режиме листинга файлов директории, которая указана, как корень веб сервера. Можно настроить работу как служба.

У программы, несмотря на видимую простоту, очень много настроек и возможностей. Они все перечислены в виде параметров в интерфейсе программы, так что можно быстро их оценить.

Предлагаю автору накидать звёздочек в github и подписаться на Telegram канал. Думаю, ему будет приятно. Программа реально интересная и необычная. Не знаю, что за мотивация у человека столько лет её развивать и поддерживать.

Мне кажется, сейчас программистов С++ уже можно по профильным школам и вузам водить, как ветеранов, и рассказывать от их лица, что программы могут быть маленькими, оптимизированными и работать быстро. А то скоро все вообще забудут, что такое в принципе может быть.

Сайт / Исходники / TG канал

#webserver #dns #dhcp #ftp
​​Сейчас без HTTPS не хотят работать многие сервисы. А даже если и работают, то браузеры не дадут спокойно пользоваться. Поэтому приходится получать и настраивать сертификаты, даже если большой нужды в этом нет. Особенно если ты работаешь с ним один в локальной сети, либо вообще поднимаешь временно. Я обычно получаю сертификаты let's encrypt и копирую на нужный сервер, если к нему не проброшен доступ из интернета.

Решил подготовить пошаговую инструкцию, чтобы быстро выпустить свой сертификат через свой CA, добавив его к себе в доверенные, чтобы браузеры не ругались. Во многих ситуациях это будет удобнее, чем постоянно обновлять доверенные сертификаты через интернет. Свой можно выпустить вечным. Покажу на примере настройки сертификата в Nginx.

Будем выпускать сертификат для доменного имени zabbix.internal и IP адреса 172.30.245.222. Будет работать и так, и эдак.

Выпускаем ключ и сертификат для своего CA:

# mkdir ~/tls && cd ~/tls
# openssl ecparam -out myCA.key -name prime256v1 -genkey
# openssl req -x509 -new -nodes -key myCA.key -sha256 -days 9999 -out myCA.crt

Вам зададут серию вопросов. Отвечать можно всё, что угодно. В данном случае это не важно. Выпускаем ключ и сертификат для сервера:

# openssl genrsa -out zabbix.internal.key 2048
# openssl req -new -key zabbix.internal.key -out zabbix.internal.csr

Тут тоже зададут похожие вопросы. Отвечать можно всё, что угодно. Готовим конфигурационный файл:

# mcedit zabbix.internal.ext

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
IP.1 = 172.30.245.222
DNS.1 = zabbix.internal

Генерируем сертификат на его основе:

# openssl x509 -req -in zabbix.internal.csr -CA myCA.crt -CAkey myCA.key \
-CAcreateserial -out zabbix.internal.crt -days 9999 -sha256 -extfile zabbix.internal.ext

Копируем сертификат и ключ в директорию веб сервера:

# mkdir /etc/nginx/certs
# cp zabbix.internal.crt /etc/nginx/certs/.
# cp zabbix.internal.key /etc/nginx/certs/.

Создаём файл dhparam, который понадобится для конфигурации Nginx:

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Добавляем в конфиг Nginx в целевом виртуальном хосте:

listen     443 http2 ssl;
server_name   zabbix.internal 172.30.245.222;
ssl_certificate /etc/nginx/certs/zabbix.internal.crt;
ssl_certificate_key /etc/nginx/certs/zabbix.internal.key;
ssl_dhparam /etc/ssl/certs/dhparam.pem;

Перезапускаем Nginx:

# nginx -t
# nginx -s reload

Передаём на свой компьютер файл myCA.crt и добавляем его в хранилище корневых доверенных центров сертификации. Настройка будет зависеть от операционной системы. Если нужно тут же, локально на сервере с Debian 12 настроить доверие этому CA, то делаем так:

# cp myCA.crt /usr/local/share/ca-certificates/.
# update-ca-certificates

Теперь можно браузером заходить по доменному имени или IP адресу, будет работать самоподписанный сертификат на 9999 дней без каких-либо предупреждений.

Получилась готовая инструкция для копипаста, которую можно сохранить и пользоваться.

#webserver
​​Существует эффективный стандарт сжатия zstd. Не так давно современные браузеры стали его поддерживать, так что можно использовать в веб серверах. Разработчики Angie подсуетились и подготовили модуль для своего веб сервера, так что включить сжатие zstd максимально просто и быстро. Достаточно установить модуль в виде deb пакета и добавить настройки в конфигурацию, которые идентичны настройкам gzip, только название меняется на zstd.

По этому поводу вышел очень информативный ролик на ютубе:

Zstd (Zstandard): новый стандарт сжатия текста. Полный тест

Автор не только показал, как настроить zstd на веб сервере, но и сравнил его эффективность с привычными gzip и brotli. Результаты тестирования в динамическом сжатии получились очень любопытные. Zstd оказался лучше всех. Но если разница с brotli не сильно заметна, то вот gzip на фоне остальных выглядит очень медленным. Буквально в разы в некоторых случаях.

Я решил провести свои тесты, чтобы убедиться в такой большой разнице. Сразу скажу, что если не настроено https, то браузеры не будут использовать ни brotli, ни zstd. Не знаю, с чем это связано, но я потратил некоторое время, пока не разобрался с тем, почему не работает ничего, кроме gzip. И второй момент. Если на веб сервере настроены все 3 типа сжатия, то разные браузеры выбирают разное сжатие: либо brotli, либо zstd. Gzip не выбирает никто.

Тестировал так же, как и автор ролика. Установил Angie и оба модуля сжатия:

# curl -o /etc/apt/trusted.gpg.d/angie-signing.gpg https://angie.software/keys/angie-signing.gpg

# echo "deb https://download.angie.software/angie/debian/ `lsb_release -cs` main" | tee /etc/apt/sources.list.d/angie.list > /dev/null

# apt update && apt install angie angie-module-zstd angie-module-brotli

Подключил оба модуля в angie.conf:

load_module modules/ngx_http_zstd_static_module.so;
load_module modules/ngx_http_zstd_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
load_module modules/ngx_http_brotli_filter_module.so;

И добавил для них настройки:

  gzip on;
  gzip_static on;
  gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
  gzip_comp_level 4;
  gzip_proxied any;
  gzip_min_length 1000;
  gzip_vary on;

  brotli on;
  brotli_static on;
  brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
  brotli_comp_level 4;

  zstd on;
  zstd_static on;
  zstd_min_length 256;
  zstd_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/x-icon image/svg+xml application/x-font-ttf;
  zstd_comp_level 4;

Если использовать ванильный Nginx, то придётся самостоятельно собирать его с нужными модулями 🤷‍♂️

Тестировал с помощью ab, передавая ему метод компрессии через заголовок:

# ab -n 1000 -k -c 1 -H "Accept-Encoding: zstd" https://10.20.1.36/scripts.js

Не буду приводить свои результаты, так как они получились примерно такие же, как у автора ролика, только разница между zstd и brotli с компрессией 4 поменьше. Zstd по rps (247) быстрее всех. Brotli чуть лучше жмёт в плане объёма, то есть трафик будет ниже, но и rps (211) немного меньше, чем у zstd.

В Angie очень легко настроить и brotli, и zstd, и gzip, так что имеет смысл это сделать. Клиент пусть сам выбирает, какой тип сжатия он будет использовать.

Один важный момент, который я вынес из этой темы. Не нужно ставить сжатие выше 3 или 4. Дальше идёт очень существенное падение производительности при незначительном уменьшении размера файлов. Я раньше бездумно ставил 9 и думал, что современные процессоры и так нормально вытягивают, если сервер не нагружен в потолок. Это не так. Смысла в высокой компрессии нет.

#webserver #angie
​​Для управления веб сервером есть множество готовых веб панелей. Основная проблема их использования - дополнительный вектор атаки сервера через эту веб панель. Причём, случается это довольно часто. В идеале, доступ к веб панели управления хостингом должен быть ограничен. Второй момент - часто веб панели раскидывают конфиги в нестандартные места, переписывают их после перезапуска службы управления. Это часто делает невозможным изменение конфигов вне веб панели, а иногда хочется, так как их возможности ограничены.

Есть промежуточные варианты автоматизации и упрощения управления веб хостингом. Набор консольных инструментов для управления. Наглядным примером подобного продукта является Bitrixenv. Это инструмент для автоматической настройки и управления веб хостингом для размещения сайтов на движке Битрикс.

Для сайтов на Wordpress есть похожий продукт - WordOps. Он позволяет автоматически разворачивать готовое окружение для сайтов на базе Wordpress, а так же любых других статических или php сайтов.

Установить WordOps можно автоматически прямо на сервер:

# wget -qO wo wops.cc && bash wo

Скрипт установки выполняет несколько простых шагов:
устанавливает необходимые системные пакеты
создаёт директории
устанавливает WordOps через pip
устанавливает acme.sh и WP-CLI

Всё это можно проделать и вручную. После установки становятся доступны консольные команды для управления хостингом. Создадим сайт Wordpress на php81 с сертификатом от Let's Encrypt:

# wo site create 330693.simplecloud.ru --wp --php81 -le

Эта команда выполнит следующие действия:
▪️ добавит репозитории Nginx, Php, MySQL в систему
▪️ установит все необходимые пакеты
▪️ создаст конфигурации Nginx и Php-fpm
▪️ получит tls сертификаты для домена
▪️ установит последнюю версию wordpress
▪️ создаст и настроит подключение к базе данных

В консоли вы получите адрес созданного сайта и учётную запись админа. При этом в директории /etc/nginx/sites-enabled будет создана конфигурация для сайта. Причём довольно навороченная. Там сразу будут лимиты на wp-cron.php и wp-login.php, ограничение доступа белым списком к xmlrpc.php, блокировка доступа к некоторым другим внутренностям Wordpress. В директории /var/www/330693.simplecloud.ru будут лежать исходники сайта, логи и некоторые настройки. В рутовском кроне /var/spool/cron/crontabs будут добавлены задания на обновление сертификатов и некоторые другие действия. Все конфигурации в стандартном формате и на своих местах. Искать ничего не надо.

Помимо Wordpress сайтов, можно создать обычный html или php:

# wo site create site.tld --html
# wo site create site.tld --mysql --php81

Из минусов сразу отмечу, то все сайты одной версии php создаются общим пулом php-fpm. Лучше было бы их разделять между собой.

Помимо управления сайтами, у WordOps есть и другие команды, с помощью которых, к примеру, можно:
● обновить системные пакеты
● настроить некоторые параметры ssh
● установить phpMyAdmin, Adminer, Dashboard, Netdata, MySQLTuner, eXtplorer Filemanager, Fail2ban, proftpd и некоторые другие программы
● посмотреть логи служб

Пример того, как может выглядеть настроенный Dashboard вашего сервера.

Про WordOps узнал случайно. Увидел упоминание в комментариях. Сам никогда не пользовался, но мне понравилось, как всё сделано - просто и удобно. Меняются системные конфигурации, при этом всё остаётся на своих местах. Можно руками что-то подправить и это ничего не сломает. Панель просто помогает выполнить настройку.

Подобный инструмент существенно упрощает и ускоряет настройку веб сервера. Желательно им пользоваться, если вы уже умеете настраивать всё это вручную сами. Либо вы далеки от темы настройки веб серверов, а вам его нужно поднять. Для веб разработчиков это отличный инструмент, чтобы поставить на какой-нибудь свой тестовый сервер для разработки.

В документации с примерами показано, как всем этим управлять. Например, добавляем FTP пользователя или используем удалённый mysql сервер.

Сайт / Исходники

#webserver
Часто доступ к веб ресурсам осуществляется не напрямую, а через обратные прокси. Причём чаще доступ именно такой, а не прямой. При возможности, я всегда ставлю обратные прокси перед сайтами даже в небольших проектах. Это и удобнее, и безопаснее, но немного более хлопотно в управлении.

Для проксирования запросов в Docker контейнеры очень удобно использовать Traefik. Удобство это в первую очередь проявляется в тестовых задачах, где часто меняется конфигурация контейнеров с приложениями, их домены, а также возникают задачи по запуску нескольких копий типовых проектов. Для прода это не так актуально, потому что он обычно более статичен в этом плане.

Сразу покажу на практике, в чём заключается удобство Traefik и в каких случаях имеет смысл им воспользоваться. Для примера запущу через Traefik 2 проекта test1 и test2, состоящих из nginx и apache и тестовой страницы, где будет указано имя проекта. В этом примере будет наглядно виден принцип работы Traefik.

Запускаем Traefik через docker-compose.yaml:

# mkdir traefik && cd traefik
# mcedit docker-compose.yaml


services:
reverse-proxy:
image: traefik:v3.0
command: --api.insecure=true --providers.docker
ports:
- "80:80"
- "8080:8080"
networks:
- traefik_default
volumes:
- /var/run/docker.sock:/var/run/docker.sock
networks:
traefik_default:
external: true


# docker compose up


Можно сходить в веб интерфейс по ip адресу сервера на порт 8080. Пока там пусто, так как нет проектов. Создаём первый тестовый проект. Готовим для него файлы:

# mkdir test1 && cd test1
# mcedit docker-compose.yaml


services:
nginx:
image: nginx:latest
volumes:
- ./app/index.html:/app/index.html
- ./default.conf:/etc/nginx/conf.d/default.conf
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx-test1.rule=Host(`test1.server.local`)"
- "traefik.http.services.nginx-test1.loadbalancer.server.port=8080"
- "traefik.docker.network=traefik_default"
networks:
- traefik_default
- test1

httpd:
image: httpd:latest
volumes:
- ./app/index.html:/usr/local/apache2/htdocs/index.html
networks:
- test1

networks:
traefik_default:
external: true
test1:
internal: true


# mcedit default.conf 

server {
listen 8080;
server_name _;

root /app;
index index.php index.html;

location / {
proxy_pass http://httpd:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}


# mcedit app/index.html


It's Container for project test1


Запускаем этот проект:

# docker compose up


В веб интерфейсе Traefik, в разделе HTTP появится запись:

Host(`test1.server.local`) http nginx-test1@docker  nginx-test1

Он по меткам в docker-compose проекта test1 автоматом подхватил настройки и включил проксирование всех запросов к домену test1.server.local в контейнер nginx-test1. При этом сам проект test1 внутри себя взаимодействует по своей внутренней сети test1, а с Traefik по сети traefik_default, которая является внешней для приёма запросов извне.

Теперь можно скопировать проект test1, изменить в нём имя домена и имя внутренней сети на test2 и запустить. Traefik автоматом подцепит этот проект и будет проксировать запросы к test2.server.local в nginx-test2. Работу этой схемы легко проверить, зайдя откуда-то извне браузером на test1.server.local и test2.server.local. Вы получите соответствующую страницу index.html от запрошенного проекта.

К Traefik легко добавить автоматическое получение TLS сертификатов от Let's Encrypt. Примеров в сети и документации много, настроить не составляет проблемы. Не стал показывать этот пример, так как не уместил бы его в формат заметки. Мне важно было показать суть - запустив один раз Traefik, можно его больше не трогать. По меткам в контейнерах он будет автоматом настраивать проксирование. В некоторых ситуациях это очень удобно.

#webserver #traefik #devops
В работе веб сервера иногда есть необходимость разработчикам получить доступ к исходникам сайта напрямую. Проще всего и безопаснее это сделать по протоколу sftp. Эта на первый взгляд простая задача на деле может оказаться не такой уж и простой с множеством нюансов. В зависимости от настроек веб сервера, может использоваться разный подход. Я сейчас рассмотрю один из них, а два других упомяну в самом конце. Подробно рассказывать обо всех методах очень длинно получится.

Для примера возьму классический стек на базе nginx (angie) + php-fpm. Допустим, у нас nginx и php-fpm работают от пользователя www-data, исходники сайта лежат в /var/www/html. Владельцем файлов и каталогов будет пользователь и группа www-data. Типичная ситуация. Нам надо дать доступ разработчику напрямую к исходникам, чтобы он мог вносить изменения в код сайта.

Сразу предвижу комментарии на тему того, что так делать неправильно и в код лезть напрямую не надо. Я был бы только рад, если бы туда никто не лазил. Мне так проще управлять и настраивать. Но иногда надо и выбирать не приходится. Разработчиков выбираю не я, как и их методы работы.

Первым делом добавляю в систему нового пользователя, для которого не будет установлен shell. Подключаться он сможет только по sftp:

# useradd -s /sbin/nologin webdev
# passwd webdev

Теперь нам нужно настроить sshd таким образом, чтобы он разрешил только указанному пользователю подключаться по sftp, не пускал его дальше указанного каталога с сайтами, а так же сразу указывал необходимые нам права доступа через umask. Позже я поясню, зачем это надо.

Находим в файле /etc/ssh/sshd_config строку и комментируем её:

#Subsystem   sftp  /usr/lib/openssh/sftp-server

Вместо неё добавляем:

Subsystem sftp internal-sftp -u 002
Match User webdev          
ChrootDirectory /var/www      
ForceCommand internal-sftp -u 002

Перезапускаем sshd:

# systemctl restart sshd

Если сейчас попробовать подключиться пользователем webdev, то ничего не получится. Особенность настройки ChrootDirectory в sshd в том, что у указанной директории владелец должен быть root, а у всех остальных не должно быть туда прав на запись. В данном случае нам это не помешает, но в некоторых ситуациях возникают неудобства. На остальных директориях внутри ChrootDirectory права доступа и владельцы могут быть любыми.

# chown root:root /var/www
# chmod 0755 /var/www

Теперь пользователь webdev может подключиться по sftp. Он сразу попадёт в директорию /var/www и не сможет из неё выйти дальше в систему. Осталось решить вопрос с правами. Я сделал так. Добавил пользователя webdev в группу www-data, а пользователя www-data в группу webdev:

# usermod -aG www-data webdev
# usermod -aG webdev www-data

Благодаря указанной umask 002 в настройках sshd все созданные пользователем webdev файлы будут иметь права 664 и каталоги 775. То есть будет полный доступ и у пользователя, и у группы. Так что веб сервер сможет нормально работать с этими файлами, и наоборот.

Способ немного корявый и в некоторых случаях может приводить к некоторым проблемам, но решаемым. Я придумал это сам по ходу дела, так как изначально к этим исходникам прямого доступа не должно было быть. Если кто-то знает, как сделать лучше, поделитесь.

Если же вы заранее планируете прямой доступ к исходникам сайта или сайтов разными людьми или сервисами, то сделать лучше по-другому. Сразу создавайте под каждый сайт отдельного системного пользователя. Запускайте под ним php-fpm пул. Для каждого сайта он будет свой. Владельцем исходников сайта делайте этого пользователя и его группу. А пользователя, под которым работает веб сервер, добавьте в группу этого пользователя. Это более удобный, практичный и безопасный способ. Я его описывал в своей статье.

Третий вариант - создавайте новых пользователей для доступа к исходникам с таким же uid, как и у веб сервера. Чрутьте их в свои домашние каталоги, а сайты им добавляйте туда же через mount bind. Я когда то давно этот способ тоже описывал в статье.

#webserver
​​Для быстрого доступа к СУБД Mysql очень удобно использовать небольшой скрипт Adminer, который представляет из себя ровно один php файл и запускается на любом хостинге. Я бы не писал о нём в очередной раз, если бы не столкнулся на днях с некоторыми нюансами при его использовании, так что решил оформить в заметку, чтобы самому потом не забыть.

С помощью Adminer можно создать пользователя и базу данных, назначить или изменить права, посмотреть содержимое таблиц, выгрузить или загрузить дамп. Лично мне для административных целей больше ничего и не надо. Разработчики, работая над сайтом, обычно просят phpmyadmin. Я не очень его люблю, потому что он монструозный, для него надо ставить дополнительные расширения php, поддерживать это дело.

Если я пользуюсь сам, то обычно просто закидываю adminer на сайт, делаю, что мне надо и потом сразу удаляю. В этот раз решил оставить на некоторое время и закрыть через basic_auth в Nginx (на самом деле в Angie). Вроде бы нет ничего проще:

# wget https://github.com/vrana/adminer/releases/download/v4.8.1/adminer-4.8.1-mysql-en.php
# mv adminer-4.8.1-mysql-en.php /var/www/html/adminer.php

Закрываем паролем. Создаём файл с учёткой:

# htpasswd -c /etc/nginx/.htpasswd admineruser21

Добавляем в Nginx:

location /adminer.php {
auth_basic "Administrator’s Area";
  auth_basic_user_file /etc/nginx/.htpasswd;
}

Перезапускаю Nginx, проверяю. Пароль не спрашивает, доступ прямой. Всё внимательно проверяю, ошибок нет. Я 100 раз это проделывал. Тут нет никаких нюансов. Но не работает.

Быстро догадался, в чём тут дело. В Nginx есть определённые правила обработки locations. Я с этой темой когда-то разбирался подробно и кое-что в памяти осело. Ниже для php файлов уже есть location:

location ~ \.php$ {
....
}

Он с регулярным выражением, поэтому обрабатывается раньше и при первом же совпадении поиск прекращается. Так что до моего location с паролем очередь просто не доходит. Сделать надо так:

location ~ adminer.php {
  auth_basic "Administrator’s Area";
  auth_basic_user_file /etc/nginx/.htpasswd;
.......................  
}

Тут надо указать все те же настройки, что у вас стоят для всех остальных php файлов в location ~ \.php$. И расположить location с adminer выше location для остальных php файлов. Это важно, так как судя по документации:

Затем nginx проверяет location’ы, заданные регулярными выражениями, в порядке их следования в конфигурационном файле. При первом же совпадении поиск прекращается и nginx использует совпавший location.

Вообще, это очень важная тема, так как сильно влияет на безопасность и многие другие вещи. Есть проект сложный с множеством locations, надо очень аккуратно их описывать и располагать в конфигурационном файле.

#webserver #nginx #mysql
​​Ранее рассказывал о том, как можно выпустить самоподписанный сертификат, установить его в веб сервер и настроить доверие. В комментариях были замечания, что это неудобно делать вручную для многих серверов. То решение было описано для одного сервера. Ниже рассмотрю вариант, как решить эту же задачу, только для всей внутренней инфраструктуры.

Речь пойдёт про open source центр сертификации от компании SmallStep - step-ca. Его можно развернуть у себя и использовать для различных задач. Я расскажу на примере получения HTTPS-сертификатов X.509 для локальных веб ресурсов с помощью протокола ACME и одноимённой утилиты. Помимо этого на базе step-ca можно организовать:
выдачу SSH-сертификатов для пользователей
выпуск токенов единого входа OAuth OIDC
выпуск клиентских сертификатов X.509 для TLS аутентификации
Всё это описано в документации и в рамках заметки не раскрыть.

Установка step-ca описана в документации. Выглядит она относительно просто, так как есть готовые пакеты. А относительно, потому что юнит systemd и рабочие каталоги придётся делать вручную.

Вот инструкция для установки на Debian/Ubuntu:

# wget https://dl.smallstep.com/cli/docs-ca-install/latest/step-cli_amd64.deb
# dpkg -i step-cli_amd64.deb

# wget https://dl.smallstep.com/certificates/docs-ca-install/latest/step-ca_amd64.deb
# dpkg -i step-ca_amd64.deb

После установки делаем начальную настройку, но перед этим выполним ручную инициализацию. Покажу свои ответы на вопросы в тестовой среде, чтобы вам не гадать, что там отвечать. Хотя по смыслу понятно.

# step-cli ca init
Deployment Type: Standalone
(e.g. Smallstep): PrivateCA (можно любое имя использовать)
(e.g. :443 or 127.0.0.1:443): :443
(e.g. you@smallstep.com): zeroxzed@gmail.com
[leave empty and we'll generate one]:
Password: E}b;-9DU9UyАВ8TU7$FINl-T8OM

Теперь переносим настройки в /etc/step-ca и запускаем как службу.

# useradd --user-group --system --home /etc/step-ca --shell /bin/false step
# setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)
# mkdir /etc/step-ca
# mv $(step path)/* /etc/step-ca

# touch /etc/step-ca/password.txt
# chmod 600 /etc/step-ca/password.txt
# mcedit /etc/step-ca/password.txt
# chown -R step:step /etc/step-ca

В файл password.txt записываем пароль от CA, который был создан во время инициализации. В файлах /etc/step-ca/config/ca.json и defaults.json меняем все пути с /root/.step на /etc/step-ca. И создаём юнит для systemd:

# mcedit /etc/systemd/system/step-ca.service

Содержимое не привожу, оно длинное, в заметку не уместится. Взял 1 в 1 из документации, он же в репозитории.

# systemctl daemon-reload
# systemctl enable --now step-ca

Служба должна запуститься на порту 443. Можно браузером зайти. Там будет страница с ошибкой, потому что никакого веб интерфейса нет, но тем не менее будет видно, что сервис работает.

Сразу отмечу важный нюанс. По умолчанию step-ca выпускает сертификаты на 24 часа. Для каких-то задач это, наверное, нормально, но для веб серверов не вижу смысла перевыпускать так часто, даже с учётом того, что это автоматизировано. Можете оставить так, а можете увеличить время. Тут об этом рассказано в доках.

Активируем ACME провизионер в step-ca:

# step ca provisioner add acme --type ACME

Эта команда добавит некоторые настройки в ca.json. Перезапускаем службу:

# systemctl restart step-ca

Теперь можно брать acme.sh или любой другой клиент (certbot и т.д.) и настраивать выпуск сертификатов через свой CA. Для этого надо либо на клиентских системах добавить root_ca.crt в системные, либо при запуске клиента указывать явно:

acme.sh --issue --standalone -d debian12-vm \
    --server https://10.20.1.36/acme/acme/directory \
    --ca-bundle ~/certs/root_ca.crt \
    --fullchain-file debian12-vm.crt \
    --key-file debian12-vm.key

Работаем с этим CA так же, как и с другими: добавляем серты в веб сервера, настраиваем автообновление. И не забываем в клиентские машины добавить CA в доверенные, чтобы в браузерах не было предупреждения.

#security #webserver
Небезызвестный Василий Озеров открыл свой youtube канал (вовремя, как раз к блокировке ютуба) и выложил первое видео. Для тех, кто не знает, поясню. Василий - сооснователь школы Rebrain, рекламу которой вы тут периодически видите, и аутсорс компании Fevlake.

Ролик получился очень информативным, наглядным, нескучным, хоть и длинным - 50 минут. Я посмотрел его весь без перемотки и не в режиме только прослушивания. Большую часть того, что услышал, знал, но не всё. Почерпнул для себя новую информацию.

▶️ Разбор TLS параметров в Nginx: Подробная инструкция по настройке TLS

Для тех, у кого нет желания или времени всё смотреть, напишу несколько основных моментов, которые будут полезны даже в таком формате.

📌 Замена TLS 1.2 на TLS 1.3 даёт уменьшение времени отклика веб сервера. Тест Василия показал уменьшение со 170 мс до 130 мс только из-за смены версии протокола. Это связано с более быстрой инициализацией подключения клиента к серверу.

📌 Сертификат сервера, основанный на протоколе ECDSA, уменьшает при прочих равных условиях нагрузку на CPU сервера в сравнении с RSA где-то на 20-25%. Это связано с гораздо меньшей длиной сертификатов ECDSA.

📌 В конфигурацию Nginx можно добавить оба сертификата: ECDSA и RSA. Это обеспечит поддержку всех клиентов, и новых, и сильно старых, которые ECDSA не поддерживают.

📌 Если у вас только один веб сервер, то нет необходимости включать ssl_session_tickets, достаточно только ssl_session. Тикеты нужны, когда клиенту могут отвечать разные веб сервера с одинаковыми приватными ключами.

Очень подробно эти и некоторые другие моменты разобраны в видео. Рекомендую к просмотру. Реально полезная база, актуальная для любых сервисов, где используется TLS. Ну и не забывайте про лайк и подписку на канал, чтобы у Василия была мотивация записывать больше роликов. Видно, что для этого проделана большая работа.

#nginx #webserver
Если хотите быстро потестировать настройки веб сервера на предмет ограничения числа одновременных соединений в Nginx совместно с баном Fail2Ban, могу предложить готовый публичный сервис:

https://loadest.nodes-studio.com

Он вообще платный, причём принимает оплату в Bitcoin, что сразу вызывает подозрение. Так выглядят платные панели управления для ддоса. Подобных сервисов много и они не особо шифруются, а представляют себя как услуги по тестированию сайтов.

Этот сервис даёт небольшой тестовый баланс, который позволяет побомбить запросами какой-то сайт. Причём любой. Достаточно указать его адрес с главной страницы и свою почту (не проверяется), на которую будет зарегистрирован личный кабинет. В нём сразу же начнётся тест по нагрузке сайта.

Я толком не понял, с какой интенсивностью происходит тестирование, так как у меня все IP адреса сервиса улетели в бан за превышение лимита в 30 запросов в секунду с одного IP. Отработала настройка Nginx:

limit_req_zone $binary_remote_addr zone=lim_20r:10m rate=20r/s;

И фильтр Fail2Ban на записи о превышении этого лимита в лог файле nginx error.log с соответствующей строкой:

limiting requests, excess: 30.080 by zone "lim_20r", client: 194.87.110.21

Забанил IP адреса в соответствии вот с этим правилом:

[Definition]
ngx_limit_req_zones = [^"]+
failregex = ^\s*\[[a-z]+\] \d+#\d+: \*\d+ limiting requests, excess: [\d\.]+ by zone "(?:%(ngx_limit_req_zones)s)", client: <HOST>,
ignoreregex =.
datepattern = {^LN-BEG}

Не рассказываю подробно о настройке Fail2Ban, так как заметка не про него, а про сервис. Мне понравилось, что без лишних телодвижений запустил тестирование с посторонних IP. Мой указанный почтовый ящик, кстати, был указан в referrer запросов от сервиса:

referer=http://loadest.io user_agent="<username@gmail.com> via http://loadest.io"

Сервис, судя по всему, российский. Посмотрел заголовки писем, которые он шлёт. Там почтовый сервер из зоны .ru используется. И бомбил он меня российскими IP адресами.

#нагрузочное_тестирование #webserver

🦖 Selectel — дешёвые и не очень дедики с аукционом!
Please open Telegram to view this post
VIEW IN TELEGRAM
Заметил по статистике, что один сайт стали донимать какие-то роботы сканированием несуществующих страниц. В статистике 404 ошибок стало существенно больше, чем 200-х ответов. Я обычно не практикую блокировку по этому признаку, так как можно словить неявные проблемы от каких-нибудь поисковиков или других легитимных пользователей. В этот раз решил сделать исключение.

С помощью fail2ban нетрудно выполнить блокировку. Не буду подробно рассказывать про настройку fail2ban, так как это не тема заметки. Покажу, как я забанил тех, от кого сыпется много 404 кодов ответа веб сервера.

Для начала создаём правило фильтрации в директории /etc/fail2ban/filter.d. Назвал его nginx-4xx.conf:

[Definition]
#failregex = ^<HOST>.*"(GET|POST).*" (404|429) .*$
failregex = ^<HOST>.*"(GET|POST).*" *.* (status=404|status=429) .*$
ignoreregex =

Закомментированная строка подойдёт для стандартного формата логов Nginx или Apache. Вторая для моего изменённого. Я обычно использую свой формат, если собираю логи в ELK и анализирую. У меня есть набор готовых grok фильтров для этого. Вот мой модернизированный формат логов:

log_format full '$remote_addr - $host [$time_local] "$request" '
  'request_length=$request_length '
  'status=$status bytes_sent=$bytes_sent '
  'body_bytes_sent=$body_bytes_sent '
  'referer=$http_referer '
  'user_agent="$http_user_agent" '
  'upstream_status=$upstream_status '
  'request_time=$request_time '
  'upstream_response_time=$upstream_response_time '
  'upstream_connect_time=$upstream_connect_time '
  'upstream_header_time=$upstream_header_time';

Соответственно, получаем вот такую запись в логе:

178.218.43.55 - site01.ru [01/Oct/2024:13:46:24 +0300] "GET /about HTTP/2.0" request_length=123 status=200 bytes_sent=489 body_bytes_sent=8 referer=https://site01.ru/ user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101" upstream_status=200 request_time=0.075 upstream_response_time=0.069 upstream_connect_time=0.000 upstream_header_time=0.069

Для тех, кто использует logstash, покажу grok фильтр для этого формата. Он позволяет анализировать некоторые метрики и выводить их на графики и дашборды. Даю для справки без объяснений, так как это отдельная большая тема.

%{IPORHOST:remote_ip} - %{DATA:virt_host} \[%{HTTPDATE:access_time}\] \"%{WORD:http_method} %{DATA:url} HTTP/%{NUMBER:http_version}\" request_length=%{INT:request_length} status=%{INT:status} bytes_sent=%{INT:bytes_sent} body_bytes_sent=%{NUMBER:body_bytes_sent} referer=%{DATA:referer} user_agent=\"%{DATA:user_agent}\" upstream_status=%{DATA:upstream_status} request_time=%{NUMBER:request_time} upstream_response_time=%{DATA:upstream_response_time} upstream_connect_time=%{DATA:upstream_connect_time} upstream_header_time=%{DATA:upstream_header_time}

Приведённая в nginx-4xx.conf регулярка находит 404 и 429 ответы в таком логе. Я не силён в написании регулярок, поэтому хз, правильно составил или нет, но на практике работает. В составлении регулярок помогают вот эти сервисы:

https://regex101.com/
https://regexper.com/

Постоянно ими пользуюсь. Вот тут была хорошая подборка по этой теме. Дальше создаём файл настроек блокировки в /etc/fail2ban/jail.d, назвал его так же nginx-4xx.conf:

[nginx-4xx]
enabled = true
filter = nginx-4xx
port = http,https
action = iptables-multiport[name=Nginx404, port="http,https", protocol=tcp]
logpath = /web/sites/*/logs/access.log
maxretry = 30
findtime = 10m
bantime = 30m

Баню на 30 минут тех, кто за последние 10 минут получил 30 раз 404 ответ. На мой взгляд это достаточно мягкое условие, которое отсечёт явных ботов, но не тронет легитимных пользователей.

Если кто-то тоже банит по признаку 404 ответа, поделитесь опытом, как это лучше делать и к каким проблемам может привести. Я немного понаблюдал, вроде никто лишний не попадается на это правило.

#fail2ban #webserver
Одной из обязательных настроек, которую делаю на новом сервере, касается ротации текстовых логов. Несмотря на то, что их активно заменяют бинарные логи systemd, я предпочитаю возвращать текстовые логи syslog. Для этого на чистый сервер устанавливаю rsyslog:

# apt install rsyslog

Далее выполняю некоторые настройки, которые относятся к ротации логов с помощью logrotate. В первую очередь в фале /etc/logrotate.conf включаю параметр:

dateext

Он нужен, чтобы в имени файла была указана дата, когда лог-файл был ротирован. С этой настройкой связан один очень важный момент, если вы хотите ротировать логи чаще, чем раз в сутки. По умолчанию logrotate во время ротации лога с этой настройкой переименовывает текущий лог файл, назначая ему имя вида access.log.20241001.gz. То есть в имени файла будет указан текущий день. Второй раз в этот день ротация закончится ошибкой, так как logrotate скажет, что не могу переименовать лог, так как файл с таким именем уже существует. Для тех логов, что точно будут ротироваться чаще, чем раз в сутки, нужно обязательно добавить параметр:

dateformat -%Y-%m-%d_%H-%s

В таком случае каждое имя файла будет уникальным и проблем не возникнет.

Далее в обязательном порядке нужно настроить запуск logrotate чаще, чем раз в сутки. По умолчанию в Debian запуск logrotate настроен в /etc/cron.daily и запускается не чаще раза в сутки. Я обычно просто добавляю запуск в /etc/crontab каждые 5 минут:

*/5 * * * * root logrotate /etc/logrotate.conf

Эти настройки особенно актуальны для веб серверов, где очень быстро могут разрастись лог файлы.

Все возможные настройки файлов logrotate можно почитать в man. Там довольно подробно всё описано. Если не хочется читать man, можно воспользоваться простым конфигуратором:

🌐 https://scoin.github.io/logrotate-tool

Там наглядно перечислены настройки с описанием. Можно мышкой потыкать и посмотреть, как меняется конфигурационный файл. Вот пример моего файла ротации логов веб сервера:

/web/sites/*/logs/*.log {
  create 644 angie webuser
  size=50M
  dateext
  dateformat -%Y-%m-%d_%H-%s
  missingok
  rotate 30
  compress
  notifempty
  sharedscripts
  postrotate
if [ -f /run/angie.pid ]; then
kill -USR1 $(cat /run/angie.pid)
fi
  endscript
}

Маска /web/sites/*/logs/*.log захватывает все виртуальные хосты веб сервера, где логи располагаются в директориях:

◽️/web/sites/site01.ru/logs/
◽️/web/sites/site02.ru/logs/
и т.д.

Когда будете настраивать ротацию логов, проверяйте, чтобы у службы, для которой управляем логами, в итоге оказался доступ к этим логам. Я иногда ошибаюсь и потом приходится разбираться, почему после ротации логи нулевого размера. Это актуально, когда логи куда-то выносятся из /var/log и отдельно настраиваются права, например, для того, чтобы какие-то пользователи имели к ним доступ, к примеру, только на чтение.

#linux #logs #logrotate #webserver
Please open Telegram to view this post
VIEW IN TELEGRAM
Немного информации для тех, кто имеет дело с обычными веб серверами под php сайты. Вчера провозился несколько часов с одним сайтом, который передали разработчики для публикации. Причём провозился из-за ерунды. Это был немного навороченный мультиязычный сайт на базе Wordpress, но с полностью самописной темой.

Я этих вордпрессов десятки устанавливал и поддерживал. Никак не ожидал проблем с этим движком. Но разработчики сумели меня удивить и нагрузить работой. Для начала пришлось повозиться с тем, что режим работы сайта http или https был жёстко зашит в коде сайта. И не где-то в настройках Wordpress или базе, а в коде темы. Это создавало некоторые проблемы при публикации за Cloudflare и Nginx в режиме proxy_pass. Пока всё развернул, разобрался, нашёл и вычистил в коде, немного подустал. Плюс, сайт под Apache разрабатывали, запустил под Nginx.

В итоге на сайте кое-где всплывали ошибки php, что-то не работало. В логе тоже ошибки и предупреждения со стороны php. Причём ошибки какие-то странные, типа скобки не закрыты, переменная не объявлена и т.д. Сначала подумал, что сайт написали под старую версию php. На веб сервере стояла относительно свежая 8.2. Уточнил у разработчиков, у них на 8.1 нормально работает. Разница в этих версиях не такая большая, должно нормально работать. Потом подумал, что по ошибке скинули какой-то черновик, а не итоговую работу.

Немного поразбирался в ошибках и выяснил, в чём проблема. В php по умолчанию параметр short_open_tag выключен. Это нормальная история, так как стандартному коду Wordpress он не нужен. Мне и в голову не пришло его включить. В версиях php до 6-й он был включен, потом стали отключать из соображений совместимости с другим кодом. Например, с тэгами <?xml.

В коде этого сайта были конструкции типа <? вместо <?php, а для их корректной работы как раз и нужен параметр short_open_tag. Есть проекты, где явно пишут, что надо включить этот параметр. А тут мне никто ни слова насчёт него не сказал. Включил параметр и всё заработало.

Если где-то придётся писать код php, то пишите сразу полные тэги <?php, а не короткие. Сейчас это более правильный подход, который улучшает переносимость проекта и не вызывает проблем с совместимостью с другим кодом, который использует тэги. Вот наглядный пример, где будут проблемы с короткими тэгами:

<?xml version="1.0"?>

Это элемент xml разметки, а с включённым short_open_tag это будет интерпретироваться как php код.

#webserver #php
Если обратиться к веб серверу на базе Nginx по IP адресу, то увидите либо первый виртуальных хост в конфигурации, либо тот, где указана директива default в параметре listen. Показывать виртуальный хост не очень хочется, поэтому обычно на IP адрес ставят какую-то заглушку. Например, так:

server {
    listen 80 default_server;
    server_name _;
    return 404;
}

С 80-м портом и протоколом HTTP проблем обычно нет. А вот с HTTPS есть нюансы, так как нам нужно использовать сертификат. Доверенный сертификат на IP адрес получить нельзя. По крайней мере я не знаю, как это сделать. Если сертификат не указать, то будет использован сертификат первого в конфигурации виртуального хоста, где он указан. То есть если сделать вот так:

server {
    listen 443 ssl default_server;
    server_name _;
    return 404;
}

То пользователь, который зайдёт по IP адресу на сервер, увидит сначала предупреждение о том, что имя домена в сертификате не соответствует домену в адресной строке браузера. А когда согласится перейти по адресу, в свойствах сертификата можно будет увидеть адрес виртуального домена, сертификат которого использован.

Можно выйти из этой ситуации, выпустив самоподписанный сертификат-пустышку, не заполняя там вообще никаких полей:

# openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /etc/nginx/certs/nginx.key -out /etc/nginx/certs/nginx.crt

Используем его:

server {
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate /etc/nginx/certs/nginx.crt;
    ssl_certificate_key /etc/nginx/certs/nginx.key;
    return 404;
}

Больше мы домены не светим, но пользователь по прежнему видит предупреждение о сертификате, что тоже не очень красиво. Хотя в целом можно оставить и так. Я всегда так и делал. А недавно увидел новое для себя решение этой же проблемы, чтобы пользователю показать сразу ошибку, без всяких предупреждений. Выглядит это вот так. Показываю сразу итоговый вариант:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 404;
}

Объединил для удобства оба протокола. Ключевой момент тут в настройке ssl_reject_handshake on. Когда она включена, веб сервер отклоняет все попытки соединения, где адрес сервера не совпадает с тем, что указано в директиве server_name. Тут у нас в этой директиве _, так что все соединения будут сразу отклоняться. Пользователь сразу увидит ошибку без необходимости выполнять какие-либо действия.

Не увидел тут никаких подводных камней. Взял на вооружение, обновил свой стандартный конфиг default.conf для подобных настроек.

❗️Если заметка вам полезна, не забудьте 👍 и забрать в закладки.

#nginx #webserver #angie
Небольшое предупреждение для тех, кто администрирует сайты и получает на них Abuse от РКН. Если на сайтах открыта регистрация пользователей и есть возможность публиковать текст, то это только вопрос времени, когда вы получите требование удалить ту или иную информацию, нарушающую закон. Боты или реальные люди будут пытаться оставить ссылку на запрещёнку везде, где это возможно: комментарии, отзывы, сообщения на форуме, поля для комментариев в профиле и т.д.

Уведомления приходят сначала провайдерам, а они уже уведомляют владельцев сайтов. Даются сутки на удаление противозаконной информации. Вот точная информация на этот счёт:

Провайдер хостинга или иное лицо, обеспечивающее размещение информационного ресурса в сети «Интернет» (далее – иное лицо, разместившее информационный ресурс), с момента получения настоящего уведомления обязаны:
- незамедлительно проинформировать владельца информационного ресурса о необходимости незамедлительного удаления распространяемой с нарушением закона информации;
- по истечении суток ограничить доступ к информационному ресурсу в случае отказа или бездействия владельца информационного ресурса в удалении распространяемой с нарушением закона информации. 

В сообщении от провайдера обычно в тикете указана вся необходимая информация. Я просто иду и удаляю то, что там указано. Когда удалю, пишу провайдеру, что сделал это. На этом всё, больше ничего не предпринимаю. К тикету прикладывается исходное уведомление от РКН, которое я обычно не читаю, так как там всё то же самое, только канцелярским языком.

На днях получил подобное уведомление. Информацию удалил. Решил прочитать исходный текст уведомления от РКН. А он существенно изменился в сравнении с тем, что я получал ещё в сентябре. В заявлении указан уникальный идентификатор. Используя этот идентификатор, необходимо отчитаться об удалении либо по email, либо через специальную форму на сайте 398-fz.rkn.gov.ru. В уведомлении есть ссылка с зашитой информацией об основных данных по этому уведомлению.

Если вы владелец или администратор сайта, то нельзя просто так взять и позволить пользователям без премодерации что-то публиковать. Вы должны либо в течении суток реагировать на обращения, либо включать премодерацию и удалять весь возможный противоправный контент заранее. Если быстро не отреагировать, то можно получить блокировку сайта.

❗️И ещё дам небольшой совет, который может сэкономить ваше время. В требовании может прийти ссылка как со слешом на конце, так и без. Я не знаю, кто и как её формирует, но сталкивался не раз. На веб сервере может быть не настроен редирект ссылок без слеша на слеш и наоборот. Речь вот о чём. Ссылки https://398-fz.rkn.gov.ru/toproviders/ и https://398-fz.rkn.gov.ru/toproviders по сути разные.

Вам может прийти требование, где указана ссылка без слеша на конце. Вы идёте на сайт и видите, что такой страницы нет, либо, что ещё хуже, можете увидеть вообще какую-то информацию, не относящуюся непосредственно к этому урлу. Некоторые CMS или самописные сайты могут по разному обрабатывать эти ситуации. Так что проверяйте на всякий случай оба варианта.

#webserver