Ejabberd.

Среди современных пользователей интернета почти каждый пользуется каким-либо сервисом мгновенных сообщений. Как известно спрос рождает предложение и, следовательно, подобных сервисов  нарожалась уйма. Это ICQ, IRC, MSN и, конечно же, Jabber. Любая уважающая себя социальная сеть предлагает такие сервисы, будь то Вконтакте, Одноклассники, Твиттер, Фэйсбук или ЖЖ. Чем же так привлекателен Jabber? Можно назвать много критериев, но самый интересный из них, IMHO - транспорты. Транспорт - это механизм взаимодействия между протоколами, позволяющий использовать  клиент, поддерживающий только протокол Jabber, для отправки и получения сообщений из других сетей мгновенных сообщений. В этой статье я опишу установку Jabber-сервера ejabberd с поддержкой  транспорта в ICQ, веб-интерфейсов и прочих вкусностей. В качестве основы я использовал Gentoo, но с некоторыми корректировками подойдет любой современный дистрибутив Linux. Для хранения оффлайновых сообщений, и разного рода служебной информации будет использоваться встроенная база данных, а для аутентификации и контактов (ростера) будет внешняя БД Postgresql, которая позволит иипользовать одинаковый пароль/логин для жаббера, почты фтп и чего-нибудь еще, если будет такая необходимость
Начинаем, разумеется с  установки ejabberd:
# emerge -av ejabberd
USE-флаги использовал следующие:
USE="mod_irc mod_muc mod_proxy65 mod_pubsub mod_statsdx odbc pam ssl web zlib -captcha -debug -ldap"
Можно немного поменять на свой вкус.
Небольшая ремарка. Я устанавливал версию не из официального дерева, а из самописного ебилда. Он доступен в моем Mercurail-репозитории на http://hg.vonabarak.ru/gentoo_overlay/  Единственное отличие от версии из официального дерева - наложение патча для корректной работы с контактами в ростере при использовании транспортов. Подробнее об этом патче тут http://spectrum.im/projects/spectrum/wiki/Remote_roster
Далее редактируем конфиг /etc/jabber/ejabberd.cfg:


{loglevel, 4}. %% Уровень информативности лога. На время отладки можно выставить 4 или 5. Как все устаканиться - 3.

{watchdog_admins, ["Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript."]}. %% jid на который будет отправляться разная информация о работе сервера.

{hosts, ["example.ru"]}. %% Доменное нашего хоста.

{listen,
 [
  %% Порт, который будет слушать ejabberd для соединения клиентов
  {5222, ejabberd_c2s, [
            %% Путь к файлу сертификата (о них немного ниже)
            {certfile, "/etc/ssl/ejabberd/server.pem"}, starttls,
            {access, c2s},
            {shaper, c2s_shaper},
            {max_stanza_size, 65536}
               ]},

  %%  Порт для соединения со старыми клиентами, не поддерживающими STARTTLS. Я не включал даже.
  %%{5223, ejabberd_c2s, [
  %%            {access, c2s},
  %%            {shaper, c2s_shaper},
  %%            {certfile, "/etc/ssl/ejabberd/server.pem"}, tls,
  %%            {max_stanza_size, 65536}
  %%               ]},

  %% Порт для соединения с другими серверами.
  {5269, ejabberd_s2s_in, [
               {shaper, s2s_shaper},
               {max_stanza_size, 131072}
              ]},

  %% Порт для подключения транспорта ICQ.
  {5238, ejabberd_service, [
                  {access, all},
                  {shaper_rule, fast},
                  {ip, {127, 0, 0, 1}},
                  {hosts, ["icq.example.ru"],
                   [{password, "icqsecret"}]
                  }
                 ]},

  %% Порт для подключения транспорта в другие сервисы на основе жаббера, но не поддерживающие server2server coединений (вконтакт, одноклассники етс.)
  {5237, ejabberd_service, [
                  {access, all},
                  {shaper_rule, fast},
                  {ip, {127, 0, 0, 1}},
                  {hosts, ["j2j.example.ru"],
                   [{password, "j2jsecret"}]
                  }
                 ]},

  %% Порт и протокол  STUN сервиса. Необходим для потокового звука и видео.
  {{3478, "81.17.141.156", udp}, ejabberd_stun, []},

  %% Порт веб-сервера. Необходим не только для администрирования, но и для http-bind/http-poll (об этом позже).
  {5280, ejabberd_http, [
             %%{request_handlers,
             %%[
             %%  {["web"], mod_http_fileserver}
             %%]},
             %% captcha,
             http_bind,
             http_poll,
             %% register,
             web_admin
            ]}

 ]}.

%% Использовать для s2s-соединений (server to server) шифрование. Советую включить, т.к. некоторые серверы отказываются принимать соединения без шифрования.
{s2s_use_starttls, true}.

%% Сертификат SSL для s2s. Можно использовать тот же, что и для с2s (client to server) соединений
{s2s_certfile, "/etc/ssl/ejabberd/server.pem"}.

%% Можно определить свой сертификат для каждого домена, если их несколько. У меня один, поэтому закомментировано.
%%{domain_certfile, "example.org", "/path/to/example_org.pem"}.
%%{domain_certfile, "example.com", "/path/to/example_com.pem"}.

%% Дефолтная политика s2s-соединений. Разрешаем.
{s2s_default_policy, allow}.

%% Можно явно разрешить или запретить соединения от некоторых серверов.
%%{{s2s_host, "goodhost.org"}, allow}.
%%{{s2s_host, "badhost.org"}, deny}.

%% Исходящие s2s-соединения. Протокол соединения (предпочтиается тот, который здесь указан первым) и таймаут соединения в миллисекундах
{outgoing_s2s_options, [ipv4, ipv6], 10000}.

%% Метод аутентикации. Мы будем использовать внешнюю базу данных Postgresql.
{auth_method, odbc}.

%% PostgreSQL
%% Хост, база, юзер и пароль для подключения.
{odbc_server, {pgsql, "localhost", "vmail", "vmail", "secret"}}.

%% Количество одновременных подключений к базе данных. Использовать больше одного смысла не вижу
{odbc_pool_size, 1}.

%% Шейперы трафика. Особо не вникал, оставил как есть.
{shaper, normal, {maxrate, 1000}}.
{shaper, fast, {maxrate, 50000}}.
{max_fsm_queue, 1000}.

%% Укажем суперюзера
{acl, admin, {user, "bob", "example.ru"}}.
{acl, local, {user_regexp, ""}}.

%% Язык по умолчанию.
{language, "ru"}.

%% Модули. Если что-то не комментирую, значит оставил по умолчанию, как было.
{modules,
 [
  {mod_adhoc,    []},
  {mod_announce, [{access, announce}]}, % recommends mod_adhoc
  {mod_blocking,[]}, % requires mod_privacy
  {mod_caps,     []},
  {mod_configure,[]}, % requires mod_adhoc
  {mod_disco,    []},
  %%{mod_echo,   [{host, "echo.localhost"}]},
  {mod_irc,      []},
  {mod_http_bind, []},
  {mod_last,     []},
  {mod_muc,      [
          {host, "conference.@HOST@"},
          {access, muc},
          {access_create, muc_create},
          {access_persistent, muc_create},
          {access_admin, muc_admin}
         ]},
  {mod_muc_log,[]},
  {mod_offline,  [{access_max_user_messages, max_user_offline_messages}]},
  {mod_ping,     []},
  {mod_privacy,  []},
  {mod_private,  []},
  {mod_proxy65,[]},
  {mod_pubsub,   [
          {access_createnode, pubsub_createnode},
          {ignore_pep_from_offline, true}, % reduces resource comsumption, but XEP incompliant
          {last_item_cache, false},
          {plugins, ["flat", "hometree", "pep"]}  % pep requires mod_caps
         ]},
  {mod_roster_odbc,   []}, %% вот здесть удалил mod_roster и написал mod_roster_odbc, так как ростер мы будем хранить в Postgresql
  {mod_service_log,[]},
  {mod_shared_roster,[]},
  {mod_stats,    []},
  {mod_time,     []},
  {mod_vcard,    []},
  {mod_version,  []}
 ]}.

%% Можно настроить модули для разных доменов по-разному.
%%{host_config, "localhost",
%% [{{add, modules},
%%   [
%%    {mod_echo, [{host, "mirror.localhost"}]}
%%   ]
%%  }
%% ]}.



Теперь о сертификатах для шифрованных SSL соединений. Можно использовать самоподписанный сертификат (информации о том, как создавать сертификаты с помощью openssl достаточно, поэтому я не стану акцентировать на этом внимания), а можно получить на https://www.startssl.com/ бесплатный сертификат, который будет распознаваться некоторыми жаббер-клиентами (например, psi). Это совершенно непринципиально, но я выбрал второй способ. Кроме того, на генту при установке из ебилда генерируется дефолтный сертификат. Если вас не особо беспокоит это, то можно просто ничего не делать. Использоваться будет сертификат автоматически созданный при установке.
База данных. Как я уже говорил, юзать будем Postgresql. И, если он еще не установлен, то самое время его установить.
# emerge -av postgresql-server
Для обращения к базе данных ejabberd использует специальный драйвер, но драйвер для Postgresql отчего-то не входит в стандартную поставку ejabberd. Поэтому я поступил следующим образом:
Скачал этот драйвер из SVN:
$ svn checkout http://svn.process-one.net/ejabberd-modules ejabberd-modules
Скомпилировал его:
$ cd ejabberd-modules/pgsql/trunk
$ ./build.sh
и скопировал полученные beam файлы из каталога ebin в /usr/local/lib/ejabberd/ebin
Чтобы ejabberd знал, откуда ему подгружать эти модули указываем их в файле /etc/jabber/ejabberdctl.cfg Добавляем туда следующую строку:
ERL_OPTIONS="-pa /usr/local/lib/ejabberd/ebin"
Конечно, это немного не gentoo-way, но это самый простой на мой взгляд способ.
О базе данных. Если установка с нуля, то нужно настроить Postgresql и создать базу. Углубляться в дебри Postgresql не стану, так как это выходит за пределы темы, но для быстрого старта могу вкратце описать создание базы с помощью CLI клиента для Postgresql:
Сначала стартуем сервер Postgresql:
# /etc/init.d/postgresql-9.1 start
Подключаемся к серверу как пользователь postgres:
# sudo -u postgres psql
Видим приглашение psql, в ответ на которое пишем:
postgres=# CREATE USER jabber UNENCRYPTED PASSWORD 'secret' ;
postgres=# CREATE DATABASE jabber OWNER jabber ;
postgres=# \q
Этими двумя SQL-запросами мы создали пользователя jabber с паролем secret и базу данных jabber с владельцем jabber. Создаем таблицы в базе для ejabberd:
$ psql jabber jabber < pg.sql
Если политика Postgresql предусматривает запрос пароля от локальных юзеров, то вводим пароль пользователя пользователя jabber (которого мы только что создали). Файл pg.sql можно взять из исходников ejabberd в src/odbc
В примере создания базы данных я использовал имя базы jabber и пользователя jabber, однако в предложенном конфиге ejabberd.cfg база данных и пользователь называются vmail. Дело в том, что я использовал уже имеющуюся базу аутентификации для postfix/dovecot, которая называлась vmail. Если создавать новую базу только для жаббера, то, конечно, логичнее назвать ее jabber и поменять сообветсвующие настройки в /etc/jabber/ejabberd.cfg В общем случае, для аутентификации неоходима только таблица, содержащая колонки username и password.
Теперь можно смело запускать ejabberd:
# /etc/init.d/ejabberd start
Создать пользователей можно через веб-интерфейс, который будет доступен на http://example.ru:5280/web или непосредственно добавляя записи в базу данных.
Для работы транспортов, многопользовательских конференций и некоторых других фишек жаббера необходимо создать поддомены и SRV-записи для домена. В случае с example.ru, который я взял за пример нужно добавить следующие строки в файл зоны:


jabber  IN      A       ваш.ip.ад.рес
conference IN   CNAME   jabber.example.ru.
proxy   IN      CNAME   jabber.example.ru.
pubsub  IN      CNAME   jabber.example.ru.
icq     IN      CNAME   jabber.example.ru.
irc     IN      CNAME   jabber.example.ru.
j2j     IN      CNAME   jabber.example.ru.
vujd    IN      CNAME   jabber.example.ru.
_xmpp-server._tcp.vonabarak.ru. SRV 5 0 5269 jabber.example.ru.
_xmpp-client._tcp.vonabarak.ru. SRV 5 0 5222 jabber.example.ru.
_jabber._tcp.vonabarak.ru. SRV 5 0 5222 jabber.example.ru.



Теперь о транспортах. Для этих целей я использовал spectrum (http://spectrum.im) версии 1.4.8. Вторая версия показалась мне уж очень нестабильной. В основном дереве портежей Gentoo ебилда для spectrum нет. Его можно взять из моего оверлея, о котором я писал выше (http://hg.vonabarak.ru/gentoo_overlay/)или поискать в других оверлеях. После установки нужного ебилда в свой локальный овелей просто устанавливаем его:
# emerge -av spectrum
далее редактируем /etc/spectrum/icq.cfg Нужно указать порт и пароль и jid, которые определены в /etc/jabber/ejabberd.cfg в секции параметров ICQ-транспорта. Для приведенного конфига ejabberd конфиг spectrum будет такой:


[service]
enable=1
protocol=icq
#encoding=CP1251
server=127.0.0.1
use_proxy=0
jid=icq.vonabarak.ru
password=icqsecret
port=5238
config_interface = /run/spectrum/icq.sock
admins=Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
name=My icq Transport
language=ru
vip_mode=0
pid_file=/run/spectrum/icq.pid

[registration]
enable_public_registration=1
[features]
filetransfer=0
avatars=1
chatstates=1
statistics=1

[logging]
log_file=/var/log/spectrum/icq.log
log_areas=xml;purple

[database]
type=sqlite

[purple]
userdir=/var/lib/spectrum/icq/userdir


и для транспорта в жаббер совместимые втконтакто-одноклассники редактируем /etc/spectrum/xmpp.cfg, аналогичным образом. Указывая в качестве jid j2j.example.ru.
запускаем spectrum:
# /etc/init.d/spectrum.icq star
t# /etc/init.d/spectrum.xmpp start
Все, можно пользоваться. О том, как это делать я напишу еще одну статью.