이미지 서버, 따로 만들어야 할까?

들어가며

서비스에서 이미지 처리는 필수적이지만, “직접 이미지 서비스를 구성” 하는게 맞을까 하는 질문이 생겼다.

과거 직접 termux 환경에서 deno를 활용한 블로그 배포를 진행한 경험에서는 nginx를 활용하여 간단히 이미지를 서빙한 적이 있었다.

당시 환경은 혼자서 약 450기가의 핸드폰을 전부 사용할 수 있으니 간단하고 빠르게 이미지를 제공하는 방법으로 nginx와, 백엔드의 간단한 파일 저장 로직을 사용했다.

당시에는 글을 작성하는 유저는 나 하나 (개인 블로그이므로), 파일 관리에 엄격할 필요가 없거니와, 간단히 termux 환경의 스마트폰에서 이미지를 정리하면 해결되는 문제였다.

하지만 이번에는 조금 경우가 다르다.

따라서 정적 파일 호스팅과 NestJS + MinIO + Sharp를 엮어서 굳이 복잡한 아키텍처를 별도로 구현할 필요가 있을까?

비교

요약

항목 Nginx 정적 호스팅 NestJS 이미지 서버 (MinIO 기반)
개념 파일 시스템 기반 단순 서빙 API 서버에서 처리·저장·전달 일원화
아키텍처 Nginx → /mnt/storage → 사용자 Nginx → NestJS → MinIO/MongoDB
초기 구현 난이도 매우 낮음 중간 이상 (다중 모듈 필요)
확장성 (MSA 환경) 낮음 — 중앙 스토리지 의존 높음 — 독립적 스케일링 가능
보안/권한 제어 제한적 (공개 URL 중심) 세밀 제어 가능 (Signed URL 등)
중복 관리 불가 가능 (SHA-256 해시 기반)
리사이징 / 썸네일 직접 구현 필요 Sharp 등 라이브러리로 자동 처리
비용 효율성 낮은 관리비, 높은 스토리지 낭비 초기비용↑, 장기비용↓ (GC로 절감)
적합 시점 PoC / MVP / 사내 내부 툴 상용 서비스 / MSA 구조 / 이미지 중심 서비스

정적 호스팅

개념

“가장 간단한 이미지 서빙”

파일 시스템 상 존재하는 이미지 파일을 Nginx가 직접 응답한다.

즉 애플리케이션 실제 로직 없이 이미 존재하는 정적 파일을 있는 그대로 제공한다.

server {
  listen 80;
  server_name example.com;

  location /images/ {
    alias /mnt/storage/images/;
    autoindex off;
    expires 30d;
  }
}

해당 사례의 경우

브라우저 요청 시 /images/cat.png -> /mnt/storage/images/cat.png 파일을 그대로 응답하여 반환한다.

장점

  • 단순하다 : 복잡한 백엔드 로직 없이 Nginx 설정으로 서빙 가능
  • 성능 : 정적 자원 처리에 특화된 Nginx, I/O 효율이 높고 캐싱 지원이 잘 되어있다.
  • 비용 : 서버 내 파일만 관리하면 되므로, 별도의 비용은 없다. (서버 자원이 곧 이미지 서버의 자원)

단점

  • 보안 제어 부재 : 파일 경로만 안다면 누구나 접근 가능. 인증된 사용자만 볼 수 있게 하려면 복잡한 구현 필수적
  • 중복 저장 발생 : 동일 이미지라도 여러 번 업로드 될 경우 중복 파일이 생성/추가 됨
  • 변환/리사이징 부재 : 다양한 썸네일 사이즈를 지원하기 위해서는 별도의 사전 생성 혹은 툴 필요
  • 확장성 한계 : 서버 로컬 디스크에 의존하여 수평 확장이 불가능하다.

그렇다면 언제?

  • 내부 툴, 단순 개념 증명, 단일 사용자용 서비스
  • 이미지 수가 적고, 권한 제어가 필요 없는 경우
  • 동작 확인을 위한 UI/UX 구현을 빠르게 해야 할 때

즉 초기의 MVP를 위해서 빠르게 설정, 관리 가능한 정도의 수준이다.

추가적인 기능을 위해서는 이미지 서버를 실제로 구현하는 것과 마찬가지의 별도의 커스터마이징이 필요해진다.

전용 이미지 서버

개념

이미지를 단순 파일로 저장하는 것이 아닌

Nest(Spring 외 다양한 백엔드 가능) -> MinIO 저장 -> 필요시 가공(Sharp) -> 별도 기능 추가

라는 흐름을 통해 제어된 접근과 가공 기능을 제공한다.

개발 단계에 따라 모듈적으로 접근할 수 있기에 초기 구현은 nginx 와 마찬가지로 이미지 서빙이 주가 되겠지만, 확장성과 이식성, MSA를 고려한 환경에서 용이해진다.

플로우는 다음과 같다.

Client
  ↓
[ NestJS API ]
  ├─ Validation (파일 타입, 크기)
  ├─ Deduplication (SHA-256)
  ├─ Resizing / Optimization (Sharp)
  └─ Upload to MinIO
        ↓
     MinIO (S3 호환)

요청 시 서버는 MinIO에서 해당 객체의 정보를 이용하여 추가적 로직을 적용한 후 클라이언트에 제공한다.

URL은 만료될 수 있다. -> 보안성

장점

  • 보안 제어 : 인증된 사용자만 접근할 수 있으며, presignedUrl 기반 접근 가능
  • 중복 방지 : SHA-256 해시를 계산하여 동일 파일 저장을 방지할 수 있다 (해당 메타데이터 관리를 위한 DB 도입 가능)
  • 리사이징/썸네일 생성 자동화 : Sharp 등 이미지 처리 라이브러리를 통해 업로드 시 자동 변환 가능
  • 확장성 : MinIO는 S3 API 호환 스토리지로, 쿠버/클라우드 환경에서 수평 확장이 가능하다.
  • 로그 및 감사 가능 : 업로드/삭제/조회 와 같은 로그를 중앙 관리할 수 있다.

단점

  • 구현 복잡도 증가 : NestJS, MinIO, ORM 등 여러 모듈의 적용이 필요하다
  • 초기비용 발생 가능성 : 스토리지 & 네트워크 필요할 수 있음
  • 성능 오버헤드 : 단순 서빙에 비해 NestJS 레이어를 거치므로 지연이 Nginx에 비해 큼

아키텍처 예상

단일 서버 & Nginx

[User] → [Nginx] → [FileSystem]

단순하고 빠르다. 스케일 아웃 불가.


확장형 시나리오

[User] → [Nginx/LoadBalancer] → [NestJS] → [MinIO]
                              ↳ [CDN] (옵션)

API 레벨 인증/가공 가능

서비스 규모가 커질수록 안정적

MinIO -> 로컬, 클라우드, 컨테이너 모두 지원


운영 관점에서의 비교

구분 Nginx 정적 호스팅 NestJS + MinIO
배포 단일 서버에 파일 직접 복사 Docker Compose, Helm 등으로 컨테이너 기반
백업 rsync / tar 기반 수동 백업 MinIO Snapshot / Object Versioning
로그 분석 Access log만 제공 업로드/다운로드 이벤트 로그 API
CDN 연동 간단함 (정적 URL 기반) 필요 시 Signed URL에 CDN Cache Key 설정 필요
GC (정리) 불가 (수동 삭제) 미사용 객체 자동 정리 가능 (메타데이터 기반)




결론

  1. Nginx 정적 호스팅을 통한 MVP 개발 (백엔드 측 파일 저장/관리에 대한 대안 필요)
  2. MVP (현 담당 개발 파트는 프론트이므로) 완성 후 이미지 서버 개발 & 마이그레이션.

이미지 서버의 본질을 다시 정의할 필요도 있다.

따라서 다음과 같은 기준을 정의해보았다.

질문 추천 선택
유저가 단일 관리자 수준인가? Nginx 정적 호스팅
업로드 권한 제어가 필요한가? NestJS 이미지 서버
썸네일, 리사이징 기능이 필요한가? NestJS 이미지 서버
서비스 트래픽이 많고 CDN 연계 예정인가? NestJS + MinIO
내부 테스트 / 개인 블로그 수준인가? Nginx

두 개의 확실한 옵션이 생겨났다.

작고 빠른 서비스를 생각하고 있다면 정적 호스팅을 통한 빠른 프로덕션 레벨로의 진입 방향

이미지 처리에 대한 확장성과 통제를 위해서라면 이미지 서버를 개발하는 것.

그렇다면. 기술 습득과 고도화를 위한 프로젝트인 만큼. 개발을 진행해보는 것은 어떨까 싶다.

이미지는 단순한 자원이 아닌, 사용자 경험의 첫인상이다.

개발자는 그것을 “어떻게” 보여줄지 고민해야 한다.

여담

1. 동일 환경에 존재하는 여러 기기에 분산 저장하여 사용하는게 가능할까?

(넷북, 안쓰는 노트북, 서버용 컴퓨터를 클러스터 구조를 잡아 스토리지로 활용 - NAS 같은 느낌)

초기 비용 발생 가능성에 대한 대안

가능하지만. 너무 복잡한 개념.

2. 이미 MSA로 별도 설계가 이루어진 경우에는 무엇이 더 괜찮을까?

해당 경우는 별도 서비스로 독립성을 확보하는 편이 좋지 않을까 싶다.

이미지 처리라는 관심사만 별도로 분리하여.

또한 추가적으로 확장성에 이점 (S3 같은)을 가질 수 있으니까.

역시 고민할게 많다.

구현도 잘 할 수 있으면 좋을텐데.