bolt Valebyte VPS от $4/мес — NVMe, запуск за 60 секунд.

Получить VPS arrow_forward
eco Начальный Туториал

Garage и SeaweedFS: своё S3-хранилище на dedicated

calendar_month Sep 24, 2026 schedule 19 мин. чтения visibility 21 просмотров
Garage и SeaweedFS: своё S3-хранилище на dedicated
info

Нужен сервер для этого гайда? Мы предлагаем выделенные серверы и VPS в 50+ странах с мгновенной настройкой.

Нужен сервер для этого гайда?

Разверните VPS или выделенный сервер за минуты.

Garage и SeaweedFS: как развернуть своё S3-хранилище на dedicated-сервере

TL;DR

В этом руководстве мы подготовим dedicated-сервер и запустим на нём два совместимых с S3 хранилища: Garage для компактной отказоустойчивой инсталляции и SeaweedFS для сценариев с большим количеством объектов и масштабированием по узлам. Доступ к обоим сервисам будет защищён HTTPS, а конфигурации и данные будут подготовлены к резервному копированию.

  • Garage подойдёт для простого приватного S3, резервных копий и приложений.
  • SeaweedFS удобнее при большом количестве файлов, высокой нагрузке и дальнейшем горизонтальном масштабировании.
  • Для тестовой единственной ноды достаточно 4 vCPU, 8 ГБ RAM и NVMe от 500 ГБ.
  • Для production лучше использовать ECC-память, RAID или ZFS, отдельные диски под данные и резервную копию вне сервера.
  • API S3 публикуется через Caddy с автоматическими сертификатами Let’s Encrypt.
  • Резервировать нужно не только конфиги, но и данные, ключи доступа, layout Garage и метаданные SeaweedFS.

1. Что мы настраиваем и зачем

Схема: 1. Что мы настраиваем и зачем
Схема: 1. Что мы настраиваем и зачем

S3 — это не конкретный сервер, а протокол объектного хранения: приложения обращаются к bucket, загружают объекты и получают их по ключам. Большинство современных клиентов, SDK и инструментов резервного копирования умеют работать с S3-compatible API. Поэтому вместо публичного облака можно запустить собственное хранилище на dedicated-сервере.

В статье рассматриваются два проекта. Garage — компактное распределённое S3-хранилище, ориентированное на простую эксплуатацию и небольшие кластеры. SeaweedFS — более универсальная распределённая файловая система с S3-шлюзом, master-сервисом, volume-серверами и filer.

Обычно не требуется использовать Garage и SeaweedFS одновременно для одних и тех же данных. Выбирайте один основной backend:

  • Garage — когда нужен понятный приватный S3, минимальное количество компонентов и несколько узлов в будущем.
  • SeaweedFS — когда ожидаются миллионы или миллиарды небольших объектов, высокая скорость записи и развитие кластера.
  • Оба на одном dedicated — только для лаборатории, миграции, сравнения или размещения разных независимых задач.

Что будет в результате

После выполнения инструкций на сервере будут работать два независимых S3 endpoint:

  • https://garage.example.com — S3 API Garage;
  • https://seaweed.example.com — S3 API SeaweedFS;
  • https://garage-admin.example.com — административный интерфейс Garage, если он потребуется;
  • локальные каталоги с объектами на отдельном диске;
  • Docker Compose-файлы, systemd-управление, firewall и схема резервного копирования.

В примерах используются домены garage.example.com и seaweed.example.com. Замените их на собственные домены. DNS-записи должны указывать на публичный IPv4-адрес сервера, а для IPv6 нужно отдельно проверить, что firewall и маршрутизация настроены корректно.

Self-hosted или managed S3

Managed S3 снимает с владельца сервера задачи эксплуатации: резервирование, замену дисков, мониторинг и расширение. Это хороший выбор, если важнее скорость запуска, чем контроль над данными. Однако цена хранения, исходящего трафика и большого количества операций может существенно вырасти.

Self-hosted S3 позволяет контролировать диски, ключи, локацию и стоимость хранения. Обратная сторона — ответственность за резервные копии, отказоустойчивость и обновления полностью лежит на администраторе. Один сервер без внешней копии не является надёжным хранилищем, даже если само ПО поддерживает репликацию.

Критерий Managed S3 Garage или SeaweedFS
Запуск Очень быстрый Требуется настройка сервера
Контроль над данными Ограниченный политикой провайдера Полный контроль
Масштабирование Обычно автоматическое Нужно планировать самостоятельно
Ответственность за бэкапы Разделяется с провайдером На владельце инфраструктуры

2. Какой VPS-конфиг нужен под эту задачу

Схема: 2. Какой VPS-конфиг нужен под эту задачу
Схема: 2. Какой VPS-конфиг нужен под эту задачу

Требования зависят от объёма данных, размера объектов и количества запросов. S3-хранилище в основном упирается в дисковую подсистему и сеть, а не в частоту CPU. Для большого числа небольших файлов SeaweedFS потребляет больше RAM на метаданные и фоновые операции, чем простой Garage-кластер.

Сценарий CPU RAM Диск Сеть
Лаборатория и тесты 2 vCPU 4 ГБ 100 ГБ SSD 100 Мбит/с
Небольшой production 4 vCPU 8–16 ГБ 500 ГБ–2 ТБ NVMe 1 Гбит/с
Много объектов и активный API 8–16 vCPU 32–64 ГБ 2–8 ТБ NVMe или отдельный storage 1–10 Гбит/с

Практический стартовый вариант

Для одной production-ноды, на которой одновременно запускаются Garage, SeaweedFS и Caddy, разумная стартовая конфигурация — 8 vCPU, 16 ГБ RAM, 1 ТБ NVMe, публичный IPv4 и порт 1 Гбит/с. Если планируется использовать только один backend, можно начать с 4 vCPU и 8 ГБ RAM.

В качестве одного из вариантов можно подобрать dedicated с такими характеристиками. Конкретный тариф не является частью архитектуры: важны производительность дисков, доступ к резервным копиям, лимит трафика и возможность добавить второй диск.

Почему dedicated может быть лучше VPS

Dedicated предпочтителен, если данные занимают сотни гигабайт или терабайты, требуется предсказуемая I/O-производительность и планируется непрерывная запись. На VPS скорость дисков может зависеть от соседей, а гарантированный объём диска иногда ограничен тарифом.

Для небольшого bucket, резервных копий и development VPS вполне достаточно. Dedicated становится оправданным при высоком количестве операций, больших последовательных загрузках, требованиях к ECC-памяти, RAID/ZFS или необходимости физически контролировать диски.

Диски и файловая система

Для объектного storage используйте локальный NVMe или enterprise SSD. Не размещайте данные на системном разделе без отдельного лимита: заполнение root filesystem может остановить SSH, Docker и системные службы. Практичная схема — отдельный том, смонтированный в /srv/object-storage.

Для одной ноды подойдут XFS или ext4. ZFS полезна при достаточном объёме RAM и необходимости snapshot, checksumming и управления пулом, но она добавляет операционную сложность. RAID защищает от отказа диска, но не заменяет резервную копию.

Локация сервера

Выбирайте дата-центр ближе к приложениям и пользователям. Это уменьшает задержку при загрузке объектов и снижает время работы multipart upload. Если хранилище используется только для бэкапов, важнее стабильный исходящий трафик и возможность передавать данные в другую географическую локацию.

Для персональных данных также учитывайте требования законодательства, договоры с клиентами и физическую юрисдикцию дата-центра. Географическая близость сама по себе не гарантирует соответствие требованиям обработки данных.

3. Подготовка сервера

Схема: 3. Подготовка сервера
Схема: 3. Подготовка сервера

Ниже предполагается Debian 12 или Ubuntu Server 24.04 LTS с чистой установкой и пользователем, имеющим временный доступ через SSH. Все команды выполняются от пользователя с sudo. В примерах используется имя storage.

Обновление системы и базовые пакеты

Сначала обновите индекс пакетов, установите исправления безопасности и инструменты, которые понадобятся для Docker, диагностики и резервного копирования.

sudo apt update && sudo apt full-upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release jq vim htop ncdu \
  unzip rsync restic ufw fail2ban dnsutils smartmontools

Создание отдельного администратора

Не используйте root для повседневной работы. Создайте пользователя, добавьте его в sudo и перенесите публичный SSH-ключ. Команду с ключом замените на собственный ключ.

sudo adduser storage
sudo usermod -aG sudo storage
sudo install -d -m 700 -o storage -g storage /home/storage/.ssh
sudo sh -c 'echo "ssh-ed25519 AAAA_REPLACE_WITH_YOUR_PUBLIC_KEY admin@workstation" > /home/storage/.ssh/authorized_keys'
sudo chown storage:storage /home/storage/.ssh/authorized_keys
sudo chmod 600 /home/storage/.ssh/authorized_keys

Откройте новую SSH-сессию и убедитесь, что вход работает. Только после проверки можно запретить парольную аутентификацию и root login.

ssh storage@SERVER_IP
sudo install -d -m 0755 /etc/ssh/sshd_config.d
sudo tee /etc/ssh/sshd_config.d/ hardening.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
EOF
sudo sshd -t
sudo systemctl reload ssh

В последней команде в реальном терминале имя файла должно быть без пробела: /etc/ssh/sshd_config.d/hardening.conf. Исправленный вариант:

sudo tee /etc/ssh/sshd_config.d/hardening.conf > /dev/null <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
EOF
sudo sshd -t
sudo systemctl reload ssh

Firewall

До включения UFW разрешите SSH на нестандартном порту, если вы его меняли, а также HTTP и HTTPS для ACME-проверки и S3 API. Административные порты Garage и SeaweedFS наружу не публикуем.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Fail2ban и каталог данных

Fail2ban будет временно блокировать адреса с большим количеством неудачных SSH-входов. Он не заменяет ключи, firewall и обновления, но снижает шум от автоматических сканеров.

sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban --no-pager
sudo mkdir -p /srv/object-storage/{garage,seaweedfs,caddy,data,backup}
sudo chown -R storage:storage /srv/object-storage

Проверьте диск до развёртывания:

df -hT
lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT,MODEL
sudo smartctl -a /dev/nvme0n1 | less

Если для данных используется отдельный диск, сначала создайте файловую систему, добавьте UUID в /etc/fstab, смонтируйте её в /srv/object-storage и только затем запускайте контейнеры. Не форматируйте диск, пока не проверили его устройство через lsblk.

4. Установка ПО

Схема: 4. Установка ПО
Схема: 4. Установка ПО

Для изоляции компонентов используем Docker Engine и Compose plugin. На production лучше фиксировать версии образов, а не использовать тег latest. В примерах приведены версии, актуальные для практического развёртывания в 2026 году; перед обновлением проверьте release notes и совместимость формата данных.

Установка Docker Engine из официального репозитория

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Добавьте репозиторий Docker для Ubuntu 24.04. Для Debian замените путь ubuntu на debian и codename на bookworm.

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker "$USER"

Перезапустите SSH-сессию или выполните newgrp docker, после чего проверьте установку:

docker run --rm hello-world
docker compose version
sudo systemctl enable --now docker

Версии образов

В примере используются Garage 2.1.0 и SeaweedFS 3.99. Если к моменту установки вышли более новые стабильные версии, сначала протестируйте их на копии данных. Нельзя бездумно менять образ с major-версией: у систем хранения миграция метаданных может быть необратимой.

Создайте рабочий каталог и файл Compose:

mkdir -p /srv/object-storage/app
cd /srv/object-storage/app
touch .env docker-compose.yml garage.toml s3.json Caddyfile
chmod 600 .env

Создание секретов

Секреты не должны храниться в публичном Git-репозитории, Dockerfile или командной истории. Сгенерируйте административный токен, access key и secret key через системный генератор случайных данных.

GARAGE_ADMIN_TOKEN=$(openssl rand -hex 32)
S3_ACCESS_KEY=$(openssl rand -hex 16)
S3_SECRET_KEY=$(openssl rand -hex 32)
sudo tee /srv/object-storage/app/.env > /dev/null <<EOF
GARAGE_ADMIN_TOKEN=${GARAGE_ADMIN_TOKEN}
S3_ACCESS_KEY=${S3_ACCESS_KEY}
S3_SECRET_KEY=${S3_SECRET_KEY}
EOF
sudo chmod 600 /srv/object-storage/app/.env

Сохраните эти значения в менеджере паролей. Потеря access key не уничтожит данные, но потребует создать новый ключ. Потеря административных секретов усложнит восстановление доступа.

5. Конфигурация Garage и SeaweedFS

Схема: 5. Конфигурация Garage и SeaweedFS
Схема: 5. Конфигурация Garage и SeaweedFS

Конфигурация Garage

Garage использует конфигурационный файл TOML и отдельный каталог метаданных. Для одной ноды зададим локальный RPC, S3 API на порту 3900 и web endpoint на порту 3902. В production-кластере RPC-порт должен быть доступен только между узлами, а не из интернета.

cat > /srv/object-storage/app/garage.toml <<'EOF'
metadata_dir = "/var/lib/garage/meta"
data_dir = "/var/lib/garage/data"
db_engine = "lmdb"

replication_factor = 1
consistency_mode = "consistent"

[rpc]
bind_addr = "[::]:3901"
secret_file = "/run/secrets/garage_rpc_secret"

[s3_api]
s3_region = "garage"
api_bind_addr = "[::]:3900"
root_domain = ".s3.garage.local"

[admin]
api_bind_addr = "[::]:3903"
admin_token = "CHANGE_IN_ENV_OR_SECRET"

[web]
bind_addr = "[::]:3902"
root_domain = ".web.garage.local"
index = "index.html"
EOF

Для production не оставляйте строку с демонстрационным токеном. В зависимости от версии Garage синтаксис секции admin может отличаться, поэтому перед запуском сверяйте пример конфигурации из release notes. Ниже используется более безопасная схема: административный API не публикуется наружу, а Docker-сервис получает токен через переменную окружения только для вспомогательных операций.

Создайте RPC-секрет и структуру каталогов:

openssl rand -hex 32 > /srv/object-storage/app/garage-rpc-secret
chmod 600 /srv/object-storage/app/garage-rpc-secret
mkdir -p /srv/object-storage/data/garage/{meta,data}
chown -R 1000:1000 /srv/object-storage/data/garage

Конфигурация SeaweedFS

На одной машине SeaweedFS можно запустить в режиме master, volume, filer и S3 gateway. Такая схема удобна для теста и небольшого production, но не даёт отказоустойчивости: отказ сервера означает недоступность всего хранилища.

cat > /srv/object-storage/app/s3.json <<'EOF'
{
  "identities": [
    {
      "name": "admin",
      "credentials": [
        {
          "accessKey": "CHANGE_ACCESS_KEY",
          "secretKey": "CHANGE_SECRET_KEY"
        }
      ],
      "actions": ["Read", "Write", "List", "Tagging"]
    }
  ]
}
EOF
chmod 600 /srv/object-storage/app/s3.json

Подставьте значения из .env вместо CHANGE_ACCESS_KEY и CHANGE_SECRET_KEY. Автоматическая подстановка без отображения секрета в аргументах процесса:

set -a
. /srv/object-storage/app/.env
set +a
sed -i "s/CHANGE_ACCESS_KEY/${S3_ACCESS_KEY}/; s/CHANGE_SECRET_KEY/${S3_SECRET_KEY}/" \
  /srv/object-storage/app/s3.json

Docker Compose

Создайте единый Compose-файл. Сервисы Garage и SeaweedFS используют разные порты и каталоги. Для SeaweedFS применён образ chrislusf/seaweedfs:3.99. Если официальный тег изменился, замените его на проверенный стабильный релиз.

services:
  garage:
    image: dxflrs/garage:v2.1.0
    container_name: garage
    restart: unless-stopped
    command: ["/garage", "-c", "/etc/garage.toml", "server"]
    volumes:
      - /srv/object-storage/app/garage.toml:/etc/garage.toml:ro
      - /srv/object-storage/app/garage-rpc-secret:/run/secrets/garage_rpc_secret:ro
      - /srv/object-storage/data/garage/meta:/var/lib/garage/meta
      - /srv/object-storage/data/garage/data:/var/lib/garage/data
    ports:
      - "127.0.0.1:3900:3900"
      - "127.0.0.1:3902:3902"
      - "127.0.0.1:3903:3903"
      - "127.0.0.1:3901:3901"
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:3903/health"]
      interval: 30s
      timeout: 5s
      retries: 5

  seaweed-master:
    image: chrislusf/seaweedfs:3.99
    container_name: seaweed-master
    restart: unless-stopped
    command: master -ip=seaweed-master -mdir=/data
    volumes:
      - /srv/object-storage/data/seaweedfs/master:/data
    expose:
      - "9333"
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "-", "http://127.0.0.1:9333/cluster/status"]
      interval: 30s
      timeout: 5s
      retries: 5

  seaweed-volume:
    image: chrislusfs/seaweedfs:3.99
    container_name: seaweed-volume
    restart: unless-stopped
    command: volume -mserver=seaweed-master:9333 -dir=/data -port=8080
    depends_on:
      seaweed-master:
        condition: service_healthy
    volumes:
      - /srv/object-storage/data/seaweedfs/volume:/data
    expose:
      - "8080"

  seaweed-filer:
    image: chrislusfs/seaweedfs:3.99
    container_name: seaweed-filer
    restart: unless-stopped
    command: filer -master=seaweed-master:9333 -ip=seaweed-filer
    depends_on:
      seaweed-master:
        condition: service_healthy
      seaweed-volume:
        condition: service_started
    volumes:
      - /srv/object-storage/data/seaweedfs/filer:/data
    expose:
      - "8888"

  seaweed-s3:
    image: chrislusfs/seaweedfs:3.99
    container_name: seaweed-s3
    restart: unless-stopped
    command: s3 -filer=seaweed-filer:8888 -port=8333 -config=/etc/seaweed/s3.json
    depends_on:
      - seaweed-filer
    volumes:
      - /srv/object-storage/app/s3.json:/etc/seaweed/s3.json:ro
    ports:
      - "127.0.0.1:8333:8333"

  caddy:
    image: caddy:2.9
    container_name: caddy
    restart: unless-stopped
    depends_on:
      - garage
      - seaweed-s3
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /srv/object-storage/app/Caddyfile:/etc/caddy/Caddyfile:ro
      - /srv/object-storage/data/caddy/data:/data
      - /srv/object-storage/data/caddy/config:/config

Проверьте синтаксис и запустите сервисы:

cd /srv/object-storage/app
docker compose --env-file .env config
docker compose --env-file .env up -d
docker compose ps
docker compose logs --tail=100 garage
docker compose logs --tail=100 seaweed-master seaweed-s3

Инициализация layout Garage

После запуска Garage необходимо получить идентификатор узла и назначить ему capacity. Команды зависят от версии CLI и могут выполняться внутри контейнера.

cd /srv/object-storage/app
docker compose exec garage garage status
docker compose exec garage garage layout assign \
  -z dc1 -c 800G NODE_ID
docker compose exec garage garage layout show
docker compose exec garage garage layout apply --version 1

Вместо NODE_ID подставьте идентификатор из вывода garage status. Значение 800G должно быть меньше свободного места на разделе. Для кластера из трёх узлов используйте разные зоны, например dc1, dc2, dc3, и replication factor 3.

Создание bucket и ключа также зависит от версии CLI. Общая последовательность выглядит так:

docker compose exec garage garage bucket create backups
docker compose exec garage garage key create app-backups
docker compose exec garage garage bucket allow \
  --read --write --owner backups --key app-backups
docker compose exec garage garage bucket list
docker compose exec garage garage key list

Не выдавайте приложениям owner-права без необходимости. Для приложения создавайте отдельный ключ и ограничивайте доступ конкретными bucket. Административный ключ храните отдельно от ключей автоматических задач.

6. TLS, DNS и проверка работы

Схема: 6. TLS, DNS и проверка работы
Схема: 6. TLS, DNS и проверка работы

DNS

Создайте A-записи:

  • garage.example.com → IPv4 сервера;
  • seaweed.example.com → IPv4 сервера.

Если используется IPv6, добавьте AAAA-записи только после проверки доступности сервера по IPv6. Ошибочная AAAA-запись может привести к тому, что часть клиентов будет подключаться к недоступному адресу.

dig +short garage.example.com
dig +short seaweed.example.com

Caddy и HTTPS

Caddy автоматически получает сертификаты Let’s Encrypt, если домен уже указывает на сервер и порты 80/443 доступны из интернета. Внутрь Garage и SeaweedFS передаётся обычный HTTP-трафик через локальную Docker-сеть; наружу открывается только HTTPS.

cat > /srv/object-storage/app/Caddyfile <<'EOF'
garage.example.com {
    reverse_proxy host.docker.internal:3900
    request_body {
        max_size 50GB
    }
}

seaweed.example.com {
    reverse_proxy seaweed-s3:8333
    request_body {
        max_size 50GB
    }
}
EOF

На Linux контейнер Caddy не всегда может обратиться к host.docker.internal без специальной настройки. Надёжнее добавить Garage в общую Docker-сеть и проксировать по имени сервиса. Для этого замените Caddyfile и Compose-файл так, чтобы Caddy и Garage находились в одной сети:

networks:
  storage_net:

services:
  garage:
    networks:
      - storage_net

  seaweed-s3:
    networks:
      - storage_net

  caddy:
    networks:
      - storage_net

После добавления сети используйте имена контейнеров:

cat > /srv/object-storage/app/Caddyfile <<'EOF'
garage.example.com {
    reverse_proxy garage:3900
    request_body {
        max_size 50GB
    }
}

seaweed.example.com {
    reverse_proxy seaweed-s3:8333
    request_body {
        max_size 50GB
    }
}
EOF
cd /srv/object-storage/app
docker compose up -d
docker compose logs --tail=100 caddy

Параметр max_size не ограничивает реальный размер bucket, а защищает reverse proxy от случайно огромного запроса. Для файлов больше 50 ГБ используйте multipart upload или увеличьте лимит с учётом диска и таймаутов.

Проверка HTTP и S3

curl -I https://garage.example.com
curl -I https://seaweed.example.com
curl -vk https://garage.example.com 2>&1 | grep -E "subject:|issuer:|HTTP/"
docker compose ps
docker stats --no-stream

Для S3-клиента установите AWS CLI v2 из официального архива AWS или используйте S3-compatible клиент. Пример с AWS CLI:

export AWS_ACCESS_KEY_ID='REPLACE_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='REPLACE_SECRET_KEY'
export AWS_DEFAULT_REGION='garage'

aws --endpoint-url https://garage.example.com s3 ls
aws --endpoint-url https://garage.example.com s3 mb s3://test-bucket
printf 's3 smoke test\n' > /tmp/test.txt
aws --endpoint-url https://garage.example.com s3 cp /tmp/test.txt s3://test-bucket/test.txt
aws --endpoint-url https://garage.example.com s3 cp s3://test-bucket/test.txt -
aws --endpoint-url https://garage.example.com s3 rb s3://test-bucket --force

Для SeaweedFS замените endpoint:

aws --endpoint-url https://seaweed.example.com s3 mb s3://seaweed-test
aws --endpoint-url https://seaweed.example.com s3 cp /tmp/test.txt s3://seaweed-test/test.txt
aws --endpoint-url https://seaweed.example.com s3 ls s3://seaweed-test/

Если HTTPS ещё не настроен, временно проверяйте локальный endpoint через http://127.0.0.1:8333. Не оставляйте локальный тестовый endpoint опубликованным на публичном интерфейсе и не отключайте проверку TLS в production-клиентах.

7. Бэкапы и обслуживание

Схема: 7. Бэкапы и обслуживание
Схема: 7. Бэкапы и обслуживание

Что нужно резервировать

У объектного хранилища есть несколько типов данных:

  • объекты пользователей в каталогах Garage и SeaweedFS;
  • метаданные Garage, его layout и конфигурация;
  • master data и filer metadata SeaweedFS;
  • Docker Compose, Caddyfile, JSON-конфигурация и секреты;
  • список bucket, пользователей, access key и политик доступа.

Копирование только Docker Compose не восстановит файлы. Копирование только volume-данных без конфигураций усложнит запуск. Перед резервированием составьте документ с версиями образов, точками монтирования и командами восстановления.

Restic на отдельный сервер

Не храните единственную копию бэкапа на том же диске. Хороший минимальный вариант — отдельный сервер по SFTP, удалённый S3 с object lock или другой дата-центр. Ниже пример restic через SFTP. На backup-сервере должен существовать пользователь restic и каталог репозитория.

Создайте файл с секретами только для root:

sudo tee /root/.restic-env > /dev/null <<'EOF'
export RESTIC_REPOSITORY='sftp:[email protected]:/srv/restic/object-storage'
export RESTIC_PASSWORD='CHANGE_TO_LONG_RANDOM_PASSWORD'
export RESTIC_SFTP_COMMAND='ssh -i /root/.ssh/restic_backup_ed25519 -o StrictHostKeyChecking=yes'
EOF
sudo chmod 600 /root/.restic-env

Инициализируйте репозиторий один раз и протестируйте соединение:

sudo bash -c 'source /root/.restic-env && restic init'
sudo bash -c 'source /root/.restic-env && restic snapshots'

Скрипт бэкапа

Для согласованной копии остановим контейнеры на короткое окно обслуживания. Это проще и безопаснее для одной ноды, чем копирование активно изменяющихся volume-файлов. Для больших хранилищ лучше использовать встроенную репликацию, snapshot файловой системы или отдельный backup-кластер.

sudo tee /usr/local/sbin/object-storage-backup > /dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail

source /root/.restic-env
APP=/srv/object-storage/app
DATA=/srv/object-storage/data
STAMP=$(date +%F-%H%M)
LOG=/var/log/object-storage-backup.log

exec > >(tee -a "$LOG") 2>&1

echo "[$(date -Is)] backup started"
cd "$APP"
docker compose stop garage seaweed-master seaweed-volume seaweed-filer seaweed-s3

restic backup \
  "$APP/garage.toml" \
  "$APP/garage-rpc-secret" \
  "$APP/s3.json" \
  "$APP/Caddyfile" \
  "$APP/docker-compose.yml" \
  "$APP/.env" \
  "$DATA/garage" \
  "$DATA/seaweedfs" \
  --tag object-storage \
  --tag "$STAMP"

docker compose start garage seaweed-master seaweed-volume seaweed-filer seaweed-s3
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check
echo "[$(date -Is)] backup completed"
EOF
sudo chmod 700 /usr/local/sbin/object-storage-backup

Файл .env содержит секреты, поэтому он включён в резервную копию только при условии, что доступ к удалённому репозиторию строго ограничен. Если политика запрещает хранить секреты в бэкапе, исключите его и сохраните секреты в отдельном зашифрованном менеджере.

Cron и проверка восстановления

sudo crontab -e

Добавьте запуск каждую ночь в 03:30:

30 3   * /usr/local/sbin/object-storage-backup

Раз в месяц проверяйте не только наличие snapshot, но и восстановление отдельного объекта в временный каталог:

sudo bash -c 'source /root/.restic-env && restic snapshots --tag object-storage'
sudo mkdir -p /srv/restore-test
sudo bash -c 'source /root/.restic-env && restic restore latest --target /srv/restore-test --tag object-storage'
sudo find /srv/restore-test -maxdepth 4 -type f | head

Бэкап, который ни разу не восстанавливали, является предположением, а не доказательством восстановления. Проверяйте контрольные файлы, размер каталогов, права доступа и возможность запустить контейнеры с восстановленной конфигурацией.

Обновления

Перед обновлением зафиксируйте текущие образы:

cd /srv/object-storage/app
docker compose images
docker image ls
sudo bash -c 'source /root/.restic-env && restic backup /srv/object-storage/app --tag pre-upgrade'

Для одной ноды используйте maintenance window: остановите запись, сделайте бэкап, скачайте новый образ и перезапустите сервисы.

docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=200 garage seaweed-master seaweed-s3

Rolling update возможен только в кластере из нескольких узлов с репликацией и совместимым протоколом. Сначала обновляют один узел, проверяют healthcheck и операции чтения/записи, затем переходят к следующему. Не обновляйте все узлы одновременно.

Мониторинг

Минимально контролируйте свободное место, inode, RAM, load average, SMART и ошибки контейнеров:

df -h /srv/object-storage
df -ih /srv/object-storage
free -h
uptime
docker compose ps
docker compose logs --since=15m garage seaweed-s3
sudo journalctl -u docker --since "15 minutes ago"

Настройте уведомление при заполнении диска выше 80–85 процентов. При 95 процентах сервисы могут начать возвращать ошибки записи, а фоновые операции восстановления — завершаться аварийно. Планируйте расширение заранее.

8. Troubleshooting и FAQ

Почему Caddy возвращает 502 Bad Gateway?

Сначала проверьте состояние контейнеров командой docker compose ps и журналы docker compose logs caddy garage seaweed-s3. Если Caddy не видит имя сервиса, убедитесь, что оба контейнера подключены к одной Docker-сети. Если используется host.docker.internal, замените его на имя сервиса, например garage:3900. Также проверьте локальный endpoint через curl http://127.0.0.1:3900 или сетевой запрос из контейнера Caddy.

Сертификат Let’s Encrypt не выпускается. Что проверить?

Проверьте A-записи командой dig, доступность портов 80 и 443 с внешней сети и отсутствие другого reverse proxy. Для домена не должен быть включён неверный AAAA-запись. Посмотрите docker compose logs caddy. Если DNS только что изменён, дождитесь обновления TTL. Не запускайте много повторных запросов при ошибке: Let’s Encrypt применяет rate limits.

Ошибка AccessDenied при загрузке в S3

Проверьте, к какому endpoint и bucket подключён клиент, а также значения переменных AWS_ACCESS_KEY_ID и AWS_SECRET_ACCESS_KEY. В Garage ключ должен иметь разрешения на конкретный bucket. В SeaweedFS проверьте формат s3.json и совпадение ключей. Для диагностики выполните aws s3 ls без multipart и проверьте, что системное время синхронизировано через NTP.

Запись завершается ошибкой No space left on device

Проверьте не только свободные гигабайты через df -h, но и inode через df -i. Миллионы маленьких файлов могут исчерпать inode раньше места. Удалите старые Docker-образы только после проверки, что они не нужны для rollback: docker system df. Не удаляйте вручную файлы внутри каталогов Garage или SeaweedFS — это может повредить метаданные и привести к потере объектов.

Какой VPS-конфиг минимально подойдёт?

Для тестирования достаточно 2 vCPU, 4 ГБ RAM и 100 ГБ SSD. Для небольшого production с одним backend разумный минимум — 4 vCPU, 8 ГБ RAM и 500 ГБ NVMe. Если одновременно запускаются Garage, SeaweedFS, Caddy и резервное копирование, лучше взять 8 ГБ RAM минимум, а для активной нагрузки — 16 ГБ. Оставляйте 20–30 процентов диска свободными для временных файлов и восстановления.

Что выбрать — VPS или dedicated для этой задачи?

VPS подходит для development, небольших bucket, резервных копий и нагрузки с предсказуемым I/O. Dedicated лучше выбрать при объёме от нескольких терабайт, высоком количестве операций, необходимости ECC, RAID/ZFS или гарантированной производительности дисков. В обоих случаях внешний бэкап обязателен. Dedicated с одним диском без копии не защищает от аппаратного отказа, ошибки администратора или шифровальщика.

Можно ли запускать Garage и SeaweedFS на одной ноде в production?

Технически можно, но это создаёт конкуренцию за RAM, CPU и дисковый I/O. Такая схема допустима для миграции, сравнения или независимых малых задач. Для постоянной эксплуатации выберите один backend и отключите второй. Если нужны разные классы хранения, лучше разделить сервисы по дискам или серверам и задать отдельные лимиты ресурсов Docker.

Как сделать хранилище отказоустойчивым?

Одна нода не является отказоустойчивой. Для Garage используйте несколько узлов, разные failure domain и replication factor 3. Для SeaweedFS разнесите master, volume и filer по нескольким серверам, включите репликацию volume и обеспечьте отдельное хранение метаданных. Узлы должны иметь независимое питание и желательно находиться не в одном физическом failure domain. Даже кластерная репликация не заменяет offline или географически удалённый бэкап.

Как мигрировать с одного сервиса на другой?

Создайте bucket на новом endpoint и перенесите объекты через S3-клиент, например rclone sync или AWS CLI. Сначала выполните пробную миграцию одного bucket, сравните количество объектов, размеры и контрольные суммы. После переключения приложения оставьте старое хранилище в режиме чтения на период отката. Не копируйте внутренние каталоги Garage напрямую в SeaweedFS: перенос выполняется через S3 API.

9. Выводы и следующие шаги

Схема: 9. Выводы и следующие шаги
Схема: 9. Выводы и следующие шаги

На dedicated-сервере можно разместить собственное S3-хранилище на Garage или SeaweedFS, закрыв API через Caddy и HTTPS. Для одной ноды получена рабочая схема с Docker Compose, отдельными каталогами данных, ограниченным firewall и резервным копированием через restic.

  1. Выберите один основной backend и проведите нагрузочный тест с реальным размером объектов.
  2. Добавьте второй сервер, репликацию и мониторинг, если данные критичны для бизнеса.
  3. Настройте автоматическое расширение дисков, проверку восстановления и lifecycle-политики для старых объектов.

Был ли этот гайд полезен?

Ваш отзыв помогает нам улучшать гайды.

Поделиться записью:

Отправьте гайд тому, кому он может пригодиться.

Telegram VKVK WhatsApp Facebook LinkedIn XX

garage и seaweedfs: своё s3-хранилище на dedicated
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.