Skip to content

Compatibilità S3

Usa l'AWS SDK per caricare, scaricare e gestire file su IPFS Ninja con lo stesso codice che usi per Amazon S3.

Endpoint

https://s3.ipfs.ninja

Credenziali

L'API S3 usa la tua chiave API di IPFS Ninja per l'autenticazione. La tua chiave API funge sia da access key che da secret key.

Come ottenere le credenziali

  1. Vai su Dashboard > API Keys
  2. Clicca Create API key e assegna un nome (es. "S3 access")
  3. Copia subito la chiave completa — viene mostrata una sola volta e non può essere recuperata in seguito

La tua chiave si presenta così:

bws_628bba35e9e0079d9ff9c392b1b55a7b
├──────────┘└──────────────────────────┘
 prefix (12 chars)    rest of key

Mappatura sulle credenziali AWS

Parametro AWSValoreEsempio
accessKeyIdPrimi 12 caratteri della tua chiave APIbws_628bba35
secretAccessKeyLa chiave API completa (tutti i 36 caratteri)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionSempre us-east-1us-east-1

WARNING

La chiave API completa viene mostrata una sola volta al momento della creazione. Se la perdi, elimina la chiave e creane una nuova dalla pagina API Keys.

Avvio Rapido

javascript
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: "https://s3.ipfs.ninja",
  credentials: {
    accessKeyId: "bws_628bba35",
    secretAccessKey: "bws_628bba35e9e0079d9ff9c392b1b55a7b"
  },
  region: "us-east-1",
  forcePathStyle: true
});

// Upload a file
const put = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "hello.json",
  Body: JSON.stringify({ hello: "IPFS" }),
  ContentType: "application/json"
}));

console.log("CID:", put.Metadata?.cid);
// CID: bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi

Bucket = Cartelle

I bucket S3 corrispondono alle tue cartelle su IPFS Ninja. Quando carichi un file in un bucket, viene salvato nella cartella corrispondente. Quando elenchi gli oggetti in un bucket, vedi i file in quella cartella.

Operazione S3Equivalente IPFS Ninja
CreateBucketCrea una nuova cartella
ListBucketsElenca le tue cartelle
DeleteBucketElimina una cartella e tutti i file al suo interno
PutObject nel bucketCarica un file nella cartella
ListObjectsV2 sul bucketElenca i file nella cartella
javascript
import { ListBucketsCommand, CreateBucketCommand, PutObjectCommand } from "@aws-sdk/client-s3";

// Create a bucket (= create a folder)
await s3.send(new CreateBucketCommand({ Bucket: "nft-metadata" }));

// Upload a file into the folder
await s3.send(new PutObjectCommand({
  Bucket: "nft-metadata",      // ← folder name
  Key: "token-42.json",        // ← filename within the folder
  Body: JSON.stringify({ name: "My NFT #42" })
}));

// List buckets (= list your folders)
const { Buckets } = await s3.send(new ListBucketsCommand({}));
console.log(Buckets);
// [{ Name: "nft-metadata", CreationDate: "2026-04-13T..." }]

TIP

Le cartelle create tramite l'API S3 sono le stesse visibili nella tua Dashboard. Puoi organizzare i file dall'API S3, dalla REST API o dall'interfaccia web — condividono tutti lo stesso sistema di cartelle.

INFO

A differenza di Amazon S3, le cartelle di IPFS Ninja sono piatte per impostazione predefinita. Per creare strutture annidate, usa gli endpoint delle cartelle della REST API con parentFolderId. Dall'API S3, usa i prefissi delle chiavi (es. images/photo.png) per organizzare i file all'interno di una cartella.

I nomi dei bucket sono univoci a livello globale

I nomi dei bucket vivono in uno spazio dei nomi globale, condiviso da tutti i clienti, in linea con la semantica di Amazon S3. Questo significa che:

  • Il primo utente che crea un bucket con un determinato nome si aggiudica quel nome a livello globale.
  • Le successive chiamate a CreateBucket con lo stesso nome, da qualsiasi account, restituiscono BucketAlreadyExists (409).
  • Se provi a ricreare un tuo bucket già esistente, ottieni BucketAlreadyOwnedByYou (409).
  • Il nome della tua cartella nella dashboard è per-account e può comunque essere qualsiasi cosa — solo il nome del bucket visibile tramite S3 passa attraverso lo spazio dei nomi globale.

Se il nome che desideri è già occupato, scegline uno più specifico (myapp-photos-2026, acme-nft-metadata) — la stessa convenzione che useresti su Amazon S3.

Operazioni Supportate

PutObject

Carica un file su IPFS. Il file viene pinnato, sottoposto a scansione di sicurezza, e il CID viene restituito negli header ETag e x-amz-meta-cid.

Per importare un file CAR invece di un file normale, aggiungi l'header di metadati x-amz-meta-import: car. Consulta CAR Import per i dettagli.

javascript
import { PutObjectCommand } from "@aws-sdk/client-s3";
import fs from "fs";

const result = await s3.send(new PutObjectCommand({
  Bucket: "my-project",
  Key: "photo.png",
  Body: fs.readFileSync("photo.png"),
  ContentType: "image/png"
}));

console.log("CID:", result.ETag);
bash
# curl equivalent
curl -X PUT "https://s3.ipfs.ninja/my-project/photo.png" \
  --data-binary @photo.png \
  -H "Content-Type: image/png" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  --user "bws_628bba35:bws_628bba35e9e0079d9ff9c392b1b55a7b"

GetObject

Scarica un file tramite la sua chiave (nome file) o CID.

javascript
import { GetObjectCommand } from "@aws-sdk/client-s3";

const result = await s3.send(new GetObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

const body = await result.Body.transformToByteArray();
console.log("Size:", body.length);
console.log("CID:", result.Metadata?.cid);

HeadObject

Ottieni i metadati del file senza scaricare il contenuto.

javascript
import { HeadObjectCommand } from "@aws-sdk/client-s3";

const head = await s3.send(new HeadObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

console.log("Size:", head.ContentLength);
console.log("Type:", head.ContentType);
console.log("CID:", head.Metadata?.cid);

DeleteObject

Rimuovi il pin di un file da IPFS ed eliminalo dal tuo account.

javascript
import { DeleteObjectCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteObjectCommand({
  Bucket: "my-project",
  Key: "photo.png"
}));

ListObjectsV2

Elenca i file in un bucket con filtro opzionale per prefisso e paginazione.

javascript
import { ListObjectsV2Command } from "@aws-sdk/client-s3";

const list = await s3.send(new ListObjectsV2Command({
  Bucket: "my-project",
  Prefix: "images/",
  MaxKeys: 100
}));

for (const obj of list.Contents ?? []) {
  console.log(obj.Key, obj.Size, obj.ETag); // ETag = CID
}

Multipart Upload

Carica file di grandi dimensioni (fino a 5 GB) usando il multipart upload. L'AWS SDK lo gestisce automaticamente:

javascript
import { Upload } from "@aws-sdk/lib-storage";
import fs from "fs";

const upload = new Upload({
  client: s3,
  params: {
    Bucket: "my-project",
    Key: "large-dataset.tar.gz",
    Body: fs.createReadStream("large-dataset.tar.gz"),
    ContentType: "application/gzip"
  },
  partSize: 10 * 1024 * 1024, // 10 MB per part
});

upload.on("httpUploadProgress", (progress) => {
  console.log(`Uploaded ${progress.loaded} of ${progress.total} bytes`);
});

const result = await upload.done();
console.log("CID:", result.ETag);

Oppure controlla le parti manualmente:

javascript
import {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand
} from "@aws-sdk/client-s3";

// 1. Start
const { UploadId } = await s3.send(new CreateMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin"
}));

// 2. Upload parts
const part1 = await s3.send(new UploadPartCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  PartNumber: 1,
  Body: chunk1
}));

// 3. Complete
const result = await s3.send(new CompleteMultipartUploadCommand({
  Bucket: "my-project",
  Key: "big-file.bin",
  UploadId,
  MultipartUpload: {
    Parts: [{ PartNumber: 1, ETag: part1.ETag }]
  }
}));

Esempio Python

python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.ipfs.ninja",
    aws_access_key_id="bws_628bba35",
    aws_secret_access_key="bws_628bba35e9e0079d9ff9c392b1b55a7b",
    region_name="us-east-1"
)

# Upload
s3.put_object(
    Bucket="my-project",
    Key="data.json",
    Body=b'{"hello": "IPFS"}',
    ContentType="application/json"
)

# List files
response = s3.list_objects_v2(Bucket="my-project")
for obj in response.get("Contents", []):
    print(obj["Key"], obj["Size"])

# Download
result = s3.get_object(Bucket="my-project", Key="data.json")
print(result["Body"].read())

Esempio Go

go
package main

import (
    "context"
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    client := s3.New(s3.Options{
        BaseEndpoint: aws.String("https://s3.ipfs.ninja"),
        Region:       "us-east-1",
        Credentials:  credentials.NewStaticCredentialsProvider("bws_628bba35", "bws_628bba35e9e0...", ""),
        UsePathStyle: true,
    })

    _, err := client.PutObject(context.TODO(), &s3.PutObjectInput{
        Bucket:      aws.String("my-project"),
        Key:         aws.String("hello.txt"),
        Body:        strings.NewReader("Hello, IPFS!"),
        ContentType: aws.String("text/plain"),
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Uploaded!")
}

Configurare CORS (accesso dall'SDK nel browser)

Se chiami l'API S3 direttamente da JavaScript nel browser (SPA, wallet app, strumento della dashboard), devi prima configurare CORS sul bucket. Altrimenti i browser bloccano il preflight e i tuoi upload falliscono con No 'Access-Control-Allow-Origin' header is present.

Stessa struttura di Amazon S3 — le sottorisorse PutBucketCors / GetBucketCors / DeleteBucketCors:

PutBucketCors

javascript
import { S3Client, PutBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new PutBucketCorsCommand({
  Bucket: "my-bucket",
  CORSConfiguration: {
    CORSRules: [{
      AllowedOrigins: ["http://localhost:3000", "https://myapp.com"],
      AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE"],
      AllowedHeaders: ["*"],
      ExposeHeaders: ["ETag", "x-amz-meta-cid", "x-amz-request-id"],
      MaxAgeSeconds: 3600,
    }],
  },
}));

GetBucketCors

javascript
import { GetBucketCorsCommand } from "@aws-sdk/client-s3";

const { CORSRules } = await s3.send(new GetBucketCorsCommand({ Bucket: "my-bucket" }));
console.log(CORSRules);

DeleteBucketCors

javascript
import { DeleteBucketCorsCommand } from "@aws-sdk/client-s3";

await s3.send(new DeleteBucketCorsCommand({ Bucket: "my-bucket" }));

Limite e valori predefiniti

  • Fino a 5 regole per bucket (la specifica ne consente 100; noi imponiamo un limite di 5 per mantenere compatta la risposta di preflight del browser).
  • Configurazione totale limitata a 64 KB serializzati.
  • Se non è impostata alcuna configurazione CORS, i preflight del browser vengono rifiutati — in linea con il comportamento predefinito di Amazon S3. Configura regole esplicite per le origini da cui servi effettivamente il tuo sito.

Nota sulla sicurezza nel mondo reale

CORS è un livello di comodità lato browser, non un confine di sicurezza. Ogni chiamata all'API S3 richiede comunque una firma SigV4 valida calcolata a partire dalla tua chiave API — una configurazione CORS permissiva non consente a chiunque di usare il tuo bucket senza quella credenziale. Ciò che CORS previene è che un'origine non voluta (es. una copia obsoleta della tua app su dev.myapp.com) invii richieste firmate da un contesto browser.

Alternativa via dashboard

La pagina Files ha una voce S3 CORS nel menu azioni di ogni cartella. Stesso storage sottostante; se non vuoi scrivere codice per PutBucketCors, configuralo da lì.

Differenze rispetto ad Amazon S3

CaratteristicaAmazon S3IPFS Ninja S3
Modello di archiviazioneOggetti mutabiliContent-addressed (CID immutabili)
Comportamento di sovrascritturaSostituisce l'oggetto sul postoCrea un nuovo CID, il vecchio CID resta accessibile
VersioningSupportatoNon supportato (usa i CID per il versioning)
Crittografia lato serverSupportataNon supportata (il contenuto è su IPFS)
Lifecycle policiesSupportateNon supportate
Bucket policies / ACLSupportateUsa le modalità di accesso gateway
Presigned URLSupportatiUsa i signed upload token
Dimensione massima oggetto5 TB5 GB (multipart), 100 MB (single PUT)
Valore ETagHash MD5IPFS CID
Header aggiuntiviS3 standardx-amz-meta-cid (IPFS CID)
Formato CIDN/ACIDv1 moderno (bafy…) per i nuovi upload; il formato legacy Qm… resta valido in input
Spazio dei nomi bucketGlobale (a livello AWS)Globale (tra tutti gli account IPFS Ninja) — stessa semantica
CORSPutBucketCors supportatoPutBucketCors supportato (limite di 5 regole)

Migrazione da Amazon S3

Sostituisci la configurazione del tuo client S3:

diff
 const s3 = new S3Client({
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "AKIA...",
-    secretAccessKey: "wJalrX..."
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
+  forcePathStyle: true
 });

Le tue chiamate PutObject, GetObject, ListObjectsV2 e DeleteObject esistenti funzionano senza modifiche.

Migrazione da Filebase

Sostituisci l'URL dell'endpoint:

diff
 const s3 = new S3Client({
-  endpoint: "https://s3.filebase.com",
+  endpoint: "https://s3.ipfs.ninja",
   credentials: {
-    accessKeyId: "FILEBASE_KEY",
-    secretAccessKey: "FILEBASE_SECRET"
+    accessKeyId: "bws_628bba35",
+    secretAccessKey: "bws_628bba35e9e0..."
   },
   region: "us-east-1",
   forcePathStyle: true
 });