Skip to content

S3 호환성

AWS SDK를 사용하여 Amazon S3에서 사용하는 것과 동일한 코드로 IPFS Ninja의 파일을 업로드, 다운로드 및 관리할 수 있습니다.

Endpoint

https://s3.ipfs.ninja

인증 정보

S3 API는 인증에 IPFS Ninja API 키를 사용합니다. API 키가 access key와 secret key 모두의 역할을 합니다.

인증 정보 얻는 방법

  1. Dashboard > API Keys로 이동
  2. Create API key를 클릭하고 이름을 지정합니다 (예: "S3 access")
  3. 즉시 전체 키를 복사하세요 — 키는 한 번만 표시되며 나중에 다시 확인할 수 없습니다

키는 다음과 같은 형태입니다:

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

AWS 인증 정보 매핑

AWS 매개변수예시
accessKeyIdAPI 키의 처음 12자bws_628bba35
secretAccessKeyAPI 키 전체 (36자 모두)bws_628bba35e9e0079d9ff9c392b1b55a7b
region항상 us-east-1us-east-1

WARNING

전체 API 키는 생성 시 한 번만 표시됩니다. 분실한 경우 키를 삭제하고 API Keys 페이지에서 새 키를 생성하세요.

빠른 시작

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: QmXnnyufdzAWL5CqZ2RnSNgPbvCc1ALT73s6epPrRnZ1Xy

Bucket = 폴더

S3 bucket은 IPFS Ninja의 폴더에 매핑됩니다. bucket에 파일을 업로드하면 해당 폴더에 저장됩니다. bucket의 객체를 나열하면 해당 폴더의 파일이 표시됩니다.

S3 작업IPFS Ninja 대응
CreateBucket새 폴더 생성
ListBuckets폴더 목록 표시
DeleteBucket폴더와 내부의 모든 파일 삭제
PutObject (bucket으로)폴더에 파일 업로드
ListObjectsV2 (bucket에서)폴더의 파일 목록 표시
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

S3 API를 통해 생성한 폴더는 Dashboard에서 볼 수 있는 폴더와 동일합니다. S3 API, REST API 또는 웹 인터페이스 어디서든 파일을 정리할 수 있습니다 — 모두 같은 폴더 시스템을 공유합니다.

INFO

Amazon S3와 달리 IPFS Ninja의 폴더는 기본적으로 플랫합니다. 중첩된 구조를 만들려면 REST API의 폴더 endpoint에서 parentFolderId를 사용하세요. S3 API에서는 키 접두사(예: images/photo.png)를 사용하여 폴더 내 파일을 정리할 수 있습니다.

지원되는 작업

PutObject

파일을 IPFS에 업로드합니다. 파일은 핀 고정되고, 보안 검사를 거치며, CID가 ETagx-amz-meta-cid 헤더로 반환됩니다.

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

키(파일명) 또는 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

콘텐츠를 다운로드하지 않고 파일 메타데이터를 가져옵니다.

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

파일의 IPFS 핀을 해제하고 계정에서 삭제합니다.

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

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

ListObjectsV2

선택적 접두사 필터링 및 페이지네이션으로 bucket의 파일을 나열합니다.

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

멀티파트 업로드를 사용하여 대용량 파일(최대 5 GB)을 업로드합니다. AWS SDK가 자동으로 처리합니다:

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

또는 파트를 수동으로 제어:

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 예제

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 예제

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

Amazon S3와의 차이점

기능Amazon S3IPFS Ninja S3
스토리지 모델변경 가능한 객체콘텐츠 주소 지정(불변 CID)
덮어쓰기 동작객체를 제자리에서 교체새 CID 생성, 이전 CID는 여전히 접근 가능
Versioning지원미지원 (CID를 사용하여 버전 관리)
서버 측 암호화지원미지원 (콘텐츠가 IPFS에 있음)
수명 주기 정책지원미지원
Bucket 정책 / ACL지원gateway 액세스 모드 사용
Presigned URL지원서명된 업로드 토큰 사용
최대 객체 크기5 TB5 GB (multipart), 100 MB (single PUT)
리전다중 리전us-east-1만 지원
ETagMD5 해시IPFS CID
추가 헤더표준 S3x-amz-meta-cid (IPFS CID)

Amazon S3에서 마이그레이션

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

기존의 PutObject, GetObject, ListObjectsV2, DeleteObject 호출은 변경 없이 그대로 작동합니다.

Filebase에서 마이그레이션

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