Смена кодировки файлов в utf8

В поддержке legacy-кода и обновлении скритов нередко возникает задача их перекодирования в utf-8. Это хорошо выполняется стандарной утилитой iconv, вот её использование для одного файла:

iconv -f cp1251 -t utf8 orig-in-cp1251.php -o out-in-utf8.php

При этом не удастся указать одинаковое входное и выходное названия: iconv начнёт писать до получения входа и получится файл нулевой длины. В этом случае станартный вывод полезно «замочить в губке» с помощью sponge. Сделаем однострочный скрипт, который делает всё сразу, он понадобится далее (назовём его to-utf8.sh):

#!/bin/sh
/usr/bin/iconv -f cp1251 -t utf8 "$1" | sponge "$1"

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

Обычно требуется сконвертить все файлы определённого расширения в целой директории. Подключаем ещё find:

find /here-is-my-files/ -type f -iname "*.js" -exec to-utf8.sh "{}" \;

На часть файлов iconv может ругнуться в STDERR и эти файлы целесообразно проверить/перекодировать вручную.

Ещё более сложный (и достаточно частый) случай, когда есть файлы в разных кодировках и их необходимо перевести в одну. iconv в этом случае может сконвертировать ещё раз и испортить файл. То есть, нужно распознать исходную кодировку и рекодить только «не те» файлы.

Тогда помогает самый лучший вариант: утилиты enca/enconv. Из них первая только распознаёт кодировку, а вторая ещё и перекодирует.Интерфейс enconv до безобразия простой: в случае одного параметра она перекодирует файл из исходной (ЛЮБОЙ распознанной!) кодировки в ту, что указана в locale. Кодировку можно указать явно, тогда вся задача решается одной строкой

find /here-is-my-files/ -type f -iname "*.js" -exec enca "{}" \;

Для улучшения точности язык также можно «подсказать», с помощью параметра (-L ru).

Последний, enca-способ, похоже самый оптимальный для большинства задач.

Копирование с сохранением жёстких ссылок

Ранее я описывал отличную схему инкрементных резервных копий, основанную на использовании жёстких ссылок. Схема позволяет хорошо сохранять место на разделе для бэкапов и на уровне приложений резервные копии видны полностью. Обратной стороной такого удобства является сложность переноса таких бэкапов с одного раздел на другой в случаях, когда это потребуется, например, при физической смене жёстких дисков или рейда для резервирования. Стандартные утилиты вроде cp воспринимают всю директорию с бэкапами как «нормальную» директорию и копируют полностью, что в результате даёт копию большого, примерно n*[размер одного бэкапа] размера. Кроме объёма, такое копирование занимает огромное количество времени.

Как скопировать быстро и сохранением симлинков? Задача, оказывается, хорошо решается всё той же проверенной утилитой rsync, которая может работать как локально, так и удалённо. При запуске ее с ключами:

rsync -aH /src-path /dst-path

она выполняет в точности, что и требуется.

Наиболее оптимальным набором параметров для локальных копий показал себя следующий

rsync -aH --delete --numeric-ids /src-path /dst-path

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

Естественно, утилита может копировать и по сети, что делает способ ещё более удобным, особенно со сжатием (-z).

nginx HTTP/2

Отлично! В энжинксе сделали полноценную поддержку http2, а если точнее, то заменили SPDY на HTTP/2. Поддержка есть в последних версиях (>=1.9.5), проверяем

$ nginx -V

и если в ответе есть --with-http_v2_module, то можно включать. Включается, как и все в nginx, очень просто — дописываем в конфигурации SSL:

listen 443 ssl http2;

или меняем spdy, если оно там стояло ранее.

PS: Если поддержка https на вашем сайте не настроена, то скорее настраиваем.

Копирование пользователей и прав MySQL

В ряде случаев бывает необходимо скопировать пользователей и их права (привилегии) на другой сервер БД. Типичная ситуация, когда это требуется — подготовка чистого сервера БД в качестве реплики, при этом пользователи берутся с мастера. Гугл предлагает готовым решением Percona Toolkit, однако, это дополнительно устанавливаемый софт, попробуем обойтись без него. Для этого скрипт, который вытягивает пользователей из базы-источника и формирует sql-файл для импорта.

#!/bin/sh
mysql -e"SELECT DISTINCT CONCAT('SHOW GRANTS FOR ', '\'', user, '\'@\'', host, '\';') AS QUERY FROM mysql.user" | sed '1d' | while read query; do
	mysql -e"$query" | sed '1d' | awk '{print $0";"}'
done
echo -e "FLUSH PRIVILEGES;\n";

На выходе получится sql-код для исполнения на слейве. Естественно, по файлу стоит пройтись вручную и удалить пользователей, которых добавлять не надо.

/etc/network/if-up.d/ в CentOS

На Debian-based операционках есть очень удобная директория /etc/network/if-up.d/, в которой находятся скрипты, запускаемые системой при интерфейса. В CentOS и других RHEL-based системах подход директорий conf.d не такой популярный и запуск скриптов после поднятия интерфейса реализован по другом. А именно, внимательным глазом в конце скрипта /etc/sysconfig/network-scripts/ifup-post можно обнаружить строки:

if [ -x /sbin/ifup-local ]; then
     /sbin/ifup-local ${DEVICE}
fi

Таким образом, если создать файл /sbin/ifup-local, в него можно прописать собственный firewall или что-то иное, необходимое в сети. Можно (и обычно удобнее) пойти и дальше, и запускать из этого скрипта готовые стандартные скрипты:

test -x /usr/local/bin/fw && /usr/local/bin/fw
test -x /usr/local/bin/fw6 && /usr/local/bin/fw6

Так можно реализовать в центе модульность, которой изначально нет.

hubbed_hosts в exim4

Иногда настраиваемый сервер имеет FQDN имя, которое им обрабатываться не должно, но именоваться он должен именно так. В тривиальной настройке exim будет трактовать почту на этот домен локальной и складывать в /var/mail или подобную директорию для локальной почты. Чтобы домен и соответствующая почта не считалась локальной можно это явно прописать в /etc/exim4/hubbed_hosts, например

example.com:  mx.example.com

Ошибка Munin INDIVIDUAL BUFFER POOL INFO

При обновлении MySQL от версии 5.6 его показатели не читаются мунином. В логах появляется ошибка:

Unknown section: INDIVIDUAL BUFFER POOL INFO at /etc/munin/plugins/mysql_innodb_rows line 1098.

Ошибка возникает в результате того, что мунин не распознает новую секцию (INDIVIDUAL BUFFER POOL INFO) в ответе СУБД. Наикратчайший (однако, не лучший) путь вылечить — отключить эту секцию. Для этого в скрипте, который парсит параметры БД /usr/share/munin/plugins/mysql_, находим немного перед 1098 строчкой определение секции

my %section_map = (

и добавляем в самом начале этой секции

'INDIVIDUAL BUFFER POOL INFO' => \&skip,

Проверить корректность запуска можно munin-run на любом из собирающих скриптов. Например:

cd /etc/munin/plugins
munin-run mysql_innodb_rows

Reboot

Иногда Linux отказывается перезагружаться стандартными коммандами. Тогда бывает полезным следующий низкоуровневый способ с помощью механизма SysRq. Для ребута комманда такая:

echo b >/proc/sysrq-trigger

Если команда не проходит сразу, то возможность использования Magic SysRq надо включить

echo 1 > /proc/sys/kernel/sysrq

Также есть полезные для размонтирования ФС (u) и синхронизации дисков (s), которые можно сделать до ребута.

Конфигурация пакетов через dialog

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

apt-get install dialog

No irq handler for vector (irq -1)

После обновления линуксового ядра с очень старого дистрибутива Debian на 3.16.xxxx в jessie иногда вылазит следующая ошибка

No irq handler for vector (irq -1)

Решается использованием опций pci=nomsi,noaer при загрузке ядра. Чтобы опции использовались постоянно целесообразно их прописать в /etc/default/grub:

GRUB_CMDLINE_LINUX="pci=nomsi,noaer"

Без правки системы загрузки также помогает остановка демона irqbalance

/etc/init.d/irqbalance stop

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

Типовая настройка DMARC

Что есть DMARC

DMARC это очередной механизм защиты от спама и от несанкционированной рассылки почты с домена. Этот механизм используется для:

  • Информирования почтового сервера получателя о наличии записей DKIM, SPF и их использовании. Частично эта же задача решается ADSP и самим SPF, однако DMARC позволяет охватить оба;
  • Рекомендации почтовому серверу получателя об обработке почты с невалидными DKIM и SPF;
  • Получения обратной связи от серверов получаетелей в формате RFC 5969 и RFC 5070, которые позволяют, в частности, узнать о несанкционированной рассылке с домена.

Как работает DMARC

В DNS-зоне домена создается TXT-запись _dmarc, в которой прописываются его параметры. При доставке почты с домена получающий почтовый сервер использует значения параметров этой записи для обработки полученного письма. Типичный пример записи строится следующим образом:

$ORIGIN example.com.
_dmarc     IN    TXT "tag_0=value_0;tag_1=value_1;...tag_N=value_N"

Текст состоит из пар «переменная=значение» с разделителем «;».

Основные параметры DMARC-записи

Параметров DMARC много и все их можно найти в официальной конфигурации. Ниже наиболее важные.

  • v=, версия. Этот параметр обязательный и должен быть первым со значением DMARC1.
  • p=, policy. Обязательный параметр, который должен быть на втором месте. Рекомендуемые действия MTA получателя для невалидной почты. Возможные значения: none — нет рекомендации почтовику; quarantine — предлагает считать получающему MTA почту с невалидными SPF и DKIM подозрительной и проводить дополнительные проверки; reject — рекомендует отклонять любую почту с невалидными SPF/DKIM.
  • sp=, policy для субдоменов. Опциональный параметр и имеет те же значения, что и p.
  • adkim=, опциональный параметр, в значении s (strict) требует совпадения домена в параметре d= DKIM и отправителя. В r (relaxed, по умолчанию) разрешает использование субдоменов. То есть, почта с user@sub.example.com будет валидной при adkim=r и невалидной при adkim=s.
  • aspf=, опциональный параметр, со значениями s (strict) и r (relaxed, по умолчанию) для SPF, требующий совпадения ответа команды MAIL FROM и заголовка From письма. r разрешает субдомены.
  • pct=, опциональный параметр, доля обрабатываемых DMARC писем. По умолчанию 100 (100 %), и может быть снижена для отладочных целей.
  • fo=, fail policy, опциональный с значением по умолчанию fo=0. В значении 0, отсылает обратный отчёт если все проверки невалидны (DKIM, SPF); в значении 1 — если какая-либо из проверок не валидна. Также возможны значения s и d, соответственно для отчетов по DKIM и SPF.
  • ri=, опциональный, время между отчетами. По умолчанию сутки, т.е. 86400 секунд.
  • rua=, опциональный, список почтовых адресов через запятую, на которые высылать агрегированные отчеты. Если адрес находится в том же домене, работает без дополнительных настроек.
  • ruf=, опциональный, список почтовых адресов через запятую, на которые высылать fail-отчеты (о невалидной почте). Если адрес находится в том же домене, работает без дополнительных настроек.

Типовые конфигурации записей DMARC

С домена отправляется почта, мягкий вариант

Мягкий вариант DMARC-записи не указывает какой-либо явной политики (policy) принимающему почтовому агенту (MTA), что делать с нелегитимной почтой. Принимающий почтовый сервер действует в соответствии со своими настройками и обычно такая почта достигает ящика отправителя. Пример записи, с получением обоих типов отчетов (aggregated & fail):

_dmarc   TXT "v=DMARC1;p=none;fo=1;rua=mailto:admin@example.com;ruf=mailto:admin@example.com"

Этот вариант годится, когда почта потенциально может отправляться с серверов, не прописанных в SPF, или, если допускается отправка неподписанной DKIM почты.

С домена отправляется почта, строгий вариант

В более жестком варианте принимающему серверу рекомендуется отклонять сообщения, не прошедшие проверку DKIM или SPF. Это наиболее типичный вариант настройки дмарка и его имеет смысл использовать если вся исходящая почта валидна по SPF и корректно подписывается DKIM

_dmarc   TXT "v=DMARC1;p=reject;sp=reject;pct=100;aspf=r;fo=1;rua=mailto:admin@example.com;ruf=mailto:admin@example.com"

С домена не отправляется почта вообще

На домене чаще не бывает почты, чем бывает. Такие «беспочтовые» домены лучше сразу настроить, чтобы сторонние сервисы воспринимали почту с них как спам. Ниже пример DMARC-записи в DNS, запрещающей отсылку почты с домена.

_dmarc   TXT "v=DMARC1; p=reject; sp=reject; pct=100; aspf=s"

Естественно, SPF-запись тоже должна быть настроена, в наиболее коротком виде:

@        TXT "v=spf1 -all"

Дополнительно

Полную документацию по DMARC можно получить на их официальном сайте и RFC.
Проверить DMARC-запись вашего домена можно, например, с помощью этого сервиса.

Быстрый анализ производительности Linux-сервера

Производительность — один из наиболее заметных параметров системы. Именно на её недостаток чаще всего жалуются пользователи. Ниже приведены некоторые элементарные способы по анализу производительности системы.

Часто ошибочно считает, что поднять скорость системы можно хорошо «оптимизировав» конфиги. Это редко бывает так. Оригинальные стоковые конфиги репозиторного софта подходят для решения многих задач. Их можно (и нужно) менять для достижения задач конкретного проекта. Естественно, все изменения следует сопровождать тестами производительности, а для этого должны быть соответствующие методики и инструменты.

Прежде чем что-то пытаться менять в конфигурации необходимо найти проблемные (узкие) места в системе. В общем случае методика исследования следующая:

  • Собирайте и анализируйте статистические данные о работе системы. На минимальном уровне это решается различными системами мониторинга, например, munin, Zabbix. В более продвинутом случае — свои плагины к этим системам мониторинга или собственные скрипты. Если пару дней назад всё работало отлично, а сейчас какие-то «тормоза» — мониторинг поможет установить их источник. Кроме этого, мониторинг позволяет обнаружить еще не проявившиеся проблемы, когда используемые ресурсы системы исчерпываются.
  • Журналируйте собственные изменения конфигурации. И сравнивайте динамику производительности (по собранным статистическим данным) до включения новой конфигурации и после нее. Это поможет узнать, какие изменения действительно эффективны, а какие бесполезны или даже вредны. Также, журналирование позволит оперативно обнаружить медленный код в бизнес-приложениях.
  • Не перегружайте систему. На небольших нагрузках кажется, что ресурсов системы очень и очень достаточно впрок. Однако, это не так. Когда загрузка какого-либо из ключевых параметов системы подходит к 100% (это может быть, например, загрузка ЦП, или ввода-вывода или даже наличие свободного места на дисках), «тормоза» системы возрастают нелинейно. В том числе это происходит из-за «накладных расходов», т.е. ресурсов системы не расходуемых на определённые процессы, а теряемые в процессе работы ОС и переключения задач.

Процессорное время (CPU)

Load average легко собираются любым мониторингом круглосуточно и его необходимо анализировать. Максимальное значение LA (в часы наибольшей нагрузки) не должно превосходить возможностей системы, т.е. количества её ядер CPU. В противном случае неизбежно замедление работы приложений, причем с увеличением LA выше возможностей системы будут возрастать потери на переключении контекста.

Когда LA достаточно высок имеет смысл посмотреть на что именно расходуются ресурсы процессора. Простейший способ это сделать — посмотреть процессы с наибольшим процессорным временем (TIME) в выводе утилит top, htop или ps aux. Далее уже пытаться снизить нагрузку именно на этом звене.

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

В тех же top и htop следует обратить внимание на процессы в состоянии D, которое обычно соответствует ожиданию ввода-вывода процесса, а также на заполнение свопа. Но об этом ниже.

Коротко (для скриптов мониторинга) значение LA можно взять из параметров системы:

cat /proc/loadavg

Вручную — легче в top и htop.

Характеристики использования процессорного времени отображается также командой vmstat:

$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0   7596 329216  13260 14506756    0    0  4625    26   42  145  4  1 81 13  0

vmstat принимает 2 аргумента: время в секундах, в течение которого необходимо наблюдать за системой, и количество генерируемых отчетов. Эту утилиту полезно запускать для наблюдения, например для формирования 10 отчетов по 1 минуте каждый:

vmstat 60 10

Колонки us (user) и sy (system) означают соответсвенно процессорное время затраченное на пользовательские процессы (демоны и прикладного ПО) и системное. Для большинства систем нормально, если время распределяется между ними поровну.

in (interrupts) и cs (context switches) это количества прерываний и переключений контекста, и оба эти параметра — накладные расходы системы и их не должно быть много.

Разбивку использования CPU по ядрам можно получить с помощью mpstat, например по всем ядрам

$ mpstat -P ALL
Linux 3.2.0-4-amd64 (sys01) 	01/05/15 	_x86_64_	(16 CPU)

16:09:51     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
16:09:51     all    3.55   18.39    9.83    1.24    0.00    0.50    0.00    0.00   66.49
16:09:51       0    5.85   43.47   11.04    1.62    0.00    6.79    0.00    0.00   31.23
16:09:51       1    4.23   29.35   10.81    1.34    0.00    0.11    0.00    0.00   54.17
16:09:51       2    3.86   24.70   10.17    1.26    0.00    0.11    0.00    0.00   59.90
16:09:51       3    3.66   22.73    9.64    1.10    0.00    0.13    0.00    0.00   62.74
16:09:51       4    6.01   15.49    8.84    4.94    0.00    0.26    0.00    0.00   64.47
16:09:51       5    3.15   12.93    8.29    1.43    0.00    0.08    0.00    0.00   74.13
16:09:51       6    2.93   12.90    8.11    1.08    0.00    0.08    0.00    0.00   74.90
16:09:51       7    2.79   14.15    8.43    0.87    0.00    0.07    0.00    0.00   73.69
16:09:51       8    4.01   24.11    8.93    0.93    0.00    0.04    0.00    0.00   61.98
16:09:51       9    2.89   15.37   10.24    0.84    0.00    0.07    0.00    0.00   70.60
16:09:51      10    2.91   15.56   10.64    0.85    0.00    0.07    0.00    0.00   69.98
16:09:51      11    2.78   15.35   10.61    0.81    0.00    0.09    0.00    0.00   70.36
16:09:51      12    2.89   11.69    8.56    0.84    0.00    0.04    0.00    0.00   75.98
16:09:51      13    3.58   12.81   12.09    0.66    0.00    0.03    0.00    0.00   70.83
16:09:51      14    2.95   12.32   11.24    0.66    0.00    0.03    0.00    0.00   72.80
16:09:51      15    2.36   11.60    9.59    0.59    0.00    0.04    0.00    0.00   75.82

Выводимые параметры утилиты понимающему человеку там очевидны.

Оперативная память (RAM)

Использование оперативной памяти «на ходу» анализируется с помощью утилит htop, vmstat, free. Лучше — смотреть в динамике в мониторинге, том же мунине. Прежде всего необходимо обратить внимание на использование свопа, который в хорошей должен быть почти свободным и не увеличиваться/уменьшаться в определённое время суток.

В выводе

$ free -h
             total       used       free     shared    buffers     cached
Mem:           47G        44G       2.3G         0B       559M        26G
-/+ buffers/cache:        18G        29G
Swap:          15G       3.6G        12G

если окажется мало free-памяти, но много cached — это нормально. Память может быть занята страничным кэшем (cached), который многократно увеличивает скорость дисковых операций. Когда «свободной» (free) памяти действительно много это даже плохо и означает, что она не полностью используется. То же самое относится к выводу vmstat.

Ввод-вывод (IO, input-output)

Статистику по ввода-выводу системы лучше собирать пакетами мониторинга. Параметр системы, на который в первую очередь необходимо обратить внимание — iowait, т.е. ожидание ввода-вывода. Его подробные значения можно получить, например, с помощью mpstat:

mpstat -P ALL

Сводные значения есть также в top, vmstat.

Часто признаком наличия проблем с вводом-выводом является большое количество процессов в состоянии D (uninterruptible sleep), в которое процесс переходит при ожидании ввода-вывода. Это не обязательно означает, что дело именно в I/O, но такая ситуация в любом случае должна быть исследована.

Счетчики чтения-записи с дисковых устройств получаются по

$ vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
sda   90878564 7454833 2829423640 647949492 205895042 265140200 14858972810 2510368504      0 448274
sdb   455801809 14612605 57375867578 2021813576 434699644 365377967 109699014136 4291627964      0 2081456
sdd   94938371 343221533 57971885640 3782143884 34980046 34425685 8816083324 1994769084      0 449787
sdf   83996804 354254620 57971510608 1338153836 35203200 34649634 8822861163 2201253492      0 462982
sde   83274303 354838922 57968955195 1266856936 34793484 34477071 8818425628 2217294360      0 461751
sdc   112569402 325806501 57972989224 4284077532 35217039 34782607 8820518859 2068813212      0 446935
sr0        0      0       0       0      0      0       0       0      0      0
loop0      0      0       0       0      0      0       0       0      0      0
loop1      0      0       0       0      0      0       0       0      0      0
loop2      0      0       0       0      0      0       0       0      0      0
loop3      0      0       0       0      0      0       0       0      0      0
loop4      0      0       0       0      0      0       0       0      0      0
loop5      0      0       0       0      0      0       0       0      0      0
loop6      0      0       0       0      0      0       0       0      0      0
loop7      0      0       0       0      0      0       0       0      0      0
md0   289404098      0 44556083939       0 123718867      0 17627362527       0      0      0

Еще более удобная утилита для этого — iostat. Как и vmstat, она принимает 2 параметра (время наблюдения и количество отчетов). Полезно снять несколько расширенных отчетов за некоторый промежуток времени, например, минуту:

$ iostat -x 60 5
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           7.83   47.27   21.99    1.52    0.00   21.39

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.50    42.87    7.70   40.28    37.27  1732.40    73.76     5.40  112.63   13.26  131.62   2.05   9.83
sdb               9.52    56.27   85.38   60.47  1459.00  5955.80   101.68    14.10   96.69   13.17  214.63   2.46  35.85
sdd               0.08     0.27    0.08    1.47    11.27    40.27    66.49     0.01    5.59   24.80    4.50   4.90   0.76
sdf               0.22     0.50    0.15    2.35    30.27    53.75    67.21     0.02    6.43   31.11    4.85   4.83   1.21
sde               0.17     0.45    0.15    2.28    24.47    44.45    56.64     0.01    4.77   11.11    4.35   3.12   0.76
sdc               0.17     0.32    0.73    1.53    25.47    49.57    66.21     0.02    8.44   12.91    6.30   4.68   1.06
md0               0.00     0.00    1.75    3.25    91.47    93.52    73.99     0.00    0.00    0.00    0.00   0.00   0.00

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

Сеть (Network)

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

Обязательно необходимо убедиться, что настройки скорости и дуплексного режима верны для сетевой карты. Это можно сделать (и изменить) с помощью утилит ethtool и mii-tool:

ethtool eth0

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

ethtool -s eth0 autoneg off speed 100 duplex full

Полезно посмотреть и другие параметры интерфейсов, грепнув их вывода ядра:

dmesg | grep -i eth

Пиковую загрузку сети лучше (как и многое остальное) мониторить постоянно и автоматически, например, тем же munin. Ориентироваться лучше на пиковую нагрузку — по ней должен быть определённый запас и в её время не должно быть больших значений iowait.

Хорошую статистику по сети и разбивку по типам траффика можно получать с помощью ntop.

Что делать

Многие убеждены, что производительность можно многократно поднять («оптимизировать») чисто софтовыми способами, т.е. изменением настроек операционной системы и прикладного софта. На деле это не всегда так.
Ядра современных дистрибутивов Linux уже хорошо настроены в плане производительности. Если задача типовая и «железо» устраивает — менять ничего не нужно. Изменение каких-либо параметров через sysctl на большинстве серверных задач не повысит скорость работы, а при плохом подгоне даже понизит. Тем более, следует скептически относиться ко всем интернет-советам по оптимизации (в том числе, описанным на этом сайте).

Какие-то параметры работы можно оптимизировать: настройками прикладного софта, перераспределением файловой системы. Но большинстве случаев наилучший способ повысить производительности системы — «железный», т.е. изменением аппаратных характеристик сервера или распределением и балансировкой нагрузки по разным серверам. При высокой нагрузке на I/O поможет использование RAID, программных (mdadm) или аппаратных.

На масштабирование «железа» и стоит в перспективе ориентироваться и не строить иллюзий по поводу софтовых оптимизаций.

Минимум настроек apache2 и nginx веб-серверов для повышения безопасности

Рассмотрим типовую схему веб-сервера: nginx используется в качестве фронтэнда (front-end), apache2 — бэкэнда (back-end). Установка пакетов из репозитариев дает стандартную конфигурацию, которая применима для сервера разработки и тестирования. Однако, стоковая конфигурация изначально подстроена под большой класс задач и требует доработки. В частности, в плане безопасности. Опишем минимум настроек, которые необходимо сделать, если настраиваемый сервер выходит в интернет для широкого использования.

apache2

Отключаем потенциально опасные и просто неиспользуемые модули, а также неиспользуемые подконфиги. Почти всегда можно (и нужно) отключить:

  • модуль autoindex, позволяющий просматривать содержимое директории при отсутствии индексного файла,
  • обработку cgi-bin, которая в deb-based системах лежит в конфиге serve-cgi-bin.conf и используется очень редко,
  • Другие неиспользуемые модули (список которых зависит от выкладываемого кода). Т.е. необходимо перешерстить директории mods-enabled, conf-enabled

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

Apache/2.4.10 (Debian) Server at ...

Этот параметр, как и некоторые другие настройки безопасности в debian-системах обычно находится в конфиге /etc/apache2/conf-available/security.conf. Переключаем в менее информативную и, соответственно, более безопасную версию:

#ServerTokens Minimal
#ServerTokens OS
#ServerTokens Full
ServerTokens Prod

Аналогичным образом стоит поступить с подписью сервера на «ошибочных» страницах

ServerSignature Off
#ServerSignature On

и трассировкой

TraceEnable Off

Последняя обычно уже отключена, но в этом необходимо убедиться.

Код некоторых выкладываемых сайтов может содержать скрытые файлы, вроде .gitignore, .svn и других, раскрывающих стуктуру кода. Их желательно отключить здесь же, в апаче, или в фронт-энде. Можно отключить сразу все скрытые файлы:

<DirectoryMatch "/\.">
	Require all denied
</DirectoryMatch>

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

Некоторые из правил для бэкэнда закрывают те же места, что и в фронтэнде. Даже если каким-то образом будет поломана конфигурация nginx, уязвимость все равно не реализуется.

Отключим доступ к скрытым файлам — в секции виртуалхоста добавляем:

RedirectMatch 404 /\..*$

Такие файлы нередко встречаются в проектах. В частности, системы контроля версий вроде git, svn. Эта метаинформация не должна попадать в прошакш, тем не менее следует превентивно защититься от такой возможности.

Если VirtualHost на сервере не один, то также не плохо будет раскомментировать секцию


   AllowOverride None
   Order Deny,Allow
   Deny from all

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


	AllowOverride All
	Order Deny,Allow
	Allow from all

Я не описываю настройку прав доступа (пользователь:группа) на уровне ОС и файловой системы и использование модуля mpm_itk с директивой AssignUserID. Это тоже должно быть сделано для серверов, на которых такое разделение требуется.

nginx

Отключим отображение скрытых файлов:

location ~ /\. {
	deny all;
}

nginx используется как frontend, и если на нем отдается контент по https, то повышаем его безопасность. Для начала отключаем SSLv3 и другие небезопасные протоколы. Если nginx свежий, то в нем это уже и так отключено, поэтому лучше просто обновиться.
Генерируем параметры обмена ключами Diffie-Hellman (которые могут генерироваться достаточно долго, запаситесь временем)

openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

и затем подключаем их в энжинксе

ssl_dhparam /etc/nginx/ssl/dhparam.pem;

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

ssl_ciphers 'AES256+EECDH:AES256+EDH:!aNULL';

Также имеет смысл включить кеширование

ssl_session_cache shared:SSL:10m;

После всех настроек желательно проверить их корректность в каком-нибудь сервисе, например, этом.

PHP

Как и в случае апача скрываем версию

expose_php = Off

В зависимости от задач можно отключить вывод ошибок:

error_reporting = 0
display_errors = Off

 

Проверки

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

HEAD example.com

Также побродим по сайту, в том числе по страницам, которые генерируют 4xx и 5xx ошибки, проверим, что версии софта не раскрываются и тем более не раскрывается внутренняя структура сервиса.

Завершающие замечания

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

Со временем пост будет пополняться.

Настройка DKIM в exim4

Заставить exim4 подписывать исходящую почту совсем просто. Для этого в конфиг экзима /etc/exim4/exim4.conf.template дополняем следующими строками

#########################
## DKIM SETTINGS

DKIM_DOMAIN = ${lc:${domain:$h_from:}}
DKIM_FILE = /etc/mail/${lc:${domain:$h_from:}}.key
DKIM_PRIVATE_KEY = ${if exists{DKIM_FILE}{DKIM_FILE}{0}}
DKIM_SELECTOR = m01

## DKIM SETTINGS END
########################

По вкусу можно поместить конфигурацию не в шаблон, а в какой-нибудь из conf.d-файлов. Далее, чтобы все работало как надо:

  • Создаем пару ключей с помощью openssl,
  • Прописываем открытый ключ в DNS,
  • Закрытый ключ помещаем в /etc/mail/domain_name.key (вместо domain_name имя домена) и меняем его права и владельца на 0640 и root:Debian-exim,
  • Перезагружаем exim4, отправляем тестовое письмо на адрес с включенной верификацией DKIM-подписи и убеждаемся, что все работает правильно.

В вышеприведенной конфигурации селектор зафиксирован в конфиге намертво (m01), обычно этого вполне достаточно если серверная инфраструктура небольшая: каждому серверу можно присвоить свой селектор. По желанию селектор можно сделать и динамическим, формируемым из расширения файла, следующим образом:

DKIM_SELECTOR = ${extract{-1}{.}{DKIM_PRIVATE_KEY}}

Кроме настройки DKIM в exim полезно настроить обрезание определённых нежелательных заголовков в целях безопасности. Такими, например, могут быть имена формирующих письмо скриптов или IP-адреса отправителей письма (при отправке по SMTP с другой машины, которая может стоять во внутренней сети), которые раскрывают внутреннюю структуру системы. Для этого в тот же шаблон /etc/exim4/exim4.conf.template рядом с DKIM добавляем фильтр по заголовкам

system_filter = /etc/exim4/filter

Содержимое файла конфигурации фильтра /etc/exim4/filter может быть, например, таким

headers remove X-PHP-Originating-Script
headers remove Received

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

$ echo "This will go into the body of the mail." | mail -s "Hello world" -a "From: me@mydomain.com" myemail@example.com

PS: вышеприведенная конфигурация — Debian-based дистрибутивов. Для RedHat и других файлы конфигов могут быть немного другими.

Формирование DKIM ключей

При администрировании почтовых (да и не только почтовых, но и любых отсылающих почту) серверов время от времени требуется создавать DKIM ключи для почты. Эта, в целом несложная, процедура состоит из генерирования ключей, добавления открытого в DNS TXT-запись домена, а закрытого — в конфиг почтового сервера. Ниже по порядку.

Генерировать ключи удобно с помощью широкоиспользуемой утилиты openssl. Чтобы не делать это каждый раз руками, полезно написать скриптик

#!/bin/sh

if [ "$1" != "" ]; then
	openssl genrsa -out "$1.key" 2048
	openssl rsa -in "$1.key" -out "$1.pub" -pubout -outform PEM
	chmod o= "$1.key"
else
	echo "Usage: $0 domainname"
fi

вызывая который с параметром — доменным именем, для которого формируем ключи, получаем пару ключей: публичный (открытый) и приватный (закрытый). В приведенной конфигурации используется 2048-битный ключ, что несколько безопаснее и потому предпочтительнее.

Публичный ключ доступен всем через DNS. Для этого помещаем его в виде TXT-записи для настраиваемого домена с именем x._domainkey, где x — это селектор. Селектор выбирается произвольно и обычно он «привязан» к серверу. Содержимое записи — это сам публичный ключ и некоторые параметры перед ним. Общий формат записи в DNS:

x._domainkey.mydomain.com.   TXT "v=DKIM1; g=*; k=rsa; p=[PUBLIC_KEY]"

Если текст записи достаточно длинный (а 2048-битный таким является), то его лучше разбить на несколько строк. Например, в DNS-сервере bind9, запись будет выглядеть так:

x._domainkey.mydomain.com.	TXT ( "v=DKIM1; g=*; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqUkhw8hQQ4NfKAPkvrQqd04Ta2fyVTfrVdbud62HeSISpDzf1GWPGrN0ikqcTT+6DW5fRwOnGO0VkennMs7+d+WkpTJ6Y63ydrFaK/sa8HoESPBJHqrNfViQzlCt5ZCc4UZN1sLLoO3HukwvLRtM"
				"wKMzxIkavknl86PLcTebS3+ac7lWdPoqJbooHQglizs0YazLqQTLn/L6mqv1OgPCMU44seEp/CZilUchbLvHAsrfK8+AADGm+/U/5qt6/SC31ZN/BmAqtMMKvT8rMFw2qj43DPWSkn9ln5EsyUJhQiORNX3v+9rndZNuw2I90xXbuIflc30gLStXG1Jqg4IAXQIDAQAB" )

Первыми в записи идут опции: версия DKIM, гранулярность, тип ключа. Подробности опций лучше прочитать в соответствующем RTFM для стандарта DKIM.

После добавления открытого ключа в DNS лучше проверить его рабочесть. Из шелла это делается так

$ host -t txt x._domainkey.mydomain.com

В случае успеха команда вернет только что добавленный ключ.

Приватный ключ добавляется в настройки почтового сервера, которые несколько различаются. Обычно приватные ключи хранятся в /etc/mail, причем для безопасности их права лучше сразу поменять на 0640 и изменить владельца так, чтобы ключ смог читать почтовый демон, но не пользователи системы.

Удаленный шелл с использованием nc

Фундаментальным и очень полезным качеством всех линуксов-юниксов является их модульность и возможность сборки из «кирпичиков» нужных инструментов. Это прекрасно иллюстрируется следующим примером из мануала утилиты netcat. Эта утилита передачи и приема произвольных данных по протоколам tcp/udp позволяет сделать элементарный и полностью рабочий шелл для работы с удалённым хостом. И это только используя эту утилиту и стандартные средства Linux вроде pipe и перенаправления данных.

На удалённой машине создаем трубу

$ rm -f /tmp/f; mkfifo /tmp/f

берем из неё данные, исполняем и результат толкаем в netcat, а его ответ обратно в трубу:

$ cat /tmp/f | /bin/sh -i 2>&1 | nc -l 127.0.0.1 1234 > /tmp/f

В результате получаем упрощённую нешифрованную версию ssh.

ssh/scp под Windows

Несколько решена проблема с доступом ssh/scp из под Windows. Cофтина позволяет монтировать ssh как логический том (sshfs). С её помощью может получиться неплохое решение для удалённых бэкапов из Windows под любые никсы. Жаль, что пока нет решения под Windows 8 и серверную 2012.

Удаление очень больших директорий в Linux

Современные файловые системы вроде ext3/ext4, xfs позволяют создавать в директориях очень большое количество файлов. В ряде случаев (обычно по ошибке или недосмотру) это реализуется на практике и тогда некоторые операции с такой директорией становятся очень медленными. Это касается прежде всего операций, требующих сортировку списка содержимого директории. Такая сортировка, например, происходит при вызове листинга ls, который по умолчанию сортируется, что естественным образом приводит к очень медленному исполнению команды. Также, большая директория очень медленно удаляется rm, поскольку последний формирует листинг.

Чтобы ускорить (а иногда и просто осуществить) удаление большой директории нужно отключить сортировку. Команда rm при удалении берет полностью список файлов, поэтому удалять очень большую директорию «в лоб» с помощью «rm -rf» очень неоптимальный вариант. Большую директорию удобнее удалять частями: листингом без сортировки некоторого количества файлов и их удалением. Сортировка в ls отключается параметром -U, что приводит к такой команде частичного удаления

ls -UA -1 . | head -n 1000 | xargs rm -f

Чтобы удалить содержимое директории полностью и при этом не грузить IO хоста постоянно лучше поставить команду в цикл с небольшими перерывами. Простейший (но не оптимальный и не самый корректный) способ осуществить это

while [ true ]; do ls -UA -1 . | head -n 100 | xargs rm -f 2>/dev/null; sleep 1; done

Альтернативный способ — изменить ionice процесса удаления.