Skip to content
Published on

파일 업로드 & 스토리지 도구 2026 — Uppy / UploadThing / Pinata IPFS / Cloudflare R2 / Backblaze B2 / Tigris / MinIO / tus protocol 심층 가이드

Authors

"파일을 받고 저장하는 일은 단순해 보이지만, 1GB 영상 한 개가 30번 재시도로 실패하는 순간 모든 추상화가 무너진다. 2026년의 파일 업로드는 더 이상 multipart/form-data가 아니다." — Transloadit Uppy 팀, 2024년 12월 인터뷰

파일 업로드는 거의 모든 서비스에서 필요하지만, 가장 자주 깨지는 기능 중 하나입니다. 모바일에서 4G로 1GB 영상을 올리다가 끊기면 처음부터 다시 받아야 하고, 사용자가 동시에 100명이 PDF를 업로드하면 메모리가 폭발합니다. 그리고 누군가는 반드시 .exe나 ZIP 폭탄을 던집니다.

2026년 5월 현재 파일 업로드와 객체 스토리지 생태계는 클라이언트 라이브러리(Client), 매니지드 SaaS(Managed), 셀프호스팅 OSS(Self-hosted), 탈중앙 스토리지(Decentralized) 네 분류로 분화되어 있고, 그 사이에 tus 프로토콜이라는 사실상의 표준이 정착했습니다. 이 글에서는 Uppy, UploadThing, Filestack, Cloudinary, ImageKit, AWS S3 Presigned URLs, Cloudflare R2, Backblaze B2, Tigris, Wasabi, Vercel Blob, Bunny Storage, MinIO, SeaweedFS, Garage, Pinata, Filebase, Storj DCS, Arweave, tus, ClamAV, Sublime Security까지 한 번에 정리합니다.

1. 2026년 파일 업로드 지도 — 4 분류

파일 업로드 인프라는 역할에 따라 크게 네 박스로 나눌 수 있습니다.

카테고리대표 제품역할
Client 라이브러리Uppy, UploadThing, Filestack JS, Cloudinary Widget, ImageKit JS브라우저/모바일에서 청크·재시도·UI를 처리
Managed SaaSUploadThing, Filestack, Cloudinary, ImageKit, Vercel Blob, BunnyAPI 한 줄로 업로드 + CDN + 변환
S3 호환 / Self-hostedAWS S3, Cloudflare R2, Backblaze B2, Wasabi, Tigris, MinIO, SeaweedFS, Garage객체 스토리지 인프라
DecentralizedPinata, Filebase, Storj DCS, ArweaveIPFS·Sia·Filecoin·Arweave 위의 영구/분산 저장

이 분류가 중요한 이유는, "어디에 저장할지(Storage)"와 "어떻게 올릴지(Transport)"가 서로 독립이기 때문입니다. Uppy(Client)는 백엔드를 S3 Presigned URL로도, Cloudflare R2로도, MinIO로도, 심지어 Pinata IPFS로도 보낼 수 있습니다. UploadThing 같은 풀스택 SaaS는 둘 다 묶어서 한 번에 팔지만, 본질은 Transport + Storage 두 레이어의 결합입니다.

또 한 가지 분기점은 트래픽(Egress) 비용 모델입니다. AWS S3는 GB당 약 0.09 USD의 외부 전송료를 받지만, Cloudflare R2와 Backblaze B2는 사실상 0 USD입니다. 영상·이미지처럼 CDN으로 자주 빠져나가는 콘텐츠라면 이 차이가 월 수천만 원 규모로 벌어집니다.

2026년의 또 다른 키워드는 resumable입니다. tus 프로토콜이 2024년 IETF Internet-Draft를 거쳐 사실상의 표준으로 자리잡았고, Uppy·UploadThing·Vercel Blob·Cloudflare R2 모두 tus를 1급으로 지원합니다. 1GB 파일이 99% 올라간 상태에서 와이파이가 끊겨도, 다시 99%부터 이어 올릴 수 있다는 뜻입니다.

2. Uppy (Transloadit) — 가장 인기있는 OSS 업로더

Uppy(uppy.io)는 Transloadit이 2017년 오픈소스로 공개한 모듈형 파일 업로더입니다. 2026년 5월 현재 GitHub 스타 30k 이상으로 클라이언트 사이드 업로더 카테고리에서 사실상의 표준입니다.

핵심 철학은 "플러그인 아키텍처"입니다. 코어는 1MB 미만이고, 필요한 기능만 플러그인으로 붙입니다.

// React + Uppy + tus + S3 + 웹캠 + 인스타그램
import Uppy from '@uppy/core'
import Dashboard from '@uppy/dashboard'
import Tus from '@uppy/tus'
import AwsS3 from '@uppy/aws-s3'
import Webcam from '@uppy/webcam'
import Instagram from '@uppy/instagram'

const uppy = new Uppy({
  restrictions: {
    maxFileSize: 1024 * 1024 * 1024, // 1GB
    maxNumberOfFiles: 10,
    allowedFileTypes: ['image/*', 'video/*', '.pdf', '.zip'],
  },
  autoProceed: false,
})
  .use(Dashboard, { inline: true, target: '#drag-drop' })
  .use(Webcam, { target: Dashboard })
  .use(Instagram, { companionUrl: 'https://companion.acme.dev' })
  .use(Tus, {
    endpoint: 'https://uploads.acme.dev/files/',
    chunkSize: 5 * 1024 * 1024, // 5MB 청크
    retryDelays: [0, 1000, 3000, 5000],
  })

이 한 덩어리에서 드래그앤드롭 UI, 진행률 바, 일시정지/재개, 청크 업로드, 재시도, 웹캠 캡처, 인스타그램 import까지 다 됩니다. 같은 코드에 @uppy/google-drive, @uppy/dropbox, @uppy/onedrive를 더하면 클라우드 import도 됩니다.

서버 사이드의 짝은 Companion(@uppy/companion)으로, OAuth를 받아 사용자의 Google Drive/Dropbox에서 직접 S3로 server-to-server 전송을 수행합니다. 브라우저가 큰 파일을 다운로드했다가 다시 업로드하는 낭비를 없애줍니다.

2025년 5월에 출시된 Uppy 4.0은 TypeScript를 1급으로 다시 작성하고 React/Vue/Svelte를 위한 공식 어댑터를 동봉했습니다. 같은 해 11월에는 Transloadit의 매니지드 변환 백엔드(@uppy/transloadit)와 통합이 강화되어, 업로드 직후 비디오 트랜스코딩·이미지 리사이즈·바이러스 스캔을 한 번에 트리거할 수 있습니다.

Uppy를 쓰면 좋은 시나리오는 자체 백엔드/스토리지를 이미 가진 팀이 클라이언트 UX만 빠르게 잡고 싶을 때입니다. UploadThing처럼 풀스택을 통째로 사기는 부담스럽고, 직접 multipart 업로드를 짜고 싶지도 않은 중간 지대에 정확히 들어맞습니다.

3. UploadThing — Vercel 친화 TS-first

UploadThing(uploadthing.com)은 2023년 Theo Browne(t3.gg)이 만들고 2024년 Y Combinator에 합류한 TypeScript 우선 업로드 SaaS입니다. 2025년 시리즈 A를 받았고, Vercel 생태계에서 가장 빠르게 성장한 스토리지 제품입니다.

핵심 차별점은 "Next.js와의 0-config 통합"과 "타입-안전한 파일 라우터"입니다.

// app/api/uploadthing/core.ts
import { createUploadthing, type FileRouter } from 'uploadthing/next'
import { auth } from '@/auth'

const f = createUploadthing()

export const ourFileRouter = {
  imageUploader: f({ image: { maxFileSize: '4MB', maxFileCount: 4 } })
    .middleware(async ({ req }) => {
      const session = await auth()
      if (!session?.user) throw new Error('Unauthorized')
      return { userId: session.user.id }
    })
    .onUploadComplete(async ({ metadata, file }) => {
      await db.media.create({
        data: { userId: metadata.userId, url: file.url, key: file.key },
      })
    }),

  pdfUploader: f({ pdf: { maxFileSize: '32MB' } })
    .middleware(async () => ({ userId: 'pdf-user' }))
    .onUploadComplete(async ({ file }) => {
      console.log('PDF uploaded:', file.url)
    }),
} satisfies FileRouter

export type OurFileRouter = typeof ourFileRouter

클라이언트 쪽은 <UploadButton endpoint="imageUploader" /> 한 줄이면 끝납니다. 라우터 타입이 그대로 컴포넌트로 흘러들어가서, 잘못된 endpoint 이름을 적으면 TypeScript가 잡아냅니다.

UploadThing의 백엔드는 처음에는 AWS S3 + Cloudflare 위에 자체 구축되어 있었지만, 2025년부터는 사용자 BYOS(Bring Your Own Storage)도 지원합니다. R2, S3, Vercel Blob 중 원하는 곳에 보낼 수 있고, 변환 파이프라인은 그대로 사용할 수 있습니다.

2026년 1월에 추가된 UTApi는 서버에서 파일을 직접 다루는 API로, 파일 삭제·메타데이터 수정·URL 갱신을 SDK 한 줄로 처리합니다.

import { UTApi } from 'uploadthing/server'

const utapi = new UTApi()
await utapi.deleteFiles(['key1', 'key2'])
await utapi.getFileUrls(['key1']) // 임시 서명 URL

UploadThing이 잘 맞는 곳은 Next.js + Vercel + Auth.js 스택의 1인~소규모 팀입니다. Stripe처럼 "5분 안에 결제 붙이듯 5분 안에 업로드를 붙이는" UX가 목표입니다.

4. Filestack / Cloudinary / ImageKit — 매니지드 미디어

매니지드 미디어 카테고리는 업로드 + CDN + 변환을 한 묶음으로 파는 시장입니다. 세 회사가 13년 가까이 경쟁하고 있습니다.

Filestack(filestack.com)은 2012년 창업한 가장 오래된 플레이어로, 2019년 Idera에 인수되었습니다. 강점은 40개 이상의 외부 소스(Facebook, Instagram, Box, Dropbox, OneDrive 등)에서 직접 import할 수 있는 Picker 위젯과, 이미지·문서·동영상을 한 API로 변환할 수 있는 Transformation Engine입니다.

<script src="//static.filestackapi.com/filestack-js/3.x.x/filestack.min.js"></script>
<script>
  const client = filestack.init('YOUR_API_KEY')
  client.picker({
    accept: ['image/*', 'application/pdf'],
    fromSources: ['local_file_system', 'instagram', 'gmail', 'webcam'],
    maxFiles: 5,
    transformations: { crop: { aspectRatio: 1 / 1, force: true } },
  }).open()
</script>

Cloudinary(cloudinary.com)는 2012년 이스라엘에서 시작한 미디어 전문 SaaS로, 2026년 기준 가장 큰 매니지드 미디어 사업자입니다. 이미지·동영상에 특화된 URL 기반 변환이 핵심입니다. 예를 들어 https://res.cloudinary.com/demo/image/upload/w_300,h_300,c_fill,f_auto,q_auto/sample.jpg처럼 URL 파라미터에 변환을 적으면 자동으로 WebP/AVIF로 인코딩되고 캐시됩니다.

업로드 위젯(cloudinary.openUploadWidget)은 외부 소스 14개와 webcam·screenshot 캡처를 지원하고, 2024년부터는 AI 기반 자동 태깅·자동 크로핑(c_auto)·배경 제거를 기본 제공합니다.

ImageKit(imagekit.io)은 2017년 인도에서 시작한 후발주자로, 가격과 성능을 무기로 빠르게 성장 중입니다. Cloudinary와 비슷한 URL 변환 API를 제공하면서 약 1/3 가격, AWS S3·R2·Backblaze 같은 외부 스토리지를 origin으로 연결(BYOS)할 수 있다는 점이 다릅니다. 직접 업로드(imagekit.upload(...))와 server-side 토큰 발급 패턴 모두 지원합니다.

세 제품을 한 표로:

제품강점약점가격대
Filestack외부 소스 가장 많음, 문서 변환비싸고 무거움월 99 USD부터
Cloudinary이미지·동영상 변환 깊이, AI 기능가격, 학습 곡선Free 25 credits, 그 이상 종량
ImageKitBYOS, 가격 효율변환 깊이 살짝 부족Free 20GB, 그 이상 종량

5. AWS S3 Presigned URLs — DIY 클래식

가장 오래된, 그리고 여전히 가장 흔한 패턴은 AWS S3 Presigned URL입니다. 2006년 S3 출시 이후 거의 그대로인 패턴으로, 서버가 임시 서명된 PUT URL을 발급해주고 브라우저가 그 URL로 직접 S3에 PUT을 날립니다.

// 서버: Next.js Route Handler
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const s3 = new S3Client({ region: 'ap-northeast-2' })

export async function POST(req: Request) {
  const { filename, contentType } = await req.json()
  const key = `uploads/${Date.now()}-${filename}`
  const command = new PutObjectCommand({
    Bucket: 'acme-uploads',
    Key: key,
    ContentType: contentType,
  })
  const url = await getSignedUrl(s3, command, { expiresIn: 60 * 5 })
  return Response.json({ url, key })
}
// 클라이언트
async function upload(file: File) {
  const res = await fetch('/api/presign', {
    method: 'POST',
    body: JSON.stringify({ filename: file.name, contentType: file.type }),
  })
  const { url, key } = await res.json()
  await fetch(url, {
    method: 'PUT',
    headers: { 'Content-Type': file.type },
    body: file,
  })
  return key
}

이 패턴의 강점은 서버를 거치지 않는다는 점입니다. 5GB 파일을 올려도 우리 Next.js 서버의 메모리·대역폭은 0이고, 모든 부하가 S3로 직접 갑니다. 인증·검증·로깅은 서명 발급 단계에서만 일어납니다.

약점은 재시도와 진행률을 직접 짜야 한다는 점입니다. fetch는 progress 이벤트를 안 주기 때문에 XMLHttpRequest나 axios의 onUploadProgress를 써야 하고, 5GB 이상은 Multipart Upload가 강제됩니다. 그래서 실무에서는 거의 항상 Uppy @uppy/aws-s3-multipart 플러그인과 함께 씁니다.

같은 패턴이 Cloudflare R2, Backblaze B2, Wasabi, MinIO, Tigris에서도 그대로 동작합니다. S3 API를 따른다는 한 줄이 객체 스토리지 시장 전체를 표준화한 결과입니다.

6. Cloudflare R2 — egress 수수료 없음

Cloudflare R2(developers.cloudflare.com/r2)는 2022년 GA된 S3 호환 객체 스토리지로, 단 한 가지 마케팅 메시지로 시장을 흔들었습니다. "egress(외부 전송) 비용 0 USD."

AWS S3에서 1TB의 이미지를 사용자에게 서빙하면 약 90 USD의 전송료를 내야 하지만, R2에서는 0 USD입니다. 저장 비용도 GB당 0.015 USD로 S3의 0.023 USD보다 35% 저렴합니다.

// R2는 S3 SDK를 그대로 씀
import { S3Client } from '@aws-sdk/client-s3'

const r2 = new S3Client({
  region: 'auto',
  endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY!,
    secretAccessKey: process.env.R2_SECRET_KEY!,
  },
})

R2의 진짜 강점은 Cloudflare Workers·Pages·CDN과의 통합입니다. R2 버킷을 Workers에 바인딩하면 SDK 없이 env.MY_BUCKET.put(key, body)로 바로 쓸 수 있고, Workers는 같은 글로벌 네트워크에서 동작합니다.

// Cloudflare Workers + R2
export default {
  async fetch(req: Request, env: Env) {
    const key = new URL(req.url).pathname.slice(1)
    if (req.method === 'PUT') {
      await env.MY_BUCKET.put(key, req.body, {
        httpMetadata: { contentType: req.headers.get('content-type') ?? '' },
      })
      return new Response('ok')
    }
    const obj = await env.MY_BUCKET.get(key)
    if (!obj) return new Response('not found', { status: 404 })
    return new Response(obj.body, { headers: { 'content-type': obj.httpMetadata?.contentType ?? '' } })
  },
}

2024년에 추가된 R2 Custom Domain + Cache Reserve는 R2 객체를 자동으로 Cloudflare CDN에 캐시해, 첫 요청 외에는 R2 GET 비용조차 들지 않습니다. 2025년 출시된 R2 Data Catalog(Iceberg 호환)은 R2를 Lakehouse 백엔드로도 쓸 수 있게 합니다.

약점은 AWS S3와 100% 호환은 아니다라는 점입니다. Object Lambda, S3 Select, S3 Inventory 같은 고급 기능은 빠져 있습니다. 단순 PUT/GET/LIST + Multipart Upload + Presigned URL만 쓰는 90% 시나리오에는 거의 차이가 없습니다.

7. Backblaze B2 / Wasabi / Tigris — S3 호환 + 가성비

S3 호환 + 가성비 카테고리는 R2가 등장하기 전부터 존재했고, 각자의 포지션이 다릅니다.

Backblaze B2(backblaze.com/b2)는 2015년 출시된 가장 오래된 S3 대안입니다. GB당 0.006 USD로 R2보다도 싸고, Cloudflare와의 "Bandwidth Alliance" 덕에 B2에서 Cloudflare CDN으로 빠지는 트래픽은 무료입니다. 2026년 5월 현재 미디어 백업·아카이브 시장에서 가장 큰 점유율을 가집니다.

# B2 CLI
b2 authorize-account $KEY_ID $APP_KEY
b2 upload-file my-bucket video.mp4 videos/2026/may.mp4
b2 download-file-by-name my-bucket videos/2026/may.mp4 ./local.mp4

Wasabi(wasabi.com)는 2017년 창업한 S3 호환 스토리지로, GB당 0.0068 USD에 egress 무료가 핵심입니다. AWS S3 베테랑이 만들어 호환성이 매우 높고, "Hot Storage" 가격 모델 하나로 단순합니다. 단점은 30일 최소 보관 기간이 있어, 자주 지우는 트랜잭션 데이터에는 비효율적입니다.

Tigris(tigrisdata.com)는 Fly.io가 후원하는 2024년 출시 신규 S3 호환 스토리지로, 글로벌 자동 복제가 차별점입니다. 객체를 PUT하면 자동으로 가장 가까운 리전부터 점진적으로 전 세계로 복제되어, 첫 GET이 어디서 와도 빠릅니다. Fly.io 위에서 동작하는 앱에는 라우팅 비용이 0입니다.

// Tigris는 S3 SDK 그대로
const tigris = new S3Client({
  region: 'auto',
  endpoint: 'https://fly.storage.tigris.dev',
  credentials: { accessKeyId: KEY, secretAccessKey: SECRET },
})

가격 비교(2026년 5월, 표준 핫 스토리지 기준):

제품저장 (GB/월)egress (GB)특징
AWS S3 Standard0.023 USD0.09 USD표준
Cloudflare R20.015 USD0 USDWorkers/CDN 통합
Backblaze B20.006 USD0 USD (Cloudflare)가장 저렴
Wasabi0.0068 USD0 USD30일 최소 보관
Tigris0.02 USD0 USD글로벌 복제 자동

8. Vercel Blob / Bunny Storage — 클라우드 빌트인

플랫폼이 직접 제공하는 빌트인 스토리지도 빠르게 성장 중입니다.

Vercel Blob(vercel.com/storage/blob)은 2024년 GA된 Vercel의 S3 호환 스토리지로, Cloudflare R2 위에 얹어진 매니지드 레이어입니다. 핵심은 Vercel 함수에서 SDK 한 줄로 업로드할 수 있고, 자동으로 Vercel Edge CDN에 캐시된다는 점입니다.

// app/api/upload/route.ts
import { put } from '@vercel/blob'

export async function POST(req: Request) {
  const file = (await req.formData()).get('file') as File
  const blob = await put(`uploads/${file.name}`, file, {
    access: 'public',
    addRandomSuffix: true,
  })
  return Response.json(blob)
}

큰 파일은 클라이언트가 직접 올리는 패턴도 지원합니다. @vercel/blob/clientupload(...)는 서버에 토큰만 요청하고 본문은 Vercel Blob으로 직접 PUT을 보냅니다. Vercel Functions의 4.5MB body limit를 우회하는 핵심 패턴입니다.

Bunny Storage(bunny.net/storage)는 슬로베니아 기반 Bunny.net CDN의 객체 스토리지로, Bunny CDN과의 통합이 강점입니다. GB당 0.01 USD에 글로벌 11개 리전 복제, 자체 Pull Zone과 자동 연결되어 CDN 캐시까지 한 번에 설정됩니다. WordPress·Drupal 같은 레거시 CMS의 미디어 백엔드로 빠르게 자리잡았습니다.

# Bunny Storage API
curl -X PUT https://storage.bunnycdn.com/$STORAGE_ZONE/$PATH/file.jpg \
  -H "AccessKey: $ACCESS_KEY" \
  --data-binary @file.jpg

플랫폼 빌트인의 공통 장점은 인프라 결합도입니다. Vercel Blob은 Vercel Edge에서 가장 빠르고, Bunny Storage는 Bunny CDN에서 가장 빠릅니다. 약점은 lock-in으로, 나가는 순간 호환되는 SDK가 사라집니다.

9. MinIO — 셀프호스팅 S3-호환 OSS

기업이 자체 데이터센터에 객체 스토리지를 두고 싶을 때 사실상의 표준이 된 것이 MinIO(min.io)입니다. 2015년 출시된 Go 작성 OSS로, GitHub 스타 48k 이상입니다.

MinIO의 강점은 S3 API의 가장 완전한 호환 구현단일 바이너리 설치입니다.

# 단일 노드 (개발용)
docker run -p 9000:9000 -p 9001:9001 \
  -e "MINIO_ROOT_USER=admin" \
  -e "MINIO_ROOT_PASSWORD=secret123" \
  -v /data:/data \
  quay.io/minio/minio server /data --console-address ":9001"

# 분산 클러스터 (4노드, 각 4 디스크 = 16 erasure)
minio server http://node{1...4}/data{1...4} \
  --console-address ":9001"

MinIO는 Erasure Coding으로 노드/디스크의 일부가 실패해도 데이터를 잃지 않습니다. 16 디스크 중 8개까지 동시 실패해도 복구할 수 있는 구성이 기본이라, 사내 백업·머신러닝 데이터 레이크·CI 아티팩트 저장소 같은 시나리오에 강합니다.

2024년부터 MinIO는 AIStor라는 AI/ML 특화 브랜드로 리포지셔닝하면서, PyTorch·TensorFlow·NVIDIA NIM과의 직접 통합을 강조하고 있습니다. 같은 S3 호환 API 위에서 페타바이트급 학습 데이터를 다루는 시장을 노립니다.

상용 라이선스로 전환된 이슈가 있긴 합니다. 2025년 4월 MinIO는 AGPL v3에서 MinIO Commercial License(자체 라이선스)로 일부 기능을 옮겼습니다. 자체 SaaS 제품에 임베드하려면 상용 라이선스가 필요할 수 있어, OSS 순수파는 대안을 찾고 있습니다. 그 대안이 다음 장의 SeaweedFS와 Garage입니다.

10. SeaweedFS / Garage (Deuxfleurs) — 그 외 OSS

SeaweedFS(github.com/seaweedfs/seaweedfs)는 2014년 처음 공개된 Go 작성 분산 객체 스토리지로, "Haystack-스타일 + S3 호환"이 특징입니다. 페이스북이 사진 저장에 쓰던 Haystack 논문(2010)에서 영감을 받아, 수십억 개의 작은 파일을 효율적으로 저장하도록 설계되었습니다.

# SeaweedFS 마스터 + 볼륨 + S3 게이트웨이
weed master -mdir /data/master &
weed volume -dir /data/volumes -port 8080 -mserver localhost:9333 &
weed s3 -port 8333 -filer localhost:8888 &

특징:

  • 작은 파일에 강함 (메타데이터 오버헤드 최소화)
  • Filer를 통한 POSIX-like API도 제공
  • S3, WebDAV, FUSE, HDFS 게이트웨이 동시 노출
  • AGPL v3 (서버), Apache 2.0 (라이브러리)

Garage(garagehq.deuxfleurs.fr)는 프랑스 Deuxfleurs 콜렉티브가 2020년 시작한 신생 S3 호환 OSS로, "저전력·저자원 환경"이 특징입니다. Raspberry Pi 같은 ARM 보드 위에서, 가정용 인터넷 회선을 통해 분산 클러스터를 만들 수 있도록 설계되었습니다.

Garage의 차별점:

  • 100% Rust로 작성, 메모리 사용량 매우 적음
  • 멀티 리전·멀티 데이터센터 네이티브 지원
  • AGPL v3
  • 작은 클러스터(3~10 노드)에 최적화
# Garage 클러스터 (각 노드에서)
garage server &
# 노드 ID 교환 후
garage layout assign -z eu-west -c 1T <node-id>
garage layout apply --version 1

MinIO가 엔터프라이즈·페타바이트를 노린다면 Garage는 community-run, 자유 소프트웨어, 작은 인프라를 노립니다. Fediverse(마스토돈)·NextCloud 운영자가 자주 선택합니다.

11. Pinata — IPFS 호스팅

여기서부터는 분산 스토리지(Decentralized Storage) 카테고리입니다. Pinata(pinata.cloud)는 2018년 미국에서 창업한 IPFS 핀(pin) 서비스로, NFT·Web3 시장에서 사실상 표준입니다.

IPFS(InterPlanetary File System)는 콘텐츠의 해시(CID)로 파일을 식별하는 P2P 프로토콜입니다. 같은 파일은 어디에 저장되어 있든 같은 CID를 가지며, 한 번 핀하면 P2P 네트워크 어디서나 가져올 수 있습니다. 단점은 누군가는 핀을 유지해야 한다는 점이고, Pinata가 그 일을 SaaS로 팝니다.

import PinataSDK from 'pinata'

const pinata = new PinataSDK({
  pinataJwt: process.env.PINATA_JWT!,
  pinataGateway: 'https://gateway.pinata.cloud',
})

// 파일 업로드 + IPFS pin
const result = await pinata.upload.file(file)
console.log(result.IpfsHash) // "QmXxx..."

// 사용자 게이트웨이로 접근
const url = `https://gateway.pinata.cloud/ipfs/${result.IpfsHash}`

2024년 출시된 Pinata Files API는 IPFS Public 네트워크가 아니라 Pinata 전용 Private Network에 저장하는 새 모드를 추가했습니다. 일반 SaaS 스토리지처럼 빠르고, 원하면 IPFS Public으로 export할 수 있습니다. 이로써 Pinata는 "Web3 전용 SaaS"에서 "일반 객체 스토리지 + IPFS 옵션"으로 확장 중입니다.

NFT 시장에서 Pinata가 흔히 쓰이는 패턴은 OpenSea 호환 메타데이터를 IPFS에 핀하고, 그 CID를 스마트 컨트랙트에 적는 것입니다. 토큰 메타데이터가 영구적이며 검열 저항적이라는 보장을 줍니다.

12. Filebase / Storj DCS / Arweave — 탈중앙 + 영구 저장

분산 스토리지 카테고리에는 Pinata 외에도 다양한 백엔드가 있습니다.

Filebase(filebase.com)는 2019년 창업한 미국 회사로, S3 호환 API로 IPFS·Sia·Skynet·Filecoin 같은 분산 네트워크에 저장합니다. 사용자는 S3 SDK만 알면 되고, 뒤에서 어느 분산 네트워크를 쓸지는 버킷 설정으로 정합니다.

# Filebase는 S3 SDK 그대로
aws s3 cp ./photo.jpg s3://my-bucket/photo.jpg \
  --endpoint-url https://s3.filebase.com \
  --profile filebase

GB당 약 0.0059 USD로 저렴하고, 매 객체에 자동으로 IPFS CID가 부여됩니다.

Storj DCS(storj.io)는 2018년에 메인넷을 띄운 분산 스토리지로, 객체를 80개 조각(Reed-Solomon erasure)으로 쪼개 전 세계 1.5만 개 이상의 노드에 분산 저장합니다. 어느 한 노드가 죽어도 39개 조각만 있으면 복원되며, 어느 단일 노드도 데이터의 의미를 알 수 없도록 클라이언트 사이드 암호화됩니다.

uplink cp video.mp4 sj://my-bucket/video.mp4

가격은 GB당 0.004 USD, egress 0.007 USD로 R2와 거의 비슷합니다. AWS·Azure를 신뢰하지 않는 정부·연구·미디어 시장에서 점유율이 높습니다.

Arweave(arweave.org)는 다른 모두와 다른 카테고리입니다. 한 번 비용을 내면 200년 보관을 보장하는 영구 저장 블록체인입니다. 일반 객체 스토리지의 월 청구 모델 대신, 업로드 시점에 한 번 비용을 내고 영원히 보관됩니다.

# Bundlr/Irys 게이트웨이 사용
npx @irys/sdk fund 100000 -t arweave -w wallet.json
npx @irys/sdk upload file.jpg -t arweave -w wallet.json
# → Arweave Transaction ID 반환

비용은 GB당 약 5~10 USD로 매우 비싸지만, 영원이라는 보장이 따라옵니다. 법적 증거·언론 백업·과학 데이터·게임 자산처럼 "다시는 사라지지 않아야 하는" 콘텐츠에 쓰입니다. 2025년부터 솔라나·이더리움 백엔드도 Irys/Bundlr를 통해 같은 패턴을 지원해, "blockchain permanence" 마켓이 확장 중입니다.

13. tus 프로토콜 — resumable 업로드

tus.io는 2014년 Transloadit이 시작한 resumable upload 프로토콜로, 2026년 현재 IETF Internet-Draft 진행 중이며 사실상의 표준입니다. Uppy, UploadThing, Vimeo, Cloudflare R2, Vercel Blob, GitLab, ownCloud 등 거의 모든 메이저 서비스가 지원합니다.

핵심 아이디어는 HEAD로 현재까지 올라간 오프셋을 묻고, PATCH로 그 지점부터 이어 올린다는 단순한 규약입니다.

# 1) 업로드 생성
POST /files HTTP/1.1
Upload-Length: 1073741824
Upload-Metadata: filename dmlkZW8ubXA0
Tus-Resumable: 1.0.0
→ 201 Created
  Location: /files/abc123

# 2) 현재 오프셋 확인 (네트워크 끊김 후 재개 시)
HEAD /files/abc123
→ 200 OK
  Upload-Offset: 524288000
  Upload-Length: 1073741824

# 3) 그 지점부터 이어 올리기
PATCH /files/abc123 HTTP/1.1
Upload-Offset: 524288000
Content-Type: application/offset+octet-stream
Tus-Resumable: 1.0.0
[binary chunk]
→ 204 No Content

이 단순한 규약 덕분에 1GB 영상이 99% 올라간 상태에서 와이파이가 끊겨도, 다음에 와이파이가 잡히면 정확히 99%부터 이어 올립니다. 모바일·위성 네트워크처럼 끊김이 잦은 환경에서 본질적입니다.

서버 측 구현은 여러 가지가 있습니다.

# tusd (공식 Go 구현)
docker run -p 1080:1080 \
  -v /data:/srv/tusd-data \
  tusproject/tusd:latest \
  -upload-dir=/srv/tusd-data

# Node tus 서버
npm i @tus/server @tus/file-store
import { Server } from '@tus/server'
import { FileStore } from '@tus/file-store'

const tus = new Server({
  path: '/files',
  datastore: new FileStore({ directory: './uploads' }),
})
// Next.js route handler에 그대로 마운트

클라이언트는 tus-js-client 또는 Uppy의 @uppy/tus 플러그인을 씁니다. 두 라이브러리 모두 자동 재시도·지수 백오프·로컬스토리지 기반 fingerprinting(같은 파일을 동일 세션으로 인식)을 제공합니다.

2025년 tus 2.0 초안이 공개되어 HTTP/3 + 0-RTT, 병렬 청크, 서명된 metadata 같은 기능이 추가되었습니다. 정식 발표는 2026년 하반기를 목표로 합니다.

14. ClamAV / Sublime Security — 바이러스 스캔

업로드받은 파일을 그대로 다시 다운로드 링크로 노출하면, 사용자는 "이 사이트에서 받은 PDF가 랜섬웨어"라는 사고를 만납니다. 2026년에는 업로드 직후 악성코드 스캔이 사실상 필수입니다.

ClamAV(clamav.net)는 1996년부터 이어진 오픈소스 안티바이러스 엔진입니다. 시그니처 기반 검사로 알려진 멀웨어를 잡습니다.

# Docker로 ClamAV 데몬 실행
docker run -d --name clamav \
  -p 3310:3310 \
  -v clam_db:/var/lib/clamav \
  clamav/clamav:stable

# 파일 스캔
clamdscan --multiscan /uploads/file.pdf
# /uploads/file.pdf: OK
# 또는: /uploads/file.pdf: Eicar-Test-Signature FOUND
// Node에서 ClamAV TCP 데몬과 통신
import { NodeClam } from 'clamscan'

const clam = await new NodeClam().init({
  clamdscan: { host: 'clamav', port: 3310 },
})

const { isInfected, viruses } = await clam.scanFile('/uploads/file.pdf')
if (isInfected) {
  await deleteFromStorage(key)
  throw new Error(`Malware detected: ${viruses.join(', ')}`)
}

ClamAV는 빠르지만 시그니처 기반의 한계가 있어, 새 변종이나 zero-day 멀웨어는 놓칠 수 있습니다. 그래서 매니지드 솔루션과 같이 쓰는 경우가 많습니다.

Sublime Security(sublimesecurity.com)는 2020년 미국에서 창업한 콘텐츠 보안 SaaS로, 이메일·업로드된 문서·HTML 페이로드의 휴리스틱 + LLM 검사를 제공합니다. 2024년 시리즈 B를 받으면서 업로드 게이트웨이 시장으로 확장했습니다.

// 가상 예시 — Sublime Detection API
const res = await fetch('https://api.sublime.security/v1/scan', {
  method: 'POST',
  headers: { Authorization: `Bearer ${SUBLIME_KEY}` },
  body: file,
})
const verdict = await res.json()
// { score: 0.92, label: 'phishing', signals: ['embedded-macro', 'suspicious-url'] }

다른 옵션:

  • VirusTotal(virustotal.com) — Google이 운영, 70개 이상의 엔진으로 동시 검사, 무료 API + 유료 Premium
  • Cloudmersive Virus Scan API — 매니지드 REST API
  • MetaDefender Cloud(OPSWAT) — 30+ 엔진 동시 검사, 멀티 스캐닝 표준
  • AWS GuardDuty Malware Protection for S3 — 2024년 GA, S3에 PUT되는 객체를 자동 스캔

업로드 파이프라인의 권장 구조는 다음과 같습니다:

  1. 클라이언트 → Presigned URL/tus로 S3/R2의 격리 버킷에 PUT
  2. 이벤트(S3 ObjectCreated, R2 Queue, Vercel Blob webhook) 발화
  3. ClamAV/GuardDuty/Sublime이 스캔
  4. 깨끗하면 public 버킷으로 이동, 멀웨어면 quarantine로 격리

이 패턴이 ZIP, TAR, WebAssembly 같은 잠재적 위험 콘텐츠도 안전하게 다루는 길입니다.

15. 한국 / 일본 — 토스 / 카카오 / 메르카리

토스(Toss) — 2024년 한국 핀테크 시장 1위로 자리잡은 토스는 KYC 문서·신분증·계약서 같은 민감한 파일을 매일 수백만 건 받습니다. 토스 테크 블로그에서 공개한 내용을 종합하면 다음 패턴이 보입니다.

  • 클라이언트 사이드: 자체 RN(React Native) 모듈로 EXIF 제거 + 클라이언트 사이드 리사이즈
  • 전송 계층: HTTPS PUT + 자체 chunked 프로토콜 (tus와 유사)
  • 1차 저장: AWS S3 격리 버킷(uploads-quarantine)
  • 스캔: ClamAV + 자체 LLM 휴리스틱(사진 안의 신분증이 유효한 KYC 문서인지 자동 판정)
  • 2차 저장: AWS S3 KMS 암호화 버킷, 액세스는 IAM Role per 마이크로서비스
  • CDN: CloudFront + Signed URL

토스가 강조하는 부분은 "업로드 직후 30초 이내 모든 스캔이 끝나야 사용자가 다음 단계로 갈 수 있다"는 SLA로, 비동기 큐가 아닌 동기 + 빠른 폴링 모델을 씁니다.

카카오(Kakao) — 카카오톡 영상 메시지·KakaoStory·KakaoTV는 일일 페타바이트급 미디어 트래픽을 처리합니다. 카카오테크 블로그에 따르면 자체 객체 스토리지 KakaoCloud Object Storage(2022년 출시, 사내 SeaweedFS 변형 + 자체 메타데이터 레이어)와 AWS S3·GCS를 멀티 클라우드로 운영합니다. 한국 내부 트래픽은 KakaoCloud로, 글로벌 트래픽은 S3+CloudFront로 분리해 egress 비용을 최적화합니다.

메르카리(Mercari) — 일본 최대 C2C 마켓플레이스로 매일 사진을 수천만 장 받습니다. 메르카리 엔지니어링 블로그에 따르면 GCP의 Cloud Storage + Cloud CDN을 기본으로 쓰고, 이미지 리사이즈는 직접 만든 imageflux 호환 layer로 처리합니다. 2024년부터는 AI 기반 자동 카테고리 분류가 업로드 즉시 일어나며, 같은 파이프라인에서 부적절한 콘텐츠(NSFW, 위조품 의심)를 자동 차단합니다.

SmartHR — 일본 HR SaaS로, 노동 계약서·급여명세서 같은 법적 문서를 다룹니다. AWS S3 + KMS + Object Lock(WORM)으로 7년 보관 의무를 충족하며, 사용자 다운로드 시점에 일회용 서명 URL을 발급합니다. 한국의 토스·일본의 SmartHR가 비슷한 규제 환경에 있는 이유로, 파일 인프라 패턴이 매우 비슷합니다.

세 회사의 공통점은 (1) S3 호환 API를 코어로 두고, (2) 클라이언트는 자체 RN/Android 모듈로 청크·재시도·EXIF를 처리하며, (3) 백엔드 스캔이 동기로 일어나야 다음 단계로 진행한다는 점입니다.

16. 누가 무엇을 골라야 하나

규모와 시나리오에 따라 다음 매트릭스를 권장합니다.

시나리오1차 추천2차 추천사유
Next.js 1인 사이드 프로젝트UploadThingVercel Blob0-config, 무료 티어
Next.js 스타트업, 자체 인증Uppy + R2 Presigned URLUppy + S3egress 절감, 락인 회피
한국 핀테크 스타트업Uppy + AWS S3 KMS + ClamAVUppy + KakaoCloud규제, KMS 통합
미디어 헤비 (이미지·동영상 변환)Cloudinary or ImageKitFilestackURL 변환, AI 자동 태깅
글로벌 SaaS, egress 큼Cloudflare R2 + Uppy tusBackblaze B2 + CDN0 egress
페타바이트급 자체 데이터센터MinIOSeaweedFSS3 호환, erasure coding
가정용·소규모 OSS 클러스터GarageSeaweedFS저전력, 멀티 리전
NFT, Web3 메타데이터Pinata IPFSFilebaseOpenSea 호환, 영구성
법적·과학·언론 영구 보존Arweave (Irys)Storj DCS한 번 결제, 검열 저항
엔터프라이즈 + 멀티 클라우드 추상MinIO + S3 + R2 fan-outTigris (글로벌 복제)벤더 락인 회피
큰 파일 (>1GB)tus + Uppy + R2tus + tusd + S3 multipartresumable 본질
바이러스 게이트 필요ClamAV + S3 격리 패턴Sublime Security + GuardDutylayered defense

원칙적 권장 사항:

  1. 클라이언트는 Uppy — 1인 프로토타입이 아니라면 거의 항상 Uppy를 쓰세요. UI·진행률·재시도·tus·청크·외부 소스가 무료로 따라옵니다.
  2. 스토리지는 S3 호환 — 락인을 피하려면 처음부터 S3 호환 API를 쓰는 백엔드를 고르세요. R2, B2, Wasabi, MinIO, Tigris 모두 같은 SDK입니다.
  3. egress가 크면 R2 / B2 — 미디어 서빙이 본업이면 egress 0 USD가 결정적입니다.
  4. 큰 파일은 무조건 tus — 1GB가 넘는 순간 tus 없는 업로드는 비효율적입니다.
  5. 민감한 파일은 격리 → 스캔 → 공개 3단계 — 받은 파일을 즉시 공개 URL에 노출하지 마세요. 격리 버킷에 받고, 스캔 통과 후에만 공개 버킷으로 옮기세요.
  6. EXIF·메타데이터는 클라이언트에서 제거 — 사진의 GPS·기기 정보는 서버까지 가기 전에 제거하세요. piexifjs, exif-stripper-js 같은 라이브러리로 충분합니다.
  7. 탈중앙은 영원이 필요할 때만 — IPFS·Arweave는 좋은 도구지만, 일반 SaaS 시나리오에는 과합니다. "이 데이터가 100년 후에도 존재해야 하나"가 Yes일 때만 쓰세요.

파일 업로드는 결제와 함께 가장 사용자에게 직접 노출되는 흐름입니다. 1GB 영상이 99%에서 끊긴 사용자는 그 서비스를 신뢰하지 않게 되고, 한 번 멀웨어가 통과한 서비스는 평판을 회복하기 어렵습니다. 2026년 도구들은 이 두 문제를 단순한 한 줄짜리 API로 줄여놓았으니, 적극적으로 활용하세요.

참고 / References