Skip to content

S3-Kompatibilität

Verwende das AWS SDK, um Dateien auf IPFS Ninja hochzuladen, herunterzuladen und zu verwalten — mit demselben Code, den du für Amazon S3 verwendest.

Endpoint

https://s3.ipfs.ninja

Zugangsdaten

Die S3 API verwendet deinen IPFS Ninja API-Schlüssel zur Authentifizierung. Dein API-Schlüssel dient gleichzeitig als Access Key und Secret Key.

So erhältst du deine Zugangsdaten

  1. Gehe zu Dashboard > API Keys
  2. Klicke auf Create API key und vergib einen Namen (z.B. „S3-Zugang")
  3. Kopiere den vollständigen Schlüssel sofort — er wird nur einmal angezeigt und kann später nicht mehr abgerufen werden

Dein Schlüssel sieht so aus:

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

Zuordnung zu AWS-Zugangsdaten

AWS-ParameterWertBeispiel
accessKeyIdErste 12 Zeichen deines API-Schlüsselsbws_628bba35
secretAccessKeyDer vollständige API-Schlüssel (alle 36 Zeichen)bws_628bba35e9e0079d9ff9c392b1b55a7b
regionImmer us-east-1us-east-1

WARNING

Der vollständige API-Schlüssel wird nur einmal angezeigt, wenn du ihn erstellst. Falls du ihn verlierst, lösche den Schlüssel und erstelle einen neuen auf der API Keys-Seite.

Schnellstart

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

Buckets = Ordner

S3-Buckets entsprechen deinen IPFS Ninja-Ordnern. Wenn du eine Datei in einen Bucket hochlädst, wird sie im entsprechenden Ordner gespeichert. Wenn du Objekte in einem Bucket auflistest, siehst du die Dateien in diesem Ordner.

S3-OperationIPFS Ninja-Entsprechung
CreateBucketNeuen Ordner erstellen
ListBucketsDeine Ordner auflisten
DeleteBucketOrdner und alle Dateien darin löschen
PutObject in BucketDatei in den Ordner hochladen
ListObjectsV2 auf BucketDateien im Ordner auflisten
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

Ordner, die über die S3 API erstellt werden, sind dieselben Ordner, die in deinem Dashboard sichtbar sind. Du kannst Dateien über die S3 API, die REST API oder die Weboberfläche organisieren — alle nutzen dasselbe Ordnersystem.

INFO

Anders als bei Amazon S3 sind IPFS Ninja-Ordner standardmäßig flach. Um verschachtelte Strukturen zu erstellen, verwende die Ordner-Endpoints der REST API mit parentFolderId. Über die S3 API kannst du Schlüssel-Präfixe (z.B. images/photo.png) verwenden, um innerhalb eines Ordners zu organisieren.

Bucket-Namen sind global eindeutig

Bucket-Namen leben in einem globalen Namensraum über alle Kunden hinweg, entsprechend der AWS-S3-Semantik. Das bedeutet:

  • Der erste Benutzer, der einen Bucket mit einem bestimmten Namen erstellt, beansprucht diesen Namen global.
  • Spätere CreateBucket-Aufrufe mit demselben Namen von einem beliebigen Konto geben BucketAlreadyExists (409) zurück.
  • Wenn du versuchst, deinen eigenen Bucket erneut zu erstellen, erhältst du BucketAlreadyOwnedByYou (409).
  • Dein Ordner-Name im Dashboard ist pro Konto vergeben und kann weiterhin beliebig sein — nur der S3-sichtbare Bucket-Name durchläuft den globalen Namensraum.

Wenn ein gewünschter Name bereits vergeben ist, wähle einen anders zugeschnittenen (myapp-photos-2026, acme-nft-metadata) — dieselbe Konvention wie bei Amazon S3.

Unterstützte Operationen

PutObject

Lade eine Datei auf IPFS hoch. Die Datei wird gepinnt, sicherheitsgeprüft, und der CID wird in den Headern ETag und x-amz-meta-cid zurückgegeben.

Um stattdessen eine CAR-Datei zu importieren, füge den Metadaten-Header x-amz-meta-import: car hinzu. Siehe CAR Import für Details.

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

Lade eine Datei anhand ihres Schlüssels (Dateiname) oder CID herunter.

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

Rufe Datei-Metadaten ab, ohne den Inhalt herunterzuladen.

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

Entferne das Pinning einer Datei von IPFS und lösche sie aus deinem Konto.

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

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

ListObjectsV2

Liste Dateien in einem Bucket auf, mit optionaler Präfix-Filterung und Paginierung.

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

Lade große Dateien (bis zu 5 GB) mit Multipart Upload hoch. Das AWS SDK erledigt dies automatisch:

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);

Oder steuere die Teile manuell:

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 }]
  }
}));

Python-Beispiel

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())

Go-Beispiel

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!")
}

CORS konfigurieren (Zugriff per Browser-SDK)

Wenn du die S3 API direkt aus Browser-JavaScript heraus aufrufst (SPA, Wallet-App, Dashboard-Tool), musst du zuerst CORS für den Bucket konfigurieren. Andernfalls blockieren Browser das Preflight, und deine Uploads schlagen mit No 'Access-Control-Allow-Origin' header is present fehl.

Gleiches Prinzip wie bei AWS S3 — die Subresourcen 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" }));

Obergrenze und Standardwerte

  • Bis zu 5 Regeln pro Bucket (die Spezifikation erlaubt 100; wir begrenzen auf 5, um die Browser-Preflight-Antwort kompakt zu halten).
  • Die gesamte Konfiguration ist auf 64 KB serialisiert begrenzt.
  • Wenn keine CORS-Konfiguration gesetzt ist, werden Browser-Preflights abgelehnt — entsprechend der Standardhaltung von AWS S3. Konfiguriere explizite Regeln für die Origins, von denen du tatsächlich ausgehst.

Sicherheitshinweis aus der Praxis

CORS ist eine browserseitige Komfortschicht, keine Sicherheitsgrenze. Jeder S3-API-Aufruf erfordert weiterhin eine gültige SigV4-Signatur, die aus deinem API-Schlüssel berechnet wird — eine großzügige CORS-Konfiguration erlaubt niemandem, deinen Bucket ohne diese Zugangsdaten zu nutzen. Was CORS verhindert: dass ein unbeabsichtigter Origin (z.B. eine veraltete Kopie deiner App auf dev.myapp.com) signierte Anfragen aus einem Browser-Kontext sendet.

Alternative über das Dashboard

Die Dateien-Seite hat einen S3 CORS-Eintrag im Aktionsmenü jedes Ordners. Gleicher zugrunde liegender Speicher; wenn du keinen PutBucketCors-Code schreiben möchtest, konfiguriere es dort.

Unterschiede zu Amazon S3

MerkmalAmazon S3IPFS Ninja S3
SpeichermodellVeränderbare ObjekteInhaltsadressiert (unveränderliche CIDs)
ÜberschreibverhaltenErsetzt Objekt direktErstellt neuen CID, alter CID bleibt zugänglich
VersionierungUnterstütztNicht unterstützt (verwende CIDs zur Versionierung)
Serverseitige VerschlüsselungUnterstütztNicht unterstützt (Inhalt liegt auf IPFS)
Lifecycle-RichtlinienUnterstütztNicht unterstützt
Bucket-Richtlinien / ACLsUnterstütztVerwende Gateway-Zugriffsmodi
Vorsignierte URLsUnterstütztVerwende signierte Upload-Tokens
Maximale Objektgröße5 TB5 GB (Multipart), 100 MB (einzelner PUT)
RegionenMulti-RegionNur us-east-1
ETag-WertMD5-HashIPFS CID
Zusätzliche HeaderStandard S3x-amz-meta-cid (IPFS CID)
CID-FormatNicht zutreffendModerne CIDv1 (bafy…) für neue Uploads; ältere Qm… bleiben als Eingabe gültig
Bucket-NamensraumGlobal (AWS-weit)Global (über alle IPFS-Ninja-Konten hinweg) — gleiche Semantik
CORSPutBucketCors unterstütztPutBucketCors unterstützt (Obergrenze 5 Regeln)

Migration von Amazon S3

Ersetze deine S3-Client-Konfiguration:

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
 });

Deine bestehenden Aufrufe von PutObject, GetObject, ListObjectsV2 und DeleteObject funktionieren unverändert weiter.

Migration von Filebase

Ersetze die Endpoint-URL:

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
 });