Supabase 셀프 호스팅 가이드
Supabase 는 백엔드를 위한 거의 모든 기능을 포함하고 있다. 클라우드에서 하나의 서비스를 사용할 수 있지만, 개발용으로 다루기 위해서는 셀프 호스팅이 편리하다. 요즘은 AI 애플리케이션을 개발하기 위해 인기가 더 높아졌다.
Supabase 셀프 호스팅 가이드
오랜만에 다뤄 보려고 하니깐 기억도 안나고 해서, 초심자의 마음으로 정리합니다.
1. Docker 기반 셀프 호스팅
따라하기 : 공식문서 - Self-Hosting with Docker
- 깃허브 다운로드 : 2026년 1월기준 최신 태그 v1.26.01
- 인스턴스용 디렉토리 생성
- 환경파일 복사
- 도커 이미지 다운로드
- 환경파일 키 생성 및 수정 (
generate-keys.sh) - 도커 컴포즈 시작
따라하기만 하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Get the code
git clone --depth 1 https://github.com/supabase/supabase
# Make your new supabase project directory
mkdir supabase-project
# Tree should look like this
# .
# ├── supabase
# └── supabase-project
# Copy the compose files over to your project
cp -rf supabase/docker/* supabase-project
# Copy the fake env vars
cp supabase/docker/.env.example supabase-project/.env
# Switch to your project directory
cd supabase-project
# Pull the latest images
docker compose pull
키를 자동으로 생성하고 적용하는 스크립트가 있어서 편하다.
1
2
3
4
5
6
7
8
# 키 생성 및 환경파일 수정 (자동)
sh ./utils/generate-keys.sh
# => JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY,
# SECRET_KEY_BASE, VAULT_ENC_KEY, PG_META_CRYPTO_KEY,
# LOGFLARE_PUBLIC_ACCESS_TOKEN, LOGFLARE_PRIVATE_ACCESS_TOKEN,
# S3_PROTOCOL_ACCESS_KEY_ID, S3_PROTOCOL_ACCESS_KEY_SECRET,
# POSTGRES_PASSWORD, DASHBOARD_PASSWORD
이 중에 DASHBOARD_PASSWORD 와 POSTGRES_PASSWORD 는 따로 작성하자. 그리고 psql 접속에 사용되는 POOLER_TENANT_ID 도 기억하기 쉽도록 수정한다.
1
2
3
4
5
vi .env
DASHBOARD_PASSWORD=...
POSTGRES_PASSWORD=...
POOLER_TENANT_ID=dev-server
준비는 다 되었고, supabase-project 디렉토리에서 명령어를 실행한다.
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
# 시작
$ docker compose up -d
WARN[0000] No services to build
[+] up 14/14
✔ Network supabase_default Created
✔ Container supabase-imgproxy Created
✔ Container supabase-vector Healthy
✔ Container supabase-db Healthy
✔ Container supabase-analytics Healthy
✔ Container supabase-pooler Created
✔ Container supabase-kong Created
✔ Container supabase-auth Created
✔ Container supabase-meta Created
✔ Container realtime-dev.supabase-realtime Created
✔ Container supabase-rest Created
✔ Container supabase-studio Created
✔ Container supabase-edge-functions Created
✔ Container supabase-storage Created
# 상태 확인
$ docker compose ps
$ docker compose logs analytics
# 종료
$ docker compose down
도커 스택이 모두 정상 작동하였으면 대시보드에 접속하자.
2. 접속 테스트
Supabase 백엔드가 잘 작동하는지 테스트를 해보자.
- API Keys 생성 : 셀프 호스팅에서는 필요 없음
edge function
rest query
GoTrue Auth API 확인하기
1
2
3
4
5
6
7
8
9
10
11
export SB_ANON_KEY="..."
curl -X GET 'http://localhost:8000/auth/v1/health' \
-H "apikey: $SB_ANON_KEY" \
-H "Authorization: Bearer $SB_ANON_KEY"
{
"version":"v2.184.0",
"name":"GoTrue",
"description":"GoTrue is a user registration and authentication API"
}
todos 테이블 생성 후 쿼리하기
1
2
3
4
5
6
7
8
9
10
11
12
export SB_ANON_KEY="..."
curl 'http://localhost:8000/rest/v1/todos' \
-H "apikey: $SB_ANON_KEY" \
-H "Authorization: Bearer $SB_ANON_KEY"
[
{"id":1,"task":"Create tables"},
{"id":2,"task":"Enable security"},
{"id":3,"task":"Add data"},
{"id":4,"task":"Fetch data from the API"}
]
db connection
연결한 김에 postgres 의 타임존(TZ)을 변경하자.
1
2
3
4
5
6
7
# direct connect
psql 'postgres://postgres.{테넌트ID}:{패스워드}@localhost:5432/postgres'
# pooling connect
psql 'postgres://postgres.{테넌트ID}:{패스워드}@localhost:6543/postgres'
ALTER DATABASE postgres SET timezone TO 'Asia/Seoul';
3. 자바스크립트 API 사용
bun 으로 TS 프로젝트를 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
# 프로젝트 생성
bun init my-app
# > Blank 선택
cd my-app
# supabase 클라이언트 패키지 설치
bun add @supabase/supabase-js
# 실행
bun index.ts
# 출력> Hello via Bun!
앞에서 생성했던 todos 테이블을 출력해 보자.
1
2
3
4
5
6
7
8
9
10
11
12
import { createClient } from '@supabase/supabase-js'
console.log("Hello via Bun!");
let SB_URL = 'http://localhost:8000'
let SB_KEY = process.env.SB_ANON_KEY;
// Create a single supabase client for interacting with your database
const supabase = createClient(SB_URL, SB_KEY);
const { data } = await supabase.from('todos').select();
console.log(JSON.stringify(data, null, 2));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 실행
bun index.ts
# 출력>
Hello via Bun!
[
{
"id": 1,
"task": "Create tables"
},
{
"id": 2,
"task": "Enable security"
},
{
"id": 3,
"task": "Add data"
},
{
"id": 4,
"task": "Fetch data from the API"
}
]
plainObject 를 class 로 변형하는 코드도 추가해 봤다.
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
const isObjectArr = (value) => {
return (
typeof value === 'object' &&
value !== null &&
Array.isArray(data)
);
}
// console.log(`=> ${isObjectArr(data) }`);
if (!isObjectArr(data)) {
throw new TypeError('data is not an Array of Objects');
}
////////////////////////////////////////////
const formatNumber = (num: number, targetLength: number): string => {
return String(num).padStart(targetLength, '0');
};
interface ITodo {
id: number;
task: string;
}
class Todo implements ITodo {
id: number;
task: string;
constructor(data: ITodo){
Object.assign(this, data);
}
getDisplayName(): string {
let paddedId = formatNumber(this.id,2);
let shortenTask = this.task.slice(0,10) + (this.task.length > 10 ? '..' : '');
return `${paddedId}-${shortenTask}`;
}
}
let todos:Todo[] = data.map(item => new Todo(item));
for (const todo of todos){
console.log(todo.getDisplayName());
}
/*
01-Create tab..
02-Enable sec..
03-Add data
04-Fetch data..
*/
원래는 typia 라이브러리를 써보려고 했는데, 무슨 이유인지 안된다.
1
2
3
4
5
6
7
8
9
$ bun add typia
$ bun typia setup --manager bun
# 소스 작성하고...
$ bun index.ts
error: Error on typia.is(): no transform has been configured.
Read and follow https://typia.io/docs/setup please.
9. Reviews
- 컴퓨터를 종료하기 전에 supabase 도커 스택도 종료해야 옳다.
- 다시 켜면 자동으로 시작되는데 정상 시동되지 않는 경우가 있다.
- 타입스크립트 오랜만에 만져보니 타이핑이 번거롭다.
- class-transformer 는 뭐고 typia 는 또 뭔가?
끝! 읽어주셔서 감사합니다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
