MinIO в Docker Compose: готовый файл
Приложению нужен S3 — принимать загрузки пользователей, хранить бэкапы, отдавать статику через SDK, который умеет только PutObject и GetObject. Держать всё в AWS ради одного бакета невыгодно: трафик наружу, счёт в долларах, задержки до региона. MinIO поднимает тот же S3 API на вашем сервере: один контейнер, один конфиг, и приложение подключается по тому же протоколу, что и к настоящему S3, просто эндпоинтом становится ваш IP.
Содержание
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что такое MinIO и зачем свой S3 на сервере
MinIO — объектное хранилище с открытым кодом, которое реализует S3 API почти один в один: те же вызовы, та же модель бакетов и объектов, та же схема подписи запросов. Для приложения разницы нет — вы меняете endpoint_url в конфиге клиента (boto3, aws-sdk, restic, s3cmd) на адрес своего сервера и указываете свои ключи вместо AWS-ключей, остальной код не трогаете.
Практические причины поставить MinIO рядом с приложением, а не идти в облачный S3:
- Деньги. Плата за исходящий трафик у облачных провайдеров часто больше, чем стоимость самого хранения. На своём сервере трафик внутри дата-центра между контейнерами бесплатный, а исходящий тарифицируется как обычный трафик VPS.
- Задержка. Бэкенд и хранилище в одной локации — доступ к объектам быстрее, чем через интернет до чужого региона.
- Совместимость без переписывания кода. Библиотеки уровня
boto3,aws-cli,rclone,restic, Terraform S3-backend работают с MinIO без модификаций — это тот же API. - Контроль над данными. Бакеты физически лежат на вашем диске, вы сами решаете про шифрование на уровне диска, репликацию и жизненный цикл объектов.
Минус тоже честно: единственный узел MinIO — это единственная точка отказа, и надёжность хранения такая же, как у диска под ним. Ниже разберём и это.
Готовый docker-compose.yml
Рабочий минимальный конфиг для одного узла — консоль администратора и S3 API в одном контейнере:
services:
minio:
image: minio/minio:RELEASE.2026-06-13T22-30-00Z
container_name: minio
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
MINIO_BROWSER_REDIRECT_URL: https://console.example.com
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 5s
retries: 3
deploy:
resources:
limits:
memory: 1g
volumes:
minio_data:
Порт 9000 — это S3 API, именно на него смотрят SDK и mc. Порт 9001 — веб-консоль администратора, отдельный интерфейс со списком бакетов, пользователями и метриками. Не путайте их в конфиге клиента: указав 9001 вместо 9000 в endpoint приложения, вы получите не тот протокол.
Точный тег версии image: minio/minio:RELEASE... вместо latest — не формальность: MinIO выпускает релизы часто, и в проде вы хотите обновляться осознанно, а не при каждом docker compose pull. Актуальный тег смотрите в официальных релизах на GitHub перед первым запуском.
Файл .env рядом с compose:
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD=выдайте-длинный-случайный-пароль-от-20-символов
chmod 600 .env
Запуск:
docker compose up -d
docker compose logs -f minio
Проверьте, что API живой:
curl -s http://localhost:9000/minio/health/live -o /dev/null -w "%{http_code}\n"
200 значит контейнер поднялся и слушает оба порта.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПеременные окружения, секреты и порты
MINIO_ROOT_USER и MINIO_ROOT_PASSWORD — это root-учётка, с полными правами на всё хранилище. Требования у MinIO жёсткие: логин минимум 3 символа, пароль минимум 8, но для прода закладывайте 20+ случайных символов — это единственная пара credentials, компрометация которой отдаёт весь бакет целиком.
Root-учётку в проде использовать для приложений не стоит — заведите отдельного пользователя с ограниченной политикой через mc admin user add (ниже в разделе про бакеты), а root оставьте только для административных операций через консоль. Тот же принцип разделения секретов и общей логики компоуз-файла, что и в любом продакшен-стеке — если у вас уже есть свой подход к секретам в других сервисах, смотрите управление паролями через Docker secrets как альтернативу голому .env.
Порты наружу открывайте по необходимости. Если API нужен только соседним контейнерам в том же compose-проекте, не пробрасывайте 9000 на хост вообще — приложение обратится к MinIO по имени сервиса внутри docker-сети:
services:
app:
environment:
S3_ENDPOINT: http://minio:9000
Это работает, если оба сервиса в одном docker-compose.yml или в одной внешней сети networks:. Наружу тогда торчит только 9001 для консоли — и то лучше за VPN или списком разрешённых IP через firewall, а не в открытый интернет.
Тома, диски и что с производительностью
Именованный том minio_data в примере выше хранит данные в управляемом Docker-области, обычно /var/lib/docker/volumes/.... Для прода часто удобнее bind mount на конкретный смонтированный диск — так проще следить за местом и переносить данные:
volumes:
- /mnt/storage/minio:/data
Смонтируйте отдельный диск под /mnt/storage заранее — держать объектное хранилище на системном разделе рискованно: если бакет разрастётся, вы рискуете уронить и ОС, и все остальные контейнеры на том же диске.
Про производительность честно: single-node MinIO на одном диске — это ровно скорость этого диска, никакой магии не происходит. SSD или NVMe обязательны, если через хранилище идёт что-то чувствительное к задержке — не путайте с холодным архивом бэкапов, для которого HDD вполне достаточен. Если объём данных измеряется терабайтами и растёт, отдельная тема — выделенный сервер под файловое хранилище на терабайты, где диски и RAID подбираются под задачу заранее, а не докупаются по факту нехватки места.
Отдельно про надёжность: single-node режим без erasure coding не защищает от порчи одного диска — упал диск, потеряли данные. MinIO умеет распределённый режим на 4+ узлах с erasure coding, где часть дисков может выйти из строя без потери данных, но это уже другая архитектура — несколько узлов, отдельная compose-конфигурация с MINIO_DISTRIBUTED и общая сеть между ними. Для одного проекта на старте это обычно избыточно; закладывайте его, когда объём данных и требования к отказоустойчивости вырастут, и решайте это отдельным бэкапом на внешнее хранилище — см. ниже.
HTTPS и reverse-proxy для консоли и API
По умолчанию MinIO в контейнере отдаёт HTTP, TLS-терминацию удобнее вынести на reverse-proxy перед ним — так же, как для любого другого сервиса за Nginx или Traefik. Ключевой нюанс с MinIO: клиенты S3 обычно грузят объекты крупными кусками, и стандартный буферинг Nginx этому мешает.
Конфиг Nginx для API (порт 9000) с отключённым буферингом:
server {
listen 443 ssl;
server_name s3.example.com;
client_max_body_size 0;
ignore_invalid_headers off;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
chunked_transfer_encoding off;
}
}
client_max_body_size 0 снимает лимит размера тела запроса — иначе загрузка крупного объекта упрётся в стандартные 1 МБ Nginx. Консоль (9001) заведите отдельным server блоком на другом поддомене, с теми же proxy_set_header, но без отключения буферинга — там оно не критично.
Если у вас уже стек за Traefik, добавьте лейблы к сервису minio в том же compose-файле вместо отдельного reverse-proxy — принцип тот же, что описан в статье про Traefik как reverse proxy для Docker, только с двумя роутерами на разные порты контейнера (9000 и 9001) вместо одного.
Первые бакеты, политики доступа и клиент mc
Управлять MinIO из терминала удобнее через официальный клиент mc — он же пригодится для скриптов бэкапа. Установка на клиентской машине или прямо на сервере:
curl https://dl.min.io/client/mc/release/linux-amd64/mc -o mc
chmod +x mc
sudo mv mc /usr/local/bin/
Подключение алиасом к вашему серверу — дальше все команды идут через этот алиас, а не через голый curl:
mc alias set myminio https://s3.example.com admin ваш-root-пароль
Создать бакет и включить версионирование объектов (полезно, если приложение перезаписывает файлы и нужна история):
mc mb myminio/uploads
mc version enable myminio/uploads
Отдельный пользователь для приложения вместо root-ключей:
mc admin user add myminio app-uploader сложный-пароль-приложения
mc admin policy attach myminio readwrite --user app-uploader
Политику можно сузить до конкретного бакета своим JSON вместо встроенной readwrite, если приложению не нужен доступ ко всему хранилищу — root-ключи в переменных окружения приложения в проде вообще не должны встречаться.
Жизненный цикл объектов — например, автоматическая чистка временных загрузок старше 7 дней:
mc ilm add myminio/uploads --expire-days 7 --prefix tmp/
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
MinIO подходит для продакшена или это только для разработки?
Подходит, но с оговорками: single-node без erasure coding — это надёжность уровня одного диска, для критичных данных нужен либо распределённый режим на нескольких узлах, либо регулярный бэкап на внешнее хранилище.
Чем MinIO отличается от обычного volume или NFS?
Volume и NFS — это файловая система, MinIO — объектное S3-совместимое хранилище со своим API. Если приложение или библиотека рассчитаны на S3-протокол (загрузка через presigned URL, метаданные объектов, версионирование), MinIO подходит напрямую, файловая система — нет.
Можно ли использовать AWS SDK для Python/Node/Go без изменений?
Да, это и есть смысл MinIO — меняете только endpoint_url на адрес своего сервера и ключи на свои, остальной код с boto3, aws-sdk-js, aws-sdk-go работает как есть.
Как бэкапить данные MinIO?
Проще всего mc mirror в другой бакет или на другой сервер, либо mc admin bucket remote для настройки репликации между двумя инстансами MinIO. Общие практики бэкапа docker-томов, применимые и здесь, разобраны в статье про бэкап Docker volume — тот же принцип регулярности и проверки восстановления работает для тома /data MinIO.
Нужен ли отдельный сервер под MinIO или можно на том же, где приложение?
Для тестового или небольшого проекта — можно на одном сервере с приложением, как в примере выше. При росте нагрузки на диск (много одновременных загрузок/выгрузок) лучше вынести на отдельный сервер, чтобы не конкурировать за I/O с базой данных или веб-сервером.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →