Zimbra

Материал из СисадминВики (SysadminWiki.ru)
Перейти к: навигация, поиск

Zimbra Collaboration Suite (ZCS) — программный продукт для автоматизации совместной деятельности рабочих групп, аналог MS Exchange, включает в себя ряд бесплатных и открытых продуктов (Apache, MySQL, Postfix и др.), предоставляя сервисы почты, обмена быстрыми сообщениями (jabber), общие документы и календари и т.д. Есть как платные так и бесплатные версии ZCS, мы будем устанавливать последнюю.

Подготовка ОС

Так как Zimbrа несёт с собой много ПО, то её лучше устанавливать на отдельный сервер, или по крайней мере перед остальными приложениями.

Удаление других почтовых программ

на Debian удаляем все пакеты почтового сервера exim4

# apt-get remove exim4-base exim4-config

Установка необходимых пакетов

Устанавливаем необходимые дополнительные пакеты (удовлетворяем зависимости).

# apt-get install libstdc++5 sysstat

Настройка МХ записи и имени домена

- Убедимся, что настроен правильно MX на hostname сервера, куда устанавливается Zimbra

# dig mx mail.domain.ru

;; ANSWER SECTION:
mail.domain.ru.            3600    IN      MX      10 domain.ru.

;; ADDITIONAL SECTION:
domain.ru.                 1882    IN      A       94.94.94.94

- Добавляем в /etc/hosts соответствующую запись вида:

94.94.94.94 mail.domain.ru mail

Установка Zimbra

Распаковываем дистрибутив Zimbra и запускаем install.sh. Если каких-то пакетов не хватает, то установщик скажет об этом и их нужно будет доустановить.

Настройка Zimbra

Настройка почтового домена

После установки зайдём на web интерфейс сервера пользователем admin и перейдём по ссылке "Администратор домена", где настроим:

Конфигурация - Класс обслуживания - default

Конфигурация - Домены - mail.domain.ru


Перенос учётных записей

Перенесём (импортируем) учётные записи из предыдущей почтовой системы. У меня использовался Postfix под управлением PostfixAdmin.

Для такого случая есть специальный скрипт.
#!/usr/bin/php

// Postfixadmin (http://postfixadmin.sourceforge.net/) to Zimbra
// (www.zimbra.com) migration script
//
// History:
// Based on work from: Jaros Baw Czarniak
// Enhanced by NERvOus (www.nervous.it) on 1-12-2009

<?php
/////////////////////////////////////////////////////////

$user="postfix";
$pass="postfixadmin";
$db="postfix";
$table_mbox="mailbox";
$table_alias="alias";
$file="import.sh";

/////////////////////////////////////////////////////////
echo "This script generates a bash script called: $file
The script contains the commands to re-create the mboxes and
aliases on zimbra server.\n\n
";

$mydb = mysql_connect('localhost',$user, $pass) or die ('Error connecting to server');
mysql_select_db($db);
mysql_query("SET CHARACTER SET utf8");
mysql_query("SET NAMES utf8");

$query = "SELECT username,password,name,maildir,quota,domain
                FROM $table_mbox";
$dane = mysql_query($query) or die ('Error during query for '.mysql_error());

echo "Writing to $file ...\n";
$fh = fopen($file, "w");

fwrite($fh, "#!/bin/sh -x\n\n");

while ($row = mysql_fetch_array($dane, MYSQL_NUM))
{
    $data_mbox = "zmprov ca ".$row[0]." dsfs123hsdyfgbsdgfbsd displayName '".$row[2]."'\n";
    $data_mbox .= "zmprov ma ".$row[0]." userPassword '{crypt}".$row[1]."'"."\n";
    fwrite($fh, $data_mbox);
}
// skip domain aliases, aliases that forward to themselves and aliases
// for which a mbox exists
$query = "SELECT address, trim(trailing ',' from goto) AS dest
                FROM ".$table_alias."
                WHERE address NOT LIKE '@%'
                        AND address NOT IN (SELECT username FROM $table_mbox)
                HAVING address != dest";
$dane = mysql_query($query) or die ('Error during query for '.mysql_error());
while ($row = mysql_fetch_array($dane, MYSQL_NUM)) {
        // multiple dests
        unset($rawdest_r);
        unset($dest_r);
        $rawdest_r = preg_split('/,/', $row[1]);
        foreach ($rawdest_r as $dest) {
                if ($dest != $row[0]) {
                // don't forward to itself
                        $dest_r[] = $dest;
                }
        }
        if (count($dest_r) > 1) {
                // distribution list
                $data_list .= "zmprov cdl $row[0]\n";
                foreach ($dest_r as $dest) {
                        $data_list .= "zmprov adlm $row[0] $dest\n";
                }
        }
        if (count($dest_r) == 1) {
                preg_match('/@(.*)$/', $row[0], $matches);
                $acct_domain = $matches[0];
                preg_match('/@(.*)$/', $dest_r[0], $matches);
                $alias_domain = $matches[0];
                if ($acct_domain == $alias_domain) {
                        // we are adding an alias, not a forward
                        // try to create alias both for a normal
                        // account and for a distribution list. One of the
                        // commands will fail, pity.
                        $data_alias .= "zmprov aaa $dest_r[0] $row[0]\n";
                        $data_alias .= "zmprov adla $dest_r[0] $row[0]\n";
                } else {
                        // we are adding a forward
                        $data_alias .= "zmprov ca $row[0] " . rand_str(11) . "\n";
                        $data_alias .= "zmprov ma $row[0] zimbraprefmailforwardingaddress $dest_r[0]\n";
                }
        }
}

// first create all distribution lists, last all aliases
// We cannot create aliases for distribution lists that do not
// exist yet
fwrite($fh, $data_list . $data_alias);
fclose($fh);


echo "Done.

Now copy $file to zimbra server and run:
# su - zimbra
$ sh ./$file
";


function rand_str($length = 32, $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890')
{
    // Length of character list
    $chars_length = (strlen($chars) - 1);

    // Start our string
    $string = $chars{rand(0, $chars_length)};

    // Generate random string
    for ($i = 1; $i < $length; $i = strlen($string))
    {
        // Grab a random character from our list
        $r = $chars{rand(0, $chars_length)};

        // Make sure the same two characters don't appear next to each
        // other
        if ($r != $string{$i - 1}) $string .=  $r;
    }

    // Return the string
    return $string;
}

Полученный с помощью этого скрипта файл import.sh выполняем на сервере Zimbra.

Скрипт я взял из вики справочника Zimbra. Он полезен, если мы не знаем пароли пользователей, если же мы их знаем, то можно подготовить файл и сделать импорт в Административной консоли управления: Адреса - Учётные записи - Групповая подготовка.


Автоматизация переноса учёток

Почтовая учётная запись создаётся двумя командами:

/opt/zimbra/bin/zmprov ca user@domain.ru userpass displayName "Фамилия Имя Отчество"
/opt/zimbra/bin/zmprov ma user@domain.ru userPassword 'userpass'

где userpass - пароль пользователя

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

Если есть список пользоватей и их пароли, то скрипт можно составить, например, в OpenOffice Calc добавить необходимые поля (команды, кавычки), и затем сохранить в формате csv с разделителем "пробел".

Можно сначала создать все учётные записи, а зетем у всех поменять пароль.

Чтобы корректно отображались кирилические буквы, скрипт лучше выполнять от имени root или можно настроить локаль. Проверить настройки локали можно командной:

# echo $LANG
ru_RU.UTF-8

а установить командами:

LANG=ru_RU.UTF-8
export $LANG


Перенос писем

Перенесём все письма со старого сервера с помощью программы imapsync, способной синхронизировать почтовые ящики по протоколу IMAP. Эта задача довольно хорошо описана на вики, на основе неё я и написал весь этот пункт. Для выполнения переноса нужно знать пароль старой учётной записи и новой, что не очень удобно для автоматизации процесса. Мы обойдём это требование, воспользовавшись своими администраторскими привилегиями. Для определённсти решим, что у нас почтовый домен mydomain.ru (хотя можно синхронизировать ящики из разных доменов), старый сервер имеет ip адрес 10.0.0.211, а новый - 10.0.0.254 (можно использовать и DNS имена) Краткий алгоритм такой (дальше будет подробней, так что, если не понятно, то не смущайтесь):

  1. Выберем любой почтовый ящик из переносимого домена, пароль которого мы знаем, скажем, user@mydomain.ru и создадим в его каталоге ссылки на все почтовые ящики (каталоги) домена.
  2. На новых ящиках придётся временно установить у всех один пароль.
  3. Синхронизировать ящики на новом сервере будем всегда с одним этим выбранным пользователем, но не весь его каталог, а лишь с тем подкаталогом, который является ссылкой на реальный ящик.
  4. После синхронизации всех ящиков восстановим пароли.


  • Сначала синхронизируем только тот ящик, пароль которого мы знаем и выбрали как основной для последующей синхронизации всех. Это нам заодно поможет выясненить точные настройки подключения к обоим IMAP серверам. создаём скрипт imap_sync_alone.sh:
#!/bin/bash
imapsync --nosyncacls --syncinternaldates \
--host1 10.0.0.211 --port1 143 --authmech1 PLAIN --user1 user@mydomain.ru --passfile1 /tmp/zimbra/user \
--host2 10.0.0.254 --ssl2 --port2 993 --authmech2 PLAIN --user2 user@mydomain.ru --passfile2 /tmp/zimbra/user INBOX/ 2> /tmp/zimbra/error.log > /tmp/zimbra/user.log

Этот скрипт можно запустить на любом из серверов. Проверяем журнал, проверяем, что письма перенесены. Теперь займёмся автоманизацией переноса остальных записей.

  • На старом сервере создаём ссылки с помощью скрипта create_links.sh:
create_links.sh
#!/bin/bash
#
# Script to create symlinks to all mail dirs
#
DATE=`date +%Y.%m.%d_%H:%M`
LOGFILE="create_links.log"
MAILDIR="/var/spool/vmail"
ADMINDIR="user@mydomain.ru"

echo "$DATE Start to create links" > $LOGFILE

# Begin 'for' loop, calling the list of user names
for USER in `ls $MAILDIR`
do
    ln -s $MAILDIR/$USER $MAILDIR/$ADMINDIR/.$USER
    echo Link created for $USER >> $LOGFILE
done

echo "" >> $LOGFILE
echo "Remove admin recursive link: $MAILDIR/$ADMINDIR/.$ADMINDIR" >> $LOGFILE
rm -f $MAILDIR/$ADMINDIR/.$ADMINDIR

echo "$DATE All done" >> $LOGFILE
  • Подготовим скрипт update_pass.sh для восстановления паролей. Для этого используем скрипт import.sh подготовленный во время переноса пользователей:
# cat ./import.sh | grep userPassword > update_pass.sh

проверьте, что в нём остались только записи вида:

zmprov ma user_name@mydomain.ru userPassword '{crypt}$1$18445fb2$8ZPUW9tFPzmT3v4j9SF5Y.'
  • Создадим временных каталог и сделаем его общедоступным:
# mkdir /tmp/zimbra
# chmod 777 /tmp/zimbra

В нём будем вести журнал выполнения синхронизации, сюда же положим дополнительные файлы

  • update_pass.sh - скрипт восстановления паролей
  • pass_adm - пароль пользователя user@mydomain.ru
  • pass_tmp - единый временный пароль для всех пользователей, я указал 1234567
  • userlist - список всех пользователей кому нужно синхронизировать ящик. Этот список можно получить из update_pass.sh, если знать как вытащить из строки подстроку между вторым и третим пробелом. С perl'ом я связываться не хотел, как сделать шелом не знаю, поэтому мне быстрее было вывести этот файл на экран командой cat затем скопировать в OpenOffice Calc разбив столбцы по пробелам и, взяв 3-й столбец, вставить его в редакторе mc в открытый файл userlist. На это ушла минута-две.
  • Создадим скрипт для синхронизации всех почтовых ящиков imap_sync_all.sh:
imap_sync_all.sh
#!/bin/bash
#
# Script to migrate all imap mailboxes using the single account
# 
DATE=`date +%Y.%m.%d_%H:%M`
TMPDIR="/tmp/zimbra"
LOGFILE=$TMPDIR/"imap_sync_all.log"
LOGERRORS=$TMPDIR/"imap_sync_errors.log"
PASSADM=$TMPDIR/pass_adm
PASSTMP=$TMPDIR/pass_tmp
PASS=`cat $PASSTMP`
echo "$DATE IMAPSync starting" > $LOGFILE
echo "$DATE IMAPSync starting" > $LOGERRORS

# Begin 'for' loop, calling the list of user names already collected
for USER in `cat $TMPDIR/userlist`
do
# Reset the Zimbra password temporarily:
zmprov setPassword $USER $PASS

# Then migrate:

echo "" >> $LOGFILE
echo "-------------------------------------------------" >> $LOGFILE
echo "--- syncronize account: $USER -------" >> $LOGFILE
echo "-------------------------------------------------" >> $LOGFILE
/usr/bin/imapsync --nosyncacls --syncinternaldates \
--host1 10.0.0.211 --port1 143 --authmech1 PLAIN --user1 user@mydomain.ru --passfile1 $PASSADM \
--host2 10.0.0.254 --ssl2 --port2 993 --authmech2 PLAIN --user2 $USER --passfile2 $PASSTMP \
--folderrec INBOX.$USER --regextrans2 's/(.*)/INBOX/' 2>> $LOGERRORS >> $LOGFILE

done

echo "" >> $LOGFILE
echo "$DATE Change the passwords back to the encrypted ones" >> $LOGFILE
$TMPDIR/update_pass.sh

echo "" >> $LOGFILE
echo "$DATE All done" >> $LOGFILE
echo "$DATE All done" >> $LOGERRORS


Учтите, что синхронизация идёт довольно долго. После завершения, загляните в журнал, всё ли прошло успешно, если да, то можно удалять каталог /tmp/zimbra

Подробней про миграцию на Zimbra можно узнать на официальной странице


Настройка алиасов домена

Настроим (если есть) алиасы домена. Если хотим сделать для существущего домена domain.com ссылку (alias) example.com, то выполняем:

$ zmprov createAliasDomain example.com domain.com zimbraMailCatchAllForwardingAddress @domain.com

Подробней можно узнать на официальной страничке


Борьба со спамом

Этому посвящена специальная статья на вики Zimbra (на англ.).

Чтобы добавить правило, редактируем файл /opt/zimbra/conf/salocal.cf.in, добавляя две строки:

body LOCAL_RULE    /порно/
score LOCAL_RULE   10.0

Проверено на кирилице в кодировке utf8. По-умолчанию файл доступен только для чтения, что можно исправить:

chmod u+w ./salocal.cf.in

После этого нужно перезагрузить zimbra:

$ zmcontrol restart

но может быть будет достаточно перезагрузить только модуль антиспама:

$ zmantispamctl restart


Ограничение размера ящика и письма

Zimbra в качестве MTA использует Postfix, где эти ограничения задаются переменными:

# устанавливаем ограничение на ящик в 100Мб и на письмо в 10Мб
mailbox_size_limit = 102400000
message_size_limit = 10240000

Конфигурационный файл /opt/zimbra/postfix/conf/main.cf генерируется при каждом запуске зимбры, поэтому исправлять его нет смысла. Редактируем файл /opt/zimbra/conf/zmmta.cf, но так как он доступен только для чтения, то сначала придётся сменить права:

$ chmod u+w ./zmmta.cf

Находим вышеуказанные переменные, присваиваем нужные значения, перезагружаем зимбру:

$ zmcontrol restart


Маршрутизация почты (mail routing)

Так как Zimbra использует Postfix как МТА, то маршрутизацию (перенаправление) почты настраиваем в нём. Создаём файл с описанием маршрутов /opt/zimbra/postfix/conf/transport-table:

mydomain.com     :[mail.otherdomain.com]
mydomain.ru      :[192.168.0.10]

В этой таблице мы перенаправляем всю почту для домена mydomain.com на другой адрес в Интернете mail.otherdomain.com, а почту для домена mydomain.ru передаём почтовому серверу 192.168.0.10 в локальной сети. При этом имя пользователя (адресата) не изменяется.


! Маршрутизация почты не затрагивает правила IP маршрутизации и меняет лишь домен назначения. Таким образом, после того как эти правила были применены дальнейшее разрешение DNS имён и отправка IP пакетов идут своим обычным чередом.


Полезные команды

Все команды запускаются от имени пользователя zimbra:

$ zmcontrol - управление всеми сервисам Zimbra сразу (status | stop | start | maintenance)

$ zmcontrol <имя_сервиса> команда - управление отдельным сервисом (status | stop | start | maintenance)

$ zmprov - работа с каталогом (LDAP). Запустив без параметров, зайдём в командный интерфейс и получим мощный инструмент для адмиинистрирования:

prov> help

 zmprov is used for provisioning. Try:

     zmprov help account         help on account-related commands
     zmprov help calendar        help on calendar resource-related commands
     zmprov help commands        help on all commands
     zmprov help config          help on config-related commands
     zmprov help cos             help on COS-related commands
     zmprov help domain          help on domain-related commands
     zmprov help freebusy        help on free/busy-related commands
     zmprov help list            help on distribution list-related commands
     zmprov help log             help on logging commands
     zmprov help misc            help on misc commands
     zmprov help mailbox         help on mailbox-related commands
     zmprov help notebook        help on notebook-related commands
     zmprov help right           help on right-related commands
     zmprov help search          help on search-related commands
     zmprov help server          help on server-related commands
     zmprov help share           help on share related commands

На оффициальной вики можно узнать подробней про команду Zmprov и примеры с ней.

Решение проблем (troubleshooting)

Не отображается "Статистика сервера"

Не отображается "Статистика сервера", при попытке обновить, выдаёт ошибку:

Message: system failure: Unable to read logger stats Error code: service.FAILURE Method: GetLoggerStatsRequest Details:soap:Receiver

Решение:нужно доустановить rsyslog и выполнить его настройку от рута:

# apt-get install rsyslog
# /opt/zimbra/bin/zmsyslogsetup

переключиться на пользователя zimbra и перезапустить:

# su - zimbra
$ zmcontrol stop
$ zmcontrol start

Unable to commit database transaction

Полное сообщение об ошибке в /opt/zimbra/log/mailbox.log может выглядить так (ip случайный):

FATAL [LmtpServer-21] [ip=193.192.191.190;] system - Unable to commit database transaction.  Forcing server to abort.

или так:

FATAL [LmtpServer-7] [name=user@domain.ru;mid=40;ip=193.192.191.190;] system - Unable to commit database transaction.  Forcing server to abort.

более подробное описание можно почитать в журнале mysql_error.log поискав по ключевому слову "error".

Решение: перезагрузить сервер. Ошибка исчезнет если была проблема в кэше. Если ошибка не исчезла, то нужно восстанавливать таблицу(ы), см. Forcing InnoDB Recovery

Перенос сервера с 32 разрядной системы на 64 разрядную

Подробный мануал есть на официальном сайте: http://wiki.zimbra.com/index.php?title=64_bit

Полезные ссылки

Zimbra и Active Directory