DevOps & Docker 12 мин чтения 2026-09-21

MinIO на VDS: собственное S3-хранилище в Docker Compose для бэкапов, медиа и CDN

Облачные S3-хранилища удобны, но стоят дорого при больших объёмах данных и хранят файлы на серверах за рубежом. Практическая инструкция по установке MinIO на VDS в Docker Compose: конфигурация одно-узлового сервера, настройка HTTPS через Nginx Reverse Proxy, создание бакетов и политик доступа, подключение автоматических бэкапов баз данных и интеграция с существующими S3-клиентами.

Инженерная редакция SysKit Проверено инженерами SysKit.ru

Облачные S3-хранилища — Amazon S3, Яндекс Object Storage, VK Cloud — удобны для старта, но при больших объёмах данных их стоимость становится трудно предсказуемой. Ежемесячная оплата за 500 ГБ хранения плюс исходящий трафик на бэкапы баз данных способна превысить стоимость аренды отдельного VDS. Кроме того, данные хранятся на серверах третьих сторон, что критично для бизнеса с чувствительной информацией.

MinIO — это высокопроизводительный сервер объектного хранилища с открытым исходным кодом, полностью совместимый с AWS S3 API. Это означает, что любой инструмент, библиотека или скрипт, работающие с Amazon S3, будут работать с MinIO без единой строки изменений в коде. Хранилище разворачивается на вашем VDS, а все данные остаются под вашим контролем.

1. Зачем поднимать собственное S3: сравнение MinIO с облачными хранилищами

Рассмотрим три наиболее распространённых сценария использования S3-хранилища и сравним стоимость облачного решения с собственным MinIO на VDS:

Параметр Яндекс Object Storage VK Cloud Storage MinIO на VDS
Стоимость 500 ГБ / мес ~700–900 ₽ + трафик ~600–800 ₽ + трафик 0 ₽ (включено в VDS)
Исходящий трафик Тарифицируется Тарифицируется Включён в тариф VDS
AWS S3 API совместимость Частичная Частичная Полная (100%)
Расположение данных Серверы провайдера Серверы провайдера Ваш VDS, ваш контроль
Версионирование объектов Платно Платно Бесплатно

На VDS с 200 ГБ NVMe вы получаете полноценное S3-хранилище с Console-интерфейсом, политиками доступа, версионированием и жизненным циклом объектов — без ежемесячных счетов за каждый гигабайт.

2. Архитектура MinIO: ключевые концепции и режимы работы

MinIO работает в нескольких режимах в зависимости от требований к отказоустойчивости:

  • SNSD (Single-Node Single-Drive): Одна нода, один диск. Простейший режим для разработки, тестирования и небольших продакшен-инсталляций с одним VDS. Именно этот режим разбирается в данной инструкции.
  • SNMD (Single-Node Multi-Drive): Одна нода, несколько дисков. Позволяет включить erasure coding — защиту данных при отказе диска без RAID.
  • MNMD (Multi-Node Multi-Drive): Распределённый кластер минимум из 4 нод. Для корпоративных инсталляций с требованиями к HA и петабайтными объёмами.

Ключевые термины, с которыми вы столкнётесь в работе:

  • Bucket (бакет): Логический контейнер для хранения объектов — аналог папки верхнего уровня. Имя бакета уникально в пределах сервера и формирует URL объектов.
  • Object (объект): Произвольный файл с метаданными. Объекты адресуются по схеме s3://bucket-name/path/to/object.ext.
  • Access Key / Secret Key: Пара учётных данных для аутентификации S3-клиентов. Аналог логина и пароля для API.
  • Policy (политика): JSON-документ в стиле AWS IAM, определяющий права доступа к бакетам и объектам.

MinIO Console — полноценный веб-интерфейс

В отличие от многих self-hosted решений, MinIO поставляется со встроенным веб-интерфейсом управления (Console) прямо в одном Docker-образе. Через браузер доступны: создание бакетов, загрузка файлов, настройка политик IAM, мониторинг метрик производительности и управление жизненным циклом объектов. Никаких отдельных инструментов устанавливать не нужно.

3. Требования к серверу и подготовка окружения на Ubuntu 24.04

Минимальные требования для одно-узлового MinIO в продакшен-конфигурации:

  • Процессор: 2 vCPU — MinIO активно использует параллельную обработку при erasure coding и шифровании.
  • Оперативная память: 2–4 ГБ RAM. MinIO рекомендует минимум 2 ГБ непосредственно для процесса хранилища.
  • Диск: NVMe предпочтительнее HDD. Объём зависит от задачи: для бэкапов баз данных достаточно 50–100 ГБ, для медиаархивов — 200 ГБ и более.
  • Сеть: Статический белый IPv4-адрес, открытый порт 443 (HTTPS через Nginx) и желательно домен с A-записью.

Обновляем систему и устанавливаем необходимые зависимости:

# Обновление пакетной базы Ubuntu 24.04
sudo apt update && sudo apt upgrade -y

# Установка утилит (curl, ufw, nginx)
sudo apt install -y curl ufw nginx certbot python3-certbot-nginx

# Установка Docker Engine и плагина Compose
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker

# Проверка установленных версий
docker --version && docker compose version

Создаём рабочую директорию для MinIO:

# Папка для конфигурации Docker Compose
sudo mkdir -p /opt/minio

# Папка для хранения данных объектов (монтируется как том в контейнер)
sudo mkdir -p /opt/minio/data

cd /opt/minio

Важно: размещайте данные на отдельном разделе

Если ваш VDS имеет несколько дисков или вы можете подключить дополнительный том, монтируйте его отдельно и используйте именно его в качестве директории данных MinIO (/opt/minio/data). Это предотвращает ситуацию, когда объекты хранилища заполняют системный раздел и приводят к ошибке No space left on device во всей операционной системе.

4. Стек Docker Compose: MinIO с постоянным томом и переменными окружения

Создаём файл переменных окружения .env с учётными данными администратора. Никогда не используйте стандартные значения minioadmin в продакшен-среде:

# Генерация криптографически стойкого пароля (минимум 8 символов)
pwgen -s 32 1
# Или через openssl
openssl rand -base64 24

Создаём файл /opt/minio/.env:

# Учётные данные root-администратора MinIO
MINIO_ROOT_USER=minio_admin
MINIO_ROOT_PASSWORD=ВАШ_НАДЕЖНЫЙ_ПАРОЛЬ_32_СИМВОЛА

# Публичный URL для генерации presigned-ссылок на объекты
MINIO_SERVER_URL=https://s3.your-domain.ru
MINIO_BROWSER_REDIRECT_URL=https://console.your-domain.ru

Создаём основной файл /opt/minio/compose.yaml:

services:
  minio:
    image: quay.io/minio/minio:latest
    container_name: minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    env_file:
      - .env
    volumes:
      - /opt/minio/data:/data
    ports:
      - "127.0.0.1:9000:9000"   # S3 API — только localhost, проксируется через Nginx
      - "127.0.0.1:9001:9001"   # MinIO Console — только localhost
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

Почему порты привязаны к 127.0.0.1?

Директива 127.0.0.1:9000:9000 означает, что MinIO слушает порт 9000 только на петлевом интерфейсе — то есть снаружи сервера он недоступен напрямую. Весь внешний S3-трафик и обращения к Console должны проходить через Nginx с HTTPS. Это исключает возможность случайного открытия хранилища в сеть без шифрования и аутентификации.

Запускаем контейнер и проверяем статус:

cd /opt/minio

# Запуск MinIO в фоновом режиме
docker compose up -d

# Проверка статуса и healthcheck
docker compose ps
docker compose logs minio --tail 20

5. Настройка Nginx Reverse Proxy и HTTPS для MinIO Console и S3 API

MinIO требует двух отдельных поддоменов: один для S3 API (s3.your-domain.ru), другой — для веб-консоли администратора (console.your-domain.ru). Создайте A-записи в DNS для обоих поддоменов, направив их на IP-адрес вашего VDS.

Убедитесь, что A-записи уже распространились:

Создаём конфигурацию Nginx для S3 API (/etc/nginx/sites-available/minio-s3):

server {
    listen 80;
    server_name s3.your-domain.ru;

    # Certbot добавит блок SSL автоматически после получения сертификата
    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $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;

        # Критично для корректной загрузки больших файлов через S3 API
        client_max_body_size 0;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Конфигурация для Console (/etc/nginx/sites-available/minio-console):

server {
    listen 80;
    server_name console.your-domain.ru;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_set_header Host $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;

        # Поддержка WebSocket для интерактивного интерфейса Console
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Активируем конфигурации, получаем SSL-сертификаты через Certbot и перезапускаем Nginx:

# Создание симлинков в sites-enabled
sudo ln -s /etc/nginx/sites-available/minio-s3 /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/minio-console /etc/nginx/sites-enabled/

# Проверка синтаксиса конфигурации
sudo nginx -t

# Применение конфигурации
sudo systemctl reload nginx

# Получение SSL-сертификатов Let's Encrypt для обоих поддоменов
sudo certbot --nginx -d s3.your-domain.ru -d console.your-domain.ru --non-interactive --agree-tos -m admin@your-domain.ru --redirect

# Итоговая перезагрузка Nginx с применёнными HTTPS-блоками
sudo systemctl reload nginx

Проверяем корректность SSL-сертификатов:

6. Создание бакетов, пользователей и политик доступа через MinIO Console

Откройте в браузере https://console.your-domain.ru и войдите с учётными данными из файла .env (MINIO_ROOT_USER / MINIO_ROOT_PASSWORD). Вы попадёте в MinIO Console — полнофункциональный дашборд управления хранилищем.

Создание бакетов

Перейдите в раздел Buckets → Create Bucket. Рекомендуемые бакеты для типовой инфраструктуры:

  • backups — автоматические резервные копии баз данных и файлов сервера.
  • media — медиафайлы сайтов (изображения, видео, документы).
  • logs — архивные логи приложений для долгосрочного хранения.

Для бакета backups сразу включите Versioning (кнопка переключателя на странице бакета) — это позволит хранить несколько версий одного файла и восстанавливать данные при случайной перезаписи.

Создание сервисного пользователя

Никогда не используйте root-ключи MinIO в приложениях и скриптах. Создайте отдельного пользователя с ограниченными правами: Identity → Users → Create User. Назначьте политику доступа — например, встроенную readwrite для конкретного бакета или создайте собственную политику IAM.

Пример политики только на запись в бакет backups (для скрипта резервного копирования):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::backups",
        "arn:aws:s3:::backups/*"
      ]
    }
  ]
}

После создания пользователя перейдите в его карточку (Identity → Users → ваш пользователь → Service Accounts) и создайте пару Access Key / Secret Key — это те самые ключи для подключения S3-клиентов.

7. Интеграция с бэкапами: PostgreSQL, MySQL и файлы сайта в S3 через mc

mc (MinIO Client) — официальный CLI-инструмент для работы с MinIO и S3-совместимыми хранилищами. Устанавливаем его на сервер-источник резервных копий:

# Загрузка бинарного файла mc для Linux amd64
curl -sL https://dl.min.io/client/mc/release/linux-amd64/mc -o /usr/local/bin/mc
chmod +x /usr/local/bin/mc

# Настройка алиаса для вашего MinIO-сервера
mc alias set myminio https://s3.your-domain.ru ACCESS_KEY SECRET_KEY

# Проверка подключения
mc ls myminio

Скрипт автоматического резервного копирования PostgreSQL в MinIO (/opt/backup-pg-minio.sh):

#!/bin/bash
# Скрипт резервного копирования PostgreSQL в MinIO S3

DB_NAME="myapp_production"
DB_USER="postgres"
BACKUP_DIR="/tmp/pg-backups"
MINIO_BUCKET="myminio/backups/postgresql"
DATE=$(date +"%Y-%m-%d_%H-%M")
FILENAME="${DB_NAME}_${DATE}.sql.gz"

# Создаём временную директорию
mkdir -p "${BACKUP_DIR}"

# Дамп базы данных с сжатием gzip
pg_dump -U "${DB_USER}" "${DB_NAME}" | gzip > "${BACKUP_DIR}/${FILENAME}"

# Загрузка дампа в MinIO
mc cp "${BACKUP_DIR}/${FILENAME}" "${MINIO_BUCKET}/${FILENAME}"

# Удаление временного файла
rm -f "${BACKUP_DIR}/${FILENAME}"

echo "[$(date)] Резервная копия ${FILENAME} успешно загружена в ${MINIO_BUCKET}"
# Сделать скрипт исполняемым
chmod +x /opt/backup-pg-minio.sh

# Добавить задание в cron — ежедневно в 03:00
crontab -e
# Добавьте строку:
0 3 * * * /opt/backup-pg-minio.sh >> /var/log/pg-minio-backup.log 2>&1

Совет инженера: шифруйте бэкапы перед загрузкой

Для дополнительной защиты резервных копий баз данных рекомендуется шифровать дамп перед отправкой в хранилище. Замените строку gzip > на конвейер с gpg: pg_dump -U "${DB_USER}" "${DB_NAME}" | gzip | gpg --symmetric --cipher-algo AES256 -o "${BACKUP_DIR}/${FILENAME}.gpg". Ключ шифрования храните отдельно от самих бэкапов.

Статья «Автоматические бэкапы VDS в S3 с уведомлениями в Telegram» подробно рассматривает более продвинутые сценарии с ротацией и мониторингом.

8. Подключение S3-клиентов: rclone, AWS CLI и SDK в приложениях

Поскольку MinIO полностью совместим с AWS S3 API, для подключения подходят все стандартные инструменты экосистемы AWS.

Настройка rclone

rclone — самый универсальный инструмент для синхронизации и работы с облачными хранилищами. Конфигурация MinIO в файле ~/.config/rclone/rclone.conf:

[minio]
type = s3
provider = Minio
access_key_id = ВАШ_ACCESS_KEY
secret_access_key = ВАШ_SECRET_KEY
endpoint = https://s3.your-domain.ru
region = us-east-1
# Синхронизация локальной папки в бакет MinIO
rclone sync /var/www/html/uploads minio:media/uploads --progress

# Список объектов в бакете
rclone ls minio:backups

Настройка AWS CLI

# Установка AWS CLI
pip3 install awscli

# Настройка профиля для MinIO
aws configure --profile minio
# AWS Access Key ID: ВАШ_ACCESS_KEY
# AWS Secret Access Key: ВАШ_SECRET_KEY
# Default region: us-east-1
# Default output format: json

# Список бакетов
aws --profile minio --endpoint-url https://s3.your-domain.ru s3 ls

# Загрузка файла
aws --profile minio --endpoint-url https://s3.your-domain.ru \
    s3 cp /path/to/file.tar.gz s3://backups/file.tar.gz

Интеграция в PHP-приложения (Laravel / WordPress)

Для подключения MinIO к Laravel достаточно отредактировать config/filesystems.php:

'disks' => [
    's3' => [
        'driver' => 's3',
        'key'    => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
        'bucket' => env('AWS_BUCKET'),
        'url'    => env('AWS_URL'),
        'endpoint' => env('AWS_ENDPOINT'),           // https://s3.your-domain.ru
        'use_path_style_endpoint' => true,           // Обязательно для MinIO!
    ],
],

Параметр use_path_style_endpoint — обязателен

AWS SDK по умолчанию использует виртуальный хостинг бакетов (bucket-name.endpoint), что требует wildcard DNS-записей. MinIO в одно-узловом режиме работает со стандартной path-style адресацией (endpoint/bucket-name). Без явного указания 'use_path_style_endpoint' => true (PHP) или forcePathStyle: true (Node.js) SDK будет пытаться резолвить несуществующие поддомены и возвращать ошибки соединения.

9. Политики жизненного цикла: автоудаление старых бэкапов и версионирование

MinIO поддерживает политики жизненного цикла (ILM — Information Lifecycle Management) в полном соответствии со стандартом AWS S3. Политики позволяют автоматически удалять устаревшие объекты и управлять версиями без ручного вмешательства.

Устанавливаем правило: хранить объекты в бакете backups не более 30 дней через mc:

# Установка политики жизненного цикла через mc
mc ilm rule add myminio/backups \
  --expire-days 30

# Просмотр текущих правил жизненного цикла
mc ilm rule ls myminio/backups

Для версионированных бакетов можно настроить отдельные правила: хранить актуальную версию 90 дней, а устаревшие (non-current) версии — только 7 дней:

# Правило для версионированного бакета: удаление устаревших версий через 7 дней
mc ilm rule add myminio/backups \
  --noncurrent-expire-days 7

Политики жизненного цикла также можно настроить графически через MinIO Console: перейдите в Buckets → ваш бакет → Lifecycle → Add Lifecycle Rule.

Совет инженера: комбинируйте версионирование и жизненный цикл

Оптимальная стратегия для бакета с резервными копиями баз данных: включите версионирование (защита от случайной перезаписи) + жизненный цикл с noncurrent-expire-days: 7. Вы всегда сможете восстановить любую версию бэкапа за последние 7 дней, при этом хранилище не будет бесконечно расти. Актуальную (последнюю) версию каждого файла удалите правилом expire-days: 30.

Рекомендуемые VDS-провайдеры

Отказоустойчивые сервера с быстрыми NVMe и каналом до 1 Гбит/с

Выбор редакции
⚡

Timeweb Cloud

Оптимальная платформа для MinIO-хранилища: быстрые NVMe-диски с защитой от деградации IOPS, гибкое расширение объёма без остановки сервера, дата-центры в Москве и Санкт-Петербурге с прямым подключением к MSK-IX.

Конфигурация
от 2 vCPU / 2 GB RAM / 40–500 GB NVMe
Максимальный объём
🔷

Selectel

Корпоративная инфраструктура Tier III с возможностью подключения дополнительных NVMe-томов до 4 ТБ, встроенной защитой от DDoS и гарантированным SLA 99.98% — идеально для производственных архивов и медиабиблиотек.

Конфигурация
от 2 vCPU / 4 GB RAM / 80–4000 GB NVMe
Быстрый старт
🟠

Beget

Простой запуск Ubuntu 24.04 LTS за 60 секунд, встроенные автоматические ежедневные снимки сервера и техническая поддержка 24/7 — хорошее решение для тестовых стендов и небольших проектов.

Конфигурация
от 1 vCPU / 2 GB RAM / 30 GB NVMe

10. Резюме: чек-лист готового MinIO-сервера к эксплуатации

Собственное S3-хранилище на базе MinIO даёт полный контроль над данными, предсказуемую стоимость хранения и стопроцентную совместимость с экосистемой AWS S3-инструментов. Одно-узловая конфигурация в Docker Compose — оптимальный старт для большинства инфраструктур малого и среднего масштаба.

Смежные статьи для расширения возможностей хранилища:

Разверните MinIO на надёжном VDS с быстрым NVMe

Производительность MinIO напрямую зависит от скорости дискового ввода-вывода. Выберите VDS с NVMe-накопителем, достаточным объёмом под ваши данные и стабильным каналом — и ваше хранилище будет работать быстрее любого публичного облака.

Выбрать VDS с NVMe для MinIO в Timeweb Cloud

Итоговый чек-лист готовности MinIO к эксплуатации:

  • Контейнер minio запущен в статусе Up (healthy) — проверено через docker compose ps.
  • Порты 9000 и 9001 привязаны к 127.0.0.1 и не доступны напрямую снаружи.
  • Nginx настроен для s3.your-domain.ru и console.your-domain.ru с действующими SSL-сертификатами.
  • Стандартные учётные данные (minioadmin) не используются — пароль root не менее 12 символов.
  • Созданы отдельные сервисные пользователи с минимально необходимыми политиками IAM для каждого приложения.
  • Тестовая загрузка файла через mc cp или AWS CLI завершилась успешно.
  • Для бакета с бэкапами включено версионирование и настроена политика жизненного цикла.
  • UFW настроен: порты 9000 и 9001 закрыты для внешних адресов, открыты 80/443 для Nginx.

Вопросы и ответы (FAQ)

Популярные вопросы вебмастеров и сисадминов по данной теме

Сколько оперативной памяти нужно для MinIO в одно-узловом режиме?
Для одно-узлового (Single-Node Single-Drive, SNSD) режима MinIO рекомендует минимум 2 ГБ RAM на сам процесс хранилища. При активном S3-трафике (загрузка и скачивание файлов более 100 МБ/с) потребление может достигать 1–1.5 ГБ. Для продакшен-сервера с нагрузкой оптимально иметь 4 ГБ RAM: 2 ГБ под MinIO, остальное — под ОС, Nginx и системные кеши файловой системы. При объёмах хранилища свыше 50 ТБ MinIO рекомендует переходить на распределённый режим (Multi-Node Multi-Drive) с минимум 4 узлами.
Можно ли подключить MinIO как стандартное S3-хранилище к WordPress, Laravel или Nextcloud?
Да, MinIO полностью совместим с AWS S3 API, поэтому любой плагин или библиотека, работающие с Amazon S3, автоматически заработают с MinIO. Для WordPress достаточно настроить плагин WP Offload Media или S3-Uploads, указав в параметрах: endpoint — ваш домен MinIO (например, https://s3.example.ru), Access Key и Secret Key от созданного пользователя MinIO, а также имя бакета. Для Laravel используется стандартный Storage::disk('s3') с параметром url и endpoint в config/filesystems.php. Nextcloud поддерживает MinIO через встроенный тип хранилища «Amazon S3-совместимый» в настройках External Storage.
Как защитить MinIO от несанкционированного доступа из интернета?
Рекомендуется многоуровневая защита. Во-первых, обязательно смените стандартные учётные данные (minioadmin/minioadmin) — MinIO не запустится с ними в продакшен-режиме, если явно не выставить флаг MINIO_VOLUMES. Во-вторых, создайте отдельных сервисных пользователей с политиками минимальных прав (только чтение или только запись в конкретный бакет) вместо использования root-ключей в приложениях. В-третьих, закройте порт 9000 (S3 API) и 9001 (Console) в UFW для внешних адресов — доступ должен идти только через Nginx по HTTPS. Порт 9001 (Console) вообще можно ограничить только вашим IP через директиву allow в Nginx.

Читайте также в блоге SysKit

Смежные руководства и полезные технические статьи