AWS CLI работает с любым S3-совместимым хранилищем, как только узнаёт три вещи, которые иначе предполагает Amazon: URL эндпоинта, то, что бакет указывается в пути, а не в имени хоста, и регион для подписи. Положите все три в именованный профиль, и каждая команда aws s3 будет работать без изменений: aws s3 ls --profile renode покажет ваши бакеты, aws s3 sync ./backups s3://my-bucket/backups --profile renode зеркалирует папку. Свежие версии CLI добавляют для многих серверов не от Amazon ещё одно требование: настройку, которая не даёт CLI отправлять заголовки контрольных сумм, непонятные серверу. В этой статье всё это настраивается, а затем разбираются команды, которыми вы действительно будете пользоваться, с флагами, которые имеют значение.
Установите CLI и проверьте версию#
Используйте AWS CLI версии 2. Это самодостаточный установщик для Windows, macOS и Linux из документации Amazon, и он не зависит от системного Python. Пакеты в дистрибутивах Linux иногда отстают на годы или всё ещё версии 1, так что проверьте:
$ aws --versionaws-cli/2.27.50 Python/3.13.4 Linux/6.8.0 exe/x86_64.ubuntu.24Всё начиная с 2.13 поддерживает endpoint_url в конфигурационном файле, и именно это делает возможным профиль для своего эндпоинта. До этого приходилось передавать --endpoint-url в каждой команде. Версия 1 тоже работает с этим флагом, но это старая линейка; начинать на ней новую настройку незачем.
Учётные данные, эндпоинт и path-style в одном профиле#
CLI читает два файла в ~/.aws/ (%USERPROFILE%\.aws\ в Windows): credentials для ключей и config для всего остального. Создайте именованный профиль, чтобы ваше S3-совместимое хранилище никогда не смешивалось с аккаунтом Amazon, который у вас тоже может быть.
$ aws configure --profile renodeAWS Access Key ID [None]: RNAKEXAMPLE123AWS Secret Access Key [None]: ****************************************Default region name [None]: us-east-1Default output format [None]: jsonЭто записывает ключи и регион. Эндпоинт и стиль адресации добавьте, отредактировав ~/.aws/config:
[profile renode]region = us-east-1output = jsonendpoint_url = https://s3.example.comrequest_checksum_calculation = when_requiredresponse_checksum_validation = when_requireds3 = addressing_style = path[renode]aws_access_key_id = RNAKEXAMPLE123aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEYЗачем нужна каждая строка:
endpoint_url- базовый URL хранилища. Если у вас есть имя хоста с HTTPS, используйте его; обычный эндпоинтhttp://host:portтоже работает, но передаёт ваши данные без шифрования.region- любое имя, которое принимает сервер. Оно входит в подпись каждого запроса, поэтому должно быть одинаковым.us-east-1- общепринятая заглушка, и с ним CLI не отправляет ограничение местоположения при создании бакетов.addressing_style = path- помещает бакет в путь URL (https://s3.example.com/bucket/key), а не в поддомен (https://bucket.s3.example.com/key), для которого нужны wildcard-DNS и wildcard-сертификат, которых у эндпоинта может не быть. Вложенный блокs3 =с настройками с отступом - синтаксис CLI для параметров конкретного сервиса.request_checksum_calculationиresponse_checksum_validation- объяснены в следующем разделе.
Обратите внимание на асимметрию: в config секция называется [profile renode], а в credentials - [renode]. Ошибка здесь - самая частая причина The config profile (renode) could not be found.
В RE:NODE панель показывает access key и secret key, сгенерированные для сервера хранилища, а первый бакет уже существует. Эндпоинт - это адрес и порт тарифа по обычному HTTP или ваше собственное имя хоста по HTTPS, после того как вы направите A-запись на слот прокси тарифа, который выпускает и продлевает сертификат.
Изменение контрольных сумм в новых версиях CLI#
В январе 2025 года AWS CLI 2.23.0 и вышедшие одновременно с ним AWS SDK изменили умолчание: теперь загрузки вычисляют контрольную сумму CRC и отправляют её в новых заголовках при каждом запросе, где операция это поддерживает, а скачивания проверяют контрольные суммы, если сервер их возвращает. Amazon S3 эти заголовки понимает. Многие S3-совместимые серверы, по крайней мере поначалу, не понимали, и результатом были упавшие загрузки с ошибками, в которых контрольные суммы вообще не упоминаются: SignatureDoesNotMatch, MissingContentLength, XAmzContentSHA256Mismatch или общая InvalidArgument.
Две настройки в профиле выше возвращают старое поведение - контрольные суммы только там, где операция их требует:
$ aws configure set request_checksum_calculation when_required --profile renode$ aws configure set response_checksum_validation when_required --profile renodeИли в виде переменных окружения, которые действуют на каждый инструмент на основе SDK в той же оболочке:
export AWS_REQUEST_CHECKSUM_CALCULATION=when_requiredexport AWS_RESPONSE_CHECKSUM_VALIDATION=when_requiredЕсли ваш сервер правильно обрабатывает новые контрольные суммы, вы ничего важного не теряете, задав эти настройки: целостность по-прежнему защищают TLS и Content-MD5 или хеш payload там, где они требуются. Если загрузки падают со странными ошибками подписи в CLI, который в прошлом году работал, это первое, что нужно проверить. Те же настройки есть в boto3 и других SDK, о них - в статье S3 из Node и Python.
Переменные окружения вместо файлов#
Для контейнеров, задач CI и разовых скриптов переменные окружения часто проще конфигурационных файлов. CLI читает:
| Переменная | Назначение |
|---|---|
AWS_ACCESS_KEY_ID | Access key |
AWS_SECRET_ACCESS_KEY | Secret key |
AWS_REGION или AWS_DEFAULT_REGION | Регион для подписи |
AWS_ENDPOINT_URL_S3 | Эндпоинт только для S3 |
AWS_ENDPOINT_URL | Эндпоинт для всех сервисов |
AWS_PROFILE | Какой профиль использовать |
У path-style адресации в CLI нет собственной переменной окружения, поэтому держите минимальный конфигурационный файл с блоком s3 = addressing_style = path, даже когда ключи берутся из окружения. AWS_CONFIG_FILE указывает CLI на конфигурационный файл в другом месте, не в ~/.aws/config, что удобно в контейнерах.
Для разовой команды к другому эндпоинту --endpoint-url https://s3.example.com в командной строке переопределяет всё остальное. Как не допустить попадания секретного ключа в историю оболочки и репозитории, разобрано в статье переменные окружения и секреты.
Повседневные команды#
Высокоуровневые команды aws s3 сами занимаются multipart-загрузками, повторами и рекурсией.
| Команда | Что делает |
|---|---|
aws s3 ls | Список бакетов |
aws s3 ls s3://bucket/prefix/ | Один уровень «папки» |
aws s3 ls s3://bucket --recursive --human-readable --summarize | Все объекты, размеры и итог |
aws s3 mb s3://new-bucket | Создать бакет |
aws s3 cp file s3://bucket/key | Загрузить один файл |
aws s3 cp s3://bucket/key file | Скачать один файл |
aws s3 cp dir s3://bucket/prefix/ --recursive | Загрузить каталог |
aws s3 mv | Скопировать, затем удалить источник |
aws s3 rm s3://bucket/prefix/ --recursive | Удалить всё под префиксом |
aws s3 rb s3://bucket --force | Удалить бакет со всем содержимым |
aws s3 presign s3://bucket/key --expires-in 3600 | Временная ссылка на скачивание |
С профилем из примера выше каждая команда принимает --profile renode, либо вы один раз на оболочку выполняете export AWS_PROFILE=renode.
$ export AWS_PROFILE=renode$ aws s3 ls2026-10-08 09:12:44 my-first-bucket$ aws s3 cp ./world-2026-10-08.tar.gz s3://my-first-bucket/minecraft/upload: ./world-2026-10-08.tar.gz to s3://my-first-bucket/minecraft/world-2026-10-08.tar.gzКосая черта в конце назначения означает «в этот префикс, с сохранением имени файла». Без неё ключ будет ровно тем, что вы написали.
Как проверить, что загрузка действительно на месте
Команда, которая напечатала upload: и завершилась со статусом 0, действительно отработала, но скрипты должны проверять, а не доверять. Самая дешёвая проверка - размер: aws s3api head-object возвращает ContentLength, и сравнение с размером локального файла ловит обрезанные источники - классический случай: дамп, упавший на полпути и давший маленький, но правдоподобный на вид файл. Для однокомпонентной загрузки ETag обычно равен MD5 содержимого, поэтому md5sum локального файла должен с ним совпасть; для multipart-загрузки ETag заканчивается на - и число частей и никогда не совпадёт с MD5, так что сравнивайте размеры или храните рядом с объектом файл .sha256.
$ stat -c %s world-2026-10-08.tar.gz734003200$ aws s3api head-object --bucket my-first-bucket \ --key minecraft/world-2026-10-08.tar.gz --query ContentLength734003200Настоящая проверка - скачать его снова в другом месте и открыть; как часто и как именно - в статье проверка восстановления до того, как оно понадобится.
cp читает из стандартного ввода, когда источник - -, и это позволяет передавать бэкап потоком, не записывая временный файл:
$ mysqldump --single-transaction app | gzip \ | aws s3 cp - s3://my-first-bucket/db/app-$(date +%F).sql.gzДля потоков больше примерно 50 GB добавьте --expected-size с приблизительным числом байт, чтобы CLI мог выбрать размер частей, укладывающийся в лимит в 10 000 частей. Полноценная задача вокруг этого построена в статье дампы баз данных в S3 по расписанию.
presign создаёт URL с подписью в строке запроса. Время жизни по умолчанию - 3600 секунд, максимум - семь дней (604 800 секунд). Любой, у кого есть этот URL, может скачать объект, пока срок не истёк, так что обращайтесь с ним как с паролем с ограниченным сроком. Сторона загрузки, которую CLI сгенерировать не может, разобрана в статье presigned URL в S3 для загрузок.
sync: что он сравнивает и как фильтровать#
aws s3 sync копирует всё новое или изменённое из источника в назначение - из локального каталога в бакет, из бакета в локальный каталог или из бакета в бакет.
$ aws s3 sync ./backups s3://my-first-bucket/backups --dryrun$ aws s3 sync ./backups s3://my-first-bucket/backupsОн считает файл изменённым, когда отличается размер или локальное время изменения новее, чем Last-Modified объекта. Содержимое он не сравнивает. Это меняют два флага:
--size-only- сравнивать только размер. Полезно, когда метки времени ненадёжны, например после копирования файлов без сохранения времени. Пропускает изменения, при которых размер не меняется.--exact-timestamps- при скачивании считать изменёнными файлы того же размера с любым расхождением во времени.
По умолчанию sync никогда ничего не удаляет. --delete удаляет из назначения объекты, которых больше нет в источнике, - а это превращает ошибку в источнике в ошибку в назначении. Sync с --delete - это зеркало, а не бэкап. Всегда сначала запускайте его с --dryrun и читайте вывод.
Фильтры - это шаблоны --exclude и --include, которые применяются по порядку, причём более поздние имеют приоритет:
# Only .tar.gz files$ aws s3 sync ./backups s3://my-first-bucket/backups \ --exclude "*" --include "*.tar.gz"# Everything except logs and temp files$ aws s3 sync ./site s3://my-first-bucket/site \ --exclude "*.log" --exclude "tmp/*"Sync работает и в обратном направлении, и так выполняется восстановление: aws s3 sync s3://my-first-bucket/backups ./restore скачивает всё, чего нет локально или что отличается. Направляйте его в пустой каталог, а не в рабочий, проверьте, что пришло, и только потом переносите на место. Sync из бакета в бакет на одном эндпоинте (aws s3 sync s3://bucket-a s3://bucket-b) использует копирование на стороне сервера, так что через вашу машину ничего не проходит.
Шаблоны сопоставляются с путём относительно каталога-источника. --exclude "*" --include "*.tar.gz" работает; в обратном порядке исключается всё, потому что побеждает более поздний --exclude "*".
Скорость, multipart и полоса пропускания#
CLI загружает файлы больше 8 MB частями по 8 MB, по десять запросов одновременно. Для больших файлов по быстрому каналу помогают более крупные части и большая параллельность; на медленном или общем канале ограничение полосы не даёт загрузке задушить всё остальное.
[profile renode]s3 = addressing_style = path max_concurrent_requests = 10 multipart_threshold = 64MB multipart_chunksize = 64MB max_bandwidth = 20MB/smax_bandwidth принимает байты в секунду с суффиксом, так что 20MB/s - это 160 Мбит/с. Поднимать max_concurrent_requests выше 20-30 при работе с одним небольшим эндпоинтом редко помогает: ограничением становятся сервер и сеть между вами. Очень крупные части означают, что упавшую часть дольше повторять; разумный диапазон - 16-64 MB.
Низкоуровневые команды через s3api#
aws s3api один к одному соответствует операциям API. Он многословен, но даёт доступ ко всему:
# Metadata of one object: size, ETag, content type, user metadata$ aws s3api head-object --bucket my-first-bucket --key db/app-2026-10-08.sql.gz# Keys and sizes under a prefix, filtered with JMESPath$ aws s3api list-objects-v2 --bucket my-first-bucket --prefix db/ \ --query 'Contents[].[Key,Size]' --output text# Find and abort abandoned multipart uploads$ aws s3api list-multipart-uploads --bucket my-first-bucket$ aws s3api abort-multipart-upload --bucket my-first-bucket \ --key big.tar --upload-id 'EXAMPLEuploadID'При загрузке файлов, которые будет запрашивать браузер, задавайте тип содержимого явно - aws s3 cp logo.svg s3://bucket/ --content-type image/svg+xml, - потому что угаданный binary/octet-stream заставляет браузеры скачивать файл вместо показа.
Устранение неполадок#
`Could not connect to the endpoint URL`. Неверный хост, порт или схема в endpoint_url либо файрвол. Попробуйте curl -I на эндпоинт: любой HTTP-ответ, даже 403, доказывает, что сетевой путь в порядке.
`InvalidAccessKeyId`. Access key неверный, или CLI использует не тот профиль, о котором вы думаете. aws configure list --profile renode показывает, какие учётные данные и регион он определил и откуда.
`SignatureDoesNotMatch`. Неверный secret key, регион отличается от того, что ожидает сервер, системные часы сбиты на минуты или - в CLI 2.23 и новее - заголовки контрольных сумм, описанные выше. Проверьте часы через date, затем настройки контрольных сумм.
`RequestTimeTooSkewed`. Часы машины слишком расходятся с часами сервера. Исправляйте синхронизацию времени (timedatectl в Linux с systemd), а не что-то в CLI.
`AccessDenied` на одном бакете, но не на другом. Ключи принадлежат другому серверу или аккаунту, чем бакет, или имя бакета написано с ошибкой - некоторые серверы на бакет, который вам не виден, отвечают отказом в доступе, а не «не найдено».
`NoSuchBucket` или ошибки DNS для `bucket.s3.example.com`. CLI использует virtual-hosted адресацию. Добавьте addressing_style = path.
`SSL: CERTIFICATE_VERIFY_FAILED`. Вы используете HTTPS-эндпоинт с сертификатом, которому CLI не доверяет, или IP-адрес с сертификатом, выпущенным на имя. Используйте имя хоста из сертификата. --no-verify-ssl убирает ошибку, убирая защиту; не оставляйте его в скриптах.
Во всех остальных случаях --debug выводит заголовки каждого запроса и ответа, и видно, что именно было подписано и что ответил сервер.
FAQ#
Нужен ли аккаунт AWS, чтобы пользоваться AWS CLI?
Нет. CLI - это просто клиент. Направьте его на любой S3-совместимый эндпоинт с ключами этого эндпоинта, и он ни разу не обратится к Amazon.
Можно ли использовать один профиль для Amazon S3 и другого провайдера?
Используйте отдельные профили. У каждого профиля свой эндпоинт, ключи и стиль адресации, а --profile или AWS_PROFILE выбирает один из них. Смешивание их в одном профиле - это то, как бэкапы оказываются не в том месте.
Почему sync заново загружает файлы, которые не менялись?
Обычно из-за времени изменения: что-то тронуло файлы, или их скопировали без сохранения меток времени, и локальные копии выглядят новее. --size-only этого избегает, если вы доверяете размерам. Другая причина - префикс назначения, отличающийся от прошлого запуска косой чертой на конце или опечаткой.
Sync с --delete - это бэкап?
Нет. Он делает назначение таким же, как источник, включая удаления и повреждения. Для бэкапов с историей используйте инструмент, который хранит снимки, например restic - см. бэкапы restic в S3, - или rclone с каталогом для изменённых и удалённых файлов.
Можно ли копировать между бакетами двух разных провайдеров?
Не одной командой. aws s3 cp и sync используют один эндпоинт за вызов, так что копирование от одного провайдера к другому - это скачивание в локальный каталог с одним профилем и загрузка с другим. rclone умеет сделать это за один шаг, передавая данные потоком между двумя remote.
Как запускать загрузки по расписанию через cron?
Cron работает с минимальным окружением, поэтому передайте задаче всё явно: полный путь к aws, AWS_PROFILE и HOME (чтобы CLI нашёл ~/.aws). Перенаправляйте вывод в файл журнала и проверяйте его, потому что задача cron, которая молча падает, - это бэкап, которого не существует.




Комментарии
Полностью анонимно: без аккаунта, без почты, без cookie. Мы храним имя, которое вы ввели, текст и время - больше ничего. Количество ссылок ограничено, разметка не отображается.