화. 8월 12th, 2025

G: 안녕하세요! 클라우드 서비스의 편리함도 좋지만, 가끔은 데이터와 인프라에 대한 완전한 통제권을 가지고 싶은 욕구가 샘솟을 때가 있죠? 바로 그럴 때 Supabase Self-Hosted 솔루션이 빛을 발합니다. Supabase는 Firebase의 오픈소스 대안으로, PostgreSQL 데이터베이스 위에 인증(Auth), 스토리지(Storage), 실시간(Realtime), 엣지 함수(Edge Functions) 등 강력한 기능을 제공합니다.

하지만 Supabase를 직접 호스팅한다는 것은 단순히 docker-compose up을 하는 것 이상의 의미를 가집니다. 특히 프로덕션 환경에서는 API Gateway를 통한 도메인 설정철저한 보안 최적화가 필수적입니다. 이 글에서는 Supabase Self-Hosted 환경에서 API Gateway(Kong)를 중심으로 도메인을 설정하고, 서비스의 안정성과 보안을 극대화하는 방법에 대해 자세히 알아보겠습니다. 🛡️


1. Supabase Self-Hosted API Gateway의 이해 🤔

Supabase Self-Hosted 스택은 여러 컴포넌트(PostgREST, goTrue, Realtime, Storage 등)로 구성되어 있으며, 이 모든 컴포넌트 앞에 Kong이라는 강력한 오픈소스 API Gateway가 위치합니다.

  • Kong이 중요한 이유:
    • 단일 진입점: 모든 Supabase 서비스로 향하는 요청을 한 곳으로 집중시켜 관리 및 보안을 용이하게 합니다.
    • 라우팅: 들어오는 요청을 적절한 Supabase 서비스(예: auth.yourdomain.comgoTrue로, api.yourdomain.comPostgREST로)로 라우팅합니다.
    • 플러그인 아키텍처: 인증, 권한 부여, 속도 제한, 캐싱, 로깅 등 다양한 기능을 플러그인 형태로 추가하여 확장할 수 있습니다.
    • 보안 계층: 가장 바깥에서 요청을 필터링하고 악성 트래픽을 차단하는 1차 방어선 역할을 합니다.

Supabase의 docker-compose.yml 파일을 살펴보면 Kong이 어떻게 설정되어 있는지 확인할 수 있습니다. 기본적으로 Kong은 내부적으로 각 서비스로 요청을 전달하며, 우리는 주로 .env 파일 설정과 외부 리버스 프록시(Nginx/Caddy 등)를 통해 Kong에 접근하고 관리하게 됩니다.


2. 도메인 설정: 첫걸음 👣

Supabase Self-Hosted를 실제 서비스에 사용하려면 localhost 대신 고유한 도메인으로 접근할 수 있도록 설정해야 합니다. 이 과정은 DNS 설정과 Supabase 환경 변수 설정으로 나뉩니다.

2.1. DNS 설정 🌐

가장 먼저, 서비스에 사용할 도메인과 서브도메인을 서버의 공인 IP 주소에 연결해야 합니다. Supabase는 다양한 서브도메인을 사용하므로, 와일드카드(Wildcard) DNS 레코드를 설정하는 것이 편리합니다.

예시 (도메인이 yourdomain.com이고 서버 IP가 123.123.123.123인 경우):

레코드 타입 호스트 (이름) 값 (대상)
A @ 123.123.123.123
CNAME * yourdomain.com
  • A 레코드는 최상위 도메인(yourdomain.com)을 서버 IP에 매핑합니다.
  • CNAME 레코드는 auth.yourdomain.com, api.yourdomain.com, storage.yourdomain.com 등 모든 서브도메인을 yourdomain.com으로 리다이렉트합니다. 이렇게 하면 각 서브도메인마다 별도의 DNS 레코드를 설정할 필요가 없어 매우 편리합니다.

💡 팁: 일부 DNS 제공업체는 와일드카드 CNAME을 지원하지 않을 수 있습니다. 이 경우, auth, api, storage, realtime 등 필요한 각 서브도메인에 대해 개별 A 레코드를 설정해야 합니다.

2.2. Supabase 환경 변수 설정 (.env) ⚙️

Supabase Self-Hosted 프로젝트의 루트 디렉토리에 있는 .env 파일은 Supabase 스택의 모든 컴포넌트에 대한 환경 변수를 정의합니다. 여기에 도메인 정보를 추가하여 Kong이 올바른 라우팅을 수행하도록 지시합니다.

# .env 파일 예시
# ... 다른 설정들 ...

# Supabase Public URL (사용자가 접근할 URL)
PUBLIC_SUPABASE_URL="https://yourdomain.com" # 또는 https://api.yourdomain.com
PUBLIC_ANON_KEY="YOUR_ANON_KEY_HERE" # 이 키는 나중에 SDK 초기화에 사용됩니다.
PUBLIC_SERVICE_ROLE_KEY="YOUR_SERVICE_ROLE_KEY_HERE" # 이 키는 서버 측에서만 사용해야 합니다!

# 모든 서비스의 베이스 URL (와일드카드 도메인 사용 시)
PUBLIC_BASE_URL="yourdomain.com"

# 각 서비스별 도메인 (필요시 개별 설정)
# PUBLIC_AUTH_URL="https://auth.yourdomain.com"
# PUBLIC_DB_URL="https://api.yourdomain.com"
# PUBLIC_STORAGE_URL="https://storage.yourdomain.com"
# PUBLIC_REALTIME_URL="https://realtime.yourdomain.com"

# ... 다른 설정들 ...
  • PUBLIC_SUPABASE_URL: 클라이언트 측 SDK에서 Supabase를 초기화할 때 사용되는 기본 URL입니다. 일반적으로 최상위 도메인이나 api 서브도메인을 사용합니다.
  • PUBLIC_BASE_URL: 와일드카드 도메인을 사용하는 경우, 이 변수를 설정하면 Supabase 내부적으로 auth, api, storage 등의 서브도메인을 자동으로 생성하여 사용합니다.
  • 각 서비스별 URL은 PUBLIC_BASE_URL이 충분히 역할을 하므로, 특별한 이유가 없다면 개별적으로 설정할 필요는 없습니다.

2.3. Supabase 스택 재시작 🔄

.env 파일을 수정한 후에는 변경사항을 적용하기 위해 Supabase Docker 스택을 재시작해야 합니다.

docker-compose down
docker-compose up -d

이제 웹 브라우저에서 설정한 도메인(예: https://yourdomain.com 또는 https://api.yourdomain.com)으로 접근하여 Supabase 스튜디오 또는 API가 정상적으로 작동하는지 확인합니다.


3. HTTPS 및 SSL/TLS 보안 강화 🔒

도메인 설정이 완료되었다면, 이제 가장 중요한 보안 조치인 HTTPS(SSL/TLS)를 적용할 차례입니다. 데이터 암호화는 물론, 사용자 신뢰 확보 및 SEO에도 필수적입니다. Supabase Self-Hosted 환경에서 SSL을 적용하는 가장 일반적인 방법은 Kong 앞에 리버스 프록시를 두어 SSL 인증서를 관리하게 하는 것입니다.

3.1. 리버스 프록시 (Nginx 또는 Caddy) 사용 🛠️

Kong은 자체적으로 SSL을 처리할 수 있지만, Let’s Encrypt와 같은 인증서를 자동 갱신하고 관리하는 데는 Nginx나 Caddy와 같은 전용 리버스 프록시가 더 효율적이고 유연합니다.

설치 및 구성 예시 (Nginx + Certbot):

  1. Nginx 설치:

    sudo apt update
    sudo apt install nginx
  2. Supabase Docker 포트 변경 (옵션): 기본적으로 Supabase의 Kong은 80/443 포트를 사용하려고 할 수 있습니다. Nginx가 80/443을 사용하도록 하려면, Supabase의 docker-compose.yml에서 Kong 서비스의 포트 매핑을 변경하여 Nginx와 충돌하지 않도록 합니다.

    # docker-compose.yml 예시
    services:
      kong:
        # ...
        ports:
          - "8000:8000" # 외부 HTTP 포트 (Nginx가 접근할 포트)
          - "8443:8443" # 외부 HTTPS 포트 (Nginx가 접근할 포트)
          # - "80:8000" # 기존 포트 매핑은 주석 처리 또는 제거
          # - "443:8443" # 기존 포트 매핑은 주석 처리 또는 제거

    이 경우, Nginx는 80/443으로 요청을 받아 Supabase의 8000/8443 포트로 포워딩하게 됩니다.

  3. Nginx 설정 (/etc/nginx/sites-available/yourdomain.com):

    server {
        listen 80;
        server_name yourdomain.com *.yourdomain.com; # 와일드카드 도메인
        return 301 https://$host$request_uri; # 모든 HTTP 요청을 HTTPS로 리다이렉트
    }
    
    server {
        listen 443 ssl http2;
        server_name yourdomain.com *.yourdomain.com;
    
        ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem; # Certbot 경로
        ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem; # Certbot 경로
    
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
    
        location / {
            proxy_pass http://localhost:8000; # Supabase Kong의 HTTP 포트
            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;
            proxy_redirect off;
    
            # 웹소켓 프록시 설정 (Realtime 서비스용)
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
    • listen 80: 모든 HTTP 요청을 HTTPS로 리다이렉트합니다.
    • listen 443 ssl http2: HTTPS 요청을 처리합니다.
    • ssl_certificate / ssl_certificate_key: Certbot이 생성한 인증서 경로를 지정합니다.
    • proxy_pass http://localhost:8000: Kong의 HTTP 포트로 요청을 전달합니다. 만약 HTTPS로 전달하고 싶다면 https://localhost:8443으로 설정하고 Kong의 HTTPS 포트를 열어주면 됩니다.
    • proxy_set_header: 원래 클라이언트 IP 등의 정보를 Kong으로 전달합니다.
    • 웹소켓 프록시 설정: Supabase Realtime 서비스는 웹소켓을 사용하므로, 이 설정을 반드시 포함해야 합니다.
  4. Certbot으로 SSL 인증서 발급:

    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d yourdomain.com -d *.yourdomain.com --agree-tos --email your_email@example.com --no-eff-email

    이 명령은 Nginx 설정을 자동으로 수정하고 인증서를 발급받아 적용합니다. 와일드카드 인증서는 DNS-01 챌린지를 요구할 수 있으므로, 해당 방법에 따라 진행해야 합니다.

  5. Nginx 설정 활성화 및 재시작:

    sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
    sudo nginx -t # 설정 파일 문법 검사
    sudo systemctl restart nginx

이제 https://yourdomain.com으로 접속하면 안전하게 암호화된 통신을 사용할 수 있습니다.


4. 핵심 보안 최적화 🛡️

도메인 설정과 SSL 암호화는 시작에 불과합니다. Supabase Self-Hosted 환경에서는 더욱 깊이 있는 보안 최적화가 필요합니다.

4.1. API 키 관리 (Anon Key & Service Role Key) 🔑

Supabase는 두 가지 주요 API 키를 사용합니다.

  • PUBLIC_ANON_KEY (Anon Key):

    • 용도: 클라이언트(웹 브라우저, 모바일 앱)에서 Supabase SDK를 초기화하고, RLS(Row-Level Security) 규칙에 따라 공개적으로 접근 가능한 리소스에 접근할 때 사용됩니다.
    • 보안: 이 키는 공개되어도 안전하도록 설계되었습니다. 왜냐하면 RLS가 적용되어 있기 때문에, 이 키만으로는 민감한 데이터에 접근할 수 없기 때문입니다.
    • 관리: .env 파일에 설정하고, 클라이언트 코드에 포함시킵니다.
  • PUBLIC_SERVICE_ROLE_KEY (Service Role Key):

    • 용도: RLS를 우회하여 데이터베이스의 모든 데이터에 대한 완전한 접근 권한을 가집니다. 서버 측 코드(예: Edge Functions, 백엔드 서버, Cron Job)에서만 사용해야 합니다.
    • 보안: 절대 클라이언트 측 코드에 노출되어서는 안 됩니다. 이 키가 노출되면 데이터베이스 전체가 위험에 처할 수 있습니다.
    • 관리: .env 파일에 설정하되, GitHub과 같은 버전 관리 시스템에 직접 커밋되지 않도록 .gitignore에 추가하고, CI/CD 환경에서는 환경 변수로 주입하는 방식을 권장합니다.

4.2. 속도 제한 (Rate Limiting) ⏳

API Gateway 수준에서 속도 제한을 적용하여 서비스 남용, DDoS 공격 및 무차별 대입 공격을 방지합니다.

  • Nginx를 통한 Rate Limiting: Nginx 설정 파일에 다음 내용을 추가할 수 있습니다.

    # http 블록 안에 추가 (전역 설정)
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s; # 10MB 메모리, 초당 10개 요청 허용
    
    server {
        # ...
        location / {
            limit_req zone=one burst=20 nodelay; # 'burst'는 일시적으로 허용되는 초과 요청 수
            # ... proxy_pass 설정 ...
        }
    }
    • 이 설정은 단일 IP 주소에서 초당 10개 이상의 요청이 들어오면 제한하고, 최대 20개까지는 일시적으로 허용합니다.
  • Kong 플러그인 (고급): Kong 자체도 Rate Limiting 플러그인을 제공합니다. docker-compose.yml을 수정하여 Kong Admin API를 노출시킨 후, Kong Admin API를 통해 플러그인을 활성화할 수 있습니다. 하지만 이는 복잡성이 높아 초보자에게는 권장하지 않습니다.

4.3. 웹 애플리케이션 방화벽 (WAF) 🚧

WAF는 SQL Injection, XSS(Cross-Site Scripting) 등 OWASP Top 10에 나열된 일반적인 웹 공격으로부터 애플리케이션을 보호합니다.

  • Nginx ModSecurity: Nginx와 함께 ModSecurity WAF 모듈을 설치하여 활용할 수 있습니다.
  • 클라우드 기반 WAF: Cloudflare, AWS WAF 등 전문 클라우드 WAF 서비스를 사용하는 것이 가장 강력하고 관리 부담이 적은 방법입니다. 서버 앞에 이러한 서비스를 두어 모든 트래픽을 필터링하게 합니다.

4.4. CORS (Cross-Origin Resource Sharing) 설정 🤝

웹 브라우저에서 Supabase API를 호출하려면 CORS 정책이 올바르게 설정되어야 합니다. Supabase는 기본적으로 이 부분을 잘 처리하지만, 특정 도메인만 허용하도록 명시적으로 설정하는 것이 보안상 유리합니다.

  • 일반적으로 .env 파일의 PUBLIC_SUPABASE_URL이 설정되면 Supabase 내부적으로 올바른 CORS 헤더를 보냅니다.
  • Kong 플러그인을 통해 특정 도메인만 허용하는 CORS 정책을 강제할 수도 있습니다.

4.5. JWT 보안 및 RLS (Row-Level Security) 🛡️🛡️

Supabase의 핵심 보안 기능입니다.

  • JWT (JSON Web Token): Supabase Auth(goTrue)는 사용자가 로그인할 때 JWT를 발급합니다. 이 토큰은 사용자의 신원과 권한 정보를 담고 있으며, API 요청 시 Authorization 헤더에 포함되어 전송됩니다. Kong은 이 토큰을 검증하여 요청의 유효성을 확인합니다.
    • 만료 시간: 토큰의 만료 시간을 적절하게 설정하고, 주기적으로 갱신(Refresh Token) 메커니즘을 사용해야 합니다.
  • RLS (Row-Level Security): Supabase 보안의 심장입니다. PostgreSQL의 강력한 RLS 기능을 활용하여, 데이터베이스 테이블의 각 행(row)에 대한 접근 권한을 사용자 역할(role), JWT 클레임 등에 따라 세밀하게 제어합니다.

    • 예시 (게시판 테이블 posts에 RLS 적용):

      • 읽기: 모든 사용자가 모든 게시물을 읽을 수 있도록 허용.
        CREATE POLICY "Enable read access for all users" ON public.posts
        FOR SELECT USING (true);
      • 쓰기: 로그인한 사용자만 게시물을 생성할 수 있고, auth.uid() 함수를 통해 자신의 user_id와 일치하는 게시물만 수정/삭제할 수 있도록 허용.

        CREATE POLICY "Users can insert their own posts" ON public.posts
        FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);
        
        CREATE POLICY "Users can update their own posts" ON public.posts
        FOR UPDATE USING (auth.uid() = user_id);
        
        CREATE POLICY "Users can delete their own posts" ON public.posts
        FOR DELETE USING (auth.uid() = user_id);
    • 핵심: service_role_key를 사용하지 않는 모든 클라이언트 요청은 RLS에 의해 통제됩니다. 데이터베이스에 RLS를 활성화하고, 각 테이블에 맞는 정책을 신중하게 정의하는 것이 매우 중요합니다.

4.6. 네트워크 보안 및 방화벽 🧱

서버 자체의 방화벽 설정은 기본 중의 기본입니다.

  • 필수 포트만 개방:
    • 22 (SSH): 원격 접속용. 특정 IP에서만 허용하는 것이 가장 안전합니다.
    • 80 (HTTP), 443 (HTTPS): 웹 서비스용. Nginx/Caddy가 사용합니다.
    • 그 외 Supabase 내부 서비스 포트(8000, 8443, 5432, 54322 등)는 외부에서 직접 접근할 수 없도록 방화벽으로 차단해야 합니다. Nginx와 같은 리버스 프록시를 통해서만 접근 가능하도록 합니다.
  • 예시 (UFW – Ubuntu Firewall):
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow ssh # 또는 sudo ufw allow from your_ip to any port 22
    sudo ufw allow http
    sudo ufw allow https
    sudo ufw enable

4.7. 로깅 및 모니터링 📊

지속적인 로깅과 모니터링은 잠재적인 보안 위협을 조기에 감지하고 문제 해결에 필수적입니다.

  • 액세스 로그: Nginx, Kong, 그리고 Supabase 컴포넌트들의 액세스 로그를 수집하고 분석합니다.
  • 에러 로그: 시스템 및 애플리케이션 에러 로그를 주기적으로 확인합니다.
  • 모니터링 도구: Prometheus, Grafana, ELK Stack(Elasticsearch, Logstash, Kibana) 등을 사용하여 시스템 성능, 트래픽, 보안 이벤트 등을 시각화하고 알림을 설정합니다.

5. 성능 최적화 및 기타 팁 🚀💨

보안만큼 중요한 것이 서비스의 성능입니다. 사용자 경험을 향상시키고 비용을 절감하는 데 기여합니다.

5.1. 캐싱 ⚡

  • API Gateway 캐싱: Kong의 캐싱 플러그인 또는 Nginx의 proxy_cache 기능을 사용하여 자주 요청되는 정적 자원이나 변경이 적은 API 응답을 캐싱하여 부하를 줄이고 응답 속도를 높일 수 있습니다.
  • CDN (Content Delivery Network): storage.yourdomain.com과 같은 스토리지 서비스에서 제공되는 이미지, 동영상 등 대용량 정적 파일은 CDN을 통해 전 세계 사용자에게 더 빠르게 전송될 수 있습니다.

5.2. Gzip 압축 📦

Nginx 설정에서 gzip on;을 활성화하여 응답 데이터를 압축함으로써 전송 속도를 향상시킬 수 있습니다.

# Nginx server 블록 또는 http 블록 안에 추가
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_comp_level 6;
gzip_min_length 1000;

5.3. 정기적인 업데이트 및 백업 💾

  • Supabase 및 Docker 컴포넌트 업데이트: Supabase Self-Hosted 스택은 지속적으로 개선되고 있습니다. 정기적으로 docker-compose.yml을 최신 버전으로 업데이트하고, 보안 패치를 적용하는 것이 중요합니다.
  • 데이터베이스 백업: 데이터는 곧 자산입니다. PostgreSQL 데이터베이스에 대한 정기적인 백업 전략을 수립하고 자동화해야 합니다. pg_dump를 사용하거나 클라우드 스토리지 서비스와 연동하여 백업을 관리합니다.

5.4. 서버 리소스 모니터링 🖥️

CPU, 메모리, 디스크 사용량, 네트워크 트래픽 등 서버 리소스를 지속적으로 모니터링하여 병목 현상을 예측하고 대응합니다. htop, nmon과 같은 도구와 함께 클라우드 제공업체의 모니터링 서비스를 활용할 수 있습니다.


결론 🎉

Supabase Self-Hosted API Gateway를 도메인 설정부터 보안 최적화까지 다루는 것은 결코 쉬운 일이 아닙니다. 하지만 이 과정을 통해 여러분은 데이터에 대한 완전한 통제권, 뛰어난 유연성, 그리고 비용 효율성을 확보할 수 있습니다. Kong과 리버스 프록시를 통해 트래픽을 효율적으로 관리하고, SSL/TLS 암호화, API 키 관리, 속도 제한, WAF, RLS, 네트워크 방화벽 등 다층적인 보안 전략을 적용함으로써 더욱 강력하고 안전한 Supabase 서비스를 구축할 수 있습니다.

물론, 직접 호스팅하는 것은 전문적인 지식과 지속적인 관리를 요구합니다. 하지만 잘 구축된 Supabase Self-Hosted 환경은 여러분의 프로젝트에 무한한 가능성을 열어줄 것입니다. 오늘 배운 지식들이 여러분의 Supabase Self-Hosted 여정에 큰 도움이 되기를 바랍니다! Happy Hacking! 🚀✨

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다