Directus Docker 설치 가이드: 데이터베이스 기반 헤드리스 CMS




개요

Directus는 모든 SQL 데이터베이스를 즉시 API와 관리자 패널로 변환하는 오픈소스 헤드리스 CMS입니다. 기존 데이터베이스에 연결하면 자동으로 REST/GraphQL API와 관리 UI가 생성됩니다. 데이터 마이그레이션 없이 바로 사용할 수 있습니다.

항목내용
GitHubhttps://github.com/directus/directus
공식 사이트https://directus.io
문서https://docs.directus.io
라이선스BSL 1.1 (소규모 무료)
GitHub Stars28K+

Directus란?

왜 Directus인가?

Strapi
→ 새 프로젝트에서 콘텐츠 타입 정의
→ Strapi 전용 스키마

Directus
→ 기존 DB에 연결하면 끝
→ 표준 SQL 테이블 그대로 사용
→ Directus 제거해도 데이터 그대로

핵심 개념

"Database-First"

1. PostgreSQL/MySQL 등 기존 DB 연결
2. Directus가 스키마 자동 감지
3. REST/GraphQL API 자동 생성
4. 관리자 UI 자동 생성
5. DB 직접 수정해도 동기화

아키텍처

┌─────────────────────────────────────────┐
│     Frontend (React/Next.js/Vue)        │
└─────────────────┬───────────────────────┘
                  │ REST / GraphQL / WebSocket
                  ▼
┌─────────────────────────────────────────┐
│              Directus                    │
│  ┌─────────────────────────────────┐    │
│  │    Admin App (관리자 UI)         │    │
│  ├─────────────────────────────────┤    │
│  │   API Layer (REST/GraphQL)      │    │
│  ├─────────────────────────────────┤    │
│  │   Flows (자동화 워크플로우)       │    │
│  ├─────────────────────────────────┤    │
│  │   File Storage (미디어 관리)     │    │
│  └─────────────────────────────────┘    │
└─────────────────┬───────────────────────┘
                  │ 스키마 미러링
                  ▼
┌─────────────────────────────────────────┐
│   Your SQL Database (표준 테이블)        │
│   PostgreSQL / MySQL / SQLite / etc.    │
└─────────────────────────────────────────┘

주요 기능

🗄️ 데이터베이스 지원

DB지원
PostgreSQL
MySQL
MariaDB
SQLite
MS SQL Server
OracleDB
CockroachDB

🔌 API

기능설명
REST API자동 CRUD
GraphQL자동 생성
WebSocket실시간 업데이트
필터/정렬/페이지네이션강력한 쿼리

🎨 Admin App

기능설명
자동 UI 생성테이블 → 폼/리스트
커스텀 대시보드드래그앤드롭
다크 모드내장
64+ 언어다국어 지원

📁 파일 관리

기능설명
Digital Asset Management이미지/파일 관리
이미지 변환실시간 리사이즈/크롭
외부 스토리지S3, GCS, Azure

⚡ Flows (자동화)

기능설명
Trigger데이터 변경, 스케줄, Webhook
Operations이메일, HTTP 요청, 스크립트
조건부 실행필터 조건

🔐 권한

기능설명
RBAC역할 기반 접근 제어
필드 레벨 권한세밀한 제어
SSOOAuth, LDAP, SAML

시스템 요구 사항

항목최소권장
CPU1 코어2+ 코어
RAM512MB2GB+
저장소10GB20GB+
포트8055

Docker 설치

방법 1: 빠른 시작 (SQLite)

docker run -d \
  --name directus \
  -p 8055:8055 \
  -e SECRET="your-random-secret-key" \
  -e ADMIN_EMAIL="admin@example.com" \
  -e ADMIN_PASSWORD="admin123" \
  -e DB_CLIENT="sqlite3" \
  -e DB_FILENAME="/directus/database/data.db" \
  -v directus-data:/directus/database \
  -v directus-uploads:/directus/uploads \
  directus/directus:11

접속: http://localhost:8055

방법 2: Docker Compose + PostgreSQL

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      DB_CLIENT: "pg"
      DB_HOST: "directus-db"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
      
      WEBSOCKETS_ENABLED: "true"
    volumes:
      - ./uploads:/directus/uploads
      - ./extensions:/directus/extensions
    depends_on:
      directus-db:
        condition: service_healthy

  directus-db:
    image: postgres:16-alpine
    container_name: directus-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: directus_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U directus"]
      interval: 5s
      timeout: 5s
      retries: 5

방법 3: MySQL 사용

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      DB_CLIENT: "mysql"
      DB_HOST: "directus-mysql"
      DB_PORT: "3306"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
    volumes:
      - ./uploads:/directus/uploads
    depends_on:
      - directus-mysql

  directus-mysql:
    image: mysql:8
    container_name: directus-mysql
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password
    environment:
      MYSQL_DATABASE: directus
      MYSQL_USER: directus
      MYSQL_PASSWORD: directus_password
      MYSQL_ROOT_PASSWORD: root_password
    volumes:
      - ./data/mysql:/var/lib/mysql

방법 4: Redis 캐시 추가

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      DB_CLIENT: "pg"
      DB_HOST: "directus-db"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
      
      # Redis 캐시
      CACHE_ENABLED: "true"
      CACHE_STORE: "redis"
      REDIS_HOST: "directus-redis"
      REDIS_PORT: "6379"
      CACHE_AUTO_PURGE: "true"
      CACHE_TTL: "5m"
      
      # Rate Limiting
      RATE_LIMITER_ENABLED: "true"
      RATE_LIMITER_STORE: "redis"
    volumes:
      - ./uploads:/directus/uploads
    depends_on:
      - directus-db
      - directus-redis

  directus-db:
    image: postgres:16-alpine
    container_name: directus-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: directus_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data

  directus-redis:
    image: redis:alpine
    container_name: directus-redis
    restart: unless-stopped

방법 5: S3 스토리지 연동

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      DB_CLIENT: "pg"
      DB_HOST: "directus-db"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
      
      # S3 스토리지
      STORAGE_LOCATIONS: "s3"
      STORAGE_S3_DRIVER: "s3"
      STORAGE_S3_KEY: "${AWS_ACCESS_KEY_ID}"
      STORAGE_S3_SECRET: "${AWS_SECRET_ACCESS_KEY}"
      STORAGE_S3_BUCKET: "your-bucket"
      STORAGE_S3_REGION: "ap-northeast-2"
    depends_on:
      - directus-db

  directus-db:
    image: postgres:16-alpine
    container_name: directus-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: directus_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data

방법 6: MinIO (S3 호환) 연동

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      DB_CLIENT: "pg"
      DB_HOST: "directus-db"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
      
      # MinIO 스토리지
      STORAGE_LOCATIONS: "s3"
      STORAGE_S3_DRIVER: "s3"
      STORAGE_S3_KEY: "minioadmin"
      STORAGE_S3_SECRET: "minioadmin"
      STORAGE_S3_BUCKET: "directus"
      STORAGE_S3_ENDPOINT: "http://minio:9000"
      STORAGE_S3_FORCE_PATH_STYLE: "true"
    depends_on:
      - directus-db
      - minio

  directus-db:
    image: postgres:16-alpine
    container_name: directus-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: directus_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data

  minio:
    image: minio/minio
    container_name: directus-minio
    restart: unless-stopped
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    volumes:
      - ./data/minio:/data
    command: server /data --console-address ":9001"

방법 7: 기존 DB 연결 (마이그레이션 없음)

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    ports:
      - "8055:8055"
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      # 기존 PostgreSQL DB 연결
      DB_CLIENT: "pg"
      DB_HOST: "your-existing-db-host"
      DB_PORT: "5432"
      DB_DATABASE: "your_existing_database"
      DB_USER: "your_db_user"
      DB_PASSWORD: "your_db_password"
    volumes:
      - ./uploads:/directus/uploads

방법 8: Traefik + HTTPS

# docker-compose.yml
services:
  directus:
    image: directus/directus:11
    container_name: directus
    restart: unless-stopped
    environment:
      SECRET: "your-random-secret-key"
      ADMIN_EMAIL: "admin@example.com"
      ADMIN_PASSWORD: "admin123"
      
      PUBLIC_URL: "https://cms.yourdomain.com"
      
      DB_CLIENT: "pg"
      DB_HOST: "directus-db"
      DB_PORT: "5432"
      DB_DATABASE: "directus"
      DB_USER: "directus"
      DB_PASSWORD: "directus_password"
    volumes:
      - ./uploads:/directus/uploads
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.directus.rule=Host(`cms.yourdomain.com`)"
      - "traefik.http.routers.directus.entrypoints=websecure"
      - "traefik.http.routers.directus.tls.certresolver=letsencrypt"
      - "traefik.http.services.directus.loadbalancer.server.port=8055"
    depends_on:
      - directus-db
    networks:
      - traefik-net
      - directus-net

  directus-db:
    image: postgres:16-alpine
    container_name: directus-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: directus
      POSTGRES_USER: directus
      POSTGRES_PASSWORD: directus_password
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    networks:
      - directus-net

networks:
  traefik-net:
    external: true
  directus-net:
    driver: bridge

환경 변수

필수

변수설명
SECRET토큰 서명 키 (필수!)
ADMIN_EMAIL첫 관리자 이메일
ADMIN_PASSWORD첫 관리자 비밀번호

데이터베이스

변수설명
DB_CLIENTpg, mysql, sqlite3, mssql, oracledb
DB_HOSTDB 호스트
DB_PORTDB 포트
DB_DATABASEDB 이름
DB_USERDB 사용자
DB_PASSWORDDB 비밀번호

캐시

변수설명
CACHE_ENABLEDtrue/false
CACHE_STOREmemory, redis
REDIS_HOSTRedis 호스트
REDIS_PORTRedis 포트
CACHE_TTL캐시 만료 시간

스토리지

변수설명
STORAGE_LOCATIONSlocal, s3
STORAGE_S3_KEYS3 액세스 키
STORAGE_S3_SECRETS3 시크릿 키
STORAGE_S3_BUCKETS3 버킷
STORAGE_S3_REGIONS3 리전

기타

변수설명
PUBLIC_URL공개 URL
WEBSOCKETS_ENABLED실시간 기능
RATE_LIMITER_ENABLED요청 제한

초기 설정

1. 시작

docker compose up -d

2. 로그인

  • http://localhost:8055 접속
  • ADMIN_EMAIL, ADMIN_PASSWORD로 로그인

3. 첫 설정 후 환경 변수 제거

프로덕션에서는 첫 실행 후 ADMIN 변수 제거:

# ADMIN_EMAIL: "admin@example.com"   # 제거
# ADMIN_PASSWORD: "admin123"          # 제거

4. Collection 생성

  1. Settings → Data Model
  2. “Create Collection” 클릭
  3. 이름 입력 (예: articles)
  4. 필드 추가:
    • title (String)
    • content (WYSIWYG)
    • cover (Image)
    • status (Status)

5. 권한 설정

  1. Settings → Access Control → Roles
  2. “Public” 역할 선택
  3. 해당 Collection의 읽기 권한 부여

6. API 테스트

# 모든 항목 조회
curl http://localhost:8055/items/articles

# 인증이 필요한 경우
curl -H "Authorization: Bearer YOUR_TOKEN" \
  http://localhost:8055/items/articles

# 필터링
curl "http://localhost:8055/items/articles?filter[status][_eq]=published"

# GraphQL
curl -X POST http://localhost:8055/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ articles { id title } }"}'

Flows (자동화)

이메일 알림 Flow

  1. Settings → Flows → Create Flow
  2. Trigger: “Event Hook” → items.create
  3. Operation: “Send Email”
  4. 조건 설정 및 저장

Webhook Flow

  1. Trigger: “Webhook”
  2. Operation: “Run Script” 또는 “Send Request”
  3. 외부 서비스 연동

백업 및 복원

데이터 구조

./
├── uploads/               # 업로드 파일
├── extensions/            # 커스텀 확장
└── data/
    └── postgres/          # PostgreSQL 데이터

백업

# 컨테이너 정지
docker compose down

# 전체 백업
tar -czvf directus-backup-$(date +%Y%m%d).tar.gz uploads/ data/

# DB만 백업
docker exec directus-db pg_dump -U directus directus > backup.sql

# 스키마 스냅샷 (Directus)
npx directus schema snapshot ./snapshot.yaml

# 재시작
docker compose up -d

복원

tar -xzvf directus-backup.tar.gz
docker compose up -d

업데이트

# 최신 이미지
docker compose pull

# 재시작
docker compose down
docker compose up -d

트러블슈팅

SECRET 오류

SECRET 환경 변수가 필수입니다.
→ 랜덤 문자열 생성: openssl rand -base64 32

DB 연결 오류

  • DB 컨테이너가 healthy 상태인지 확인
  • depends_oncondition: service_healthy 추가

권한 오류

sudo chown -R 1000:1000 ./uploads ./extensions

대안 비교

기능DirectusStrapiHasura
기존 DB 연결✅ 즉시
스키마 자동 감지
REST API
GraphQL✅ (플러그인)
WebSocket
관리자 UI✅ 풍부❌ (별도)
Flows/자동화✅ 내장
라이선스BSL 1.1MITApache 2.0

선택 가이드

용도추천
기존 DB 연결Directus
새 프로젝트Strapi
GraphQL 중심Hasura
비개발자 관리Directus

활용 사례

1. 레거시 DB 현대화

구성:

  • 기존 PostgreSQL/MySQL 연결
  • 마이그레이션 없이 즉시 API 생성
  • 레거시 시스템과 병행 운영

2. 백오피스/관리자 패널

구성:

  • 내부 데이터 관리 UI
  • 역할별 권한 설정
  • 커스텀 대시보드

3. 헤드리스 CMS

구성:

  • 콘텐츠 관리
  • Next.js/Nuxt 프론트엔드
  • 실시간 WebSocket 업데이트

4. 데이터 플랫폼

구성:

  • 다양한 DB 통합
  • Flows로 데이터 파이프라인
  • API 게이트웨이 역할

마무리

Directus는 “Database-First” 철학의 헤드리스 CMS입니다. 기존 데이터베이스에 연결하면 즉시 API와 관리자 UI가 생성되어, 마이그레이션 없이 바로 사용할 수 있습니다.

핵심 장점

장점설명
기존 DB 연결마이그레이션 불필요
자동 API 생성REST + GraphQL + WebSocket
풍부한 관리자 UI비개발자도 사용
Flows내장 자동화
벤더 종속 없음표준 SQL 테이블
다양한 DB 지원7개+ 데이터베이스



댓글 남기기