S3 SDK setup
PutObject readyDrop-in snippets per language so your first PutObject succeeds — pre-configured to bypass the AWS SDK ≥ 1.36 streaming-checksum default that causes silent 403s.
Since early 2025, botocore, the JS SDK v3, and aws-sdk-go-v2 all default to streaming PUTs with a CRC32 trailer. Our S3-compatible gateway doesn't parse that wire format, so the edge proxy returns a generic 403 Forbidden HTML page with no S3 error code, no request-id, and no x-amz-* headers — looks identical to a permission bug, but it's not.
Every snippet below sets request_checksum_calculation = when_required so PutObject uses the classic non-streaming SigV4 shape and succeeds. ListBuckets, multipart upload, and presigned URLs always work — so if those succeed and PutObject 403s, you have this exact issue.
What you need
- Endpoint URL
https://s3south.storage.com.vn— issued with your bucket. Use HTTPS only. - Access key + secret keySent in the bucket provisioning email. Treat the secret as a password — never commit to a repo or ship to a browser.
- Region + addressing styleRegion
s3south— SigV4 mathematically requires some region string; the gateway treats it as an opaque value (not an AWS region). Path-style addressing for the apex TLS cert.
Copy a snippet and PutObject
Replace<your-access-key> & <your-secret-key> with the values from your provisioning email.import boto3
from botocore.client import Config
# Endpoint, access key, and secret come from your bucket provisioning email.
EP = "https://s3south.storage.com.vn"
AK = "<your-access-key>"
SK = "<your-secret-key>"
cfg = Config(
signature_version="s3v4",
region_name="s3south", # opaque SigV4 placeholder, not AWS
s3={"addressing_style": "path"},
request_checksum_calculation="when_required", # opt out of CRC32 streaming
response_checksum_validation="when_required",
)
s3 = boto3.client(
"s3",
aws_access_key_id=AK,
aws_secret_access_key=SK,
endpoint_url=EP,
config=cfg,
)
# Some edge proxies reject these headers on small-body PUTs. Strip them once
# at client construction time and every PutObject will be happy.
def _strip(request, **_):
for h in ("Expect", "expect", "amz-sdk-invocation-id", "amz-sdk-request"):
request.headers.pop(h, None)
s3.meta.events.register("before-send.s3.*", _strip)
# Round-trip a small object to confirm the client is wired correctly.
s3.put_object(Bucket="my-bucket", Key="hello.txt", Body=b"hello from htx")
print(s3.get_object(Bucket="my-bucket", Key="hello.txt")["Body"].read())
What works today
- ListBuckets / CreateBucket / HeadBucket / DeleteBucket
- PutObject / GetObject / HeadObject / CopyObject / DeleteObject (all sizes)
- Multipart upload (recommended for files larger than 5 MB)
- Presigned PUT and GET URLs
- Canned bucket ACL — public-read / private (the "Make public" flow)
Tier-gated (request to enable)
- PutBucketPolicy (resource policies)
- PutBucketVersioning
- PutBucketLifecycleConfiguration
- PutBucketCORS
- PutBucketTagging
- PutObjectAcl (per-object grants — only canned bucket ACL is exposed)
These return 403 even with correct client config — it's a backend tier setting, not a client bug. Contact sales@vinacis.com if you need them for a workload.
Troubleshoot a 403
- Look at the response body. An HTML
403 Forbiddenwith nox-amz-request-idheader means the edge proxy rejected the request — apply the streaming-checksum opt-out above. An XML<Error>with anx-amz-request-idmeans the S3 backend saw the request and refused it (permissions, quota, or wrong bucket). - Test ListBuckets first. If
ListBucketssucceeds andPutObject403s with the same credentials, it is the streaming-checksum gotcha — credentials are fine. - Try a multipart upload. If multipart succeeds but single-shot PutObject 403s, it is the same gotcha (multipart uses non-streaming PUT under the hood).
- Capture the wire headers. In Python, set
http.client.HTTPConnection.debuglevel = 1. Look forTransfer-Encoding: chunked,Content-Encoding: aws-chunked, orX-Amz-Trailer: x-amz-checksum-crc32— any of those on a PutObject confirms the SDK is using streaming-checksum.
Frequently asked questions
Still seeing a 403?
Send us the failing request — endpoint, method, key, and the response body — and we'll trace it from the edge proxy through to the gateway. Email sales@vinacis.com or file a ticket from Notifications.