Infisical на сервере: частые ошибки и решения
Если команда выросла настолько, что пароли от продакшена и токены API уже не помещаются в общий файл в чате, самостоятельный хостинг Infisical выглядит логичным шагом — открытый код, свой сервер, никаких сторонних SaaS с чужими ключами шифрования. Но между «поднял docker-compose» и «команда реально пользуется» лежит десяток мест, где всё разваливается: контейнер падает через пять секунд, логин зацикливается, письма с приглашением не приходят. Разберём самые частые причины по порядку.
Содержание
- Контейнер не запускается: ENCRYPTION_KEY, AUTH_SECRET и другие обязательные переменные
- Backend не видит PostgreSQL или Redis
- Редирект-петля и CORS-ошибки после логина (SITE_URL)
- Secure cookies и HTTPS за обратным прокси (Traefik/Nginx)
- SMTP не работает: не приходят письма верификации и приглашений
- Ошибки миграций и потеря доступа к секретам при смене ENCRYPTION_KEY
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Контейнер не запускается: ENCRYPTION_KEY, AUTH_SECRET и другие обязательные переменные
Самый частый сценарий: docker compose up -d отрабатывает без видимых ошибок, но через несколько секунд backend уходит в перезапуск по кругу. В логах — docker compose logs -f backend — обычно видно что-то вроде «missing required environment variable» или процесс просто падает без внятного сообщения на старте.
Infisical при самостоятельном хостинге требует минимум трёх переменных в .env, без которых backend не поднимется:
ENCRYPTION_KEY= # ключ симметричного шифрования секретов
AUTH_SECRET= # секрет для подписи JWT-токенов сессий
SITE_URL= # публичный адрес, по которому команда заходит в панель
Генерируются они локально, не в контейнере:
openssl rand -hex 16 # для ENCRYPTION_KEY
openssl rand -base64 32 # для AUTH_SECRET
Частая ошибка — скопировать пример .env.example из репозитория и забыть заменить плейсхолдеры на реальные значения, либо оставить кавычки вокруг значения (ENCRYPTION_KEY="abc123" вместо ENCRYPTION_KEY=abc123) — некоторые версии парсера переменных окружения в docker compose кавычки не срезают, и в приложение улетает строка вместе с кавычками.
Второй момент — после того как контейнер один раз успешно стартовал с определённым ENCRYPTION_KEY, менять это значение на живой базе с уже сохранёнными секретами нельзя (подробнее — в разделе про миграции ниже). Сгенерируйте ключи один раз и сразу сохраните .env в защищённое хранилище — восстановить доступ к секретам без исходного ENCRYPTION_KEY невозможно в принципе, это не баг, а следствие модели шифрования.
Если разворачиваете Infisical с нуля, порядок первого запуска и структура docker-compose подробно разобраны в статье Как установить и настроить Infisical на VPS — эта статья дальше исходит из того, что базовая установка уже сделана и что-то пошло не так после неё.
Backend не видит PostgreSQL или Redis
Вторая по частоте причина падения контейнера — backend поднимается, но не может достучаться до базы данных. В логах типичны строки вида ECONNREFUSED, the database system is starting up или Could not connect to Redis.
Разбирается по шагам:
- Проверьте, что контейнер базы вообще жив:
docker compose ps— еслиdbилиpostgresв статусеrestarting, проблема на уровне самой базы, а не Infisical. - Сверьте имя хоста в строке подключения. В
DB_CONNECTION_URIдолжно стоять имя сервиса из docker-compose (postgres,db), а неlocalhost— внутри docker-сети контейнеры обращаются друг к другу по имени сервиса,localhostвнутри backend-контейнера — это сам backend. - Пароль в URI должен совпадать с
POSTGRES_PASSWORDконтейнера базы. Если меняли пароль в.envпосле первого запуска, а volume базы уже создан со старым паролем — новое значение работать не будет, пока не смените пароль и внутри самой СУБД. - Дайте базе время подняться до старта backend. Без
depends_onсcondition: service_healthyи healthcheck на postgres backend может стартовать раньше, чем база готова принимать соединения, и не переподключается сам:
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U infisical"]
interval: 5s
timeout: 5s
retries: 10
backend:
depends_on:
db:
condition: service_healthy
С Redis логика похожая — REDIS_URL формата redis://:пароль@redis:6379, где redis — имя сервиса, а не адрес хоста. Если Redis запущен без пароля, а в URL он всё равно указан (или наоборот), подключение падает с ошибкой NOAUTH/WRONGPASS в логах контейнера redis.
Общие приёмы диагностики обрыва связи backend—PostgreSQL разобраны в статье PostgreSQL не принимает подключения: причины и решение — пригодится, если проблема не ушла после проверки всех пунктов выше.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверРедирект-петля и CORS-ошибки после логина (SITE_URL)
Отдельная категория проблем начинается уже после того, как всё поднялось: страница логина открывается, форма отправляется, но вместо панели браузер либо гоняет по кругу между /login и /, либо в консоли разработчика видна ошибка CORS вида has been blocked by CORS policy.
Практически всегда причина одна — SITE_URL в .env не совпадает с тем адресом, по которому команда реально заходит в интерфейс. Частые варианты рассинхрона:
- в
.envстоитhttp://, а реально заходят поhttps://(или наоборот, за проксом без TLS); - в
.envуказан IP-адрес сервера, а команда заходит по домену — или наоборот; - есть завершающий слэш там, где его не ждёт код (
https://secrets.example.com/вместоhttps://secrets.example.com); .envпоменяли, но забыли пересоздать контейнер —docker compose restartне всегда достаточно, если переменная читается только при пересоздании контейнера, нуженdocker compose up -d --force-recreate backend.
SITE_URL используется не только для отображения — от него зависят домен cookie сессии и список разрешённых origin для CORS. Несовпадение даже в схеме (http/https) браузер и backend трактуют как разные источники. После правки обязательно очистите cookie для домена (или откройте приватное окно) — старая cookie, выданная под прежний SITE_URL, будет конфликтовать с новой сессией и создавать ощущение, что фикс не сработал.
Secure cookies и HTTPS за обратным прокси (Traefik/Nginx)
Если Infisical стоит за Traefik или Nginx, который терминирует TLS и проксирует на backend уже по HTTP внутри docker-сети, встречается ещё один вариант той же болезни: логин формально проходит, но пользователя тут же выкидывает обратно на страницу входа, либо в логах backend мелькает что-то про CSRF или недействительную сессию.
Причина в том, что cookie сессии выставляется с флагом Secure (обязательным для HTTPS), а backend, получая запрос от прокси уже как обычный HTTP-трафик внутри сети, не всегда понимает, что снаружи соединение было по HTTPS — если прокси не передаёт (или backend не учитывает) заголовок X-Forwarded-Proto.
Traefik и Nginx Proxy Manager сами добавляют X-Forwarded-Proto и X-Forwarded-For по умолчанию — если используете голый nginx-конфиг вручную, эти заголовки нужно прописать явно:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Real-IP $remote_addr;
Если проблема сохраняется — стоит проверить общие грабли самого прокси отдельно, они часто маскируются под «ошибку приложения»: разобраны в статье Traefik на сервере: частые ошибки и решения.
Отдельно: если Infisical временно доступен только по HTTP (например, на этапе теста без домена и сертификата), а в .env уже прописан https:// в SITE_URL, получите ту же петлю логина, что и в предыдущем разделе. На время теста без TLS ставьте SITE_URL со схемой http://, переключайте на https:// только когда сертификат реально выпущен.
SMTP не работает: не приходят письма верификации и приглашений
Без рабочего SMTP новый пользователь, приглашённый в организацию, не сможет подтвердить почту и попасть в интерфейс — письмо просто не уходит, а в логах backend видна ошибка вроде ECONNREFUSED на порт SMTP или Invalid login.
Переменные, которые за это отвечают:
| Переменная | Назначение | Частая ошибка |
|---|---|---|
SMTP_HOST | адрес почтового сервера | опечатка, либо адрес внутреннего relay, недоступного с сервера |
SMTP_PORT | обычно 587 (STARTTLS) или 465 (SSL) | порт указан, а флаг шифрования — нет |
SMTP_USERNAME / SMTP_PASSWORD | учётные данные | для Gmail/Yandex нужен именно пароль приложения, не основной пароль аккаунта |
SMTP_FROM_ADDRESS | адрес отправителя | домен не совпадает с доменом, для которого настроен SMTP-аккаунт |
Если провайдер SMTP требует явного указания шифрования, а в конфиге есть отдельный флаг secure/TLS — сверьте его с портом: 465 обычно означает SSL с самого начала соединения, 587 — STARTTLS поверх обычного; перепутанная комбинация порт/флаг — частая причина «сервер как будто принял соединение и тут же его оборвал».
Проверить SMTP отдельно от Infisical можно через swaks, не гадая, где проблема — в приложении или в почтовом сервере:
swaks --to test@example.com --from noreply@secrets.example.com \
--server smtp.example.com:587 --auth LOGIN \
--auth-user your-user --auth-password 'your-pass' -tls
Если письмо через swaks уходит, а через Infisical — нет, дело в переменных .env. Если не уходит и через swaks — проблема не в приложении: проверяйте firewall (исходящий 587/465 не должен быть заблокирован) и репутацию исходящего IP — свежий VPS без SPF/DKIM/PTR для отправляющего домена почтовые провайдеры нередко заворачивают в спам или отклоняют совсем.
Ошибки миграций и потеря доступа к секретам при смене ENCRYPTION_KEY
Последняя категория — то, что случается не при первом запуске, а при обновлении версии или после восстановления из бэкапа.
Обновление версии и застрявшие миграции. Backend при старте новой версии образа обычно сам прогоняет миграции схемы базы. Если версию поднимали сразу через несколько релизов, миграции могут упасть на промежуточном шаге, а backend уйдёт в бесконечный рестарт с ошибкой уровня SQL в логах. Разбираться в такой ситуации сложнее, чем предотвратить её:
- обновляйте образ пошагово, а не «на самую свежую версию сразу», если между текущей и последней прошло много релизов;
- перед апгрейдом снимайте дамп базы:
docker compose exec db pg_dump -U infisical infisical > backup.sql; - после обновления образа следите за логами backend вживую (
docker compose logs -f backend), а не просто проверяйте, что контейнер в статусеUp— контейнер может быть «жив», но крутиться в цикле неуспешных попыток миграции.
Смена ENCRYPTION_KEY на непустой базе — необратимая потеря данных. Это не баг, а следствие модели шифрования: ENCRYPTION_KEY шифрует секреты на лету, и без него зашифрованные значения в базе — бессмысленный набор байт. Если ключ потерян или заменён без специальной процедуры ротации, все ранее сохранённые секреты становятся нечитаемыми навсегда — не восстановить ни через поддержку, ни через дамп базы.
Практический вывод: .env с ENCRYPTION_KEY и AUTH_SECRET — такая же критичная тайна, как сами секреты внутри Infisical, и бэкапить её нужно так же серьёзно, как базу данных, причём отдельно от неё.
Если рассматриваете Infisical как один из вариантов, а не финальное решение, есть смысл сравнить его с более тяжеловесным HashiCorp Vault по модели эксплуатации — разница описана в статье HashiCorp Vault: управление секретами.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли развернуть Infisical без Redis, оставив только PostgreSQL?
Для части функций (сессии, очереди фоновых задач) Redis используется как обязательный компонент в большинстве актуальных версий self-hosted развёртывания — без него часть функциональности либо не запустится, либо будет работать нестабильно. Проверяйте требования конкретной версии образа перед тем, как убирать сервис из docker-compose.
Безопасно ли открывать порт Infisical напрямую в интернет без прокси?
Технически панель поднимется и так, но вы теряете единую точку выпуска и продления TLS-сертификата и стандартные заголовки безопасности. Практически всегда лучше держать Infisical за Traefik или Nginx с отдельным поддоменом и закрытым файрволом на прямой порт контейнера.
Как понять, упал ли контейнер из-за нехватки памяти, а не из-за конфигурации?
Проверьте docker compose ps на код завершения (Exited (137) — почти всегда OOM-killer) и dmesg | grep -i oom на хосте. Node.js-backend плюс PostgreSQL и Redis на одном сервере с 1 ГБ RAM — частый сценарий именно такого падения, а не ошибки в .env.
Нужно ли отдельно бэкапить сами секреты, или достаточно бэкапа PostgreSQL?
Дамп PostgreSQL уже содержит зашифрованные секреты — этого достаточно для восстановления при условии, что вместе с дампом сохранён и актуальный ENCRYPTION_KEY. Бэкап одной базы без ключа шифрования бесполезен.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →