Skip to main content
Storage • 2 mins read

Advanced Usage

Advanced Usage

You already have a bucket and a file. This page covers sharing, public access, scoped credentials, large uploads, and hosting.

Connection details (endpoint https://s3.hippius.com, region decentralized, path-style) live in Getting Started. For the full operation list, see the Compatibility matrix.

Share a time-limited download

Generate a URL that works without credentials and expires on its own. Max expiry is 7 days (604800 seconds).

url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": "my-bucket", "Key": "hello.txt"},
ExpiresIn=86400, # 24 hours
)

Anyone with the link can download until it expires. No cleanup job needed.

Client setup: Python, JavaScript, AWS CLI.

Let a browser upload without keys

Never put your secret key in client-side code. Generate a presigned PUT on your server and have the browser upload to that URL.

Server (Node.js):

import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { PutObjectCommand } from "@aws-sdk/client-s3";

const uploadUrl = await getSignedUrl(
s3,
new PutObjectCommand({ Bucket: "my-bucket", Key: "user-upload.jpg" }),
{ expiresIn: 300 },
);

Browser:

await fetch(uploadUrl, {
method: "PUT",
body: file,
headers: { "Content-Type": file.type },
});

Do not append extra query parameters to a presigned URL — they invalidate the signature.

Make a bucket or object public

Buckets are private by default. Public objects are readable at:

https://s3.hippius.com/{bucket}/{key}

Whole bucket (ACL):

aws s3api put-bucket-acl --bucket my-bucket --acl public-read \
--endpoint-url https://s3.hippius.com

Whole bucket (policy, recommended):

import json

policy = {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": ["s3:GetObject"],
"Resource": ["arn:aws:s3:::my-bucket/*"],
}],
}
s3.put_bucket_policy(Bucket="my-bucket", Policy=json.dumps(policy))

One object, bucket stays private:

aws s3api put-object-acl --bucket my-bucket --key document.pdf \
--acl public-read --endpoint-url https://s3.hippius.com

Public objects are still encrypted at rest with per-bucket keys. Use this for websites, images, and videos you intend anyone to fetch. Keep private data on a private bucket and share with a presigned URL instead.

Canned ACLs: private (default), public-read, public-read-write, authenticated-read.

Share with another Hippius account

Grant by canonical user ID (every key on that account gets access):

aws s3api list-buckets --endpoint-url https://s3.hippius.com \
--query 'Owner.ID' --output text

aws s3api put-bucket-acl --bucket my-bucket \
--grant-read 'id="their_canonical_id_here"' \
--grant-full-control 'id="your_canonical_id_here"' \
--endpoint-url https://s3.hippius.com
warning

Always include --grant-full-control for yourself, or you can lock yourself out.

Permission types: READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL.

To undo grants:

aws s3api put-bucket-acl --bucket my-bucket --acl private \
--endpoint-url https://s3.hippius.com

Grant one access key

accessKey= is a Hippius extension. Use it when you want one key, not a whole account.

aws s3api put-bucket-acl --bucket my-bucket \
--grant-read 'accessKey="YOUR_ACCESS_KEY"' \
--grant-full-control 'id="your_canonical_id"' \
--endpoint-url https://s3.hippius.com

Master keys bypass ACLs. Sub-tokens need an explicit grant unless you created them with access to that bucket in the console.

Give an app scoped credentials

Do not hand a master token to a backup script, a CDN, or a contractor. Create a sub-token:

WhyExample
One bucketA backup job that should never see production media
Read onlyA CDN that must not overwrite or delete
Time limitedVendor access that expires in a week
Easy revokeKill that integration without rotating the master

Create them in the console: S3 Buckets → Sub Tokens. Pick the buckets, Get / List or Get / List / Put / Delete, and an expiry (7 days, 30 days, 1 year, or a date). The secret is shown once.

Rotate keeps the same Access Key ID and issues a new secret. Revoke is immediate and cannot be undone.

Programmatic create / list / rotate / revoke: Management API.

Upload large files

The console caps a single upload at 100 MB. For anything larger, use a client that speaks multipart — AWS CLI, boto3, and the AWS SDK all do this automatically.

s3.upload_file("large_file.zip", "my-bucket", "large_file.zip")

MinIO lets you set part size and parallelism:

client.fput_object(
"my-bucket",
"large_file.zip",
"large_file.zip",
part_size=10 * 1024 * 1024,
num_parallel_uploads=3,
)

Objects can go up to ~5 TiB via multipart. See Troubleshooting if transfers are slow.

Tag buckets and objects

s3.put_bucket_tagging(
Bucket="my-bucket",
Tagging={"TagSet": [
{"Key": "Project", "Value": "MyProject"},
{"Key": "Environment", "Value": "Production"},
]},
)

s3.put_object_tagging(
Bucket="my-bucket",
Key="hello.txt",
Tagging={"TagSet": [{"Key": "Type", "Value": "Document"}]},
)

Host a static site or stream video

Make the bucket public, then upload. Files are served from the path-style URL — no extra web server.

aws s3api put-bucket-acl --bucket my-site --acl public-read \
--endpoint-url https://s3.hippius.com

aws s3 sync ./dist s3://my-site/ --endpoint-url https://s3.hippius.com

Site: https://s3.hippius.com/my-site/index.html

Video tags work the same way. Hippius supports HTTP range requests, so browsers can seek without downloading the whole file:

<video controls>
<source src="https://s3.hippius.com/my-videos/my-video.mp4" type="video/mp4">
</video>

For a private video, inject a presigned GET into the src. There is no custom-domain support yet.

Stop a version being deleted

Object Lock makes a version immutable for a retention window (GOVERNANCE or COMPLIANCE) or until you release a legal hold. COMPLIANCE cannot be shortened or bypassed by anyone, and the object still bills for the whole period.

Full guide: Object Lock (WORM).

More