Todos os SDKs da AWS funcionam. Basta informar o endpoint (informado na ativação) e usar forcePathStyle (ou equivalente). Credenciais em variáveis de ambiente, nunca no código.
export S3_ENDPOINT=https://ENDPOINT-DA-API
export AWS_ACCESS_KEY_ID=SUA_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=SUA_SECRET_KEY
export AWS_REGION=us-east-1
Node.js (@aws-sdk/client-s3)
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import fs from "node:fs";
const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT,
region: process.env.AWS_REGION,
forcePathStyle: true,
});
// upload
await s3.send(new PutObjectCommand({ Bucket: "midia-site", Key: "img/foto.jpg", Body: fs.createReadStream("foto.jpg"), ContentType: "image/jpeg" }));
// link temporário (15 min)
const url = await getSignedUrl(s3, new GetObjectCommand({ Bucket: "backups-vps", Key: "relatorio.pdf" }), { expiresIn: 900 });
Python (boto3)
import boto3, os
s3 = boto3.client("s3", endpoint_url=os.environ["S3_ENDPOINT"])
s3.upload_file("foto.jpg", "midia-site", "img/foto.jpg", ExtraArgs={"ContentType": "image/jpeg"})
s3.download_file("backups-vps", "relatorio.pdf", "relatorio.pdf")
url = s3.generate_presigned_url("get_object", Params={"Bucket": "backups-vps", "Key": "relatorio.pdf"}, ExpiresIn=900)
PHP (aws/aws-sdk-php)
$s3 = new Aws\S3\S3Client([
'version' => 'latest', 'region' => getenv('AWS_REGION'),
'endpoint' => getenv('S3_ENDPOINT'), 'use_path_style_endpoint' => true,
]);
$s3->putObject(['Bucket' => 'midia-site', 'Key' => 'img/foto.jpg', 'SourceFile' => 'foto.jpg']);
$cmd = $s3->getCommand('GetObject', ['Bucket' => 'backups-vps', 'Key' => 'relatorio.pdf']);
$url = (string) $s3->createPresignedRequest($cmd, '+15 minutes')->getUri();
Laravel: no config/filesystems.php, disco s3 com 'endpoint' => env('S3_ENDPOINT') e 'use_path_style_endpoint' => true; depois Storage::disk('s3')->put(...).
WordPress: plugins de "offload media" (ex.: WP Offload Media, Media Cloud) aceitam provedor "S3 compatível" com endpoint personalizado.
Erros comuns
SignatureDoesNotMatch: região diferente entre cliente e servidor, ou relógio fora de hora.PermanentRedirect/ tentativa de acessarbucket.amazonaws.com: faltou o endpoint ou o path-style.- Upload grande falhando: use o upload multipart do SDK (
Uploadno Node,upload_filejá faz isso no Python).