Raff Object Storage exposes an S3-compatible API, so you can use the AWS CLI for bucket operations, uploads, downloads, directory syncs, and presigned URLs by pointing commands at https://s3.raffusercloud.com. In this tutorial, you will configure a dedicated AWS CLI profile, use a bucket-scoped access key where possible, create and verify a bucket, transfer files, test a safe sync workflow, create a temporary download URL, and clean up test objects without exposing credentials.
This tutorial targets Raff's current Object Storage feature set. Standard object operations, multipart uploads, presigned URLs, bucket policies and ACLs, and SigV4 authentication are supported. Versioning, lifecycle rules, Object Lock, cross-region replication, and static website hosting are not currently supported, so this guide does not depend on those features. See Raff Object Storage for the current compatibility and pricing matrix.
AWS documents --endpoint-url as the option for overriding a service endpoint, and its current aws s3 commands include cp, ls, mb, rm, rb, sync, and presign. AWS CLI v2 also requires an explicit signing region for presigned URLs. This tutorial uses the existing Raff-compatible signing value us-east-1 and the Raff endpoint on every S3 command.
Step 1 — Install and Verify AWS CLI v2
On Ubuntu 24.04, install the utilities needed for the official AWS CLI v2 installer:
sudo apt update sudo apt install -y curl unzip
Download and install the current AWS CLI v2 package for x86_64 Linux:
curl -fsSLo awscliv2.zip \ https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip unzip -q awscliv2.zip sudo ./aws/install rm -rf aws awscliv2.zip
If your VM uses ARM64, use AWS's ARM64 package instead of the x86_64 archive. AWS also provides a current install script and Snap package; follow the official AWS CLI installation documentation if you need another architecture or update method.
Verify:
aws --version
The command should report AWS CLI 2.x and exit without an error.
Step 2 — Create a Scoped Raff Object Storage Access Key
Open the Raff dashboard and go to Object Storage. Create or select the bucket you want this CLI profile to access, then create an access key with the narrowest permissions your workflow needs.
For an upload/download workflow, prefer a key limited to the intended bucket with read-write access instead of sharing a full-access key across multiple applications. Raff currently supports bucket-scoped read and read-write grants for access keys.
Record the access key ID and secret access key in a password manager when the secret is shown. Do not paste the secret into Git, source code, screenshots, shell scripts, tickets, or chat messages.
Verify: You should have the endpoint https://s3.raffusercloud.com, an access key ID, a secret access key, and the name of the bucket or permission to create one.
Step 3 — Configure a Dedicated AWS CLI Profile
Set a restrictive shell umask before creating the credential files:
umask 077 aws configure --profile raff
Enter:
AWS Access Key ID: YOUR_RAFF_ACCESS_KEY AWS Secret Access Key: YOUR_RAFF_SECRET_KEY Default region name: us-east-1 Default output format: json
AWS CLI stores profile credentials under ~/.aws/credentials and non-secret profile settings under ~/.aws/config. These files contain sensitive material and should only be readable by your user.
Enforce restrictive permissions:
chmod 700 ~/.aws chmod 600 ~/.aws/credentials ~/.aws/config
Do not print the credential file contents as a verification step. Instead, check the profile exists:
aws configure list --profile raff
Verify: The profile should show a configured access key source and us-east-1 region without displaying the full secret key.
Step 4 — Test Authentication Against the Raff S3 Endpoint
List buckets using Raff's custom endpoint:
aws s3 ls \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
If the scoped key can only access a specific bucket, a global bucket listing may be restricted. In that case, test the intended bucket directly:
aws s3 ls s3://YOUR_BUCKET_NAME/ \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
An empty bucket can produce no object lines while still returning successfully.
Verify: The command should complete without an authentication or signature error. A permission-denied response is only acceptable when the key is intentionally scoped away from the attempted operation.
Step 5 — Create a Bucket When Your Key Allows It
Skip this step if you already have a bucket or your key is intentionally limited to an existing bucket.
Choose a bucket name using lowercase letters, numbers, and hyphens. Avoid sensitive information in bucket names and avoid periods for better compatibility with HTTPS virtual-hosted addressing.
Create the bucket:
BUCKET="my-project-files-$(date +%Y%m%d)" aws s3 mb "s3://$BUCKET" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
AWS's general S3 naming guidance uses 3-63 characters, lowercase letters, numbers, periods, and hyphens, with names beginning and ending in a letter or number. Raff may enforce its own namespace availability, so use a name that is unlikely to collide.
Verify:
aws s3 ls "s3://$BUCKET/" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
The command should return successfully, even if the new bucket is empty.
Step 6 — Upload, List, Download, and Compare an Object
Create a small test object:
printf 'Raff Object Storage verification\n' > /tmp/raff-s3-test.txt
Upload it:
aws s3 cp /tmp/raff-s3-test.txt "s3://$BUCKET/raff-s3-test.txt" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
List the object:
aws s3 ls "s3://$BUCKET/raff-s3-test.txt" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
Download it to a different local path:
aws s3 cp "s3://$BUCKET/raff-s3-test.txt" /tmp/raff-s3-downloaded.txt \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
Compare the files locally:
cmp /tmp/raff-s3-test.txt /tmp/raff-s3-downloaded.txt \ && echo 'Upload/download verification passed'
Verify: The cmp command should print Upload/download verification passed.
Step 7 — Sync a Directory Safely with a Dry Run First
Create a small local directory:
mkdir -p ~/raff-s3-sync-demo printf 'alpha\n' > ~/raff-s3-sync-demo/a.txt printf 'beta\n' > ~/raff-s3-sync-demo/b.txt
Preview the sync before transferring anything:
aws s3 sync ~/raff-s3-sync-demo/ "s3://$BUCKET/sync-demo/" \ --dryrun \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
If the preview is correct, run the sync:
aws s3 sync ~/raff-s3-sync-demo/ "s3://$BUCKET/sync-demo/" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
AWS documents sync as recursively copying new and updated files from source to destination. Do not add --delete casually: that option can delete destination objects that no longer exist in the source.
Also note that a sync is not a versioned backup. Raff Object Storage does not currently support object versioning, so overwriting the same key does not provide a built-in object-history recovery mechanism.
Verify:
aws s3 ls "s3://$BUCKET/sync-demo/" \ --recursive \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1
Both a.txt and b.txt should appear.
Step 8 — Generate a Temporary Presigned Download URL
Generate a one-hour presigned URL for the test object:
PRESIGNED_URL="$(aws s3 presign "s3://$BUCKET/raff-s3-test.txt" \ --expires-in 3600 \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1)"
AWS CLI currently supports presigned expiry values up to 604800 seconds, or seven days. Anyone who has a valid presigned URL can use it until it expires, so treat the URL like a temporary bearer credential.
Test it without printing the full URL into shared logs:
curl -fsS "$PRESIGNED_URL" -o /tmp/raff-s3-presigned.txt cmp /tmp/raff-s3-test.txt /tmp/raff-s3-presigned.txt \ && echo 'Presigned URL verification passed'
Unset the shell variable after the test:
unset PRESIGNED_URL
Verify: The comparison should print Presigned URL verification passed.