Medusa на сервере: частые ошибки и решения
Medusa — headless-платформа для интернет-магазина: бэкенд на Node.js, витрину и админку можно собирать отдельно, а логику checkout, каталога и заказов оставить на сервере. Удобство оборачивается ценой — вместо одного монолита вы получаете связку из API-сервера, PostgreSQL, Redis, воркера очередей и (часто) отдельного storefront-приложения, и любое звено этой цепочки может подвести. Ниже — ошибки, с которыми реально сталкиваешься при разворачивании Medusa на своём VPS, и как их закрывать без танцев с бубном.
Содержание
- Сервер не стартует: "Cannot connect to Postgres" и похожие ошибки
- Redis: воркер зависает или очереди не разгребаются
- CORS блокирует storefront или админку
- Загрузка файлов и изображений товаров не работает
- Долгий старт, таймауты и падение процесса под нагрузкой
- Миграции и обновление версии ломают админку
- SSL, домен и продакшн-окружение вокруг Medusa
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Сервер не стартует: "Cannot connect to Postgres" и похожие ошибки
Первое, с чем сталкиваются почти все — бэкенд падает при старте, не успев поднять HTTP-порт. Причины почти всегда в подключении к базе.
Проверьте DATABASE_URL в .env — формат должен быть строго:
DATABASE_URL=postgres://medusa_user:пароль@127.0.0.1:5432/medusa_db
Частые промахи:
- localhost вместо 127.0.0.1 — если PostgreSQL слушает только IPv4-сокет, а Node резолвит localhost в
::1, соединение отвалится с ECONNREFUSED; - пароль с спецсимволами (
@,#,:) без URL-кодирования — ломает парсинг строки подключения; - база не создана заранее. Medusa не создаёт саму базу данных — только таблицы внутри неё. Создайте её вручную:
sudo -u postgres psql -c "CREATE DATABASE medusa_db;"
sudo -u postgres psql -c "CREATE USER medusa_user WITH ENCRYPTED PASSWORD 'ваш_пароль';"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE medusa_db TO medusa_user;"
После этого прогоните миграции — без них Medusa упадёт с ошибкой отсутствующих таблиц:
npx medusa db:migrate
Если база на отдельном сервере или в докер-контейнере, проверьте, что PostgreSQL слушает внешний интерфейс (listen_addresses в postgresql.conf) и что в pg_hba.conf разрешён вход с адреса вашего backend-сервера. Разбор похожих проблем с самим PostgreSQL — в статье PostgreSQL на сервере: частые ошибки и решения.
Redis: воркер зависает или очереди не разгребаются
В Medusa v2 Redis используется для event bus и очередей (workflows, отложенные задачи вроде отправки email или пересчёта остатков). Если Redis недоступен, сервер обычно всё же стартует, но события начинают теряться или зависать в очереди без обработки.
Симптомы: заказ создался, а письмо клиенту не ушло; изменения статуса заказа не триггерят связанные workflow; в логах мелькает ECONNREFUSED 127.0.0.1:6379 или MaxRetriesPerRequestError.
Проверьте переменные окружения:
REDIS_URL=redis://127.0.0.1:6379
EVENT_BUS_REDIS_URL=redis://127.0.0.1:6379
WORKFLOW_ENGINE_REDIS_URL=redis://127.0.0.1:6379
В версии 2.x эти три URL можно (и часто нужно) развести по разным базам Redis (/0, /1, /2), чтобы не смешивать очереди воркфлоу с обычным кешем — особенно если тот же Redis использует ещё что-то на сервере. Убедитесь, что сам Redis жив и не упирается в лимит памяти:
redis-cli ping
redis-cli info memory | grep used_memory_human
Если Redis настроен с maxmemory и политикой allkeys-lru, он может вытеснять ключи очередей под нагрузкой — это тихо ломает workflow-движок без явных ошибок в логе Medusa. Для очередей ставьте noeviction или выносите event bus в отдельный инстанс Redis без лимита. Больше типовых проблем разобрано в статье Redis на сервере: частые ошибки и решения.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверCORS блокирует storefront или админку
Классика: витрина или React-админка стучится в API и получает в консоли браузера has been blocked by CORS policy. Medusa требует явно перечислять разрешённые origin'ы — по умолчанию не разрешено ничего, кроме localhost для разработки.
В .env бэкенда должны быть заданы (в v2 — через переменные, раньше это делалось в medusa-config.js):
STORE_CORS=https://shop.example.com,https://www.example.com
ADMIN_CORS=https://admin.example.com
AUTH_CORS=https://shop.example.com,https://admin.example.com
Частые ошибки здесь:
- забыли добавить
www-версию домена, если она используется отдельно от корневого; - в CORS указан HTTP, а витрина реально работает по HTTPS (или наоборот, после смены сертификата);
- значение задано как
*— работает для API-запросов без credentials, но ломается, если storefront шлёт куки авторизации; - после правки
.envзабыли перезапустить процесс — Medusa не подхватывает.envна лету, только при старте.
Если перед Medusa стоит nginx как reverse proxy, проверьте заодно, что сам nginx не режет заголовок Origin или не добавляет свой Access-Control-Allow-Origin, конфликтующий с тем, что отдаёт Node — задвоенные CORS-заголовки браузер тоже трактует как ошибку. Настройка прокси разобрана в статье Nginx как reverse proxy: частые ошибки и решения.
Загрузка файлов и изображений товаров не работает
По умолчанию Medusa хранит загруженные файлы (изображения товаров) локально на диске сервера — это работает для теста, но не переживает передеплой, масштабирование на несколько инстансов или простое обновление контейнера. Плюс локальное хранилище не отдаёт файлы через CDN, что бьёт по скорости витрины.
Правильный путь для прода — S3-совместимое хранилище через @medusajs/file-s3 (или аналогичный provider). Пример конфигурации модуля файлов в medusa-config.ts:
{
resolve: "@medusajs/medusa/file",
options: {
providers: [
{
resolve: "@medusajs/medusa/file-s3",
id: "s3",
options: {
file_url: process.env.S3_FILE_URL,
access_key_id: process.env.S3_ACCESS_KEY_ID,
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
region: process.env.S3_REGION,
bucket: process.env.S3_BUCKET,
endpoint: process.env.S3_ENDPOINT,
},
},
],
},
},
Для self-hosted варианта отлично подходит MinIO, поднятый на соседнем сервере или в том же docker-compose стеке — S3 API совместим один в один, и не нужно платить внешнему провайдеру. Установка описана в статье Как установить и настроить MinIO на VPS, а частые грабли — в MinIO на сервере: частые ошибки и решения. Не забудьте выставить публичный read-доступ на бакет с изображениями и настроить file_url так, чтобы он указывал на реально доступный извне адрес — иначе картинки будут грузиться в админке (у неё есть доступ к внутренней сети), но не на витрине.
Долгий старт, таймауты и падение процесса под нагрузкой
Medusa API-сервер — это Node.js-процесс, и он подвержен всем обычным болезням Node в проде: утечки памяти при долгом аптайме, падение по OOM при пиковой нагрузке, зависание event loop на тяжёлых синхронных операциях (например, при экспорте большого CSV каталога).
Голый node index.js в screen-сессии — плохая идея для прода: процесс упадёт при первой необработанной ошибке и никто его не поднимет. Используйте process-менеджер. Проще всего — PM2:
npm install -g pm2
pm2 start "npx medusa start" --name medusa-backend
pm2 save
pm2 startup
PM2 перезапустит процесс при падении и даст ротацию логов через pm2-logrotate. Полезно сразу ограничить память, при превышении которой PM2 сам перезапустит воркер:
pm2 start "npx medusa start" --name medusa-backend --max-memory-restart 800M
Отдельно вынесите воркер очередей (MEDUSA_WORKER_MODE=worker) в свой процесс, если у вас высокая нагрузка на event bus — так падение воркера не утянет за собой обработку HTTP-запросов, и наоборот. Для honest-оценки, сколько памяти реально нужно под ваш каталог и трафик, ориентируйтесь на минимум 2 ГБ RAM для связки backend + Postgres + Redis на небольшом магазине — но это именно ориентир, у вас может уйти заметно больше или меньше в зависимости от числа SKU и одновременных запросов.
Миграции и обновление версии ломают админку
После npm update мажорной или минорной версии Medusa админка иногда просто отдаёт белый экран или 500-ю на /app. Почти всегда причина — рассинхрон между схемой базы и кодом: обновили пакет, но не прогнали миграции, либо наоборот — прогнали миграции новой версии на бэкенде, который ещё не обновлён.
Порядок действий при апгрейде:
- Сделайте бэкап базы перед любым обновлением:
pg_dump -U medusa_user -h 127.0.0.1 medusa_db > medusa_backup_$(date +%F).sql
- Обновите зависимости согласно официальному changelog версии (Medusa нередко требует промежуточных шагов при переходе через несколько минорных версий подряд).
- Прогоните миграции:
npx medusa db:migrate
- Пересоберите админку, если она собирается отдельно:
npx medusa build
- Перезапустите процесс и проверьте логи на предмет ошибок инициализации модулей.
Если что-то пошло не так — откатывайтесь на бэкап базы и предыдущую версию пакетов из package-lock.json, а не пытайтесь чинить схему руками. Ручная правка таблиц Medusa (там сложные связи между заказами, вариантами и ценами) почти всегда создаёт больше проблем, чем решает.
SSL, домен и продакшн-окружение вокруг Medusa
Сама Medusa не занимается TLS — это задача reverse proxy перед ней. Типичная связка: nginx (или Caddy) снаружи, Medusa API-сервер и, при желании, storefront на Next.js — оба за одним прокси, но на разных путях или поддоменах (api.shop.example.com и shop.example.com).
Убедитесь, что:
- переменная
MEDUSA_BACKEND_URLв конфиге storefront указывает на публичный HTTPS-адрес API, а не наlocalhost:9000; - прокси не режет длинные запросы — экспорт каталога или загрузка изображений может занимать больше стандартных 60 секунд,
proxy_read_timeoutв nginx стоит поднять до 120–300 секунд для путей/adminи/store; - заголовок
X-Forwarded-Protoпрокидывается корректно, иначе Medusa может генерировать ссылки сhttp://даже за HTTPS-прокси.
Если хотите автоматический выпуск и продление сертификатов без ручной возни с certbot, вариант с Caddy заметно проще в поддержке — конфиг короче, а обновление сертификата происходит само. Сравнение подходов — в статье Caddy или Nginx: что выбрать для сервера. Готовый прод-стек в docker-compose (с volumes, healthcheck и переменными окружения) разобран в Docker Compose для продакшена: частые ошибки и решения — многие грабли (не тот network mode, забытые volumes для базы, restart-политика) актуальны и для стека Medusa.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько RAM нужно для Medusa в проде?
Для небольшого магазина хватает 2 ГБ на связку backend + Postgres + Redis, но это ориентировочная цифра — при большом каталоге, активном экспорте отчётов или нескольких воркерах закладывайте 4 ГБ и выше. Точную цифру для вашего случая даст только нагрузочный тест на реальных данных.
Можно ли развернуть Medusa без Redis?
Технически бэкенд стартует и без него в упрощённом режиме, но event bus и workflow-движок в v2 рассчитаны на Redis — без него часть асинхронной логики (уведомления, отложенные задачи) просто не будет работать надёжно. Для продакшена Redis нужен.
Почему после деплоя админка не видит новые модули или плагины?
Чаще всего забыли пересобрать проект (npx medusa build) после установки пакета, либо не перезапустили процесс — Node не подхватывает новые файлы модулей на лету.
Как хранить .env с секретами базы и S3-ключами безопасно?
Не коммитьте .env в репозиторий, ограничьте права на файл (chmod 600 .env), а на сервере с несколькими сервисами используйте отдельного системного пользователя для процесса Medusa, чтобы утечка в одном контейнере не давала доступ к секретам другого.
Нужен ли отдельный сервер под storefront?
Необязательно — Next.js-витрину можно держать на том же VPS, что и backend, если трафик небольшой. При росте нагрузки разумно развести их по разным серверам или хотя бы разным процессам с раздельными лимитами памяти.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →