Разворачивание сервера на FreeBSD 8.0 с применением ZFS и размещением сервисов в jail'ах

Содержание

Введение, о чём этот текст

Почему FreeBSD?

Почему ZFS?

Почему jail?

Почему Microsoft Comic Sans?

Постановка задачи

Сервисы для локальной сети

Сервисы предназначенные для работы как внутрь так и наружу

Железо (вернее кремний)

Установка системы, ZFS

Создание и обслуживание jail

Что неудалось поместить в jail

jail и NFS

jail и DHCP

jail и DNS

jail и Qemu

Неожиданные проблемы конфигурирования системы с jail'ами

jail и sendmailВведение, о чём этот текст

Текст, который вы видите перед собой повествует об опыте настройки одного сервера под управлением FreeBSD 8.0, на котором в многочисленных jail'ах были подняты различные сервисы. При его настройке автору пришлось столкнуться с некоторым количеством неожиданностей и багов, да и с багами тоже, куда ж без них.

База, на которой была поднята система: операционная система FreeBSD, файловая система ZFS, разграничение сервисов при помощи jail. Выбор этой связки был обусловлен следующими причинами:Почему FreeBSD?

Загибайте пальцы:

Дёшево.

Стабильно. Я имею ввиду стабильность интерфейса, а не стабильность самой системы. Например Linux тоже стабилен, но его интерфейс не стабилен и вопрос его стабильности меньше всего беспокоит разработчиков. У меня есть масса других увлекательных занятий кроме наблюдения за тем как раз в несколько месяцев выходят новые версии ядра, дыры в старых версиях не фиксятся и я должен переползать на новые ядра, а стабильности интерфейса на них мы не наблюдаем. Даже имена файлов устройств (даже вичтестеров!) могут меняться от версии к версии.

Поддерживается. FreeBSD популярная система. Завтра не помрёт. А вот что будет с OpenSolaris? От души желаю этому проекту здоровья и долгих лет жизни. Хороший проект, не чета Linux. Но мне пока боязно к нему привязываться.

Почему ZFS? к содержанию

Негатив

ZFS в FreeBSD новьё, а новьё всегда подозрительно. Для внедрения ZFS требуется тюнинг ядра, при этом во что выставлять параметры неочевидно, существуют только общие советы относительно данного пункта. Причём, в случае неверно выставленных параметров возможен kernel panic. Это очевидный негатив.

Впрочем, гугление показывает, что на архитектуре amd64 при достаточном количестве оперативной памяти, тюнинг ядра не требуется. Проблема относится скорее к i386.

Нейтраль

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

В FreeBSD 8.0 ZFS поддерживает флаги, которые расставляет команда chflags. В этом отношении ZFS сравнялась с UFS, ушёл один из главных недостатков файловой системы.

Позитив

Огромный функционал файловой системы:

RAIDZ. ZFS позволяет выстраивать RAID-5, В ядре FreeBSD до сих пор был функционал только на RAID-3. То, что в ZFS называется RAIDZ по факту даже больше, чем RAID-5, Если RADZ1 (минимальное количество девайсов — 3), который мы будем поднимать, подразумевает, что позволительно крушение одного винчестера, то RAIDZ2 (минимальное количество девайсов — 4) подразумевает возможность крушения одновременно двух винчестеров. В OpenSolaris (но пока не в FreeBSD) реализован даже RAIDZ3.

Гибкость. Если завтра понадобится доставить ещё 1 терабайт, я куплю два терабайтных диска, скажу ZFS что из них надо сделать зеркало и добавить их к имеющемуся массиву. Всё. Это можно сделать даже не останавливая сервер (ведь SATA поддерживает горячее подключение)! После этого массив данных будет жить на одном RAIDZ1 ёмкостью 3 Tb из 4-х терабайтных дисков и на одном зеркале ёмкостью 1 Tb состоящем из двух терабайтных дисков. (Числа я привожи просто для иллюстрации.)

Потрясающее удобство администрирования. Резервные копии изготавливаются просто и быстро: делаете снапшот каталога и всё. (Разумеется, для надёжного резервного копирования надо эти снапшоты потом заливать на другой компьютер, который работает в другом городе, а лучше в другой стране, но это отдельная тема.) Можно делать сжатые папки. Можно для избранных каталогов запретить создание файлов с именами в кодировке отличной от UTF-8. Список «фич» чрезвычайно велик.

Разумная производительность. Вот цифры: как я сказал, у меня собран RAIDZ1 из 4-х терабайтных дисков. Скорость чтения с физического диска составляет 84 мегабайта в секунду в начале диска, к концу диска линейно снижается. Скорость записи на RAIDZ1 составила 160 мегабайт в секунду, скорость чтения 240 мегабайт в секунду. (Я писал большие объёмы нулей из /dev/zero при помощи команды dd). Т.е. в RAIDZ1 реализовано распределение нагрузки по винчестерам. При помощи утилит мониторинга (zpool iostat -v 1) видно как сбрасывается буфер из оперативной памяти синхронно на все винты одновременно.

В моём случае плюсы перевесили. Но, хотя в сети хватает инструкций по установке ZFS в корневой раздел системы, мне это показалось экстремизмом. Я пошёл иным путём: корневой раздел я установил на CompactFlash карту и подсоединил её через адаптер к IDE интерфейсу как маленький винчестер. Корневой раздел отформатирован в UFS, это проверенная годами практика. Если ZFS отвалится, мы будем нормально грузиться с этой карты и в нашем распоряжении будет совершенно целая система. А чтобы не страдать журналом, мы корневую систему будем монтировать только в режиме ReadOnly. Это продлит жизнь CF карте, и защитит файловую систему на ней от сбоев питания.

Итак, корневая система на UFS в ReadOnly, В остальных местах ZFS.Почему jail?

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

По этой причине захотелось вынести сервисы в отдельные jail'ы, но тут нас ждало немало сюрпризов. И вот из-за этих сюрпризов я и пишу данный текст.Почему Microsoft Comic Sans?

во-первых, я использую свои странички при настройке клиентских машин: если MS Comic виден, то шрифты пакета webfonts адекватно воткнуты в X-сервер,

во-вторых, луркоморье нам не указ, потому что создатель интернетов всегда прав.

Постановка задачи

Сервисы для локальной сети:

DHCP сервер,

Большая файловая помойка должна быть расшарена на локальную сеть. (Кленты на FreeBSD, MacOS X и Windows). Вероятно нам понадобится шарить данные при помощи протоколов:

NFS и

Samba.

Было бы неплохо иметь возможность на этом же сервере запускать альтернативные операционные системы, т.е. нам понадобится виртуализация. По ряду дурацких причин мы отринем XEN и предпочтём ему Qemu.

Административные задачи:

Монитроинг состояния UPS,

Мониторинг состояния жёстких дисков,

Мониторинг достуности внешних узлов.Сервисы предназначенные для работы как внутрь так и наружу: к содержанию

DNS сервер. Разумеется наружу и внутрь он должен поставлять разные данные.

Почта, сюда входят протоколы SMTP и IMAP,

Web.

Сервисов предназначенных для работы исключительно наружу в нашем случае нет. Но есть вопросы касающиеся безопасности всего этого хозяйства. Нам понадобится защита сетевого периметра. Не то, чтобы наш сервер был расположен непосредственно на периметре сети. Нет, возможно он будет там расположен когда-то, но сейчас он будет представлять из себя лишь Bastion host. Он должен качественно защищать себя, но поскольку по условиям задачи он является прокси-сервером минимум для протокола SMTP, то он будет так же выполнять задачи фильтрации трафика. Итак, мы будем поднимать на нём:

Пакетный фильтр,

контент-анализ в лице защиты от SPAM'а,

NIDS. (Тема межсетевого экрана вообще и NIDS в частности пока в документе не раскрыта)Железо (вернее кремний) к содержанию

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

Архитектура amd64,

CPU 4-х ядерный Athlon II X4 620,

RAM 8 Gb на 4-х планках (включён двухканальный режим),

4 винчестера объемом 1 Tb каждый,

Compact Flash 4 Gb (меньше не нашёл) для корневой партиции,

Видеокарта PCI S3 Trio 64V+ (должно же что-то достаться новому серверу от старого)

Главным образом, указанный объём памяти и мощный процессор закладывались для того, чтобы запускать Qemu. Кроме того, для функционирования ZFS приветвуется объём памяти порядка одного гигабайта. В виду большого объёма оперативной памяти на сервере не используется SWAP.Установка системы, ZFS

При установке системы никаких особых чудес. Мне пока кажется экстремистской идея размещать корневой каталог на ZFS. Даже если это технически возможно (а это технически возможно), сервер — не то место, где надо проверять такие фокусы без повода.

В сервер устанавливаем CF карту через CF->IDE адаптер. Размечаем весь диск под одну единственную партицию и устанавливаем в неё всю систему без SWAP'а. Позже мы смонтируем некоторые каталоги будущей системы в каталоги /usr, /var и /tmp. При этом файлы, которые мы сейчас туда установим будут заслонены и при работе системы они будут невидны. Но если массив ZFS отвалится, то эти каталоги не подмонтируются куда надо и изначальные файлы в исключительной ситуации снова станут доступны. В нашем распоряжении окажется рабочая система, при помощи которой можно будет производить какие-то аварийные работы.

После установки системы переводим корневой каталог в режим read-only. Отныне и далее в файле /etc/fstab будет всего одна строка:

# Device Mountpoint FStype Options Dump Pass#

/dev/ad0s1a / ufs ro 1 1

Теперь создаём ZFS pool. Можно действовать по методике изложенной в ZFS — quick start. В файл /etc/rc.conf пишем:

zfs_enable="YES"

И конструируем партиции в консоли. Не стоит переживать, если вам трудно заранее представить что вы хотите создать: после можно будет менять почти все опции партиций налету, можно будет переименовывать их, уничтожать, создавать другие. При этом вы не должны придумывать на какую партицию сколько надо выделить места. Партиции делят общее пространство создаваемого пула tank. Если же вы захотите ограничить какой-то каталог, то можно воспользоваться опцией quota.

# zpool create tank raidz ad4 ad5 ad6 ad7

# zfs create tank/usr

# zfs create tank/var

# zfs create tank/tmp

# zfs create -o compress=gzip tank/usr/src

# zfs create -o compress=gzip tank/usr/ports

# zfs create -o compress=off tank/usr/ports/distfiles

Затем изменим точки монтирования некоторых каталогов:

# zfs set mountpoint=/usr tank/usr

# zfs set mountpoint=/var tank/var

# zfs set mountpoint=/tmp tank/tmp

Для шары раздел можно создать примерно так:

# zfs create -o utf8only=yes tank/storage

Опцию utf8only можно задать только при создании раздела. Эта опция приведёт к тому, что файлы в этом каталоге можно будет создавать с названиями только в кодировке UFT-8. Это приведёт к тому, что мы неправильно сконфигурированные клиенты, которые попытаются создать файлы с названиями в кодировке koi8-r или cp1251, не смогут этого сделать. Мы гарантированы от путаницы кодировок.

И тут нас ждёт первое разочарование. SMB клиент FreeBSD не умеет работать с кодировкой UFT-8 на сервере.

# mount_smbfs -E koi8-r:utf-8 -I smb //user@smb/public mnt/net0

Увы, листинг каталога в котором есть есть хоть один файл с русскими буквами в названии вы при этом не получите. Это не баг серверной части, это баг именно клиентской части интегрированной в ядро операционной системы. Если сервер будет держать всё в однобайтовой кодировке, например в koi8-r, то при надлежащих настройках Samba сервера всё будет хорошо, но мы-то хотели хранить всё в utf-8. Тут нужно предпринять два действия: во-первых полить говном разработчиков, которые интегрируют любую чепуху в ядро (славьтесь-славьтесь микроядра, коих днём с огнём не видать), а во-вторых использовать другие клиенты. Например konqueror, это не так удобно, но работает. Некторые программы придётся пересобрать с поддержкой smb протокола. Например mplayer после персборки понимает URL типа smb://host/share/film.avi.

А может ну его, будем работать с однобайтовыми шарами по-старинке? А с путанницей кодировок будем бороться «организационными мерами»? Нельзя всю жизнь вот так прятаться от проблем. В MacOS X, например шара сделана на UTF-8, и файловая система HFS+ занимается автоматической нормализацией имён. И что, нам с этими серверами не знаться? Нет братцы, сервера будем делать как следует, и примиримся с тем фактом, что в FreeBSD клиент глюкав.

Для перевода клиентской FreeBSD с koi8-r на utf-8 может помочь утилита convmv:

$ cd /usr/ports/converters/convmv

# make install clean

<...>

# convmv --preserve-mtimes -f KOI8-R -t UTF-8 -r --notest /home

Кроме того, в файле /etc/login.conf надо сделать следующие изменения:

default:

<...>

:setenv=<...>MM_CHARSET=UTF-8,<...>:

<...>

russian-utf:

:charset=UTF-8:

:lang=ru_RU.UTF-8:

:lc_all=ru_RU.UTF-8:

:tc=default:

Затем в командной строке:

# cap_mkdb /etc/login.conf

# pwd usermod <username> -L russian-utfСоздание и обслуживание jail к содержанию

Про создание jail'ов написано немало. Базовую методику можно почитать здесь. Но если вы собираетесь запускать большое количество jail'ов, тут есть небольшая специфика. Конечно нет никакой необходимости собирать мир столько раз, сколько вы планируете постоить jail'ов. Разумная методика выглядит примерно так:

$ cd /usr/src

# make clean buildworld

# make installworld DESTDIR=/tank/jails/share

# make distribution DESTDIR=/tank/jails/share

# make installworld DESTDIR=/tank/jails/mail

# make distribution DESTDIR=/tank/jails/mail

# make installworld DESTDIR=/tank/jails/www

# make distribution DESTDIR=/tank/jails/www

# make installworld DESTDIR=/tank/jails/qemufactory

# make distribution DESTDIR=/tank/jails/qemufactory

Для любознательных: цель world, упоминаемая в большинстве инструкций на самом деле является синтезом из buildworld и installworld, при этом только последняя использует переменную DESTDIR. Цель distribution занимается копированием конфигурационных файлов. В стандартной процедуре переустановки мира вместо неё используется команда mergemaster.

На каждый jail вы должны написать в /etc/rc.conf не меньше пяти параметров. Файл станет неоправданно длинным и это никому на пользу не пойдёт. Я могу предложить вам поместить повторяющиеся команды в цикл, а хуки которые надо выполнить перед и после запуска jail'ов вынести во внешние сценарии. В /etc/rc.conf пишем:

################

# jail section #

################

jail_enable="YES"

jail_list="share mail www qemufactory"

jail_set_hostname_allow="NO"

jail_socket_unixiproute_only="YES"

jail_devfs_enable="YES"

jail_devfs_ruleset="devfsrules_jail"

jail_qemufactory_devfs_ruleset="devfsrules_qemufactory"

jail_flags="-l -U root securelevel=3"

jail_share_ip="172.19.0.201"

jail_mail_ip="172.19.0.202"

jail_www_ip="172.19.0.203"

jail_qemufactory_ip="172.19.0.204"

for JAIL in $jail_list

do

JPATH="/tank/jails/${JAIL}"

eval jail_${JAIL}_rootdir="${JPATH}"

eval jail_${JAIL}_hostname="${JAIL}.${MYDOMAIN}"

eval jail_${JAIL}_exec_prestart0="/bin/sh /etc/rc.jail ${JAIL}"

eval jail_${JAIL}_exec_poststop0="/bin/sh /etc/shutdown.jail ${JAIL}"

[ -f /etc/rc.jail-${JAIL} ] &&

eval jail_${JAIL}_exec_prestart1="/bin/sh /etc/rc.jail-${JAIL}"

[ -f /etc/shutdown.jail-${JAIL} ] &&

eval jail_${JAIL}_exec_poststop1="/bin/sh /etc/shutdown.jail-${JAIL}"

done

В файл /etc/rc.jail кладём команды, которые надо выполнить перед запуском jail'ов, а в /etc/shutdown.jail команды, которые надо выполнить после остановки jail'ов. В моём случае /etc/rc.jail:

#!/bin/sh

jail=$1

jpath=/tank/jails/${jail}

/sbin/mount_nullfs /usr/ports ${jpath}/usr/ports

/sbin/mount_nullfs /usr/ports/distfiles ${jpath}/usr/ports/distfiles

/bin/chflags schg ${jpath}/etc/rc.conf

nullfs помогает нам иметь доступ к одному и тому же каталогу из разных jail'ов. После остановки jail'ов надо эти каталоги размонтировать, для этого применим /etc/sutdown.jail:

#!/bin/sh

jail=$1

jpath=/tank/jails/${jail}

/sbin/umount ${jpath}/usr/ports/distfiles

/sbin/umount ${jpath}/usr/ports

Обратите внимание, это не системные файлы, я самостоятельно поставил вызов этих сценариев в /etc/rc.conf! Хуки индивидуальные для отдельных jail'ов мы можем раскладывать по именным файлам, например для jail'а share в нашем примере, мы можем записать файл /etc/rc.jail-share:

#!/bin/sh

/sbin/mount_nullfs /tank/storage /tank/jails/share/storage

и /etc/shutdown.jail-share:

#!/bin/sh

/sbin/umount /tank/jails/share/storage

А теперь, внимание... БАГ!

В листинге /etc/rc.conf, который был приведён выше, использована переменная jail_flags, предназначенная для передачи параметров jail'у. К сожалению, эта конструкция не работает в том виде, который здесь обозначен. У команды jail есть два вида вызова: старый, в котором аргументы были позиционные и новый (jail2), где опции могут задаваться в произвольном порядке в форме key=value. Скрипт /etc/rc.d/jail вызывает jail'ы по-старому. Поэтому ряд аргументов передать программе невозможно. Например, опцию allow.raw_sockets, которая открывает программам в jail'е доступ к сырым сокетам (в частности, разрешает в jail'е ping и traceroute), её вообще невозможно передать команде jail из файла /etc/rc.conf. Для того, чтобы в переменной jail_flags можно было передавать опции в новом стиле и использовать всю мощь команды jail, мне пришлось слегка переписать сценарий /etc/rc.d/jail:

638,639c638,641

< eval ${_setfib} jail ${_flags} -i ${_rootdir} ${_hostname}

< "${_addrl}" ${_exec_start} > ${_tmp_jail} 2>&1

---

> eval ${_setfib} jail -i -c ${_flags} path=${_rootdir}

> host.hostname=${_hostname}

> ip4.addr="${_addrl}"

> command=${_exec_start} > ${_tmp_jail} 2>&1Что неудалось поместить в jail к содержанию

Кое-что мне не удалось поместить в jail, кое-что не захотелось туда помещать. Далее я позволю себе поделиться своим опытом на эту тему. А кое-где ограничусь не опытом, а рассуждениями.jail и NFS к содержанию

Кажется, эта связка невозможна. У меня ничего не вышло. Литературный поиск ничего определённого не показал. Здесь, например, пишут, что задача имеет решение (если выставить на экспортируемом каталоге ZFS специальные опции, надо думать sharenfs), но возможны проблемы с безопасностью. Заметим, что все кто даёт советы, рассуждают теоретически, т.е. я не нашёл ни одного сообщения где было бы написано я делаю так, вместо этого применяется обтекаемое попробуйте это.

Проблемы происходят не только с серверной частью, но и с клиентской. Практически все в итоге приходят к тому же, к чему пришёл и я: с NFS надо работать снаружи jail'а.jail и DHCP к содержанию

Сервер DHCP можно запустить в jail'е. У меня вышло, но это не просто, и налицо неприспособленность стандартного сценария запуска /usr/local/etc/rc.d/isc-dhcpd к условиям функционирования в jail. Можно запускать DHCP снаружи в окружении chroot, с пониженными привелегиями (вариант, на котором я в итоге остановился). Установить DHCP внутрь jail и запустить там но без chroot'а тоже удаётся, если добавить в jail снаружи Berkley packet filter. А вот для того, чтобы запустить DHCP внутри jail'а и внутри chroot'а нужно обучить сценарий /usr/local/etc/rc.d/isc-dhcpd монтировать devfs внутри jail'а. У меня есть сомнения возможно ли это. Можно примонтировать devfs к chroot/dev снаружи перед запуском DHCP сервера, но тогда сценарий /usr/local/etc/rc.d/isc-dhcpd потребует адаптации к новым условиям (короче, свой сценарий запуска сервиса придётся писать). Это не бог весть какая задача, но мне кажется, что всесь этот геморрой просто не стоит затевать. В любом случае, для того, чтобы DHCP сервер работал в jail'е вам придётся существенно ослабить защиту jail'а, и зачем всё это тогда затевать?jail и DNS к содержанию

Это безусловно решаемая задача. Единственное ноу-хау, надо перед стартом jail'а монтировать devfs в каталог, куда буднт чрутиться bind. Сделать это можно через /etc/rc.jail, как описано выше. В отличие от сценария запуска DHCP, сценарий /etc/rc.d/named корректно работает с заранее подмонтированным каталогом chroot/dev.

Но по принципиальным причинам я противник запуска службы DNS во вспомогательных операционных системах внутри эмуляторов и т.п. Это слишком критичный сервис, от него слишком много зависит. DNS должен стартовать вместе с базовой системой хотя бы потому, что он может быть жизненно необходим ей самой для работы её собственных сервисов.jail и Qemu к содержанию

Модуль ядра kqemu подгрузить из jail'а невозможно. Нужно собрать этот модуль снаружи и подключать его в базовой системе, тогда его сможет использовать qemu запущенная внутри jail. Но эта qemu будет функционировать только в userspace. Это значит, что вы не сможете поставить её в мост с физическим интерфейсом машины. Даже если вы сделаете видимыми tap устройства внутри jail, qemu не сможет с ними взаимодействовать. Но qemu может использовать NAT. Поэтому гостевые системы будут сидеть в сети 10.0.2.0/24, и выходить наружу через NAT. Подсовывать им файлы можно через iso образы дисков и через samba. В репозитории в большой Интернет они ходить будут. Если вам понадобится форвардить порт внутрь, qemu может и это. Например:

qemu -hda WinXP.img -localtime -kernel-kqemu -m 512 -monitor stdio -usbdevice tablet -vnc :0 -net nic -net user,hostfwd=tcp::3389-:3389,smb=/home/user/smb-share

Здесь запускается Windows XP, в свойм сетевом окружении он будет видеть машину по имени qemu, в которой он найдёт файлы из каталога /home/user/smb-share, куда их по мере надобности можно будет подкладывать и забирать назад. В большой Интернет этот Windows будет ходить через NAT, а сели мы подконнектимся к порту 3389 jail'а qemufactory, то qemu пробросит это соединение на порт 3389 Windows XP и мы полусчим доступ к службе rdesktop.

В описанном виде qemu нормально работает в jail'е.

Сайд эффект: поскольку мы запускаем qemu в jail без доступа к сырым сокетам, изнутри Windows нельзя пустить пинг наулицу. Не нравится? — Передайте jail'у флаг allow.rawsockets. А мне наоборот, нравится.

Но если вы жаждете сложного эксперимента связанного с объединением jail'ов в мост с реальным интерфейсом, выход один — переносите qemu во внешнюю систему.Неожиданные проблемы конфигурирования системы с jail'ами к содержанию

jail и sendmail к содержанию

Итак, у нас есть один jail (допустим mail.mydomain), который должен принимать почту. Хотелось бы читать на нём письма адресованные всем рутам наших jail'ов. Для этого в каждом jail'е в файл с алиасами (/etc/mail/aliases) мы можем прописать:

root: admin@mydomain

далее перестраиваем базу алиасов и вся почта рута будет направлена админу, где он будет её преспокойно почитывать thunderbird'ом или чем ему там нравится. Целесообразно будет не валить эту почту в личный ящик, а автоматически раскладывать по папкам при помощи procmail.

Сюрприз ждёт нас на основной машине. Поскольку все IP адреса jail'ов являются её алиасами, она откажется посылать почту в jail'ы и при наличии указанного перенаправления в файле /etc/mail/aliases, вообще грохнет всю почту со следующей диагностикой в файле /var/log/maillog:

Jan 24 13:16:12 main sendmail[17149]: o0OAGCQm017149: from=admin, size=31, class=0, nrcpts=1, msgid=<201001241016.o0OAGCQm017149@main.mydomain>, relay=root@localhost

Jan 24 13:16:12 main sm-mta[17150]: o0OAGCUo017150: from=<admin@main.mydomain>, size=404, class=0, nrcpts=1, msgid=<201001241016.o0OAGCQm017149@main.mydomain>, proto=ESMTP, daemon=IPv4, relay=localhost [127.0.0.1]

Jan 24 13:16:12 main sendmail[17149]: o0OAGCQm017149: to=root, ctladdr=admin (1002/1002), delay=00:00:00, xdelay=00:00:00, mailer=relay, pri=30031, relay=[127.0.0.1] [127.0.0.1], dsn=2.0.0, stat=Sent (o0OAGCUo017150 Message accepted for delivery)

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017150: SYSERR(root): MX list for mydomain. points back to main.mydomain

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017150: to=admin@mydomain, ctladdr=<admin@main.mydomain> (1002/1002), delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=30712, relay=mydomain., dsn=5.3.5, stat=Local configuration error

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017150: o0OAGCUo017151: DSN: Local configuration error

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017151: to=admin@mydomain, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=31736, relay=mydomain., dsn=5.3.5, stat=Local configuration error

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017151: o0OAGCUp017151: return to sender: Local configuration error

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUp017151: to=admin@mydomain, delay=00:00:00, xdelay=00:00:00, mailer=esmtp, pri=32760, relay=mydomain., dsn=5.3.5, stat=Local configuration error

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017151: Losing ./qfo0OAGCUo017151: savemail panic

Jan 24 13:16:12 main sm-mta[17151]: o0OAGCUo017151: SYSERR(root): savemail: cannot save rejected email anywhere

Т.е. sendmail видит, что почта переадресуется на IP адрес, который закреплён за его интерфейсом и отваливается с диагностикой MX list for mydomain. points back to main.mydomain. Затем он выясняет, что даже Reject ему послать никак невозможно и, тяжело вздохнув, уничтожает корреспонденцию.

Для борьбы с этим явлением я предпринял следующее действие: в каталоге /etc/mail редактируем файл main.mydomain.submit.mc:

dnl FEATURE(`msp', `[127.0.0.1]')dnl

FEATURE(`msp', `[mail.mydomain]')dnl

Актуализируем сделанные изменения:

$ cd /etc/mail

# make

# make install

# make restart

В /etc/rc.conf пишем:

sendmail_enable="NO"

sendmail_msp_queue_enable="YES"

sendmail_outbound_enable="NO"

sendmail_submit_enable="NO"

Для любознательных: последние три опции не документированы в man rc.conf, они документированы в man rc.sendmail

Ну и на принимающей стороне, в jail'е mail.mydomain в файл /etc/mail/local-host-names надо дописать домен основной машины:

mydomain

main.mydomain

Полагаю, что ранее вы не забыли не выключить макрос define(`confCW_FILE', `-o /etc/mail/local-host-names') в конфигурационном файле sendmail'а почтового jail'а

Конечно алиас перенаправляющий почту админу теперь должен присутсвовать в почтовом jail'е (но ведь вы его туда всё равно впишете, не так ли). /etc/mail/aliases:

root: admin

Теперь sendmail основной машины всю почту будет отправлять через 25-й порт почтового jail'а mail.mydomain, указаного в макросе FEATURE(`msp', `[mail.mydomain]'), а он и рад, так как считает себя конечной точкой для этого домена, благодаря соответсвующей записи в /etc/mail/local-host-names. Ну, а поскольку почту он должен доставить руту, то, согласно алиасу, он перекладывает её админу.

Считаю разумным перенаправлять почту из других jail'ов на почтовый тем же способом, хотя для них оба способа работают.

Для любознательных: tcpdump показывает нам, что несмотря на указание реальных IP адресов закреплённых за реальной сетевой картой, взаимодействие между jail'ами идёт через кольцевой интерфейс.

http://house.hcn-strela.ru/

Обновлено: 12.03.2015