mailcow пишет REDISPASS is not set, хотя пароль есть в mailcow.conf: где на самом деле теряется переменная
Пароль есть в mailcow.conf, а docker compose всё равно предупреждает, что переменная REDISPASS не задана, и сервисы падают на подключении к Redis. Дело не в самом пароле — переменная теряется на шаге между mailcow.conf и Docker Compose. Разбираю на кейсе клиента, где именно рвётся цепочка и как её проверить за пять минут.
Кейс: ВокалГрад обновился и остался без почты в разгар набора учеников
Школа вокала «ВокалГрад» — 19 рабочих мест, свой mailcow на выделенном VPS: администратор, три педагога с общими ящиками для заявок и рассылка расписания родителям. Мы ведём для них корпоративную почту с 2023 года, апдейты обычно проходят без сюрпризов — до конца января 2025-го, когда штатное обновление с 2024-11b на 2025-01 положило весь стек одним разом: письма не уходят, веб-интерфейс SOGo не открывается, вход в панель администратора недоступен.
В выводе docker compose при запуске — сухое предупреждение: The "REDISPASS" variable is not set. Defaulting to a blank string. Первая реакция администратора клиента была понятной: открыть mailcow.conf и убедиться, что переменная REDISPASS там есть и не пустая. Она была на месте, с честным 28-символьным значением. Но Docker Compose всё равно поднимал сервисы так, будто пароля не существует. Это тот случай, когда «переменная есть в конфиге» и «переменная видна процессу» — два разных утверждения, и разница между ними стоила школе почти суток простоя почты в период набора на весенний семестр.
Ниже — то, как я диагностирую эту ошибку у клиентов на mailcow, почему она вообще появилась именно в январе 2025-го и что проверить в первую очередь, если видите REDISPASS is not set у себя, даже если update идёт с версии куда более свежей, чем 2024-11b.
- REDISPASS is not set — типичная ошибка после пересечения границы обновления 2025-01
- пароль в mailcow.conf может быть корректным и всё равно не доходить до контейнера
- проблема не в Redis, а в том, как Compose интерполирует переменные из .env
- чинится за минуты, если знать, где смотреть
Что изменилось в январе 2025-го: у Redis впервые появился пароль
До релиза 2025-01 mailcow пускал к своему Redis без аутентификации вообще — считалось нормальным, потому что Redis был доступен только из Docker-сети mailcow и с localhost хоста. В официальном анонсе релиза «Janmooary 2025 Update» (сам 2025-01 вышел в конце января, исправляющий 2025-01a — 4 февраля 2025 года) разработчики написали прямо: «Redis got a password now. This will not cause any change for a regular mailcow usage without customizations» — то есть для типовой инсталляции ничего не сломается. Но там же отдельным абзацем: «External Apps or Websites which use mailcow's Redis need to use the newly and automatically set Redis password (set inside mailcow.conf) from now on» — внешние приложения, которые ходят в Redis mailcow напрямую, обязаны подхватить новый пароль.
Технически при новой установке пароль генерирует скрипт generate_config.sh, а на существующем сервере его дописывает в mailcow.conf update.sh (модуль _modules/scripts/new_options.sh), если переменной ещё не было. Строка в generate_config.sh выглядит так — REDISPASS=${MAILCOW_REDISPASS:-$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)}. Если задать MAILCOW_REDISPASS заранее через окружение, скрипт использует его; если нет — сгенерирует случайные 28 символов и запишет в mailcow.conf. Дальше этот пароль подставляется в docker-compose.yml без какого-либо значения по умолчанию: REDISPASS=${REDISPASS} — именно в таком виде переменная объявлена у одиннадцати сервисов: redis-mailcow, rspamd-mailcow, php-fpm-mailcow, sogo-mailcow, dovecot-mailcow, postfix-mailcow, acme-mailcow, netfilter-mailcow, watchdog-mailcow, dockerapi-mailcow и postfix-tlspol-mailcow.
Ключевая деталь — отсутствие fallback-значения. Когда у переменной в Compose-файле нет :-default, а сама переменная не попала в окружение, с которым запускается docker compose up, подстановка превращается в пустую строку. Compose выводит предупреждение, что переменная не задана, контейнеры стартуют с пустым REDISPASS и не могут авторизоваться в Redis — хотя в mailcow.conf строка REDISPASS=... стоит на своём месте. Это не баг mailcow и не баг Docker — это ожидаемое поведение интерполяции, которое подводит ровно тогда, когда файл с переменными и файл, который реально читает Compose, — не одно и то же.
Где на самом деле рвётся цепочка: mailcow.conf, .env и то, что видит Compose
mailcow исторически хранит настройки в mailcow.conf, а Docker Compose по умолчанию ищет переменные в файле .env рядом с docker-compose.yml. Разработчики решили эту развилку просто: .env должен быть символической ссылкой на mailcow.conf, а не отдельным файлом. generate_config.sh в актуальных версиях репозитория прямо проверяет это условие при запуске: if [ ! -L "${PWD}/.env" ]; then — если .env не symlink, скрипт останавливается с просьбой запустить его из каталога установки mailcow, а если ссылка есть, но ведёт не на mailcow.conf (проверка через readlink -f), выводит Please create a symbolic link .env -> mailcow.conf inside the mailcow directory и подсказку ln -s mailcow.conf .env.
Проблема в том, что на инсталляциях, которые разворачивались давно или переносились вручную между серверами, .env вполне может оказаться обычным файлом-копией, а не ссылкой: кто-то один раз скопировал mailcow.conf в .env, чтобы «на всякий случай», и с тех пор оба файла живут своей жизнью. mailcow.conf получает REDISPASS при апдейте, а .env — нет, потому что update.sh правит именно mailcow.conf (через sed -i --follow-symlinks и дописывание в конец файла), ожидая, что .env автоматически подтянет то же самое через symlink. Ровно это описано в комментариях к issue #6282 в репозитории mailcow-dockerized: пользователь CameronMunroe 30 января 2025 года написал, что после апдейта видел в логах REDISPASS not set, а добавление переменной вручную и в mailcow.conf, и в .env временно сняло проблему.
6 февраля 2025 года в том же issue ответил мейнтейнер проекта DerLinkman: «Please make sure the .env file is a link to mailcow.conf. I'm currently implementing a detection of that» — то есть подтвердил, что корень проблемы именно в разошедшихся .env и mailcow.conf, и что в код добавляется автоматическая проверка. Если у вас .env — не ссылка, а копия, вы не увидите новых переменных вроде REDISPASS ни при одном последующем обновлении, пока не устраните расхождение вручную.
Эта проверка появилась в generate_config.sh не случайно и не только ради REDISPASS — тот же скрипт, если ссылка ведёт не туда, выводит подсказку с готовой командой: cd /path/to/mailcow && ln -s mailcow.conf .env && ./generate_config.sh. То есть разработчики закладывают, что вариантов развития событий ровно два: либо .env — валидная ссылка и все переменные из mailcow.conf доходят до Compose автоматически, либо администратор явно получает ошибку и инструкцию, что делать. Молчаливого сценария «часть переменных дошла, часть — нет» в актуальном коде быть не должно, но на инсталляциях со старой историей переноса эта проверка могла не сработать ни разу — просто потому, что сам generate_config.sh с ней запускался позже, чем появился расходящийся .env.
Как диагностировать за пять минут, не трогая продакшен
Первый шаг — убедиться, что переменная вообще доходит до Compose, а не гадать по логам контейнеров. Команда docker compose config --environment выводит именно тот набор переменных окружения, который Compose использует для интерполяции прямо сейчас — если REDISPASS в этом списке нет или он пустой, контейнеры и не могли получить пароль, вне зависимости от того, что написано в mailcow.conf.
Второй инструмент — пара docker compose config --no-interpolate и обычный docker compose config. Первая команда показывает модель без подстановки значений, со всеми плейсхолдерами вида ${REDISPASS}, — так видно, какие сервисы вообще ждут переменную. Если же в обычном (интерполированном) выводе docker compose config вы видите пустые значения REDISPASS: "" у сервисов redis-mailcow и dovecot-mailcow — это прямое подтверждение, что переменная не пришла из окружения, и дело не в самом Redis.
Третий шаг — сверить содержимое файлов напрямую: grep -c REDISPASS mailcow.conf .env. Если grep находит строку в mailcow.conf, но не находит в .env (или находит с другим значением), перед вами и есть расхождение, которое описано в issue #6282. Дальше остаётся выяснить, почему .env не ссылка на mailcow.conf — обычно это следы ручного переноса конфигурации со старого сервера или бэкапа, сделанного до перехода на текущую схему generate_config.sh.
Все три проверки безопасно выполнять на живом сервере в рабочее время: они не меняют состояние, только читают его. Это важно, когда почта уже частично работает и нет желания рисковать ещё одним перезапуском стека, пока не понятна причина. Только после того как диагностика однозначно указала на расхождение .env и mailcow.conf, имеет смысл переходить к правке — иначе есть риск чинить не ту причину и получить повторный инцидент через пару недель на следующем обновлении. Похожая логика «переменная объявлена, но процесс её не видит» встречается и за пределами Docker: я разбирал этот же класс проблем на примере systemd, когда Environment=PATH=$PATH не расширяет PATH внутри unit-файла — там переменная тоже формально задана, но подставляется не в том контексте, в котором её ожидает процесс.
Что чинили у ВокалГрада и что делаю теперь на всех клиентских mailcow
У ВокалГрада .env оказался обычным файлом — остатком переноса на новый VPS полтора года назад: администратор копировал каталог mailcow вручную через scp -r, а такая команда по умолчанию следует за символической ссылкой и копирует содержимое файла, на который она указывает, а не саму ссылку. В итоге на новом сервере появился .env с содержимым mailcow.conf на момент переноса — обычный текстовый файл, а не ссылка. Дальше эти два файла жили порознь: mailcow.conf получал все новые параметры при апдейтах, а .env оставался тем же снимком полуторагодичной давности, из которого потом и подставлялись переменные в Docker Compose.
Мы удалили .env, пересоздали ссылку командой ln -s mailcow.conf .env, перезапустили стек: docker compose down && docker compose up -d. Все сервисы поднялись с корректным REDISPASS с первого раза, почта и SOGo вернулись за две минуты. Отдельно сверили docker compose config --environment | grep REDISPASS — значение совпало с тем, что стоит в mailcow.conf, и на этом инцидент закрыли, без необходимости менять сам пароль или что-то пересобирать.
После этого случая я завёл для всех клиентских mailcow-серверов на обслуживании простое правило: перед каждым апдейтом (./update.sh) выполняем readlink -f .env и сверяем, что путь ведёт на mailcow.conf в том же каталоге. Это одна команда, но она снимает целый класс проблем — не только с REDISPASS, а с любой новой переменной, которую разработчики mailcow добавят в будущих релизах по той же схеме: механизм тот же самый, поменяется только имя переменной.
- readlink -f .env перед каждым update.sh — путь должен указывать на mailcow.conf
- если .env не symlink: mv .env .env.bak && ln -s mailcow.conf .env, сверить diff перед удалением бэкапа
- после апдейта — docker compose config --environment | grep REDISPASS, значение не должно быть пустым
- внешние приложения, которые ходят в Redis mailcow напрямую (мониторинг, кастомные скрипты), нужно вручную обновить с новым паролем из mailcow.conf
Почему эта ошибка возвращается на старых инсталляциях снова и снова
Граница 2025-01 — не разовое событие в истории проекта, а точка, через которую рано или поздно проходит любой mailcow-сервер, который вообще обновляется. Актуальный на сегодня релиз — 2026-09 (Mootember 2026, вышел 21 сентября 2026 года, с обновлением Unbound до 1.26.1, SOGo до 5.12.11 и самого Redis до 7.4.11) — и в нём тот же самый механизм: REDISPASS без значения по умолчанию в docker-compose.yml, генерация через generate_config.sh, обязательная символическая ссылка .env на mailcow.conf. Если сервер годами обновлялся релиз за релизом без пропусков, .env-symlink давно проверен и живёт своей нормальной жизнью. Проблема настигает тех, кто admin-ил сервер редко: перетаскивал каталог между VPS, восстанавливал из архивного бэкапа, доставал mailcow.conf из старой копии после переустановки ОС. Ещё один источник таких же по природе сюрпризов — сам update.sh: я отдельно разбирал случай, когда update.sh mailcow отвергает Docker Compose v5 из-за проверки версии, которая не поспевает за реальными релизами Compose.
Именно поэтому я советую делать проверку .env-symlink не разовой акцией после инцидента, а пунктом регламента: она занимает секунду, ничего не меняет на сервере, если всё в порядке, и один раз спасает от простоя, если что-то разошлось. То же самое касается любых будущих переменных, которые mailcow может ввести аналогичным образом — принцип «.env это ссылка, а не копия» не привязан к конкретному релизу и конкретной переменной, это общее правило работы с Docker Compose в этом проекте. На новых инсталляциях я закладываю такую проверку сразу — когда разворачиваем mailcow с нуля для клиента, .env-symlink попадает в тот же чек-лист, что и проверка DNS-записей и сертификатов, а не остаётся на усмотрение будущего апдейта.
Частые вопросы
Можно ли просто вписать REDISPASS в docker-compose.yml вручную, минуя .env?
Не стоит — файл docker-compose.yml перезаписывается при каждом обновлении mailcow из репозитория, и любая ручная правка потеряется при следующем ./update.sh. Переменная должна приходить через .env, который обязан быть ссылкой на mailcow.conf.
Что если .env вообще отсутствует?
Docker Compose тогда просто не найдёт файла с переменными окружения, и все интерполяции вида ${REDISPASS} превратятся в пустые строки для всех сервисов сразу, не только для Redis. Создайте ссылку: `ln -s mailcow.conf .env` из каталога установки mailcow.
Почему в моей версии mailcow вообще нет строки REDISPASS в mailcow.conf?
Значит, апдейт до 2025-01 ещё не проходил или оборвался раньше, чем update.sh дописал новые параметры. Запустите `./update.sh` из каталога установки — он добавит недостающий REDISPASS в mailcow.conf. Не запускайте для этого `./generate_config.sh`: при существующем mailcow.conf он предлагает перезаписать файл целиком.
Изменение REDISPASS повлияет на почту, письма, ящики?
Нет — Redis в mailcow хранит служебные данные (сессии и настройки веб-интерфейса, данные Rspamd, лимиты отправки, статистику), а не как хранилище писем. Смена пароля требует только перезапуска стека и обновления внешних интеграций, данные ящиков на Redis не завязаны.
Нужно ли вручную задавать REDISPASS при установке mailcow с нуля?
Нет, generate_config.sh сгенерирует случайный 28-символьный пароль автоматически при первом запуске. Вручную задавать имеет смысл только если вы восстанавливаете сервер и хотите сохранить прежний пароль для внешних интеграций — тогда экспортируйте MAILCOW_REDISPASS перед запуском скрипта.
Источники
- GitHub Issue #6282 — mailcow-dockerized — Комментарий CameronMunroe (30.01.2025) о логах REDISPASS not set после апдейта и ответ мейнтейнера DerLinkman (06.02.2025) о .env как symlink на mailcow.conf. https://github.com/mailcow/mailcow-dockerized/issues/6282
- mailcow blog — Janmooary 2025 Update (2025-01a) — Официальный анонс: у Redis появился пароль, внешние приложения обязаны использовать REDISPASS из mailcow.conf. https://mailcow.email/posts/2025/release-2025-01/
- mailcow-dockerized, docker-compose.yml (master) — Строки REDISPASS=${REDISPASS} без значения по умолчанию у сервисов redis-mailcow, dovecot-mailcow, php-fpm-mailcow. https://github.com/mailcow/mailcow-dockerized/blob/master/docker-compose.yml
- mailcow-dockerized, generate_config.sh (master) — Проверка .env как symlink на mailcow.conf и генерация REDISPASS через MAILCOW_REDISPASS. https://github.com/mailcow/mailcow-dockerized/blob/master/generate_config.sh
- Docker Compose docs — Variable interpolation — Поведение незаданной переменной без default (замена на пустую строку) и синтаксис ${VAR:-default}. https://docs.docker.com/compose/how-tos/environment-variables/variable-interpolation/
- Docker Compose docs — docker compose config — Флаги --environment и --no-interpolate для проверки, какие переменные реально попадают в интерполяцию. https://docs.docker.com/reference/cli/docker/compose/config/



