TELEPASI

검색하기 전에 통하다

Self-hosted Supabase API 도메인 연결

강병우
2026.07.18 👁️ 106

Self-hosted Supabase API 도메인 연결

관련 시리즈
Self-hosted Supabase Google 로그인 설정 (1/3) - 개념과 Google Cloud 설정
Self-hosted Supabase Google 로그인 설정 (2/3) - 서버 설정
Self-hosted Supabase Google 로그인 설정 (3/3) - Web 연동과 테스트

Self-hosted Supabase를 외부에서 접근하려면 도메인, DNS, HTTPS 인증서, Nginx 프록시를 설정해야 합니다. 이 문서는 Google 로그인뿐만 아니라 모든 Supabase API 외부 연결에 적용되는 범용 인프라 가이드입니다.


예시 환경

  • Supabase 외부 API 도메인: sb.example.com
  • Supabase 설치 경로: /root/supabase/docker
  • API Gateway: Kong (Docker 컨테이너, 포트 8000)
  • 호스트 Nginx: 443 (HTTPS) → 8000 (Kong)
  • 운영체제: Ubuntu 예시

중요: 이 문서의 example.com은 예제 도메인입니다. 실제 설정할 때는 자신이 소유한 도메인으로 모두 바꿔야 합니다.


1. 포트와 네트워크 구조 이해

Self-hosted Supabase의 요청 흐름을 이해하면 설정이 명확해집니다.

1.1 전체 요청 경로

인터넷 (브라우저)
  ↓ HTTPS :443
호스트 Nginx
  ↓ HTTP :8000 (loopback)
Docker Kong 컨테이너
  ↓ Docker Network
Supabase Auth/REST/Storage 컨테이너들

1.2 포트 종류

외부 HTTPS 포트 443

사용자 브라우저가 접속하는 공개 포트입니다.

https://sb.example.com:443

HTTPS의 기본 포트이므로 실제 URL에서는 :443을 생략합니다. 이 포트는 호스트 OS에서 실행 중인 Nginx가 사용합니다.

호스트 포트 8000

Docker가 Kong 컨테이너의 포트를 서버 호스트에 연결한 포트입니다.

서버 호스트의 localhost:8000

Nginx는 이 주소로 요청을 전달합니다.

Kong 컨테이너 포트 8000

Kong 컨테이너 내부에서 API 요청을 받는 포트입니다. Docker Compose의 ports가 호스트 포트와 컨테이너 포트를 연결합니다.

ports:
  - ${KONG_HTTP_PORT}:8000/tcp

.env가 다음과 같다면:

KONG_HTTP_PORT=8000

실제 의미는 다음과 같습니다.

호스트 8000번 포트 → Kong 컨테이너 8000번 포트

Docker Compose의 일반적인 포트 표기법은 HOST_PORT:CONTAINER_PORT입니다.

Docker Network

Docker Compose로 실행한 컨테이너는 기본적으로 같은 전용 네트워크에 연결됩니다. 이 환경의 네트워크 이름은 supabase_default입니다.

같은 네트워크의 컨테이너는 IP 주소를 직접 외우지 않고 Compose 서비스 이름으로 서로를 찾을 수 있습니다.

Kong 컨테이너 → http://auth:9999
Kong 컨테이너 → http://rest:3000
Kong 컨테이너 → http://storage:5000

여기서 auth, rest, storage는 인터넷 도메인이 아니라 docker-compose.yml의 서비스 이름입니다. Docker 내부 DNS가 이름을 컨테이너 IP로 변환합니다.

1.3 실제 요청 이동 경로

브라우저가 다음 주소를 요청한다고 가정합니다.

https://sb.example.com/auth/v1/settings

요청은 다음 순서로 이동합니다.

[1] 사용자 브라우저
    https://sb.example.com/auth/v1/settings
                     │
                     │ DNS: sb.example.com → 서버 공인 IP
                     ▼
[2] 서버 호스트의 Nginx
    0.0.0.0:443 (HTTPS 종료, 인증서 검증)
                     │
                     │ proxy_pass http://127.0.0.1:8000
                     ▼
[3] Docker가 공개한 Kong 호스트 포트
    127.0.0.1:8000
                     │
                     │ host port 8000 → container port 8000
                     ▼
[4] supabase-kong 컨테이너
    Kong :8000
                     │
                     │ /auth/v1/settings 경로 규칙 확인
                     │ Docker 내부 주소 http://auth:9999/settings
                     ▼
[5] supabase-auth 컨테이너
    GoTrue :9999

Nginx는 /auth/v1/settings의 의미를 해석하지 않습니다. 경로를 그대로 Kong에 전달합니다. 어떤 컨테이너로 보낼지 결정하는 프로그램은 Kong입니다.

1.4 호스트 Nginx와 컨테이너 Nginx의 차이

이 문서의 Nginx는 Docker 컨테이너가 아니라 서버 호스트에 설치된 Nginx입니다. 따라서 다음 주소를 사용합니다.

proxy_pass http://127.0.0.1:8000;

호스트 Nginx는 Docker 내부 서비스 이름 kong, auth를 기본적으로 해석할 수 없습니다. 다음 설정은 이 구성에서 사용하면 안 됩니다.

# 호스트 Nginx에서는 일반적으로 동작하지 않음
proxy_pass http://kong:8000;
proxy_pass http://auth:9999;

반대로 Nginx도 Docker 컨테이너로 실행하고 Supabase와 같은 Docker Network에 연결했다면 다음처럼 서비스 이름으로 접근할 수 있습니다.

# Nginx 역시 같은 Docker Network 안에 있을 때만 사용
proxy_pass http://kong:8000;

두 방식을 섞지 않는 것이 중요합니다.


2. DNS 설정

도메인 관리 서비스에서 Supabase API 하위 도메인을 서버 공인 IP로 연결합니다.

2.1 A 레코드 등록

유형: A
호스트/이름: sb
값: 서버의 공인 IPv4 주소
TTL: 자동 또는 300

등록 결과:

sb.example.com → 서버 공인 IP

2.2 DNS 확인

dig +short sb.example.com

서버 공인 IP와 같은 값이 나와야 합니다. DNS 전파에는 수분에서 수십 분이 걸릴 수 있습니다.


3. Kong 포트를 호스트에 공개하기

docker-compose.yml의 Kong 서비스에 포트 매핑이 있어야 합니다.

3.1 기본 포트 매핑

기본 예:

services:
  kong:
    ports:
      - ${KONG_HTTP_PORT}:8000/tcp
      - ${KONG_HTTPS_PORT}:8443/tcp

이 형식은 기본적으로 0.0.0.0:8000에 바인딩될 수 있어 방화벽 설정에 따라 인터넷에서 서버IP:8000으로 직접 접근될 가능성이 있습니다.

3.2 보안 강화: loopback 바인딩

Nginx와 Kong이 같은 서버에 있고 외부에서 Kong 포트에 직접 접근할 이유가 없다면, 다음처럼 loopback에만 바인딩하는 구성이 더 안전합니다.

services:
  kong:
    ports:
      - "127.0.0.1:${KONG_HTTP_PORT}:8000/tcp"
      - "127.0.0.1:${KONG_HTTPS_PORT}:8443/tcp"

3.3 변경 적용

변경 후 Kong을 다시 생성합니다.

cd /root/supabase/docker
docker compose up -d --force-recreate --no-deps kong

3.4 포트 확인

ss -lntp | grep -E ':(8000|8443)\b'

권장 결과:

127.0.0.1:8000
127.0.0.1:8443

8443은 Kong 자체 HTTPS 포트입니다. 이 구성에서는 Nginx가 공인 인증서와 HTTPS를 처리하므로 Nginx의 upstream은 일반 HTTP 127.0.0.1:8000을 사용합니다. 같은 서버 내부의 loopback 통신이기 때문에 이 구간을 다시 HTTPS로 암호화할 필요는 일반적으로 없습니다.


4. Nginx 설치

4.1 패키지 설치 (Ubuntu)

apt update
apt install -y nginx certbot python3-certbot-nginx

systemctl enable --now nginx
systemctl status nginx

4.2 방화벽 설정

방화벽을 사용한다면 HTTP/HTTPS를 허용합니다.

ufw allow 'Nginx Full'
ufw status

Kong의 8000, Auth의 9999 포트를 외부 방화벽에 열 필요는 없습니다.


5. HTTP 서버 블록 생성

인증서가 아직 없다면 인증서 경로를 포함한 HTTPS 설정부터 작성하면 Nginx가 시작되지 않습니다. 먼저 HTTP 전용 설정을 만듭니다.

5.1 최초 HTTP 설정

파일:

/etc/nginx/sites-available/sb.example.com

최초 설정:

server {
    listen 80;
    listen [::]:80;
    server_name sb.example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        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;
    }
}

5.2 설정 활성화

ln -s /etc/nginx/sites-available/sb.example.com \
  /etc/nginx/sites-enabled/sb.example.com

nginx -t
systemctl reload nginx

이미 심볼릭 링크가 있다면 File exists가 출력될 수 있으며 새로 만들 필요가 없습니다.

5.3 HTTP 연결 확인

curl -I http://sb.example.com/auth/v1/health

정상적인 경우 Supabase Auth의 응답을 받습니다.


6. Let's Encrypt 인증서 발급

DNS가 서버를 가리키고 Nginx의 80번 포트가 외부에서 접근 가능해야 합니다.

6.1 Certbot 실행

certbot --nginx -d sb.example.com

Certbot 질문에 따라:

  • 이메일 입력
  • 약관 동의
  • HTTP → HTTPS 리디렉션 선택 (권장)

6.2 인증서 확인

certbot certificates
systemctl status certbot.timer

6.3 자동 갱신 테스트

certbot renew --dry-run

7. 최종 HTTPS 설정

인증서 발급 후 다음처럼 구성합니다.

7.1 최종 Nginx 설정

파일: /etc/nginx/sites-available/sb.example.com

# HTTP 요청을 HTTPS로 이동
server {
    listen 80;
    listen [::]:80;
    server_name sb.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS 요청을 Kong으로 전달
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name sb.example.com;

    ssl_certificate /etc/letsencrypt/live/sb.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sb.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    access_log /var/log/nginx/sb.example.com.access.log;
    error_log /var/log/nginx/sb.example.com.error.log;

    client_max_body_size 100m;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;

        # Realtime WebSocket 연결에도 필요한 헤더
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # 원래 요청의 도메인, IP, HTTPS 정보를 Kong/서비스에 전달
        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_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        proxy_buffering off;
    }

    add_header Strict-Transport-Security \
      "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
}

7.2 각 핵심 지시문의 의미

  • listen 443 ssl: 외부 HTTPS 요청 수신
  • server_name: 이 설정을 적용할 도메인
  • ssl_certificate: 브라우저가 신뢰할 인증서
  • location /: 모든 Supabase API 경로를 같은 upstream으로 전달
  • proxy_pass: 호스트에 공개된 Kong 포트
  • Host: 원래 도메인을 upstream에 전달
  • X-Forwarded-Proto: 원래 요청이 HTTPS였음을 서비스에 전달
  • Upgrade, Connection: Supabase Realtime WebSocket 지원

7.3 설정 적용

nginx -t
systemctl reload nginx

nginx -t가 실패하면 reload하지 말고 표시된 파일과 줄 번호를 먼저 수정합니다.


8. 브라우저에서 정상 접속 확인

Nginx 설정을 반영한 후 브라우저에서 다음 주소를 엽니다.

https://sb.example.com

다음 상태라면 Nginx에서 Supabase까지의 기본 연결은 정상입니다.

  • ✓ HTTPS 자물쇠가 표시되고 인증서 경고가 없습니다.
  • ✓ Supabase Dashboard 인증 창 또는 Supabase 화면이 표시됩니다.
  • 502 Bad Gateway, DNS 오류, 연결 시간 초과가 없습니다.

8.1 추가 확인

특정 API 엔드포인트 테스트:

curl -I https://sb.example.com/auth/v1/health

9. 외부에 열어야 하는 포트

일반적인 단일 서버 구성의 권장 범위:

80/tcp   외부 허용: Let's Encrypt ACME 챌린지와 HTTPS 리디렉션
443/tcp  외부 허용: Supabase HTTPS API
8000/tcp 외부 차단: Nginx만 loopback으로 접근
8443/tcp 외부 차단: 이 구성에서는 직접 사용하지 않음
9999/tcp 외부 차단: Docker 내부 Auth 전용

정리하면, 사용자는 https://sb.example.com의 443번 포트만 사용합니다. Nginx 뒤의 80009999는 외부 사용자가 직접 접근할 포트가 아닙니다.


10. 일반적인 문제와 해결

10.1 브라우저에서 사이트를 찾을 수 없음

원인: DNS가 서버를 가리키지 않습니다.

해결:

dig +short sb.example.com

서버 공인 IP가 나와야 합니다. 결과가 없거나 다른 IP가 나온다면 DNS 레코드를 확인하고 전파를 기다립니다.

10.2 인증서 경고

원인:

  • 인증서가 발급되지 않았거나 만료됨
  • 도메인 불일치

해결:

certbot certificates

인증서 도메인과 만료일을 확인합니다. 필요하면 재발급:

certbot --nginx -d sb.example.com --force-renewal

10.3 502 Bad Gateway

원인: Nginx는 정상이지만 Kong이 응답하지 않습니다.

해결:

# Kong 컨테이너 상태 확인
cd /root/supabase/docker
docker compose ps kong

# Kong 로그 확인
docker compose logs --tail=100 kong

# Kong 재시작
docker compose restart kong

10.4 연결 시간 초과

원인:

  • 서버 방화벽이 443 포트를 차단
  • Nginx가 중지됨

해결:

# Nginx 상태 확인
systemctl status nginx

# 방화벽 확인
ufw status

# 포트 리스닝 확인
ss -lntp | grep :443

11. 보안 체크리스트

  • Kong 포트는 loopback에만 바인딩되어 있습니다.
  • 외부 방화벽에서 80, 443 외의 포트는 차단되어 있습니다.
  • Let's Encrypt 자동 갱신이 활성화되어 있습니다.
  • Nginx 로그 파일 권한이 적절히 제한되어 있습니다.
  • HTTPS에서만 Supabase API에 접근합니다.
  • Nginx에 HSTS 헤더가 설정되어 있습니다.

12. 다음 단계

인프라 설정이 완료되었다면 이제 Supabase의 특정 기능을 설정할 수 있습니다.

관련 시리즈:

주파수 소통방 (0)

로딩 중...