Grommunio: различия между версиями
Vovan (обсуждение | вклад) (→Записи для домена) |
Vovan (обсуждение | вклад) (→Скрипт получения адресных книг из аккаунтов zimbra) |
||
| (не показано 36 промежуточных версий этого же участника) | |||
| Строка 25: | Строка 25: | ||
при инсталляции. | при инсталляции. | ||
| + | |||
| + | Порты 80 и 443 должны быть зарулены на сервер, если предполагается настройка сертификатов инсталлером через LestsEncrypt! | ||
| + | |||
| + | |||
| + | После инсталляции админка будет доступна на порту | ||
| + | |||
| + | 8443 | ||
| + | |||
| + | и туда входить нужно только по логину (не по полной почте). | ||
| + | |||
| + | Т.е. только по | ||
| + | |||
| + | admin | ||
| + | |||
| + | , а не по | ||
| + | |||
| + | admin@myorg.net | ||
| + | |||
| + | |||
| + | А в веб интерфейсе почты -- наоборот. Он находится по стандартному порту | ||
| + | |||
| + | 443 | ||
| + | |||
| + | и туда входим по | ||
| + | |||
| + | admin@myorg.net | ||
| + | |||
| + | , а не по | ||
| + | |||
| + | admin | ||
| + | |||
| + | |||
| + | Остальные порты важны будут при эксплуатации и при развёртывании их можно не забрасывать, о них -- ниже. | ||
==Порты== | ==Порты== | ||
| Строка 66: | Строка 99: | ||
| '''Маршрутизация почты''' || <code>MX</code> || <code>dig MX myorg.net +short</code> || <code>1 mail.myorg.net.</code> | | '''Маршрутизация почты''' || <code>MX</code> || <code>dig MX myorg.net +short</code> || <code>1 mail.myorg.net.</code> | ||
|- | |- | ||
| − | | '''IP-адрес узла''' || <code>A</code> || <code>dig A mail.myorg.net +short</code> || <code>37. | + | | '''IP-адрес узла''' || <code>A</code> || <code>dig A mail.myorg.net +short</code> || <code>37.1.2.3</code> |
|- | |- | ||
| − | | '''Обратная зона (PTR)''' || <code>PTR</code> || <code>dig -x 37. | + | | '''Обратная зона (PTR)''' || <code>PTR</code> || <code>dig -x 37.1.2.3 +short</code> || <code>mail.myorg.net.</code> |
|- | |- | ||
| − | | '''Разрешенные отправители (SPF)''' || <code>TXT</code> || <code>dig TXT myorg.net +short | grep spf</code> || <code>"v=spf1 a mx ip4:37. | + | | '''Разрешенные отправители (SPF)''' || <code>TXT</code> || <code>dig TXT myorg.net +short | grep spf</code> || <code>"v=spf1 a mx ip4:37.1.2.3 ~all"</code> |
|- | |- | ||
| '''Цифровая подпись (DKIM)''' || <code>TXT</code> || <code>dig TXT mailserver._domainkey.myorg.net +short</code> || <code>"v=DKIM1; k=rsa; p=MIGfMA...AFwIDAQAB"</code> | | '''Цифровая подпись (DKIM)''' || <code>TXT</code> || <code>dig TXT mailserver._domainkey.myorg.net +short</code> || <code>"v=DKIM1; k=rsa; p=MIGfMA...AFwIDAQAB"</code> | ||
| Строка 76: | Строка 109: | ||
| '''Политика безопасности (DMARC)''' || <code>TXT</code> || <code>dig TXT _dmarc.myorg.net +short</code> || <code>"v=DMARC1; p=quarantine; rua=mailto:admin@myorg.net"</code> | | '''Политика безопасности (DMARC)''' || <code>TXT</code> || <code>dig TXT _dmarc.myorg.net +short</code> || <code>"v=DMARC1; p=quarantine; rua=mailto:admin@myorg.net"</code> | ||
|} | |} | ||
| + | |||
| + | |||
| + | БОльшую часть из этой информации можно также получить из формы настроек домена из админки grommunio. | ||
| + | |||
| + | Но есть нюанс с двумя записями: | ||
| + | |||
| + | 1. Обратная зона (PTR) -- её невозможно настроить в админке провайдера днс зоны. Её должен настроить провайдер, выдающий интернет для почтового сервера и статический айпи адрес для него. Здесь необходимо добиться от интернет-провайдера, чтобы на его стороне была прописана эта самая обратная зона PTR. Суть в том, чтобы происходил процесс наоборот: по айпи адресу -- выдавался домен. Для почтовых серверов это важно! | ||
| + | |||
| + | 2. Цифровая подпись (DKIM) -- чтобы корректно работала эта запись, сначала её необходимо настроить. Об этом подробно написано ниже! | ||
| + | |||
| + | 3. Разрешенные отправители (SPF) -- здесь также должен фигурировать статический айпи адрес почтового сервера. | ||
| + | |||
| + | В примере это адрес 37.1.2.3, в реальном кейсе это должен быть везде айпи адрес конкретного сервера | ||
==Настроить подпись писем через DKIM== | ==Настроить подпись писем через DKIM== | ||
| Строка 113: | Строка 159: | ||
The private key has been generated on the server at | The private key has been generated on the server at | ||
| − | /var/lib/grommunio-admin-api/myorg.net. | + | /var/lib/grommunio-admin-api/myorg.net.dkim.key |
Этот путь до файла ключа будет нужен потом при настройке сервера по ssh. | Этот путь до файла ключа будет нужен потом при настройке сервера по ssh. | ||
| − | ===Настройка сервера по ssh=== | + | ===Настройка сервера по ssh и настройки конфигов на сервере=== |
Для доступа по ssh под root лучше сразу получить на сервер открытую часть ssh ключа и настроить конфиг ssh для быстрого подключения. Под root на сервер по паролю подключиться не получится. А через виртуальный дисплей виртуальной машины нельзя будет скопировать текст на сервер. | Для доступа по ssh под root лучше сразу получить на сервер открытую часть ssh ключа и настроить конфиг ssh для быстрого подключения. Под root на сервер по паролю подключиться не получится. А через виртуальный дисплей виртуальной машины нельзя будет скопировать текст на сервер. | ||
| Строка 140: | Строка 186: | ||
2. Копируем тот самый файл, путь к которому нам сообщили в веб интерфейсе в предыдущем пункте в файл с названием селектора в только что созданный каталог | 2. Копируем тот самый файл, путь к которому нам сообщили в веб интерфейсе в предыдущем пункте в файл с названием селектора в только что созданный каталог | ||
| − | cp /var/lib/grommunio-admin-api/myorg.net. | + | cp /var/lib/grommunio-admin-api/myorg.net.dkim.key /var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key |
3. Создайм файл | 3. Создайм файл | ||
| Строка 149: | Строка 195: | ||
sign_authenticated = true; | sign_authenticated = true; | ||
sign_local = true; | sign_local = true; | ||
| + | |||
| + | use_domain = "header"; | ||
| + | use_domain_sign_local = "full"; | ||
domain { | domain { | ||
"myorg.net" { | "myorg.net" { | ||
| − | path = "/var/lib/grommunio-antispam/dkim/myorg.net | + | path = "/var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key"; |
selector = "mailserver"; | selector = "mailserver"; | ||
} | } | ||
} | } | ||
| − | + | EOF | |
</pre> | </pre> | ||
| Строка 163: | Строка 212: | ||
chown -R groas:grommunio /var/lib/grommunio-antispam/dkim/ | chown -R groas:grommunio /var/lib/grommunio-antispam/dkim/ | ||
| − | chmod 600 /var/lib/grommunio-antispam/dkim/myorg.net | + | chmod 600 /var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key |
| + | |||
| + | 5. Оставляем в доверенных сетях только локальную петлю и устанавливаем параметр non_smtpd_milters в файл конфигурации postfix | ||
| + | |||
| + | echo 'mynetworks = 127.0.0.0/8' >> /etc/postfix/main.cf | ||
| + | echo 'non_smtpd_milters = inet:localhost:11332' >> /etc/postfix/main.cf | ||
| − | + | 6. Перезапустить сервисы | |
systemctl restart grommunio-antispam | systemctl restart grommunio-antispam | ||
systemctl restart postfix | systemctl restart postfix | ||
| + | |||
| + | Перезапуска этих сервисов для полноценной работы механизма подписи емэйлов может быть недостаточно. Тогда перезагружаем сервер полностью | ||
| + | |||
| + | reboot | ||
| + | |||
| + | А если и это не помогло, то смотрим что в логах | ||
| + | |||
| + | tail -f /var/log/grommunio-antispam/rspamd.log | ||
| + | |||
| + | ====Важный момент при настройке почтового сервера на доменах третьего уровня==== | ||
| + | |||
| + | Общая суть в том, что понадобятся параметры | ||
| + | |||
| + | use_esld = false; | ||
| + | use_effective_domain = false; | ||
| + | |||
| + | в файле | ||
| + | |||
| + | /etc/grommunio-antispam/override.d/dkim_signing.conf | ||
| + | |||
| + | Иначе сервер будет схлопывать домен до первого уровня и подставлять это в тело письма вот сюда (это часть письма в сыром виде): | ||
| + | |||
| + | ...DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=myorg.net; s=mailserver; t=1785189679;... | ||
| + | |||
| + | В случае с доменом третьего уровня, например, unit.myorg.net, значение должно быть | ||
| + | |||
| + | d=unit.myorg.net | ||
| + | |||
| + | , а без этих параметров оно: | ||
| + | |||
| + | d=myorg.net | ||
| + | |||
| + | Следовательно, принимающие сервера пытаются прочитать ключ для проверки подписи с домена myorg.net, а не с домена unit.myorg.net и не могут её проверить. | ||
| + | |||
| + | |||
| + | |||
| + | Пример рабочего конфига для домена третьего уровня | ||
| + | <pre> | ||
| + | cat << 'EOF' > /etc/grommunio-antispam/override.d/dkim_signing.conf | ||
| + | enabled = true; | ||
| + | sign_authenticated = true; | ||
| + | sign_local = true; | ||
| + | |||
| + | use_domain = "header"; | ||
| + | |||
| + | # КРИТИЧЕСКИ ВАЖНО: Выключаем нормализацию eSLD, которая схлопывает домен unit.myorg.net до myorg.net | ||
| + | use_esld = false; | ||
| + | use_effective_domain = false; | ||
| + | |||
| + | selector = "mailserver"; | ||
| + | path = "/var/lib/grommunio-antispam/dkim/unit.myorg.net.mailserver.key"; | ||
| + | EOF | ||
| + | </pre> | ||
===Настройка TXT записи для домена=== | ===Настройка TXT записи для домена=== | ||
| Строка 198: | Строка 305: | ||
Перед тем, как конфигурировать TXT запись на уровне DNS необходимо свериться: точно ли у ключа, который ранее был скопирован в файл | Перед тем, как конфигурировать TXT запись на уровне DNS необходимо свериться: точно ли у ключа, который ранее был скопирован в файл | ||
| − | /var/lib/grommunio-antispam/dkim/myorg.net/ | + | /var/lib/grommunio-antispam/dkim/myorg.net/dkim.key |
base64 строка соответствует значению ключа | base64 строка соответствует значению ключа | ||
| Строка 208: | Строка 315: | ||
Получить этот ключ можно следующим образом: | Получить этот ключ можно следующим образом: | ||
| − | openssl rsa -in /var/lib/grommunio-antispam/dkim/myorg.net/ | + | openssl rsa -in /var/lib/grommunio-antispam/dkim/myorg.net/dkim.key -pubout -outform DER 2>/dev/null | base64 -w 0 |
В ответ придёт что-то вроде: | В ответ придёт что-то вроде: | ||
| Строка 299: | Строка 406: | ||
Важно! У сервиса этого есть ограничения на кол-во проверок в сутки. Потом он просит денюжку или ждать следующего дня. Поэтому сначала проверяем текст в исходниках письма, как описано выше, и только потом - через сервис. | Важно! У сервиса этого есть ограничения на кол-во проверок в сутки. Потом он просит денюжку или ждать следующего дня. Поэтому сначала проверяем текст в исходниках письма, как описано выше, и только потом - через сервис. | ||
| − | == | + | ==Скрипты и автоматизация== |
| + | |||
| + | Все скрипты, представленные здесь, запускать необходимо с сервера Grommunio! | ||
| + | |||
| + | |||
| + | ===Скрипт создания одного ящика=== | ||
| + | |||
| + | <pre> | ||
| + | cat << 'EOF' > create_mailbox.sh | ||
| + | #!/bin/bash | ||
| + | USER_GROMMUNIO="$1" | ||
| + | PASS_GROMMUNIO="$2" | ||
| + | |||
| + | # Проверка входных параметров | ||
| + | if [ -z "$USER_GROMMUNIO" ] || [ -z "$PASS_GROMMUNIO" ]; then | ||
| + | echo "Использование: $0 <user_grommunio> <pass_grommunio>" | ||
| + | echo "Пример: $0 user@domain.ru 'ThePass'" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | echo "=== 1. Проверка / Создание ящика $USER_GROMMUNIO в Grommunio ===" | ||
| + | |||
| + | # Проверяем наличие ящика | ||
| + | if grommunio-admin user show "$USER_GROMMUNIO" >/dev/null 2>&1; then | ||
| + | echo "i Ящик $USER_GROMMUNIO уже существует. Пропускаем создание." | ||
| + | else | ||
| + | echo "Пользователь не найден. Создаём ящик $USER_GROMMUNIO..." | ||
| + | |||
| + | DISPLAY_NAME=$(echo "$USER_GROMMUNIO" | cut -d'@' -f1) | ||
| + | |||
| + | # Создаем юзера | ||
| + | grommunio-admin user create "$USER_GROMMUNIO" | ||
| + | if [ $? -ne 0 ]; then | ||
| + | echo "Ошибка создания пользователя $USER_GROMMUNIO!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | # Устанавливаем свойства пользователю | ||
| + | grommunio-admin user modify \ | ||
| + | --property givenname="$DISPLAY_NAME" \ | ||
| + | --property surname="$DISPLAY_NAME" \ | ||
| + | --property displayname="$DISPLAY_NAME" \ | ||
| + | --property country="Russian Federation" \ | ||
| + | "$USER_GROMMUNIO" | ||
| + | if [ $? -ne 0 ]; then | ||
| + | echo "Ошибка установки свойств пользователя $USER_GROMMUNIO!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | # Задаем пароль | ||
| + | grommunio-admin passwd --password "$PASS_GROMMUNIO" "$USER_GROMMUNIO" | ||
| + | if [ $? -ne 0 ]; then | ||
| + | echo "Ошибка установки пароля для $USER_GROMMUNIO!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | echo "✓ Ящик $USER_GROMMUNIO успешно создан и пароль установлен." | ||
| + | fi | ||
| + | EOF | ||
| + | |||
| + | chmod +x create_mailbox.sh | ||
| + | </pre> | ||
| + | |||
| + | |||
| + | ===Скрипт переноса одного ящика из Zimbra в Grommunio=== | ||
| + | |||
| + | Для работы скрипта необходимо наличие рядом предыдущего скрипта (create_mailbox.sh) | ||
| + | |||
| + | А также внутри скрипта необходимо задать адрес сервера Zimbra и логин и пароль мастер-аккаунта Zimbra | ||
| + | |||
| + | <pre> | ||
| + | |||
| + | cat << 'EOF' > migrate_account_from_zimbra_to_grommunio.sh | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Настройки серверов | ||
| + | ZIMBRA_SERVER="192.168.0.1" | ||
| + | GROMMUNIO_SERVER="127.0.0.1" | ||
| + | |||
| + | # Мастер-аккаунт с Zimbra с паролем | ||
| + | ZIMBRA_ADMIN_USER="admin@myorg.net" | ||
| + | ZIMBRA_ADMIN_PASS="SuperAdminPassword" | ||
| + | |||
| + | # Определяем директорию, в которой расположен текущий скрипт | ||
| + | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| + | CREATE_SCRIPT="$SCRIPT_DIR/create_mailbox.sh" | ||
| + | |||
| + | # Чтение аргументов | ||
| + | USER_ZIMBRA="$1" | ||
| + | USER_GROMMUNIO="$2" | ||
| + | PASS_GROMMUNIO="$3" | ||
| + | |||
| + | # Проверка входных параметров | ||
| + | if [ -z "$USER_ZIMBRA" ] || [ -z "$USER_GROMMUNIO" ] || [ -z "$PASS_GROMMUNIO" ]; then | ||
| + | echo "Использование: $0 <mailbox_zimbra> <mailbox_grommunio> <pass_grommunio>" | ||
| + | echo "Пример: $0 old_user@domain.ru new_user@domain.ru 'GromPass'" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | # Проверка наличия и прав на выполнение вспомогательного скрипта | ||
| + | if [ ! -f "$CREATE_SCRIPT" ]; then | ||
| + | echo "Ошибка: Вспомогательный скрипт '$CREATE_SCRIPT' не найден!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | if [ ! -x "$CREATE_SCRIPT" ]; then | ||
| + | echo "Ошибка: Скрипт '$CREATE_SCRIPT' найден, но не имеет прав на выполнение (chmod +x)!" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | # Вызов внешнего скрипта для создания ящика | ||
| + | "$CREATE_SCRIPT" "$USER_GROMMUNIO" "$PASS_GROMMUNIO" | ||
| + | if [ $? -ne 0 ]; then | ||
| + | echo "Ошибка при подготовке ящика $USER_GROMMUNIO через $CREATE_SCRIPT" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | echo "=== 2. Запуск переноса почты из Zimbra в Grommunio ===" | ||
| + | |||
| + | set -x | ||
| + | |||
| + | # Создаем временные защищенные файлы для паролей | ||
| + | PASSFILE1=$(mktemp) | ||
| + | PASSFILE2=$(mktemp) | ||
| + | |||
| + | printf '%s' "$ZIMBRA_ADMIN_PASS" > "$PASSFILE1" | ||
| + | printf '%s' "$PASS_GROMMUNIO" > "$PASSFILE2" | ||
| + | |||
| + | imapsync \ | ||
| + | --host1 "$ZIMBRA_SERVER" \ | ||
| + | --user1 "$USER_ZIMBRA" \ | ||
| + | --authuser1 "$ZIMBRA_ADMIN_USER" \ | ||
| + | --passfile1 "$PASSFILE1" \ | ||
| + | --authmech1 PLAIN \ | ||
| + | --ssl1 \ | ||
| + | --sslargs1 SSL_verify_mode=0 \ | ||
| + | --host2 "$GROMMUNIO_SERVER" \ | ||
| + | --user2 "$USER_GROMMUNIO" \ | ||
| + | --passfile2 "$PASSFILE2" \ | ||
| + | --authmech2 LOGIN \ | ||
| + | --ssl2 \ | ||
| + | --sslargs2 SSL_verify_mode=0 \ | ||
| + | --useheader "Message-ID" \ | ||
| + | --automap \ | ||
| + | --f1f2 "Sent=&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-" \ | ||
| + | --f1f2 "Trash=&BCMENAQwBDsENQQ9BD0ESwQ1-" \ | ||
| + | --f1f2 "Junk=&BB0ENQQ2BDUEOwQwBEIENQQ7BEwEPQQwBE8- &BD8EPgRHBEIEMA-" \ | ||
| + | --f1f2 "Drafts=&BCcENQRABD0EPgQyBDgEOgQ4-" \ | ||
| + | --noflags \ | ||
| + | --errorsmax 500000 \ | ||
| + | --noauthmd5 | ||
| + | |||
| + | # если не надо синхронизировать спам и корзину | ||
| + | # --exclude "Junk" \ | ||
| + | # --exclude "Trash" \ | ||
| + | |||
| + | # Удаляем временные файлы с паролями | ||
| + | rm -f "$PASSFILE1" "$PASSFILE2" | ||
| + | EOF | ||
| + | |||
| + | chmod +x migrate_account_from_zimbra_to_grommunio.sh | ||
| + | |||
| + | </pre> | ||
| + | |||
| + | ===Скрипт переноса всех ящиков из Zimbra в Grommunio=== | ||
| + | |||
| + | Для работы скрипта необходимо наличие рядом предыдущего скрипта (migrate_account_from_zimbra_to_grommunio.sh, для которого необходимо наличие предпредыдущего скрипта (create_mailbox.sh)) | ||
| + | |||
| + | Чтобы скрипт знал какие ящики переносить необходимо создать файл mailboxes.txt, в котором одна строчка - один ящик. Например так: | ||
| + | |||
| + | <pre> | ||
| + | cat << 'EOF' > mailboxes.txt | ||
| + | admin@myorg.net | ||
| + | manager@myorg.net | ||
| + | EOF | ||
| + | </pre> | ||
| + | |||
| + | |||
| + | В результате работы скрипта в Grommunio будут созданы ящики со случайными паролями, в которые будут перемещены все письма из аналогичных аккаунтов Zimbra. | ||
| + | |||
| + | Файл с данными новых ящиков будет называться: | ||
| + | |||
| + | migrated_passwords.csv | ||
| + | |||
| + | При повторном запуске скрипта предварительно будет создаваться резервная копия этого файла, при его наличии. | ||
| + | |||
| + | Это сделано чтобы не потерять данные случайно сгенерированных паролей при прошлом запуске скрипта. | ||
| + | |||
| + | |||
| + | Сам скрипт: | ||
| + | <pre> | ||
| + | cat << 'EOF' > migrate_all_zimbra_accounts.sh | ||
| + | #!/bin/bash | ||
| + | |||
| + | TARGET_SCRIPT="./migrate_account_from_zimbra_to_grommunio.sh" | ||
| + | MAILBOXES_FILE="mailboxes.txt" | ||
| + | OUTPUT_CSV="migrated_passwords.csv" | ||
| + | |||
| + | if [ ! -f "$TARGET_SCRIPT" ]; then | ||
| + | echo "Ошибка: Исполняемый файл '$TARGET_SCRIPT' не найден!" >&2 | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | if [ ! -x "$TARGET_SCRIPT" ]; then | ||
| + | echo "Ошибка: Файл '$TARGET_SCRIPT' существует, но у него нет прав на выполнение (chmod +x)!" >&2 | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | if [ ! -f "$MAILBOXES_FILE" ]; then | ||
| + | echo "Ошибка: Файл со списком ящиков '$MAILBOXES_FILE' не найден!" >&2 | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | generate_password() { | ||
| + | # 16 символов: буквы (разного регистра), цифры и безопасные спецсимволы | ||
| + | LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16 | ||
| + | } | ||
| + | |||
| + | |||
| + | OUTPUT_CSV_BACKUP="${OUTPUT_CSV%.csv}_$(date +%Y-%m-%d-%H-%M-%S).csv" | ||
| + | |||
| + | if [ -f "$OUTPUT_CSV" ]; then | ||
| + | cp "$OUTPUT_CSV" "$OUTPUT_CSV_BACKUP" | ||
| + | echo "Создан бэкап предыдущего CSV: $OUTPUT_CSV_BACKUP" | ||
| + | fi | ||
| + | |||
| + | # Инициализация / очистка CSV файла | ||
| + | echo "Email;Password" > "$OUTPUT_CSV" | ||
| + | |||
| + | echo "Все проверки пройдены. Начинаем обработку списков..." | ||
| + | echo "------------------------------------------------" | ||
| + | |||
| + | while read ACCOUNT; do | ||
| + | # Пропускаем пустые строки | ||
| + | [ -z "$ACCOUNT" ] && continue | ||
| + | |||
| + | NEW_PASS=$(generate_password) | ||
| + | |||
| + | echo "Обработка ящика: $ACCOUNT" | ||
| + | |||
| + | echo "Сохраняем данные аккаунта ${ACCOUNT} в файл $OUTPUT_CSV" | ||
| + | echo "${ACCOUNT};${NEW_PASS}" >> "$OUTPUT_CSV" | ||
| + | |||
| + | echo "Начата синхронизация аккаунта ${ACCOUNT}..." | ||
| + | if "$TARGET_SCRIPT" "$ACCOUNT" "$ACCOUNT" "$NEW_PASS"; then | ||
| + | echo "Успешно: $ACCOUNT" | ||
| + | else | ||
| + | echo "ОШИБКА: Сбой при обработке $ACCOUNT" >&2 | ||
| + | fi | ||
| + | |||
| + | echo "------------------------------------------------" | ||
| + | |||
| + | done < "$MAILBOXES_FILE" | ||
| + | |||
| + | echo "Готово! Сгенерированные пароли сохранены в файл: $OUTPUT_CSV" | ||
| + | EOF | ||
| + | |||
| + | chmod +x migrate_all_zimbra_accounts.sh | ||
| + | </pre> | ||
| + | |||
| + | ===Автоматизация обновления ssl сертификатов, если веб-интерфейс стоит за реверс-прокси nginx, работающим на базе vestacp=== | ||
| + | |||
| + | |||
| + | ====Создаём скрипт==== | ||
| + | <pre> | ||
| + | cat << 'EOF' > /usr/local/bin/sync-vesta-certs.sh | ||
| + | #!/usr/bin/env bash | ||
| + | set -euo pipefail | ||
| + | |||
| + | # === НАСТРОЙКИ === | ||
| + | # предполагается что доступ без пароля на $VESTA_HOST настроен в файле /root/.ssh/config | ||
| + | VESTA_HOST="vesta" | ||
| + | VESTA_USER="root" | ||
| + | |||
| + | # Пути к сертификатам на VestaCP | ||
| + | REMOTE_CERT="/home/admin/conf/web/ssl.mail.myorg.net.pem" | ||
| + | REMOTE_KEY="/home/admin/conf/web/ssl.mail.myorg.net.key" | ||
| + | |||
| + | # Пути к сертификатам в Grommunio | ||
| + | # (При необходимости скорректируйте пути под вашу конфигурацию Nginx/Postfix/Grommunio) | ||
| + | LOCAL_CERT="/etc/grommunio-common/ssl/server-bundle.pem" | ||
| + | LOCAL_KEY="/etc/grommunio-common/ssl/server.key" | ||
| + | |||
| + | TMP_DIR="/tmp/vesta_ssl_sync" | ||
| + | UPDATED=0 | ||
| + | |||
| + | # === ЛОГИКА === | ||
| + | mkdir -p "$TMP_DIR" | ||
| + | chmod 700 "$TMP_DIR" | ||
| + | |||
| + | # Функция очистки при завершении | ||
| + | cleanup() { | ||
| + | rm -rf "$TMP_DIR" | ||
| + | } | ||
| + | trap cleanup EXIT | ||
| + | |||
| + | # 1. Скачивание файлов с VestaCP | ||
| + | scp -q "$VESTA_USER@$VESTA_HOST:$REMOTE_CERT" "$TMP_DIR/remote.pem" | ||
| + | scp -q "$VESTA_USER@$VESTA_HOST:$REMOTE_KEY" "$TMP_DIR/remote.key" | ||
| + | |||
| + | # 2. Сравнение сертификата | ||
| + | if [ ! -f "$LOCAL_CERT" ] || ! cmp -s "$TMP_DIR/remote.pem" "$LOCAL_CERT"; then | ||
| + | echo "$(date): Обнаружен новый SSL-сертификат. Обновляем..." | ||
| + | cp "$TMP_DIR/remote.pem" "$LOCAL_CERT" | ||
| + | chmod 644 "$LOCAL_CERT" | ||
| + | UPDATED=1 | ||
| + | fi | ||
| + | |||
| + | # 3. Сравнение приватного ключа | ||
| + | if [ ! -f "$LOCAL_KEY" ] || ! cmp -s "$TMP_DIR/remote.key" "$LOCAL_KEY"; then | ||
| + | echo "$(date): Обнаружен новый приватный ключ. Обновляем..." | ||
| + | cp "$TMP_DIR/remote.key" "$LOCAL_KEY" | ||
| + | chmod 600 "$LOCAL_KEY" | ||
| + | UPDATED=1 | ||
| + | fi | ||
| + | |||
| + | # 4. Перезапуск сервисов Grommunio при обновлении | ||
| + | if [ "$UPDATED" -eq 1 ]; then | ||
| + | echo "$(date): Сертификаты обновлены. Перезапуск почтовых сервисов..." | ||
| + | |||
| + | # Перезапуск веб-сервера и системных служб Grommunio | ||
| + | systemctl restart nginx || true | ||
| + | systemctl restart postfix || true | ||
| + | systemctl restart "gromox-*" || true | ||
| + | systemctl restart grommunio-admin-api || true | ||
| + | |||
| + | echo "$(date): Перезапуск успешно завершен." | ||
| + | else | ||
| + | echo "$(date): Сертификаты не изменились." | ||
| + | fi | ||
| + | EOF | ||
| + | |||
| + | |||
| + | chmod +x /usr/local/bin/sync-vesta-certs.sh | ||
| + | </pre> | ||
| + | |||
| + | |||
| + | ====Ставим его в планировщик==== | ||
| + | |||
| + | (crontab -l 2>/dev/null | grep -Fv "/usr/local/bin/sync-vesta-certs.sh"; echo "30 3 * * * /usr/local/bin/sync-vesta-certs.sh >> /var/log/vesta-cert-sync.log 2>&1") | crontab - | ||
| + | |||
| + | |||
| + | ====Если grommunio изначально был установлен в режиме получения сертификата LetsEncrypt...==== | ||
| + | |||
| + | , а потом появилась необходимость поставить перед ним реверс-прокси, который решает проблемы обновления сертификата, то: | ||
| + | |||
| + | Убираем из базы данных сертификатов certbot сертификат | ||
| + | |||
| + | certbot delete --non-interactive --cert-name mail.myorg.net | ||
| + | |||
| + | Посмотреть список сертификатов в базе данных можно так: | ||
| + | |||
| + | certbot certificates | ||
| + | |||
| + | ===Скрипт получения адресных книг из аккаунтов zimbra=== | ||
| + | |||
| + | <pre> | ||
| + | cat << 'EOF' > export_all_contacts.sh | ||
| + | #!/bin/bash | ||
| + | |||
| + | # Проверяем, запущен ли скрипт от пользователя zimbra | ||
| + | if [ "$(whoami)" != "zimbra" ]; then | ||
| + | echo "Ошибка: этот скрипт должен запускаться от имени пользователя zimbra." | ||
| + | echo "Выполните: su - zimbra" | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | OUTPUT_DIR="/tmp/zimbra_all_contacts" | ||
| + | FINAL_FILE="/tmp/zimbra_all_contacts_combined.csv" | ||
| + | |||
| + | echo "==> Создаем рабочую директорию: $OUTPUT_DIR" | ||
| + | rm -rf "$OUTPUT_DIR" | ||
| + | mkdir -p "$OUTPUT_DIR" | ||
| + | |||
| + | echo "==> Получаем список активных почтовых ящиков..." | ||
| + | ACCOUNTS=$(zmprov -l gaa) | ||
| + | |||
| + | if [ -z "$ACCOUNTS" ]; then | ||
| + | echo "Ошибка: не найдено ни одного аккаунта." | ||
| + | exit 1 | ||
| + | fi | ||
| + | |||
| + | COUNT=0 | ||
| + | SUCCESS=0 | ||
| + | |||
| + | for account in $ACCOUNTS; do | ||
| + | COUNT=$((COUNT + 1)) | ||
| + | # Убираем недопустимые символы для имени файла, если такие вдруг будут | ||
| + | safe_name=$(echo "$account" | tr '/' '_') | ||
| + | file_path="$OUTPUT_DIR/${safe_name}.csv" | ||
| + | |||
| + | # Экспортируем контакты конкретного ящика | ||
| + | zmmailbox -z -m "$account" getRestURL "/Contacts?fmt=csv" > "$file_path" 2>/dev/null | ||
| + | |||
| + | # Проверяем, скачался ли непустой файл (минимальный CSV содержит хотя бы заголовки) | ||
| + | if [ -s "$file_path" ]; then | ||
| + | SUCCESS=$((SUCCESS + 1)) | ||
| + | else | ||
| + | # Удаляем пустые файлы, чтобы они не мешали | ||
| + | rm -f "$file_path" | ||
| + | fi | ||
| + | done | ||
| + | |||
| + | echo "==> Экспорт завершен. Успешно выгружено ящиков с контактами: $SUCCESS из $COUNT" | ||
| + | |||
| + | # Объединяем файлы в один | ||
| + | if [ $SUCCESS -gt 0 ]; then | ||
| + | echo "==> Объединяем файлы в один общий: $FINAL_FILE" | ||
| + | |||
| + | # Берем заголовки из самого первого попавшегося файла | ||
| + | FIRST_FILE=$(ls "$OUTPUT_DIR"/*.csv | head -n 1) | ||
| + | head -n 1 "$FIRST_FILE" > "$FINAL_FILE" | ||
| + | |||
| + | # Склеиваем содержимое всех файлов, пропуская первую строку (заголовки) | ||
| + | for f in "$OUTPUT_DIR"/*.csv; do | ||
| + | tail -n +2 "$f" >> "$FINAL_FILE" | ||
| + | done | ||
| + | |||
| + | echo "==> Готово! Общий файл сохранен как: $FINAL_FILE" | ||
| + | echo " Размер файла: $(du -h "$FINAL_FILE" | cut -f1)" | ||
| + | else | ||
| + | echo "==> Внимание: ни у одного аккаунта не найдено контактов для экспорта." | ||
| + | fi | ||
| + | EOF | ||
| + | </pre> | ||
| + | |||
| + | chmod +x export_all_contacts.sh | ||
| + | |||
| + | ==Особенности работы и способы починки== | ||
| + | |||
| + | ===Ошибки входа в веб интерфейс=== | ||
| + | |||
| + | После нескольких итераций создания/удаления пользователя с одинаковым емэйлом веб интерфейс почтового ящика (не админский интерфейс на порту 8443, а обычный - на порту 443) показывает невменяемые ошибки прав доступа. | ||
| + | |||
| + | Как конкретно это решить без перезагрузки сервера до сих пор выяснить не удалось. | ||
| + | |||
| + | Но перезагрузка сервера - точно решает большинство таких проблем. Наверное, даже, все. | ||
| + | |||
| + | Кратко: ошибка где-то в кешах сессий или что-то в этом роде. | ||
| + | |||
| + | Перезагрузка сервера решает эту проблему. Поэтому это проблемой можно не считать | ||
| + | |||
| + | ===Комьюнити версия не разрешает создавать больше 5 учётных записей почты на домен=== | ||
| + | |||
| + | Чтобы создавать больше - нужно покупать лицензию. Или... | ||
| + | |||
| + | Открываем файл | ||
| + | |||
| + | /usr/share/grommunio-admin-api/orm/users.py | ||
| + | |||
| + | Ищем там строчки по | ||
| + | |||
| + | License user limit exceeded | ||
| + | |||
| + | Включаем скилл программиста и комментируем по вкусу. Затем перезагружаемся. | ||
| + | |||
| + | В этом разделе специально подробно не описан процесс решения этой проблемы - из-за солидарности с разработчиками продукта. | ||
| + | |||
| + | ===Переиндексация SQLite баз данных ящиков=== | ||
| + | |||
| + | Есть гипотеза, что это поможет ускорить поиск по письмам в веб интерфейсе почты, если ящик содержит десятки тысяч писем. | ||
| + | |||
| + | Гипотеза пока не проверена до конца. | ||
| + | |||
| + | Индексы лежат здесь | ||
| + | |||
| + | /var/lib/grommunio-web/sqlite-index/ | ||
| + | |||
| + | Внутри находятся каталоги, имена которых соответствуют именам ящиков. Внутри этих каталогов лежат файлы | ||
| + | |||
| + | index.sqlite3 | ||
| + | |||
| + | Удаляем все индексы | ||
| + | |||
| + | rm -rf /var/lib/grommunio-web/sqlite-index/* | ||
| + | |||
| + | Перезапускаем сервис | ||
| + | |||
| + | systemctl restart grommunio-index.service | ||
| + | |||
| + | За работой сервиса можно проследить так | ||
| + | |||
| + | journalctl -f -u grommunio-index | ||
| + | |||
| + | , либо наблюдать за появлением в каталоге | ||
| + | |||
| + | /var/lib/grommunio-web/sqlite-index | ||
| + | |||
| + | новых каталогов с названиями, идентичными ящикам и файлами внутри них... | ||
| + | |||
| + | ====Перенастройка таймера переиндексации==== | ||
| + | |||
| + | По умолчанию таймер настроен на запуск раз в 15 минут. | ||
| + | |||
| + | Перенастроить на запуск каждую ночь можно так: | ||
| + | |||
| + | systemctl edit grommunio-index.timer | ||
| + | |||
| + | В открывшемся файле внимательно читаем предостережения сверху и в нужное место вставляем новые параметры | ||
| + | |||
| + | [Timer] | ||
| + | OnCalendar= | ||
| + | OnCalendar=*-*-* 03:00:00 | ||
| + | |||
| + | , затем сохраняем файл. | ||
| + | |||
| + | Проверяем | ||
| − | + | systemctl cat grommunio-index.timer | |
Текущая версия на 21:10, 16 сентября 2026
Содержание
- 1 Развёртывание
- 1.1 Где брать, как ставить
- 1.2 Порты
- 1.3 Записи для домена
- 1.4 Настроить подпись писем через DKIM
- 1.5 Скрипты и автоматизация
- 1.5.1 Скрипт создания одного ящика
- 1.5.2 Скрипт переноса одного ящика из Zimbra в Grommunio
- 1.5.3 Скрипт переноса всех ящиков из Zimbra в Grommunio
- 1.5.4 Автоматизация обновления ssl сертификатов, если веб-интерфейс стоит за реверс-прокси nginx, работающим на базе vestacp
- 1.5.5 Скрипт получения адресных книг из аккаунтов zimbra
- 1.6 Особенности работы и способы починки
Развёртывание
Где брать, как ставить
Для развёртывания на PVE можно прямо в хранилище PVE затащить образ по ссылке
https://download.grommunio.com/appliance/grommunio.x86_64-latest.install.iso
Ставить по этой инструкции
https://docs.grommunio.com/admin/installation/
Если ваши будущие емэйлы будут вида
user@myorg.net
То нужно ориентироваться на домены
mail.myorg.net
и
myorg.net
при инсталляции.
Порты 80 и 443 должны быть зарулены на сервер, если предполагается настройка сертификатов инсталлером через LestsEncrypt!
После инсталляции админка будет доступна на порту
8443
и туда входить нужно только по логину (не по полной почте).
Т.е. только по
admin
, а не по
admin@myorg.net
А в веб интерфейсе почты -- наоборот. Он находится по стандартному порту
443
и туда входим по
admin@myorg.net
, а не по
admin
Остальные порты важны будут при эксплуатации и при развёртывании их можно не забрасывать, о них -- ниже.
Порты
| Порт | Протокол | Сервис / Назначение в Grommunio |
|---|---|---|
| 25 | TCP | SMTP — входящая почта (передача между почтовыми серверами) |
| 80 | TCP | HTTP — веб-интерфейс (перенаправление на HTTPS / Let's Encrypt) |
| 110 | TCP | POP3 — получение почты (незашифрованный) |
| 143 | TCP | IMAP — получение почты (незашифрованный / STARTTLS) |
| 443 | TCP | HTTPS — Grommunio Web (Webmail), Outlook (EAS/MAPI over HTTP), Admin API |
| 465 | TCP | SMTPS — защищённая отправка почты клиентами (SSL/TLS) |
| 587 | TCP | SMTP Submission — отправка почты клиентами (STARTTLS) |
| 993 | TCP | IMAPS — защищённое получение почты (SSL/TLS) |
| 995 | TCP | POP3S — защищённое получение почты (SSL/TLS) |
| 5349 | TCP | STUN/TURN (coturn) — установка видеосоединений Jitsi за NAT (HTTPS/TLS) |
| 8443 | TCP | Grommunio Admin Admin Web Console — веб-панель администратора |
| 10000 | UDP | Jitsi Videobridge — медиапоток (аудио, видео, шеринг экрана) |
Записи для домена
| Назначение | Тип | Команда для проверки | Ожидаемый результат |
|---|---|---|---|
| Маршрутизация почты | MX |
dig MX myorg.net +short |
1 mail.myorg.net.
|
| IP-адрес узла | A |
dig A mail.myorg.net +short |
37.1.2.3
|
| Обратная зона (PTR) | PTR |
dig -x 37.1.2.3 +short |
mail.myorg.net.
|
| Разрешенные отправители (SPF) | TXT |
dig TXT myorg.net +short | grep spf |
"v=spf1 a mx ip4:37.1.2.3 ~all"
|
| Цифровая подпись (DKIM) | TXT |
dig TXT mailserver._domainkey.myorg.net +short |
"v=DKIM1; k=rsa; p=MIGfMA...AFwIDAQAB"
|
| Политика безопасности (DMARC) | TXT |
dig TXT _dmarc.myorg.net +short |
"v=DMARC1; p=quarantine; rua=mailto:admin@myorg.net"
|
БОльшую часть из этой информации можно также получить из формы настроек домена из админки grommunio.
Но есть нюанс с двумя записями:
1. Обратная зона (PTR) -- её невозможно настроить в админке провайдера днс зоны. Её должен настроить провайдер, выдающий интернет для почтового сервера и статический айпи адрес для него. Здесь необходимо добиться от интернет-провайдера, чтобы на его стороне была прописана эта самая обратная зона PTR. Суть в том, чтобы происходил процесс наоборот: по айпи адресу -- выдавался домен. Для почтовых серверов это важно!
2. Цифровая подпись (DKIM) -- чтобы корректно работала эта запись, сначала её необходимо настроить. Об этом подробно написано ниже!
3. Разрешенные отправители (SPF) -- здесь также должен фигурировать статический айпи адрес почтового сервера.
В примере это адрес 37.1.2.3, в реальном кейсе это должен быть везде айпи адрес конкретного сервера
Настроить подпись писем через DKIM
Действия мышкой в админке
Сначала внутри админки нужно создать домен и перейти в форму управления этим доменом.
Там нужно настроить всякие умолчания для вновь создаваемых пользователей этого домена.
С этими умолчаниями пользователи будут создаваться, если их создавать из админки.
Для настройки подписи через DKIM нужно нажать соответствующую кнопку в форме управления доменом. В открывшемся окне выполнить создание ключевой пары для подписи.
Выбрать алгоритм RSA и selector. По умолчанию selector имеет значение
dkim
, но можно установить свой. Этот селектор будет использован при настройке TXT записи для почтового домена.
Например, можно выбрать селектор
mailserver
В ответ на запрос генерации ключей придёт примерно такой шаблон для настройки TXT записи для домена:
mailserver._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDc" "iA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB" ) ;
и будет сказано что ключ лежит где-то здесь:
The private key has been generated on the server at /var/lib/grommunio-admin-api/myorg.net.dkim.key
Этот путь до файла ключа будет нужен потом при настройке сервера по ssh.
Настройка сервера по ssh и настройки конфигов на сервере
Для доступа по ssh под root лучше сразу получить на сервер открытую часть ssh ключа и настроить конфиг ssh для быстрого подключения. Под root на сервер по паролю подключиться не получится. А через виртуальный дисплей виртуальной машины нельзя будет скопировать текст на сервер.
Поэтому самый верный вариант - зайти на сервер через виртуальный дисплей виртуальной машины, скопировать через scp открытую часть ключа с другой машины по сети, затем перейти на другую машину и подключаться по ключу с ней на сервер.
Войдя по ssh на сервер необходимо сделать ряд настроек:
Если ваш домен:
myorg.net
а селектор
mailserver
1. Создаём каталог
mkdir -p /var/lib/grommunio-antispam/dkim/myorg.net
2. Копируем тот самый файл, путь к которому нам сообщили в веб интерфейсе в предыдущем пункте в файл с названием селектора в только что созданный каталог
cp /var/lib/grommunio-admin-api/myorg.net.dkim.key /var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key
3. Создайм файл
cat << 'EOF' > /etc/grommunio-antispam/override.d/dkim_signing.conf
enabled = true;
sign_authenticated = true;
sign_local = true;
use_domain = "header";
use_domain_sign_local = "full";
domain {
"myorg.net" {
path = "/var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key";
selector = "mailserver";
}
}
EOF
4. Устанавливаем права доступа на каталог и файл
chown -R groas:grommunio /var/lib/grommunio-antispam/dkim/ chmod 600 /var/lib/grommunio-antispam/dkim/myorg.net.mailserver.key
5. Оставляем в доверенных сетях только локальную петлю и устанавливаем параметр non_smtpd_milters в файл конфигурации postfix
echo 'mynetworks = 127.0.0.0/8' >> /etc/postfix/main.cf echo 'non_smtpd_milters = inet:localhost:11332' >> /etc/postfix/main.cf
6. Перезапустить сервисы
systemctl restart grommunio-antispam systemctl restart postfix
Перезапуска этих сервисов для полноценной работы механизма подписи емэйлов может быть недостаточно. Тогда перезагружаем сервер полностью
reboot
А если и это не помогло, то смотрим что в логах
tail -f /var/log/grommunio-antispam/rspamd.log
Важный момент при настройке почтового сервера на доменах третьего уровня
Общая суть в том, что понадобятся параметры
use_esld = false; use_effective_domain = false;
в файле
/etc/grommunio-antispam/override.d/dkim_signing.conf
Иначе сервер будет схлопывать домен до первого уровня и подставлять это в тело письма вот сюда (это часть письма в сыром виде):
...DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=myorg.net; s=mailserver; t=1785189679;...
В случае с доменом третьего уровня, например, unit.myorg.net, значение должно быть
d=unit.myorg.net
, а без этих параметров оно:
d=myorg.net
Следовательно, принимающие сервера пытаются прочитать ключ для проверки подписи с домена myorg.net, а не с домена unit.myorg.net и не могут её проверить.
Пример рабочего конфига для домена третьего уровня
cat << 'EOF' > /etc/grommunio-antispam/override.d/dkim_signing.conf enabled = true; sign_authenticated = true; sign_local = true; use_domain = "header"; # КРИТИЧЕСКИ ВАЖНО: Выключаем нормализацию eSLD, которая схлопывает домен unit.myorg.net до myorg.net use_esld = false; use_effective_domain = false; selector = "mailserver"; path = "/var/lib/grommunio-antispam/dkim/unit.myorg.net.mailserver.key"; EOF
Настройка TXT записи для домена
Эта настройка делается в веб панели управления доменом. В зависимости от того, где арендован домен. Например, reg.ru, beget.com и т.д...
Нюанс
Веб админка выдала на генерацию ключей что-то типа того:
mailserver._domainkey IN TXT ( "v=DKIM1; k=rsa; " "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDc" "iA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB" ) ;
Это на самом деле означает, что значение TXT записи
mailserver._domainkey
в веб админке провайдера днс должно быть таким:
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDciA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB
, а на строчки оно разбивается по некоторым историческим причинам, суть которых в ограничении длины строки. Видимо, особенности протокола DNS...
Перед тем, как конфигурировать TXT запись на уровне DNS необходимо свериться: точно ли у ключа, который ранее был скопирован в файл
/var/lib/grommunio-antispam/dkim/myorg.net/dkim.key
base64 строка соответствует значению ключа
p=
из значения для TXT записи, приведённой выше.
Получить этот ключ можно следующим образом:
openssl rsa -in /var/lib/grommunio-antispam/dkim/myorg.net/dkim.key -pubout -outform DER 2>/dev/null | base64 -w 0
В ответ придёт что-то вроде:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDciA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB
В теории (в теории, но на практике было и по другому. Это надо проверить ещй раз!) эти ключи должны совпадать. Т.е. ключ, который с переносами и кавычками был выдан веб интеряейсом, и ключ, который выдала команда выше -- должны быть одинаковы. Ведь файл ключа одинаковый (мы его просто скопировали для донастройки grommunio-antispam)!
Но на практике было и так что команда
openssl rsa -in...
выдавала ключ, который отличается. Если ключи будут отличаться, то в значение
p=
для DNS записи необходимо заменить на значение, полученное от команды:
openssl rsa -in...
Далее в веб-админке DNS сервера добавляем запись типа
TXT
, поддомен которой должен быть такой (полный домен имеется в виду такой: mailserver._domainkey.myorg.net)
mailserver._domainkey
, а его значением должно быть
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDciA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB
т.е. в общем виде так:
v=DKIM1; k=rsa; p=<результат, полученный от команды openssl rsa -in...>
Проверка TXT записи
После того, как TXT запись домена проделегируется проверить это можно командой:
dig TXT mailserver._domainkey.myorg.net +short
в ответ должно прийти что-то типа
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/D2gdESmBR0TqqeZ42wXCsEjGpPOB7uxp4uY0De+297hKs3XV+1CehUu5BxXxKKeJJIKRzogvzzOj76AXWMpiF5LS4oOUd3I+I+H8aCAC69QuV/TKHuB0Qqv7c8S54dw4210fHOSMMwVYlzfRGeyPfrKBcfZi4v98j7jh2on5f5btiaeppkUgUxMOPjTRepl3VzxTkID9cLrIEDciA3nVMXbkj4wULMNSL3IjfuW4MRIJ6a4zZZqOECjrhBiSgAies+l0yh/+mn3LQmVcjba0RTuxa7x5xuf21AnKZvv0uZeQrROd0WrbLYGLFRO2Nk6/jUQPaPHS3ThDggbXz3RwIDAQAB"
здесь важно проверить что значение
p=
соответствует той самой base64 строке, которая выше была получена через
openssl rsa -in...
Проверка работы механизма подписи емэйлов
Войти в веб интерфейс почты (не в админку по https://mail.myorg.net:8443, а просто на https://mail.myorg.net) любым ящиком, который есть в домене и отправить с него письмо куда-нибудь себе на ящик (gmail, yandex и.т.д...).
У себя в аккаунте (gmail, yandex и.т.д...) ищем исходники письма (это обычно PlainText) и там должны быть такие строки:
Раз! Само наличие этой строки говорит о том, что сервер стал подписывать письма!
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=myorg.net; s=mailserver; t=1785189679; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type; bh=ckTMbuexoDGBdcu/luc2eNS+Ap0k9i9yjhltmXYdzGo=; b=BOe7sXr+EW6iTfZdDVCxA8gZ2gXBw3KcWC2PFALvbi6inSXlO/u3cZCLtEcBCJ9/accyFP Hn1W2qHSKEeY1B8Ri5SqqUoXBO7bEc5IPOr0dYyrivABFsT+Zr7XNeDUHlC6Lbt7YvaI4z vatOvc5T+qzDv/bqu685KqqK33PRQiY=
Но это ещё не всё... Необходимо проверить проверку этой подписи. Здесь как раз важно, чтобы TXT запись у домена была корректна.
Два!
Для этого также ищем среди исходинка письма следующую строку:
Authentication-Results: mx.google.com; dkim=pass header.i=@myorg.net header.s=mailserver header.b=BOe7sXr+; spf=pass (google.com: domain of admin@myorg.net designates 37.112.130.81 as permitted sender) smtp.mailfrom=admin@myorg.net; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=myorg.net
Здесь важно увидеть
dkim=pass
и
spf=pass
После этого можно проверить работу сервера через внешний сервис
https://mail-tester.com/
При корректной настройке почтового сервера этот сервис должен показать 10 из 10 возможных "попугаев".
Важно! У сервиса этого есть ограничения на кол-во проверок в сутки. Потом он просит денюжку или ждать следующего дня. Поэтому сначала проверяем текст в исходниках письма, как описано выше, и только потом - через сервис.
Скрипты и автоматизация
Все скрипты, представленные здесь, запускать необходимо с сервера Grommunio!
Скрипт создания одного ящика
cat << 'EOF' > create_mailbox.sh
#!/bin/bash
USER_GROMMUNIO="$1"
PASS_GROMMUNIO="$2"
# Проверка входных параметров
if [ -z "$USER_GROMMUNIO" ] || [ -z "$PASS_GROMMUNIO" ]; then
echo "Использование: $0 <user_grommunio> <pass_grommunio>"
echo "Пример: $0 user@domain.ru 'ThePass'"
exit 1
fi
echo "=== 1. Проверка / Создание ящика $USER_GROMMUNIO в Grommunio ==="
# Проверяем наличие ящика
if grommunio-admin user show "$USER_GROMMUNIO" >/dev/null 2>&1; then
echo "i Ящик $USER_GROMMUNIO уже существует. Пропускаем создание."
else
echo "Пользователь не найден. Создаём ящик $USER_GROMMUNIO..."
DISPLAY_NAME=$(echo "$USER_GROMMUNIO" | cut -d'@' -f1)
# Создаем юзера
grommunio-admin user create "$USER_GROMMUNIO"
if [ $? -ne 0 ]; then
echo "Ошибка создания пользователя $USER_GROMMUNIO!"
exit 1
fi
# Устанавливаем свойства пользователю
grommunio-admin user modify \
--property givenname="$DISPLAY_NAME" \
--property surname="$DISPLAY_NAME" \
--property displayname="$DISPLAY_NAME" \
--property country="Russian Federation" \
"$USER_GROMMUNIO"
if [ $? -ne 0 ]; then
echo "Ошибка установки свойств пользователя $USER_GROMMUNIO!"
exit 1
fi
# Задаем пароль
grommunio-admin passwd --password "$PASS_GROMMUNIO" "$USER_GROMMUNIO"
if [ $? -ne 0 ]; then
echo "Ошибка установки пароля для $USER_GROMMUNIO!"
exit 1
fi
echo "✓ Ящик $USER_GROMMUNIO успешно создан и пароль установлен."
fi
EOF
chmod +x create_mailbox.sh
Скрипт переноса одного ящика из Zimbra в Grommunio
Для работы скрипта необходимо наличие рядом предыдущего скрипта (create_mailbox.sh)
А также внутри скрипта необходимо задать адрес сервера Zimbra и логин и пароль мастер-аккаунта Zimbra
cat << 'EOF' > migrate_account_from_zimbra_to_grommunio.sh
#!/bin/bash
# Настройки серверов
ZIMBRA_SERVER="192.168.0.1"
GROMMUNIO_SERVER="127.0.0.1"
# Мастер-аккаунт с Zimbra с паролем
ZIMBRA_ADMIN_USER="admin@myorg.net"
ZIMBRA_ADMIN_PASS="SuperAdminPassword"
# Определяем директорию, в которой расположен текущий скрипт
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CREATE_SCRIPT="$SCRIPT_DIR/create_mailbox.sh"
# Чтение аргументов
USER_ZIMBRA="$1"
USER_GROMMUNIO="$2"
PASS_GROMMUNIO="$3"
# Проверка входных параметров
if [ -z "$USER_ZIMBRA" ] || [ -z "$USER_GROMMUNIO" ] || [ -z "$PASS_GROMMUNIO" ]; then
echo "Использование: $0 <mailbox_zimbra> <mailbox_grommunio> <pass_grommunio>"
echo "Пример: $0 old_user@domain.ru new_user@domain.ru 'GromPass'"
exit 1
fi
# Проверка наличия и прав на выполнение вспомогательного скрипта
if [ ! -f "$CREATE_SCRIPT" ]; then
echo "Ошибка: Вспомогательный скрипт '$CREATE_SCRIPT' не найден!"
exit 1
fi
if [ ! -x "$CREATE_SCRIPT" ]; then
echo "Ошибка: Скрипт '$CREATE_SCRIPT' найден, но не имеет прав на выполнение (chmod +x)!"
exit 1
fi
# Вызов внешнего скрипта для создания ящика
"$CREATE_SCRIPT" "$USER_GROMMUNIO" "$PASS_GROMMUNIO"
if [ $? -ne 0 ]; then
echo "Ошибка при подготовке ящика $USER_GROMMUNIO через $CREATE_SCRIPT"
exit 1
fi
echo "=== 2. Запуск переноса почты из Zimbra в Grommunio ==="
set -x
# Создаем временные защищенные файлы для паролей
PASSFILE1=$(mktemp)
PASSFILE2=$(mktemp)
printf '%s' "$ZIMBRA_ADMIN_PASS" > "$PASSFILE1"
printf '%s' "$PASS_GROMMUNIO" > "$PASSFILE2"
imapsync \
--host1 "$ZIMBRA_SERVER" \
--user1 "$USER_ZIMBRA" \
--authuser1 "$ZIMBRA_ADMIN_USER" \
--passfile1 "$PASSFILE1" \
--authmech1 PLAIN \
--ssl1 \
--sslargs1 SSL_verify_mode=0 \
--host2 "$GROMMUNIO_SERVER" \
--user2 "$USER_GROMMUNIO" \
--passfile2 "$PASSFILE2" \
--authmech2 LOGIN \
--ssl2 \
--sslargs2 SSL_verify_mode=0 \
--useheader "Message-ID" \
--automap \
--f1f2 "Sent=&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-" \
--f1f2 "Trash=&BCMENAQwBDsENQQ9BD0ESwQ1-" \
--f1f2 "Junk=&BB0ENQQ2BDUEOwQwBEIENQQ7BEwEPQQwBE8- &BD8EPgRHBEIEMA-" \
--f1f2 "Drafts=&BCcENQRABD0EPgQyBDgEOgQ4-" \
--noflags \
--errorsmax 500000 \
--noauthmd5
# если не надо синхронизировать спам и корзину
# --exclude "Junk" \
# --exclude "Trash" \
# Удаляем временные файлы с паролями
rm -f "$PASSFILE1" "$PASSFILE2"
EOF
chmod +x migrate_account_from_zimbra_to_grommunio.sh
Скрипт переноса всех ящиков из Zimbra в Grommunio
Для работы скрипта необходимо наличие рядом предыдущего скрипта (migrate_account_from_zimbra_to_grommunio.sh, для которого необходимо наличие предпредыдущего скрипта (create_mailbox.sh))
Чтобы скрипт знал какие ящики переносить необходимо создать файл mailboxes.txt, в котором одна строчка - один ящик. Например так:
cat << 'EOF' > mailboxes.txt admin@myorg.net manager@myorg.net EOF
В результате работы скрипта в Grommunio будут созданы ящики со случайными паролями, в которые будут перемещены все письма из аналогичных аккаунтов Zimbra.
Файл с данными новых ящиков будет называться:
migrated_passwords.csv
При повторном запуске скрипта предварительно будет создаваться резервная копия этого файла, при его наличии.
Это сделано чтобы не потерять данные случайно сгенерированных паролей при прошлом запуске скрипта.
Сам скрипт:
cat << 'EOF' > migrate_all_zimbra_accounts.sh
#!/bin/bash
TARGET_SCRIPT="./migrate_account_from_zimbra_to_grommunio.sh"
MAILBOXES_FILE="mailboxes.txt"
OUTPUT_CSV="migrated_passwords.csv"
if [ ! -f "$TARGET_SCRIPT" ]; then
echo "Ошибка: Исполняемый файл '$TARGET_SCRIPT' не найден!" >&2
exit 1
fi
if [ ! -x "$TARGET_SCRIPT" ]; then
echo "Ошибка: Файл '$TARGET_SCRIPT' существует, но у него нет прав на выполнение (chmod +x)!" >&2
exit 1
fi
if [ ! -f "$MAILBOXES_FILE" ]; then
echo "Ошибка: Файл со списком ящиков '$MAILBOXES_FILE' не найден!" >&2
exit 1
fi
generate_password() {
# 16 символов: буквы (разного регистра), цифры и безопасные спецсимволы
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16
}
OUTPUT_CSV_BACKUP="${OUTPUT_CSV%.csv}_$(date +%Y-%m-%d-%H-%M-%S).csv"
if [ -f "$OUTPUT_CSV" ]; then
cp "$OUTPUT_CSV" "$OUTPUT_CSV_BACKUP"
echo "Создан бэкап предыдущего CSV: $OUTPUT_CSV_BACKUP"
fi
# Инициализация / очистка CSV файла
echo "Email;Password" > "$OUTPUT_CSV"
echo "Все проверки пройдены. Начинаем обработку списков..."
echo "------------------------------------------------"
while read ACCOUNT; do
# Пропускаем пустые строки
[ -z "$ACCOUNT" ] && continue
NEW_PASS=$(generate_password)
echo "Обработка ящика: $ACCOUNT"
echo "Сохраняем данные аккаунта ${ACCOUNT} в файл $OUTPUT_CSV"
echo "${ACCOUNT};${NEW_PASS}" >> "$OUTPUT_CSV"
echo "Начата синхронизация аккаунта ${ACCOUNT}..."
if "$TARGET_SCRIPT" "$ACCOUNT" "$ACCOUNT" "$NEW_PASS"; then
echo "Успешно: $ACCOUNT"
else
echo "ОШИБКА: Сбой при обработке $ACCOUNT" >&2
fi
echo "------------------------------------------------"
done < "$MAILBOXES_FILE"
echo "Готово! Сгенерированные пароли сохранены в файл: $OUTPUT_CSV"
EOF
chmod +x migrate_all_zimbra_accounts.sh
Автоматизация обновления ssl сертификатов, если веб-интерфейс стоит за реверс-прокси nginx, работающим на базе vestacp
Создаём скрипт
cat << 'EOF' > /usr/local/bin/sync-vesta-certs.sh
#!/usr/bin/env bash
set -euo pipefail
# === НАСТРОЙКИ ===
# предполагается что доступ без пароля на $VESTA_HOST настроен в файле /root/.ssh/config
VESTA_HOST="vesta"
VESTA_USER="root"
# Пути к сертификатам на VestaCP
REMOTE_CERT="/home/admin/conf/web/ssl.mail.myorg.net.pem"
REMOTE_KEY="/home/admin/conf/web/ssl.mail.myorg.net.key"
# Пути к сертификатам в Grommunio
# (При необходимости скорректируйте пути под вашу конфигурацию Nginx/Postfix/Grommunio)
LOCAL_CERT="/etc/grommunio-common/ssl/server-bundle.pem"
LOCAL_KEY="/etc/grommunio-common/ssl/server.key"
TMP_DIR="/tmp/vesta_ssl_sync"
UPDATED=0
# === ЛОГИКА ===
mkdir -p "$TMP_DIR"
chmod 700 "$TMP_DIR"
# Функция очистки при завершении
cleanup() {
rm -rf "$TMP_DIR"
}
trap cleanup EXIT
# 1. Скачивание файлов с VestaCP
scp -q "$VESTA_USER@$VESTA_HOST:$REMOTE_CERT" "$TMP_DIR/remote.pem"
scp -q "$VESTA_USER@$VESTA_HOST:$REMOTE_KEY" "$TMP_DIR/remote.key"
# 2. Сравнение сертификата
if [ ! -f "$LOCAL_CERT" ] || ! cmp -s "$TMP_DIR/remote.pem" "$LOCAL_CERT"; then
echo "$(date): Обнаружен новый SSL-сертификат. Обновляем..."
cp "$TMP_DIR/remote.pem" "$LOCAL_CERT"
chmod 644 "$LOCAL_CERT"
UPDATED=1
fi
# 3. Сравнение приватного ключа
if [ ! -f "$LOCAL_KEY" ] || ! cmp -s "$TMP_DIR/remote.key" "$LOCAL_KEY"; then
echo "$(date): Обнаружен новый приватный ключ. Обновляем..."
cp "$TMP_DIR/remote.key" "$LOCAL_KEY"
chmod 600 "$LOCAL_KEY"
UPDATED=1
fi
# 4. Перезапуск сервисов Grommunio при обновлении
if [ "$UPDATED" -eq 1 ]; then
echo "$(date): Сертификаты обновлены. Перезапуск почтовых сервисов..."
# Перезапуск веб-сервера и системных служб Grommunio
systemctl restart nginx || true
systemctl restart postfix || true
systemctl restart "gromox-*" || true
systemctl restart grommunio-admin-api || true
echo "$(date): Перезапуск успешно завершен."
else
echo "$(date): Сертификаты не изменились."
fi
EOF
chmod +x /usr/local/bin/sync-vesta-certs.sh
Ставим его в планировщик
(crontab -l 2>/dev/null | grep -Fv "/usr/local/bin/sync-vesta-certs.sh"; echo "30 3 * * * /usr/local/bin/sync-vesta-certs.sh >> /var/log/vesta-cert-sync.log 2>&1") | crontab -
Если grommunio изначально был установлен в режиме получения сертификата LetsEncrypt...
, а потом появилась необходимость поставить перед ним реверс-прокси, который решает проблемы обновления сертификата, то:
Убираем из базы данных сертификатов certbot сертификат
certbot delete --non-interactive --cert-name mail.myorg.net
Посмотреть список сертификатов в базе данных можно так:
certbot certificates
Скрипт получения адресных книг из аккаунтов zimbra
cat << 'EOF' > export_all_contacts.sh
#!/bin/bash
# Проверяем, запущен ли скрипт от пользователя zimbra
if [ "$(whoami)" != "zimbra" ]; then
echo "Ошибка: этот скрипт должен запускаться от имени пользователя zimbra."
echo "Выполните: su - zimbra"
exit 1
fi
OUTPUT_DIR="/tmp/zimbra_all_contacts"
FINAL_FILE="/tmp/zimbra_all_contacts_combined.csv"
echo "==> Создаем рабочую директорию: $OUTPUT_DIR"
rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"
echo "==> Получаем список активных почтовых ящиков..."
ACCOUNTS=$(zmprov -l gaa)
if [ -z "$ACCOUNTS" ]; then
echo "Ошибка: не найдено ни одного аккаунта."
exit 1
fi
COUNT=0
SUCCESS=0
for account in $ACCOUNTS; do
COUNT=$((COUNT + 1))
# Убираем недопустимые символы для имени файла, если такие вдруг будут
safe_name=$(echo "$account" | tr '/' '_')
file_path="$OUTPUT_DIR/${safe_name}.csv"
# Экспортируем контакты конкретного ящика
zmmailbox -z -m "$account" getRestURL "/Contacts?fmt=csv" > "$file_path" 2>/dev/null
# Проверяем, скачался ли непустой файл (минимальный CSV содержит хотя бы заголовки)
if [ -s "$file_path" ]; then
SUCCESS=$((SUCCESS + 1))
else
# Удаляем пустые файлы, чтобы они не мешали
rm -f "$file_path"
fi
done
echo "==> Экспорт завершен. Успешно выгружено ящиков с контактами: $SUCCESS из $COUNT"
# Объединяем файлы в один
if [ $SUCCESS -gt 0 ]; then
echo "==> Объединяем файлы в один общий: $FINAL_FILE"
# Берем заголовки из самого первого попавшегося файла
FIRST_FILE=$(ls "$OUTPUT_DIR"/*.csv | head -n 1)
head -n 1 "$FIRST_FILE" > "$FINAL_FILE"
# Склеиваем содержимое всех файлов, пропуская первую строку (заголовки)
for f in "$OUTPUT_DIR"/*.csv; do
tail -n +2 "$f" >> "$FINAL_FILE"
done
echo "==> Готово! Общий файл сохранен как: $FINAL_FILE"
echo " Размер файла: $(du -h "$FINAL_FILE" | cut -f1)"
else
echo "==> Внимание: ни у одного аккаунта не найдено контактов для экспорта."
fi
EOF
chmod +x export_all_contacts.sh
Особенности работы и способы починки
Ошибки входа в веб интерфейс
После нескольких итераций создания/удаления пользователя с одинаковым емэйлом веб интерфейс почтового ящика (не админский интерфейс на порту 8443, а обычный - на порту 443) показывает невменяемые ошибки прав доступа.
Как конкретно это решить без перезагрузки сервера до сих пор выяснить не удалось.
Но перезагрузка сервера - точно решает большинство таких проблем. Наверное, даже, все.
Кратко: ошибка где-то в кешах сессий или что-то в этом роде.
Перезагрузка сервера решает эту проблему. Поэтому это проблемой можно не считать
Комьюнити версия не разрешает создавать больше 5 учётных записей почты на домен
Чтобы создавать больше - нужно покупать лицензию. Или...
Открываем файл
/usr/share/grommunio-admin-api/orm/users.py
Ищем там строчки по
License user limit exceeded
Включаем скилл программиста и комментируем по вкусу. Затем перезагружаемся.
В этом разделе специально подробно не описан процесс решения этой проблемы - из-за солидарности с разработчиками продукта.
Переиндексация SQLite баз данных ящиков
Есть гипотеза, что это поможет ускорить поиск по письмам в веб интерфейсе почты, если ящик содержит десятки тысяч писем.
Гипотеза пока не проверена до конца.
Индексы лежат здесь
/var/lib/grommunio-web/sqlite-index/
Внутри находятся каталоги, имена которых соответствуют именам ящиков. Внутри этих каталогов лежат файлы
index.sqlite3
Удаляем все индексы
rm -rf /var/lib/grommunio-web/sqlite-index/*
Перезапускаем сервис
systemctl restart grommunio-index.service
За работой сервиса можно проследить так
journalctl -f -u grommunio-index
, либо наблюдать за появлением в каталоге
/var/lib/grommunio-web/sqlite-index
новых каталогов с названиями, идентичными ящикам и файлами внутри них...
Перенастройка таймера переиндексации
По умолчанию таймер настроен на запуск раз в 15 минут.
Перенастроить на запуск каждую ночь можно так:
systemctl edit grommunio-index.timer
В открывшемся файле внимательно читаем предостережения сверху и в нужное место вставляем новые параметры
[Timer] OnCalendar= OnCalendar=*-*-* 03:00:00
, затем сохраняем файл.
Проверяем
systemctl cat grommunio-index.timer