Working With Buckets and Objects Using the AWS CLI
Goal
Get hands-on with the basic operations of S3-compatible storage — profile, bucket, object upload, prefix, listing, ETag, copy, metadata — using the aws CLI, and feel for yourself that there are no directories in object storage.
Why it matters
Understanding the S3 API is not learning a particular vendor. AWS S3, SeaweedFS, Garage, Ceph RGW and MinIO all speak the same API, so this API is in effect a portability layer. This is why the migration cost on the application side was small when the MinIO community edition stopped distribution in 2025–2026 — if you just changed the endpoint and credentials, the code stayed largely the same. This lab environment went through the same thing. The server changed from MinIO to SeaweedFS's S3 gateway, but the commands you type here run on AWS without changing a single character. What to remember especially in this lab is the ETag in step 6. For a single-part upload, the ETag is the md5 of the content, so the client can verify on its own whether the upload was intact. When the next lab covers how the ETag of a multipart upload differs from this, the rule you see here is the starting point.
Steps
- With
aws configure set, put four values into the profilelocal—aws_access_key_id,aws_secret_access_key,regionandendpoint_url(http://127.0.0.1:9000). The credentials are in/opt/fixtures/s3/creds.env.aws --profile local s3 lsmust finish without an error. - Create the bucket
lab-media. It must appear in theaws --profile local s3 lslist. - Upload
/opt/fixtures/s3/logo.pngtos3://lab-media/img/logo.png. - From
/opt/fixtures/s3/, uploadbanner.pngasimg/banner.png,readme.txtasdoc/readme.txtandsales.csvasdoc/sales.csv. - Save the output of
aws --profile local s3 ls --recursive s3://lab-mediato/root/s3/list.txt. It must be exactly 4 lines. - In
/root/s3/etag.txt, write two lines,etag=<값>andmd5=<값>(each with the actual value in place of the placeholder). The ETag oflogo.png(with the quotes removed) and the md5 of the local file must be the same. - Server-side copy
doc/readme.txttodoc/README.txtand then delete the original.aws --profile local s3 ls s3://lab-media/doc/must show onlyREADME.txtand notreadme.txt. - Upload
sales.csvagain with the Content-Typetext/csv. In the output ofaws --profile local s3api head-object --bucket lab-media --key doc/sales.csv, theContentTypemust betext/csv.
Notes
- Check the profile:
aws configure list --profile local(only the last four characters of the secret are shown) - If you don't want to add
--profile localevery time, useexport AWS_PROFILE=local - Recursive listing:
aws s3 ls --recursive s3://lab-media - Object metadata:
aws s3api head-object --bucket lab-media --key img/logo.png - Specifying the Content-Type:
aws s3 cp 파일 s3://버킷/키 --content-type text/csv(file, bucket and key in the placeholders) aws s3is a high-level command used like a file copy, andaws s3apicorresponds 1:1 to each S3 API call. When you want to see what actually goes back and forth, uses3api.- Common mistake 1: using uppercase letters or underscores in a bucket name — bucket names follow DNS rules.
- Common mistake 2: mistaking
img/for a folder and trying to create it separately — it is only part of the key name.
Set up an S3 profile
With aws configure set, put four values into the profile local — aws_access_key_id, aws_secret_access_key, region and endpoint_url (http://127.0.0.1:9000). The credentials are in /opt/fixtures/s3/creds.env. aws --profile local s3 ls must finish without an error.
You bundle the endpoint and credentials into one profile. The credentials are in /opt/fixtures/s3/creds.env, and if you leave out endpoint_url, the CLI tries to go out to the real AWS.
Create a bucket
Create the bucket lab-media. It must appear in the aws --profile local s3 ls list.
Bucket names follow DNS rules — only lowercase letters, digits and hyphens are allowed.
Upload one object
Upload /opt/fixtures/s3/logo.png to s3://lab-media/img/logo.png.
Specify the local path and the destination key together. The slash in the destination key is part of the name, not a folder.
Organize with prefixes
From /opt/fixtures/s3/, upload banner.png as img/banner.png, readme.txt as doc/readme.txt and sales.csv as doc/sales.csv.
Upload them split under img/ and doc/. In reality no folders are created; the key names just come out that way.
Pull a recursive listing
Save the output of aws --profile local s3 ls --recursive s3://lab-media to /root/s3/list.txt. It must be exactly 4 lines.
The default listing shows things folded by prefix. There is an option that expands everything.
Compare the ETag with a local hash
In /root/s3/etag.txt, write two lines, etag=<값> and md5=<값> (each with the actual value in place of the placeholder). The ETag of logo.png (with the quotes removed) and the md5 of the local file must be the same.
The ETag of a single-part upload is the md5 of the content. Write the two values side by side and compare them.
Delete the original after a server-side copy
Server-side copy doc/readme.txt to doc/README.txt and then delete the original. aws --profile local s3 ls s3://lab-media/doc/ must show only README.txt and not readme.txt.
There is no rename. Copying and deleting is the rename. Make sure it is handled on the server without downloading.
Upload with a Content-Type and check it
Upload sales.csv again with the Content-Type text/csv. In the output of aws --profile local s3api head-object --bucket lab-media --key doc/sales.csv, the ContentType must be text/csv.
It is sometimes guessed from the extension, but it is safer to state it explicitly. Look up the object's metadata to confirm.