Почта перестала быть просто почтой уже давно. Сегодня это центр деловой переписки, хранилище документов, канал уведомлений от десятков сервисов и одновременно сейф с личными данными. Привычные клиенты вроде Thunderbird или встроенного приложения в смартфоне отлично справляются со своей задачей, но у них есть одна особенность. Они привязаны к устройству. А что делать, если к почте нужен доступ с любого компьютера, из любого места, без установки лишнего софта? Ответ находится в категории веб-интерфейсов - и Rainloop здесь занимает особое место.

Почему Rainloop остаётся хорошим выбором для собственного почтового веб-интерфейса в 2024 году

Rainloop написан на PHP и работает как посредник между браузером пользователя и почтовыми серверами по протоколам IMAP и SMTP. Никаких собственных почтовых ящиков он не создаёт, никаких писем на сервере не хранит. Вся логика построена вокруг одной идеи - предоставить быстрый и красивый веб-интерфейс для уже существующих почтовых учёток. Это принципиально важный момент. Rainloop не конкурирует с Postfix или Dovecot, а дополняет их.

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

Ubuntu 22.04 Jammy Jellyfish в роли хостовой системы - решение логичное. LTS-релиз с поддержкой до 2027 года, свежие пакеты в репозиториях, устоявшаяся экосистема. Для почтового сервиса, который должен работать без сбоев, такой фундамент подходит идеально. Чего-то экзотического здесь не требуется, но внимания к деталям настройка потребует немало.

Подготовка сервера и настройка брандмауэра для защиты почтовых портов от посторонних

Любая серьёзная установка начинается с обновления системы. Банально, но без этого дальше двигаться нет смысла.

$ sudo apt update && sudo apt upgrade

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

$ sudo apt install wget curl nano unzip -y

Файрвол ufw в Ubuntu по умолчанию знает только про SSH. Для веб-интерфейса и почтовых соединений этого мало. Сначала смотрим текущее положение дел.

$ sudo ufw status

Ответ будет примерно таким.

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Теперь открываем HTTP и HTTPS - без них Rainloop работать не сможет.

$ sudo ufw allow http
$ sudo ufw allow https

Отдельно открываем порты для почтовых протоколов. 587 отвечает за отправку через SMTP с аутентификацией, 993 за безопасный IMAP, 465 за устаревший SMTPS, который до сих пор используется многими почтовыми провайдерами.

$ sudo ufw allow 587/tcp
$ sudo ufw allow 993/tcp
$ sudo ufw allow 465/tcp

Проверяем результат.

$ sudo ufw status

Установка свежей версии Nginx из официального репозитория и замена устаревшей сборки из стандартного дистрибутива

В Ubuntu 22.04 поставляется не самая новая версия Nginx. Для продакшена лучше подтянуть актуальный релиз из официального репозитория разработчика. Сначала добавляем ключ подписи.

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

Прописываем сам репозиторий со стабильной веткой.

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

Обновляем списки пакетов.

$ sudo apt update

Ставим сам Nginx.

$ sudo apt install nginx

Проверяем, что установилась именно та версия, которая нужна.

$ nginx -v

Дальше начинается история с PHP. Rainloop капризничает с новыми версиями языка и требует именно PHP 8.0, хотя в Ubuntu 22.04 по умолчанию идёт 8.1. Спасает классический репозиторий Ondrej Sury, который держит в актуальном состоянии все живые ветки PHP.

$ sudo add-apt-repository ppa:ondrej/php

Ставим PHP 8.0 со всеми нужными расширениями. Курсор, обработка строк, работа с базой, XML - без них веб-клиент не заведётся.

 $ sudo dnf install php8.0-fpm php8.0-curl php8.0-mbstring php8.0-mysql php8.0-xml php8.0-cli

Убеждаемся в корректной версии.

$ php --version

Проверяем, что сервис PHP-FPM живой.

$ sudo systemctl status php8.0-fpm

Тонкая настройка PHP-FPM под пересылку крупных вложений и смена пользователя на nginx

По умолчанию PHP разрешает загружать файлы размером до 2 мегабайт. Для электронной почты это катастрофически мало. Современные вложения легко переваливают за 10-15 мегабайт, а документы с картинками встречаются и тяжелее. Открываем основной конфиг.

$ sudo nano /etc/php/8.0/fpm/php.ini

Находим и меняем две строки. Значение 25 мегабайт - разумный компромисс между удобством и безопасностью.

upload_max_filesize = 25M
post_max_size = 25M

Теперь редактируем пул PHP-FPM, чтобы процессы запускались от пользователя nginx. Иначе веб-сервер не сможет читать сгенерированные файлы.

$ sudo nano /etc/php/8.0/fpm/pool.d/www.conf

Меняем пользователя и группу процесса.

...
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
; RPM: apache user chosen to provide access to the same directories as httpd
user = nginx
; RPM: Keep a group allowed to write in log dir.
group = nginx
...

И параметры сокета.

...
; Set permissions for unix socket, if one is used. In Linux, read/write
; permissions must be set in order to allow connections from a web server. Many
; BSD-derived systems allow connections regardless of permissions. The owner
; and group can be specified either by name or by their numeric IDs.
; Default Values: user and group are set as the running user
;                 mode is set to 0660
listen.owner = nginx
listen.group = nginx
...

Перезапускаем сервис.

$ sudo systemctl restart php8.0-fpm

Настройка базы данных MySQL и создание изолированного пользователя для работы Rainloop

MySQL в Ubuntu 22.04 идёт свежий и ставится одной командой.

$ sudo apt install mysql-server

Смотрим версию.

$ mysql --version

Для версий 8.0.28 и выше нужен небольшой хак. Заходим в консоль.

$ sudo mysql

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

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourPassword12!';

Выходим.

mysql> exit

Запускаем стандартный скрипт безопасности. Он задаст серию вопросов и поможет закрыть типовые дыры, через которые обычно проникают злоумышленники.

$ sudo mysql_secure_installation

При прохождении скрипта стоит согласиться с установкой компонента проверки паролей, выбрать уровень проверки 2 (самый строгий), отказаться от смены рутового пароля (его уже задали), убрать анонимных пользователей, запретить удалённый вход для рута, удалить тестовую базу и перезагрузить таблицы привилегий.

Теперь заходим снова с паролем.

$ sudo mysql -u root -p

Создаём базу под Rainloop.

mysql> CREATE DATABASE rainloop;

Отдельного пользователя для работы с этой базой. Принцип минимальных привилегий - один из краеугольных камней безопасности, и пренебрегать им не стоит.

mysql> CREATE USER 'rainuser'@'localhost' IDENTIFIED BY 'YourPassword23!';

Выдаём права только на одну базу.

mysql> GRANT ALL ON rainloop.* TO 'rainuser'@'localhost';

Применяем изменения и выходим.

mysql> FLUSH PRIVILEGES;
mysql> exit

Скачивание Rainloop распаковка файлов и выдача правильных прав на каталоги веб-приложения

Создаём каталог под веб-приложение.

$ sudo mkdir /var/www/html/rainloop -p

Скачиваем последнюю версию.

$ wget http://www.rainloop.net/repository/webmail/rainloop-community-latest.zip

Распаковываем архив прямо в нужный каталог.

$ sudo unzip rainloop-community-latest.zip -d /var/www/html/rainloop

Передаём владение веб-серверу.

$ sudo chown -R nginx:nginx /var/www/html/rainloop

Выставляем аккуратные права на директории и файлы. Такая схема - 755 для папок и 644 для файлов - считается безопасным стандартом для веб-приложений на PHP.

$ sudo find /var/www/html/rainloop -type d -exec chmod 755 {} \;
$ sudo find /var/www/html/rainloop -type f -exec chmod 644 {} \;

Получение сертификата Let's Encrypt и настройка виртуального хоста Nginx с современной криптографией

Работать с почтой по HTTP в 2024 году - моветон. Бесплатные сертификаты от Let's Encrypt решают вопрос шифрования без единой копейки затрат. Устанавливаем Snapd core.

$ sudo snap install core

Ставим Certbot.

$ sudo snap install --classic certbot

Создаём символическую ссылку.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Получаем сертификат для домена.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. -d rainloop.example.com

Генерируем параметры Диффи-Хеллмана на 4096 бит. Процесс не быстрый, на слабой виртуалке может занять несколько минут.

$ sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Чтобы обновление сертификата шло автоматически, добавляем хуки для остановки и запуска Nginx.

$ sudo nano /etc/letsencrypt/renewal/rainloop.example.com.conf

В конец файла вставляем.

pre_hook = systemctl stop nginx
post_hook = systemctl start nginx

Проверяем работоспособность обновления в режиме холостого запуска.

$ sudo certbot renew --dry-run

Теперь правим главный конфиг Nginx.

$ sudo nano /etc/nginx/nginx.conf

После строки include /etc/nginx/conf.d/*.conf добавляем параметр.

server_names_hash_bucket_size  64;

Создаём отдельный конфиг для Rainloop.

$ sudo nano /etc/nginx/conf.d/rainloop.conf

Внутри помещаем полноценную конфигурацию с редиректом на HTTPS, современными шифрами и OCSP stapling.

server {

    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name rainloop.example.com;
    root /var/www/html/rainloop;

    index index.php;
    client_max_body_size 25M;

    access_log  /var/log/nginx/rainloop.access.log;
    error_log   /var/log/nginx/rainloop.error.log;

    ssl_certificate      /etc/letsencrypt/live/rainloop.example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/rainloop.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/rainloop.example.com/chain.pem;
    
    ssl_session_timeout  5m;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        fastcgi_keep_conn on;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    location ~ /\.ht {
        deny all;
    }

    location ^~ /data {
        deny all;
    }
}
# enforce HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name  rainloop.example.com;
    return 301   https://$host$request_uri;
}

Обращает на себя внимание блок с правилом deny all для каталога /data. Это критически важная деталь безопасности. В указанном каталоге Rainloop хранит конфигурационные файлы и данные пользователей, и прямой доступ к ним извне стал бы катастрофой. Проверяем синтаксис конфигурации.

$ sudo nginx -t

Перезапускаем веб-сервер.

$ sudo systemctl restart nginx

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

Административная панель открывается по специальному адресу. URL выглядит так.

https://rainloop.example.com/?admin

Дефолтные учётные данные для первого входа стандартные и нуждаются в немедленной замене.

  1. Логин admin
  2. Пароль 12345
  3. Переход в раздел Security
  4. Генерация нового длинного пароля
  5. Настройка раздела Contacts с выбором MySQL
  6. Ввод созданных ранее учётных данных базы
  7. Нажатие кнопки Test и проверка зелёной индикации подключения

После смены пароля можно переходить к настройке контактов. В разделе Contacts выбирается MySQL в выпадающем меню, вводятся данные созданного пользователя rainuser и пароль, затем проверяется соединение. Зелёная индикация кнопки Test говорит об успехе - таблицы создались, база готова принимать адресные записи.

Дальше остаётся добавить конкретные почтовые аккаунты. Rainloop умеет работать с любыми IMAP-серверами - от корпоративных решений до классических провайдеров. Достаточно знать адреса входящего и исходящего серверов, номера портов и реквизиты учётной записи.

Установка веб-клиента собственного размещения - история не только про удобство, но и про контроль. Кто владеет сервером, тот владеет данными. Никакие сторонние сервисы не читают заголовки писем, не показывают рекламу на основе содержимого переписки, не продают информацию рекламным сетям. Приватность в чистом виде, добытая собственными руками за час работы в терминале. А навык быстрого развёртывания таких сервисов - один из тех, что окупают себя многократно при любой смене места работы или запуске нового проекта.