Привет! Наконец-то я завершил перенос хранения файлов, загруженных в мой блог, с локального серверного диска на сервис типа S3, который я развернул в своей лаборатории с помощью решения RustFS (совместимого с Amazon S3, как MinIO / Spaces / R2 и т. д.).
Почему я решил мигрировать с локального диска?
Локальное хранилище в Laravel (через storage/app/public + storage:link) работало нормально, но начали появляться некоторые ограничения. Ниже я постарался перечислить основные из них:
Масштабирование: несколько экземпляров приложения требуют одновременного использования общего хранилища, а совместное использование файловой системы между ними приводит к потере производительности и требует нетривиальных решений. Если ваш сайт размещен на географически распределенных узлах, то эта задача становится практически невыполнимой и потребует значительных усилий и затрат для реализации.
Резервное копирование: резервное копирование растущего объема файлов вместе с кодом и базой данных также не является правильным решением.
CDN и географическое распределение: контейнер, подобный S3, можно легко разместить за CDN без изменения кода.
Поэтому логичным шагом было переместить все загрузки в отдельное хранилище объектов, которое бы позволяло получить к ним доступ с помощью API, подобного S3.
Подготовка Laravel для S3
В проекте уже был подключён драйвер league/flysystem-aws-s3-v3, так что ничего ставить не пришлось, но для установки в принципе достаточно выполнить команду:
composer require league/flysystem-aws-s3-v3 "^3.0"Дальше я просто переключил диск по умолчанию в .env:
FILESYSTEM_DISK=s3
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your_bucket_name
AWS_URL=https://your-bucket-url.com
# для кастомного S3
# AWS_ENDPOINT=https://your-custom-endpoint.com
# AWS_USE_PATH_STYLE_ENDPOINT=trueLaravel уже умеет подхватывать это из config/filesystems.php, так что весь код, который работал через Storage::disk() и Storage::url(), сразу начал смотреть в мой бакет.
Отдельный момент — Livewire: временные загрузки тоже нужно отправлять в S3, иначе часть файлов будет оставаться на локальном диске.
LIVEWIRE_TEMPORARY_FILE_UPLOAD_DISK=s3Миграция уже загруженных файлов
Так как в опубликованных мной ранее постах блога уже были размещены файлы изображений storage/app/public , их нужно было аккуратно перенести, не ломая существующие ссылки.
Самый простой путь — воспользоваться aws-cli (или аналогами rclone, s3cmd) и просто Если у провайдера свой endpoint, можно добавить --endpoint-url https://your-endpoint или использовать rclone с нужным backend’ом.
Важно сохранить ту же структуру каталогов и имена файлов — тогда Laravel продолжит строить те же относительные пути, уже поверх S3.
Критичный момент: если Вы храните ссылки в БД.
Если хранятся относительные пути (
posts/123/image.jpg), то после переключенияFILESYSTEM_DISKприложение просто начнёт генерировать S3‑URL поверх тех же путей.Если хранились полные локальные пути, может понадобиться миграция, которая превратит их в относительные пути или сразу в S3‑URL.
Я ориентировался на первый вариант и убедился, что везде в коде использую Storage::url($path):
Storage::disk(config('filesystems.default'))->url(
'path/to/file.jpg'
);Чистка, кеши и символические ссылки
После переключения диска я почистил кеши Laravel, чтобы приложение гарантированно использовало обновленную конифгурацию:
php artisan config:clear
php artisan cache:clear
php artisan route:clearСимволическую ссылку public/storage, которую создаёт php artisan storage:link, можно не трогать, если вы больше не обслуживаете файлы с локального диска.
В моём случае часть файлов ещё жила локально, поэтому ссылку я оставил — переход получился плавным: новый контент уже летит в S3, старый постепенно мигрирует.
Нюансы S3‑совместимого сервиса
Когда используешь не чистый AWS, а свой S3‑подобный сторедж, всплывают дополнительные детали.
CORS: если фронтенд обращается к бакету напрямую, нужно правильно прописать CORS‑правила под домен блога.
CDN: S3‑совместимый бакет удобно прятать за CloudFront или другим CDN, увеличивая скорость раздачи статики во всём мире.
Права доступа: нельзя раздавать бакету публичную запись; для приватных загрузок — pre‑signed URL или серверный upload‑поток.
Path‑style vs virtual host: многие кастомные S3‑сервисы требуют
AWS_USE_PATH_STYLE_ENDPOINT=trueи своегоAWS_ENDPOINT.
Ниже я привел для удобства небольшой чек‑лист, чтобы не упустить какой-либо шаг изменения конфигурации:
Проверить наличие
league/flysystem-aws-s3-v3вcomposer.json.Прописать S3‑учётки и
FILESYSTEM_DISK=s3в.env.Настроить
LIVEWIRE_TEMPORARY_FILE_UPLOAD_DISK.Синхронизировать
storage/app/*в бакет.Очистить кеши и вручную проверить несколько ссылок на файлы в интерфейсе.
В итоге блог продолжил работать как раньше, но хранение файлов стало независимым от конкретного сервера, готовым к масштабированию и интеграции с CDN.
Собрал в список полезные ссылки по тематике облачного хранилища RustFS и его использования в Laravel:
RustFS как S3‑совместимое хранилище
Официальный сайт RustFS: архитектура, позиционирование, доки и сценарии использования
https://rustfs.comGitHub репозиторий RustFS (README, запуск через Docker, настройки, фичи)
https://github.com/rustfs/rustfsДокументация по S3‑совместимости RustFS: детали реализации S3 API и нюансы работы
https://docs.rustfs.com/features/s3-compatibilityСтатья по использованию RustFS как локального S3‑аналогa, в том числе пример с AWS CLI
https://zenn.dev/onozaty/articles/local-s3-rustfs
Laravel + S3 (применимо и к RustFS)
Официальная документация Laravel по файловому хранилищу (File Storage / Filesystem)
https://laravel.com/docs/12.x/filesystemСекция про S3‑совместимые файловые системы (в том числе RustFS, R2, Spaces и т.п.)
https://laravel.com/docs/12.x/filesystem#amazon-s3-compatible-filesystemsРусская документация по файловому хранилищу Laravel с примерами конфигурации S3
https://laravel.su/docs/12.x/filesystem
RustFS в Laravel Sail / локальной разработке
Официальная документация Laravel Sail: секция про RustFS как S3‑совместимое хранилище для локальной разработки
https://laravel.com/docs/12.x/sail#file-storageКоммит в репозитории
laravel/sail, добавляющий сервис RustFS в docker‑compose — полезно как пример конфигурации
https://github.com/laravel/sail/actions/runs/18779929551
Буду рад увидеть ваши комментарии, мнения, советы по выбранному решению и его реализации, а также напишите в комментариях, если вам интересно узнать больше о RustFS и о том, как я сам развернул его за 5 минут с нуля до готового к использованию решения.


Станьте первым, кто прокомментирует эту запись