포스트

[이제와서 시작하는 Metabase 마스터하기 #14] 커스터마이징 - 화이트라벨링

[이제와서 시작하는 Metabase 마스터하기 #14] 커스터마이징 - 화이트라벨링

학습 목표

이 포스트를 마치면 다음을 할 수 있습니다:

  • Metabase 외관을 회사 브랜드에 맞게 커스터마이징
  • 로고, 색상, 폰트 변경
  • 커스텀 도메인 설정
  • 환경 변수로 고급 설정
  • 플러그인과 확장 기능 활용

브랜딩 커스터마이징

Application Settings

1
2
3
4
5
6
7
8
9
10
11
Admin > Settings > Appearance

Application name:
  Metabase → "Your Company Analytics"

Application description:
  "Business intelligence platform for Your Company"

Application color:
  Default: #509EE3 (Metabase blue)
  Custom: #007bff (Your brand color)

로고 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Admin > Settings > Appearance > Logo

Logo image:
  - Format: PNG, SVG (recommended)
  - Size: 60px height, max 200px width
  - Background: Transparent
  - Upload: [Choose file]

Favicon:
  - Format: ICO, PNG
  - Size: 32x32px or 16x16px
  - Upload: [Choose file]

Powered by Metabase:
  ☐ Show "Powered by Metabase" (Paid feature)
  ☑ Hide branding (Enterprise plan)

색상 테마

Primary Colors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Admin > Settings > Appearance > Colors

Primary color: #007bff
  - Buttons
  - Links
  - Active states

Accent color: #28a745
  - Success messages
  - Positive metrics
  - Call-to-actions

Navigation bar color: #343a40
  - Top navigation background
  - Sidebar background

커스텀 CSS (고급):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* metabase-custom.css */

/* Navigation bar */
.Nav {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

/* Primary button */
.Button--primary {
  background-color: #007bff;
  border-color: #007bff;
}

.Button--primary:hover {
  background-color: #0056b3;
  border-color: #004085;
}

/* Cards */
.Card {
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

/* Question titles */
.Question-header {
  font-family: 'Roboto', sans-serif;
  font-weight: 700;
}

폰트 커스터마이징

1
2
3
4
5
6
7
8
9
10
11
12
Admin > Settings > Appearance > Font

Font family (URL):
  https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap

Font family name:
  'Roboto', sans-serif

Apply to:
  ☑ Headings
  ☑ Body text
  ☑ UI elements

지원되는 Google Fonts:

1
2
3
4
5
6
7
8
9
10
11
12
13
Sans-serif:
  - Roboto
  - Open Sans
  - Lato
  - Montserrat

Serif:
  - Merriweather
  - Playfair Display

Monospace:
  - Roboto Mono
  - Source Code Pro

커스텀 도메인

도메인 설정

Step 1: DNS 설정

1
2
3
4
5
CNAME record:
  analytics.yourcompany.com → metabase.yourcompany.com

또는 A record:
  analytics.yourcompany.com → 203.0.113.1 (Metabase server IP)

Step 2: Metabase 설정

1
2
# Environment variable
MB_SITE_URL=https://analytics.yourcompany.com

Step 3: SSL/TLS 인증서

1
2
3
4
5
6
# Let's Encrypt (무료)
sudo certbot --nginx -d analytics.yourcompany.com

# 또는 상용 인증서
# SSL certificate: /etc/ssl/certs/yourcompany.crt
# SSL key: /etc/ssl/private/yourcompany.key

Step 4: Nginx 리버스 프록시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# /etc/nginx/sites-available/metabase

server {
    listen 80;
    server_name analytics.yourcompany.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name analytics.yourcompany.com;

    ssl_certificate /etc/letsencrypt/live/analytics.yourcompany.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/analytics.yourcompany.com/privkey.pem;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
}

환경 변수 설정

주요 환경 변수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# Site URL
MB_SITE_URL=https://analytics.yourcompany.com

# Database (H2 → PostgreSQL 권장)
MB_DB_TYPE=postgres
MB_DB_DBNAME=metabase
MB_DB_PORT=5432
MB_DB_USER=metabase
MB_DB_PASS=secure_password
MB_DB_HOST=db.yourcompany.com

# Email
MB_EMAIL_SMTP_HOST=smtp.gmail.com
MB_EMAIL_SMTP_PORT=587
MB_EMAIL_SMTP_SECURITY=tls
MB_EMAIL_SMTP_USERNAME=metabase@yourcompany.com
MB_EMAIL_SMTP_PASSWORD=app_password
MB_EMAIL_FROM_ADDRESS=metabase@yourcompany.com

# Security
MB_PASSWORD_COMPLEXITY=strong
MB_PASSWORD_LENGTH=10
MB_SESSION_COOKIES=true
MB_EMBEDDING_SECRET_KEY=your-secret-key-min-64-chars

# Performance
MB_JETTY_MAX_THREADS=100
MB_ASYNC_QUERY_THREAD_POOL_SIZE=50
MB_QUERY_TIMEOUT=120

# Caching
MB_APPLICATION_DB_MAX_CONNECTION_POOL_SIZE=15

# Logging
MB_LOG_LEVEL=INFO
MB_PLUGINS_DIR=/plugins

Docker Compose 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# docker-compose.yml
version: '3.8'

services:
  metabase:
    image: metabase/metabase:latest
    container_name: metabase
    hostname: metabase
    ports:
      - 3000:3000
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: metabase
      MB_DB_PORT: 5432
      MB_DB_USER: metabase
      MB_DB_PASS: ${MB_DB_PASS}
      MB_DB_HOST: postgres
      MB_SITE_URL: https://analytics.yourcompany.com
      MB_EMBEDDING_SECRET_KEY: ${MB_EMBEDDING_SECRET_KEY}
    volumes:
      - ./metabase-data:/metabase-data
      - ./plugins:/plugins
    depends_on:
      - postgres
    restart: always

  postgres:
    image: postgres:15
    container_name: metabase-postgres
    environment:
      POSTGRES_USER: metabase
      POSTGRES_PASSWORD: ${MB_DB_PASS}
      POSTGRES_DB: metabase
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: always

volumes:
  postgres-data:

.env 파일:

1
2
3
# .env
MB_DB_PASS=your-secure-database-password
MB_EMBEDDING_SECRET_KEY=your-very-long-secret-key-at-least-64-characters-long

고급 커스터마이징

커스텀 Drivers

MongoDB driver 추가:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. Driver 다운로드
wget https://github.com/metabase/metabase-mongodb-driver/releases/download/v1.0.0/mongodb.metabase-driver.jar

# 2. Plugins 디렉토리에 복사
mkdir -p /path/to/metabase/plugins
cp mongodb.metabase-driver.jar /path/to/metabase/plugins/

# 3. Metabase 재시작
docker-compose restart metabase

# 4. 확인
Admin > Databases > Add database
  → MongoDB should appear in the list

지원되는 커뮤니티 Drivers:

1
2
3
4
5
6
- MongoDB
- Presto
- Druid
- Vertica
- Exasol
- Oracle (free driver)

Landing Page 커스터마이징

1
2
3
4
5
# Environment variable
MB_SITE_HOMEPAGE=custom

# 또는
MB_SITE_HOMEPAGE=/dashboard/1  # Specific dashboard

Custom homepage HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- /path/to/metabase/resources/frontend_client/index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Your Company Analytics</title>
  <link rel="stylesheet" href="/app/dist/app.css">
  <style>
    body {
      font-family: 'Roboto', sans-serif;
    }
    .homepage-banner {
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      padding: 60px 20px;
      color: white;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="homepage-banner">
    <h1>Welcome to Your Company Analytics</h1>
    <p>Empowering decisions with data</p>
  </div>
  <div id="root"></div>
  <script src="/app/dist/app.js"></script>
</body>
</html>

Email 템플릿 커스터마이징

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!-- Email alert template -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: 'Roboto', sans-serif;
      background-color: #f4f4f4;
      padding: 20px;
    }
    .container {
      max-width: 600px;
      margin: 0 auto;
      background: white;
      border-radius: 8px;
      overflow: hidden;
    }
    .header {
      background: #007bff;
      color: white;
      padding: 30px;
      text-align: center;
    }
    .logo {
      max-width: 150px;
    }
    .content {
      padding: 30px;
    }
    .metric {
      font-size: 36px;
      font-weight: bold;
      color: #007bff;
      margin: 20px 0;
    }
    .footer {
      background: #f8f9fa;
      padding: 20px;
      text-align: center;
      font-size: 12px;
      color: #6c757d;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="header">
      <img src="https://yourcompany.com/logo.png" alt="Your Company" class="logo">
      <h1>Analytics Alert</h1>
    </div>
    <div class="content">
      <h2></h2>
      <p></p>
      <div class="metric"></div>
      <p><a href="" style="background: #007bff; color: white; padding: 10px 20px; text-decoration: none; border-radius: 4px;">View Dashboard</a></p>
    </div>
    <div class="footer">
      <p>&copy; 2025 Your Company. All rights reserved.</p>
      <p><a href="">Unsubscribe</a></p>
    </div>
  </div>
</body>
</html>

조직별 커스터마이징

Enterprise Use Cases

1. Multi-tenant SaaS

1
2
3
4
5
6
# 각 테넌트별 브랜딩
MB_SITE_NAME= Analytics
MB_SITE_URL=https://.analytics.yourcompany.com

# 테넌트별 로고 (동적 로딩)
# Application에서 tenant_id로 로고 조회

2. 금융 기관

1
2
3
4
5
6
7
8
9
# 보안 강화
MB_PASSWORD_COMPLEXITY=strong
MB_PASSWORD_LENGTH=12
MB_SESSION_TIMEOUT=30  # minutes
MB_ENABLE_AUDIT_APP=true

# 화이트라벨링
MB_HIDE_METABASE_BRANDING=true
MB_CUSTOM_LOGIN_MESSAGE="Secure Financial Analytics Portal"

3. 이커머스

1
2
3
4
5
6
7
# 실시간 대시보드
MB_CACHE_TTL_SHORT=60  # 1 minute for real-time data
MB_CACHE_TTL_LONG=3600  # 1 hour for historical

# 고객 대면 임베딩
MB_EMBEDDING_ENABLED=true
MB_EMBEDDING_HOMEPAGE=/dashboard/customer-analytics

사용자 경험 개선

기본 대시보드 설정

1
2
3
4
5
6
7
8
9
10
Admin > Settings > General

Default Dashboard:
  ☑ Set a default dashboard for new users
  Dashboard: "Company Overview"

New user experience:
  ☑ Show onboarding
  ☑ Show tips
  Tutorial collection: "Getting Started"

Question Templates

1
2
3
4
5
6
7
8
9
10
11
-- Template: "Monthly Sales Report"
-- Saved as a template with placeholders

SELECT
  DATE_TRUNC('month', created_at) as month,
   as value,  -- Placeholder
   as category  -- Placeholder
FROM orders
WHERE created_at >= 
GROUP BY month, 
ORDER BY month DESC

Snippets Library

1
2
3
4
5
6
7
8
-- Snippet: "current_quarter"
DATE_TRUNC('quarter', CURRENT_DATE)

-- Snippet: "revenue_query"
SUM(total) FILTER (WHERE status = 'completed')

-- Snippet: "active_users"
COUNT(DISTINCT user_id) FILTER (WHERE last_active >= CURRENT_DATE - INTERVAL '30 days')

모니터링 및 유지보수

Health Checks

1
2
3
4
5
6
7
8
9
# API endpoint
GET /api/health

Response:
{
  "status": "ok",
  "database": "ok",
  "cache": "ok"
}

모니터링 대시보드:

1
2
3
4
5
6
7
8
-- System metrics
SELECT
  metric_name,
  metric_value,
  recorded_at
FROM metabase_metrics
WHERE recorded_at >= NOW() - INTERVAL '24 hours'
ORDER BY recorded_at DESC

Backup & Restore

1
2
3
4
5
6
7
8
9
# Backup Metabase database (PostgreSQL)
pg_dump -h localhost -U metabase metabase > metabase_backup_$(date +%Y%m%d).sql

# Backup uploaded files
tar -czf metabase_data_$(date +%Y%m%d).tar.gz /path/to/metabase-data/

# Restore
psql -h localhost -U metabase metabase < metabase_backup_20250101.sql
tar -xzf metabase_data_20250101.tar.gz -C /path/to/restore/

Upgrade 프로세스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. Backup (위 참조)

# 2. Docker image 업데이트
docker-compose pull metabase

# 3. 서비스 재시작
docker-compose up -d metabase

# 4. 확인
docker logs -f metabase

# 5. 테스트
# - 로그인 확인
# - 대시보드 로딩 확인
# - Query 실행 확인

실전 연습 문제

연습 1: 기본 브랜딩 (초급)

과제: 회사 브랜드 적용

  • 로고 변경
  • 색상 테마 적용
  • 커스텀 도메인 설정
해답 보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1. 로고 준비:
   - Company logo: 200x60px PNG (transparent)
   - Favicon: 32x32px ICO

2. Metabase 설정:
   Admin > Settings > Appearance

   Application name: "Acme Analytics"

   Logo:
     - Upload: acme-logo.png
     - Position: Left aligned

   Favicon:
     - Upload: acme-favicon.ico

   Colors:
     - Primary: #E91E63 (Acme brand pink)
     - Accent: #FFC107 (Acme brand yellow)
     - Navigation: #212121 (Dark gray)

   Font:
     - URL: https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700
     - Family: 'Poppins', sans-serif

3. 커스텀 도메인:

   DNS (Cloudflare):
     CNAME analytics → metabase.acme.com

   Environment:
     MB_SITE_URL=https://analytics.acme.com

   SSL:
     certbot --nginx -d analytics.acme.com

   Nginx:
     server_name analytics.acme.com;
     proxy_pass http://localhost:3000;

4. 테스트:
   - https://analytics.acme.com 접속
   - 로고 표시 확인
   - 색상 테마 확인
   - SSL 인증서 확인

연습 2: 이메일 템플릿 커스터마이징 (중급)

과제: 브랜드 일치 이메일 템플릿

해답 보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<!-- /resources/email-templates/alert.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <style>
    body {
      font-family: 'Poppins', -apple-system, sans-serif;
      margin: 0;
      padding: 0;
      background-color: #f5f5f5;
    }
    .email-container {
      max-width: 600px;
      margin: 20px auto;
      background: white;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
    .email-header {
      background: linear-gradient(135deg, #E91E63, #C2185B);
      padding: 40px 30px;
      text-align: center;
    }
    .email-header img {
      max-width: 180px;
      height: auto;
    }
    .email-header h1 {
      color: white;
      margin: 20px 0 10px;
      font-size: 28px;
    }
    .email-header p {
      color: rgba(255,255,255,0.9);
      margin: 0;
    }
    .email-body {
      padding: 40px 30px;
    }
    .metric-card {
      background: #FFF9C4;
      border-left: 4px solid #FFC107;
      padding: 20px;
      margin: 20px 0;
      border-radius: 4px;
    }
    .metric-value {
      font-size: 48px;
      font-weight: 700;
      color: #E91E63;
      margin: 10px 0;
    }
    .metric-label {
      font-size: 14px;
      color: #666;
      text-transform: uppercase;
      letter-spacing: 1px;
    }
    .cta-button {
      display: inline-block;
      background: #E91E63;
      color: white;
      padding: 12px 30px;
      text-decoration: none;
      border-radius: 4px;
      font-weight: 600;
      margin: 20px 0;
    }
    .email-footer {
      background: #fafafa;
      padding: 30px;
      text-align: center;
      font-size: 12px;
      color: #999;
    }
    .email-footer a {
      color: #E91E63;
      text-decoration: none;
    }
  </style>
</head>
<body>
  <div class="email-container">
    <div class="email-header">
      <img src="https://acme.com/assets/logo-white.png" alt="Acme">
      <h1>Alert Triggered</h1>
      <p></p>
    </div>

    <div class="email-body">
      <h2></h2>
      <p></p>

      <div class="metric-card">
        <div class="metric-label">Current Value</div>
        <div class="metric-value"></div>
        <p></p>
      </div>

      <p><strong>What this means:</strong></p>
      <p></p>

      <p><strong>Recommended action:</strong></p>
      <ul>
        <li></li>
        <li></li>
      </ul>

      <center>
        <a href="" class="cta-button">
          View Dashboard
        </a>
      </center>
    </div>

    <div class="email-footer">
      <p>&copy; 2025 Acme Corporation. All rights reserved.</p>
      <p>
        <a href="">Notification Preferences</a> |
        <a href="">Unsubscribe</a>
      </p>
      <p style="margin-top: 20px; font-size: 11px;">
        This is an automated alert from Acme Analytics.
        For support, contact analytics@acme.com
      </p>
    </div>
  </div>
</body>
</html>

다음 단계

커스터마이징을 마스터했습니다. 다음 포스트에서는:

  • 운영과 모니터링: 백업, 복구, 성능 모니터링
  • 고가용성: Load balancing, Clustering
  • 문제 해결: Common issues, Debugging

요약

커스터마이징 체크리스트

브랜딩:

  • 로고 및 Favicon 변경
  • 색상 테마 적용
  • 폰트 커스터마이징
  • Application 이름 변경

도메인:

  • 커스텀 도메인 설정
  • SSL 인증서 설치
  • Nginx/Reverse proxy 설정
  • DNS 설정 완료

고급:

  • 환경 변수 최적화
  • 이메일 템플릿 커스터마이징
  • 커스텀 Drivers 설치
  • Landing page 설정

유지보수:

  • 정기 백업 스케줄
  • 업그레이드 계획
  • 모니터링 설정
  • 문서화 완료

다음 포스트에서는 Metabase를 안정적으로 운영하는 방법을 배웁니다!

📚 시리즈 전체 목차

🚀 기초편 (1-5화)

  1. Metabase 소개와 핵심 개념
  2. 설치와 초기 설정
  3. 샘플 데이터 둘러보기
  4. 첫 차트 만들기 - 실습 완전정복
  5. 대시보드 만들기 - 한 화면에 모으기

💪 활용편 (6-10화)

  1. 필터와 파라미터
  2. SQL 네이티브 쿼리
  3. 데이터 모델링
  4. 자동화와 알림
  5. 권한과 보안

🎯 고급편 (11-16화)

  1. 임베딩과 공유
  2. 성능 최적화
  3. 멀티 데이터소스
  4. [커스터마이징] (현재 글)
  5. 운영과 모니터링
  6. 실전 프로젝트
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.