[DRAFT] GBrain을 AWS에 프라이빗하게 배포하고 노트북에서 쓰는 법
AI 에이전트에게 "내 기억"을 달아주기 — GBrain을 AWS에 프라이빗하게 배포하고 노트북에서 쓰는 법
이 글은 garrytan/gbrain v0.51.6.0을 코드 수정 없이 AWS CDK만으로 서울 리전에 올리고, 맥북의 CLI와 Claude Desktop에서 실제로 사용하기까지의 기록입니다. 모든 수치는 2026-09-22~24에 직접 측정한 값이고, 모든 명령은 실제로 실행해 동작을 확인한 것입니다.
1. 왜 이걸 했나
Claude, Kiro, Cursor 같은 AI 에이전트를 매일 쓰다 보면 한 가지가 계속 아쉽습니다. 대화가 끝나면 다 잊는다는 것. 어제 결정한 내용, 지난주 회의 메모, 어떤 고객이 뭘 물어봤는지를 매번 다시 붙여넣어야 합니다.
GBrain은 이 문제를 푸는 오픈소스입니다. 마크다운 페이지를 PostgreSQL + pgvector에 저장하고, 어떤 에이전트든 MCP(Model Context Protocol)로 붙어서 검색하고, 기억하고, 인용하며 답하게 해 줍니다. 밤에는 dream이라는 배치가 돌아 중복을 정리하고 사실을 추출합니다. Y Combinator의 Garry Tan이 자기 에이전트용으로 만들어 공개했고, 15만 페이지 규모로 운영 중이라고 합니다.
문제는 어디에 둘 것인가입니다. 업스트림 문서는 Supabase나 Railway 같은 SaaS, 혹은 Tailscale로 노트북을 공개하는 방법을 안내합니다. 저는 세 가지 조건이 있었습니다.
- 데이터는 내 AWS 계정 안에, 서울 리전에 머물러야 한다.
- 인터넷에서 들어오는 길이 하나도 없어야 한다.
- IAM 사용자 정적 액세스 키를 하나도 만들지 않아야 한다.
3번은 회사 계정 정책이지만, 개인 계정에서도 그렇게 하는 것이 맞습니다. 이 글은 그 조건을 전부 만족시키면서 GBrain을 올린 결과물입니다.
2. 무엇이 만들어지나
노트북 AWS ap-northeast-2 (전부 프라이빗 서브넷)
┌────────────────────────┐ ┌───────────────────────────────────────────┐
│ gbrain CLI │──┐ │ bastion(t4g.nano) ─▶ 내부 ALB ─▶ Fargate │
│ Claude Desktop │──┼─ :3131 ────┼─ SSM 터널 ┌─ gbrain serve --http │
│ 브라우저 /admin │──┘ │ └─ litellm ─▶ Bedrock │
└────────────────────────┘ │ RDS PostgreSQL 16 + pgvector (KMS, TLS) │
│ EventBridge 07:00 UTC ─▶ dream 태스크 │
│ CloudWatch 알람 6개 ─▶ SNS ─▶ 이메일 │
└───────────────────────────────────────────┘
| 구성 요소 | 선택 | 이유 |
|---|---|---|
| 컴퓨트 | ECS Fargate 1태스크 (1 vCPU / 3 GiB), 루트 FS 읽기 전용 | 서버 관리 없음. gbrain은 상태를 전부 DB에 두므로 컨테이너는 언제든 버려도 됨 |
| DB | RDS PostgreSQL 16.13 + pgvector 0.8.1, db.t4g.medium 50 GiB | 업스트림 권장 엔진. isolated 서브넷, rds.force_ssl=1, 고객 KMS 키 |
| LLM | LiteLLM 사이드카 -> Amazon Bedrock | gbrain은 OpenAI 호환 API를 기대. LiteLLM이 Bedrock으로 번역하고 태스크 롤로 인증 -> API 키 0개 |
| 모델 | 채팅 apac.anthropic.claude-3-5-sonnet-20241022-v2:0, 임베딩 amazon.titan-embed-text-v2:0 (1024차원) |
둘 다 APAC 안에서만 라우팅. 최신 Claude는 서울에서 global.* 프로파일만 있어 데이터가 리전 밖으로 나갈 수 있어 제외 |
| 입구 | 내부 ALB + SSM 포트포워딩 bastion | 공개 IP 없음. 접속 권한 = IAM 권한 |
| 운영 | dream 스케줄 태스크, 알람 6개, Budgets, VPC Flow Logs | 밤에 알아서 돌고, 깨지면 메일 |
CDK 스택은 4개(Network -> Data -> Service -> Ops)이고, 전체 비용은 월 약 $195(+ Bedrock 사용량, 개인 사용 기준 몇 달러)입니다. 절반 이상이 RDS($72)와 NAT 게이트웨이($45)입니다.
3. 배포 — 실제로 걸린 시간
cp .env.example .env # 계정 ID, 리전, 모델 ID, 이미지 다이제스트, 알람 이메일
npm ci && npx cdk synth # 4스택 합성 + 75개 단위 테스트
npx cdk deploy GbrainNetwork GbrainData # 17분 (RDS 생성이 14분)
npx cdk deploy GbrainService GbrainOps # 13분 (이미지 빌드·푸시 포함)
두 가지 설계 선택이 배포를 단순하게 만들었습니다.
DB 초기화를 CloudFormation 커스텀 리소스로. pgvector 확장 설치와 애플리케이션 롤 생성을 Lambda가 배포 중에 수행합니다. 사람이 psql로 들어갈 일이 없고, 로그에 비밀이 남지 않도록 결과만 (vector extension ok, BYPASSRLS ok) 찍습니다.
컨테이너 엔트리포인트가 gbrain init을 매번 실행. 첫 태스크는 스키마 마이그레이션(v159)을 적용하고, 이후 태스크는 Brain ready. N pages만 찍고 지나갑니다. 멱등이라는 것을 실측으로 확인했기 때문에 "초기화 완료 여부"를 어디에 기록할 필요가 없습니다.
실제로 부딪힌 것들
문서만 보고 짠 코드가 실제 배포에서 깨진 지점들입니다. 같은 구성을 하실 분들이 시간을 아끼시길 바라며 그대로 적습니다.
| 증상 | 원인 | 해결 |
|---|---|---|
self signed certificate in certificate chain |
gbrain 런타임인 Bun 1.3은 시스템 CA 저장소를 안 보고, postgres.js는 URL의 sslrootcert를 무시 |
Dockerfile에 RDS CA 번들을 넣고 NODE_EXTRA_CA_CERTS로 지정 |
unrecognized configuration parameter "sslrootcert" |
postgres.js가 모르는 URL 파라미터를 그대로 서버 세션 설정으로 넘김 | URL에서 제거, ?sslmode=verify-full만 남김 |
ECS Exec agent STOPPED |
루트 FS를 읽기 전용으로 잠갔더니 SSM 에이전트가 쓸 곳이 없음 | /var/lib/amazon, /var/log/amazon에 임시 볼륨 마운트 |
Bedrock model_not_found + "marked by provider as Legacy" |
인퍼런스 프로파일 상태는 ACTIVE인데 실제 호출은 거부 | 프로파일 목록만 믿지 말고 converse 1회 호출로 확인. 모델 교체 |
dream이 ANTHROPIC_API_KEY 요구 |
업스트림 기본값이 게이트웨이(LiteLLM)를 안 씀 | gbrain config set agent.use_gateway_loop true |
| Budgets 재배포 실패 "same name but a different internalId" | 구독자 변경 = 리소스 교체인데 이름이 고정 | 구독자를 SNS 토픽으로 고정하고 토픽이 이메일로 fan-out |
배포 후 "잘못된 태스크 정의를 배포하면 어떻게 되나"도 확인했습니다. 일부러 DB 포트를 틀리게 넣어 배포하자 ECS 서킷 브레이커가 10분 19초에 자동 롤백했고, 브레인의 페이지는 그대로였습니다.
4. 노트북에서 쓰기
여기서부터가 매일 하는 일입니다.
4.1 준비물 (한 번)
- AWS CLI v2 +
session-manager-plugin(brew install awscli session-manager-plugin) - 그 계정에
ssm:StartSession(터널)과ecs:ExecuteCommand(최초 클라이언트 등록) 권한 - Bun 1.3.11+ (
curl -fsSL https://bun.sh/install | bash) - gbrain CLI — npm에 없습니다. npm의
gbrain은 이름만 같은 무관한 패키지라 설치하면 진짜 바이너리를 가립니다. 서버와 같은 태그로 GitHub에서 설치합니다.
bun install -g github:garrytan/gbrain#v0.51.6.0
gbrain --version # 0.51.6.0
4.2 터널 열기 (매번)
별도 터미널 탭에 띄워 두고 닫지 않습니다. 로컬 포트는 반드시 3131입니다. 서버가 OAuth 발급자 주소를 http://localhost:3131로 고정해서 돌려주기 때문에, 3132로 열면 토큰 요청이 400으로 실패합니다(직접 확인했습니다).
aws ssm start-session --target <bastion-instance-id> \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters host=<internal-alb-dns>,portNumber=80,localPortNumber=3131 \
--region ap-northeast-2
curl -s localhost:3131/health
# {"status":"ok","version":"0.51.6.0","engine":"postgres"}
이 명령은 CDK 스택 Output(TunnelCommand)에 완성된 형태로 나오므로 외울 필요는 없습니다.
4.3 자격증명 만들기 (한 번)
서버 안에서 gbrain auth 명령을 실행해야 합니다. 컨테이너에 SSH가 없으니 ECS Exec을 씁니다. 노트북 터미널에서 그대로 치면 AWS가 컨테이너 안에서 대신 실행해 결과를 보여 줍니다.
TASK=$(aws ecs list-tasks --cluster gbrain-dev --service-name gbrain-dev-serve \
--desired-status RUNNING --region ap-northeast-2 --query 'taskArns[0]' --output text | awk -F/ '{print $NF}')
# CLI용 OAuth 클라이언트 (id + secret)
aws ecs execute-command --cluster gbrain-dev --task "$TASK" --container gbrain --interactive --region ap-northeast-2 \
--command 'gbrain auth register-client mylaptop --grant-types client_credentials --scopes write'
# Claude Desktop 등 MCP 클라이언트용 Bearer 토큰
aws ecs execute-command --cluster gbrain-dev --task "$TASK" --container gbrain --interactive --region ap-northeast-2 \
--command 'gbrain auth create claude-desktop --scopes read,write'
출력되는 secret과 토큰은 그 자리에서만 보입니다. 서버는 해시만 저장하니 바로 저장하세요. 잃으면 새로 만들면 됩니다.
자동화 도구에서 이 명령을 돌리면 TTY가 없어
script -qec "…" /dev/null래퍼가 필요한데, macOS의 BSDscript에는-c가 없습니다. 사람이 터미널에서 칠 때는 래퍼 없이 위 명령 그대로가 맞습니다.
4.4 CLI 초기화와 일상 명령
export GBRAIN_HOME=~/.gbrain-seoul # 다른 브레인 설정과 분리
export GBRAIN_REMOTE_CLIENT_ID=gbrain_cl_…
export GBRAIN_REMOTE_CLIENT_SECRET=gbrain_cs_…
gbrain init --mcp-only --issuer-url http://localhost:3131 --mcp-url http://localhost:3131/mcp
# ✓ discovery ✓ token ✓ MCP initialize → Thin-client mode configured
이후는 세 명령이 전부입니다.
gbrain capture "오늘 회의: 예산 필터를 Project 태그로 바꾸기로 함"
gbrain search "예산"
gbrain think "예산 관련해서 결정한 게 뭐였지?"
search는 관련 페이지 목록을 돌려주고, think는 그 페이지들을 근거로 **답변 + 인용 + "브레인이 모르는 부분"**을 써 줍니다. "뭘 결정했었지?"에는 think가 맞고, "그 문서 어디 있지?"에는 search가 맞습니다.
5. Claude Desktop에 붙이기
GBrain에는 공식 데스크톱 앱이 없습니다. 설계 철학이 "UI는 여러분이 이미 쓰는 에이전트, GBrain은 그 뒤의 기억"이기 때문입니다. 그래서 Claude Desktop이 사실상 GBrain의 GUI입니다.
한 가지 함정이 있습니다. Claude Desktop의 Settings > Integrations(커넥터)에 http://localhost:3131/mcp를 넣으면 안 됩니다. 커넥터는 Anthropic 서버를 경유해 접속하므로 노트북에서만 보이는 주소에 닿지 못합니다. 업스트림 가이드는 Tailscale로 공개 HTTPS 주소를 만들라고 하는데, 우리는 "인터넷 입구 0"이 조건이라 그 길을 쓸 수 없습니다.
대신 로컬 stdio 브리지를 씁니다. Claude Desktop이 노트북에서 작은 프로세스(mcp-remote)를 띄우고, 그 프로세스가 터널을 타고 서버로 갑니다. 모든 통신이 노트북 안에서 시작하므로 localhost가 문제되지 않습니다.
~/Library/Application Support/Claude/claude_desktop_config.json (사내 배포 빌드는 Claude-3p/)에 기존 내용은 그대로 두고 mcpServers만 추가합니다.
{
"preferences": { "...기존 내용 그대로..." },
"mcpServers": {
"gbrain-seoul": {
"command": "npx",
"args": [
"-y", "mcp-remote@latest",
"http://localhost:3131/mcp",
"--header", "Authorization:Bearer ${GBRAIN_TOKEN}"
],
"env": { "GBRAIN_TOKEN": "4.3에서 받은 토큰" }
}
}
}
순서: Claude Desktop 완전 종료(Cmd+Q) -> 파일 편집 -> chmod 600 -> 터널 켜기 -> 앱 실행 -> 새 대화에서 "내 브레인에서 예산 관련 내용 찾아줘". 도구 목록에 gbrain-seoul이 뜨면 성공입니다.
안 보일 때 확인 순서:
- Claude Desktop은 로그인 셸 PATH를 물려받지 못합니다.
which npx결과를command에 절대경로로 넣으세요. - 터널이 끊겼으면 다시 열고 앱을 재시작해야 브리지가 재연결됩니다.
- 사내 배포 빌드는 조직 정책으로 로컬 MCP를 막을 수 있습니다. "disabled by organization" 메시지면 설정 문제가 아닙니다.
같은 JSON 블록을 Kiro(~/.kiro/settings/mcp.json), Cursor 등 stdio MCP를 지원하는 어떤 클라이언트에도 그대로 쓸 수 있습니다.
6. 알아서 돌아가는 것
- 매일 16:00 KST dream. 페이지 정리, 사실 추출, 임베딩, 중복 제거. 첫 수동 실행은 53초, 리포트
status: ok. 파일시스템 브레인 디렉터리가 없는 DB-only 구성이라 lint/sync 단계는no_brain_dir로 건너뛰는데, 이것이 정상입니다. - 실패하면 메일. dream 태스크가 exit 0이 아니면 EventBridge -> SNS -> 이메일. 일부러 잘못된 플래그로 돌려 알림이 오는지까지 확인했습니다. ALB 5xx, 태스크 0개, RDS CPU/메모리/스토리지 알람 6개도 같은 토픽으로 옵니다.
- 비용 멈추기.
aws ecs update-service --desired-count 0으로 Fargate만 내리면 데이터는 그대로 두고 월 $120(RDS·NAT·ALB·bastion)만 남습니다. 되살리면 2~3분 뒤 페이지가 그대로 나옵니다.
7. 안 되는 것과 다음
첨부파일(gbrain files upload)은 꺼져 있습니다. GBrain의 S3 저장소 코드가 정적 액세스 키(accessKeyId/secretAccessKey)만 받고, 없으면 생성자에서 예외를 던집니다. 컨테이너에는 IAM 롤(임시 자격증명)이 있지만 코드가 그걸 쓰려 하지 않습니다. 정적 키를 만들지 않는 것이 조건이므로 v1에서는 파일 기능을 포기했습니다.
고치는 방법은 작습니다. 두 키가 모두 없을 때 S3Client에 credentials를 넘기지 않으면 AWS SDK가 기본 체인으로 롤을 찾아 씁니다. 20줄 정도의 변경과 판별 테스트를 업스트림에 PR로 제출해 두었습니다(garrytan/gbrain#5344). 반영된 릴리스가 나오면 .env의 GBRAIN_REF를 올리고 S3 버킷 + 태스크 롤 권한을 CDK에 추가하는 것으로 정적 키 없이 첨부파일이 켜집니다.
그 외 v1 제한:
- 브라우저나 앱에서 직접 접속 불가 — 항상 SSM 터널
- Fargate 태스크 1개 — 재배포 중 2~3분 끊김 (개인용이라 감수)
- 최신 Claude(Sonnet 4.x)는 서울에서 글로벌 프로파일만 있어 제외 —
.env한 줄로 바꿀 수 있지만 데이터가 APAC 밖으로 나갈 수 있다는 점을 알고 바꿔야 함
8. 정리
| 배포 시간 | 약 30분 (RDS 14분이 대부분) |
| 월 비용 | ≈ $195 (Fargate 정지 시 $120) |
| 인터넷 인바운드 | 0 (내부 ALB + SSM 터널) |
| 정적 AWS 키 | 0 (Bedrock·Secrets·로그 전부 태스크 롤) |
| 데이터 리전 | 서울 유지 (APAC 내 라우팅 모델만 선택) |
| 잘못된 배포 | 서킷 브레이커 10분 자동 롤백, 데이터 무손실 확인 |
| 매일 하는 일 | 터널 1개 열기 |
GBrain을 "내 계정 안에, 문 닫고, 키 없이" 올리는 것은 가능했고, 실제로 부딪힌 문제는 GBrain보다 Bun의 TLS 처리, 읽기 전용 FS와 SSM 에이전트, Bedrock 레거시 모델처럼 주변에서 나왔습니다. CDK 코드와 상세 운영 문서(배포 절차, 21개 리스크 표, 사용 가이드)는 정리 후 공개할 예정입니다.