Terraform으로 Neon DB + Hasura GraphQL API 서버 구축하기
프로젝트 개요
- 백엔드 인프라: Neon PostgreSQL + Hasura (EC2) + AWS Secret Manager + IAM
- 프론트엔드: Next.js (Vercel 배포 예정) + Apollo Client + GraphQL Code Generator
- 패키지 매니저: pnpm
1. 인프라 구축 (Terraform)
1.1 사전 준비
Neon DB
- neon.tech 가입 및 프로젝트 생성
- Connection string 복사
postgresql://[user]:[password]@[endpoint]/[dbname]?sslmode=require
SSH 키 준비
# SSH 키가 없다면 생성
ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa
# 공개키 확인
cat ~/.ssh/id_rsa.pub
내 IP 확인
curl ifconfig.me
# 출력 예: 123.456.789.012
1.2 Terraform 파일 구성
프로젝트 디렉토리 생성
mkdir hasura-terraform
cd hasura-terraform
주요 파일
main.tf
: 메인 Terraform 설정 (EC2, Security Group, IAM 등)user_data.sh
: EC2 초기화 스크립트 (Docker, Hasura 설치)terraform.tfvars
: 변수 값 정의 (⚠️ 절대 git에 커밋하지 말 것!)
terraform.tfvars 작성
aws_region = "ap-northeast-2" # 서울 리전
# Neon DB 연결 URL
neon_database_url = "postgresql://user:password@ep-xxx.aws.neon.tech/neondb?sslmode=require"
# Hasura 관리자 비밀번호
hasura_admin_secret = "your-super-secret-password-here"
# 내 IP 주소 (SSH 접속용, /32 붙이기)
my_ip = "123.456.789.012/32"
1.3 AWS Secret Manager 설정
main.tf
에서 AWS Secret Manager 리소스 정의- Neon DB URL, Hasura Admin Secret 저장
- EC2가 접근할 수 있도록 IAM Role 설정
1.4 IAM 설정
- EC2 인스턴스 프로파일 생성
- Secret Manager 읽기 권한 부여
# 예시- secretsmanager:GetSecretValue- secretsmanager:DescribeSecret
1.5 Security Group 설정
- 8080 포트: Hasura Console 및 GraphQL 엔드포인트 (내 IP만 허용)
- 22 포트: SSH 접속 (내 IP만 허용)
1.6 Terraform 실행
# 초기화
terraform init
# 실행 계획 확인
terraform plan -out=myplan.tfplan
# 인프라 배포
terraform apply myplan.tfplan
# 출력 정보 확인
terraform output
출력 예시:
ec2_public_ip = "13.125.123.456"
hasura_console_url = "http://13.125.123.456:8080/console"
hasura_graphql_endpoint = "http://13.125.123.456:8080/v1/graphql"
ssh_command = "ssh -i ~/.ssh/id_rsa ubuntu@13.125.123.456"
2. Hasura 설정 및 데이터베이스 스키마
2.1 Hasura Console 접속
- 브라우저에서
hasura_console_url
접속 hasura_admin_secret
값으로 로그인
2.2 데이터베이스 연결 확인
- Neon DB 자동 연결 확인 (user_data.sh에서 환경 변수로 설정됨)
2.3 SQL 스키마 작성 시 주의사항 ⚠️
문제 상황:
- SQL로 테이블 생성 시
uuid
컬럼을 PK로 의도했으나 - 실제로는
no
같은 다른 컬럼이 PK로 설정되는 문제 발생 - Hasura가 테이블을 제대로 인식하지 못함
해결 방법:
- 잘못된 테이블 모두 DROP
- SQL 다시 작성 - PRIMARY KEY를 명시적으로 지정
CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, created_at TIMESTAMPTZ DEFAULT NOW());
- Hasura Console에서 SQL 실행
- 테이블 Track 확인
핵심: uuid
를 PK로 사용하려면 반드시 PRIMARY KEY
를 명시!
2.4 Permissions 설정 🔐
반드시 설정해야 함: 각 테이블마다 Role 기반 권한 설정
Role 구분
- admin: 모든 CRUD 권한
- user: 제한된 권한 (자신의 데이터만)
각 테이블별 설정 항목
Insert:
user
role: 자신의 데이터만 삽입 가능- Check 조건 예:
{"user_id": {"_eq": "X-Hasura-User-Id"}}
Select:
- Row level filter:
{"user_id": {"_eq": "X-Hasura-User-Id"}}
- Column 권한: 민감한 컬럼 제외
Update:
- Filter + Check 조건 설정
- 예: 자신의 데이터만 수정 가능
Delete:
- Filter 조건으로 제한
- 필요시 soft delete 사용
설정 예시
users 테이블:
- admin: 모든 권한
- user:
- select: WHERE user_id = X-Hasura-User-Id
- update: WHERE user_id = X-Hasura-User-Id (email, name만 수정)
- insert: user_id는 자동 설정
- delete: 불가
주의: 각 작업(Insert/Select/Update/Delete)마다 개별 설정 필요!
3. Next.js 프론트엔드 설정
3.1 프로젝트 생성 및 패키지 설치
# Next.js 프로젝트 생성
pnpm create next-app@latest
# Apollo Client 설치
pnpm add @apollo/client graphql rxjs @apollo/client-integration-nextjs
# GraphQL Code Generator 설치
pnpm add -D @graphql-codegen/cli \
@graphql-codegen/typescript \
@graphql-codegen/typescript-operations \
@graphql-codegen/typescript-react-apollo
3.2 Apollo Client 설정
// lib/apollo-client.ts
import { HttpLink } from "@apollo/client";
import {
ApolloClient,
InMemoryCache,
registerApolloClient,
} from "@apollo/client-integration-nextjs";
export const { getClient, query, PreloadQuery } = registerApolloClient(() => {
return new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri:
process.env.HASURA_GRAPHQL_ENDPOINT ??
"http://localhost:8080/v1/graphql",
}),
});
});
3.3 GraphQL Code Generator 설정
codegen.ts 작성
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
overwrite: true,
schema: [
{
[
process.env.HASURA_GRAPHQL_ENDPOINT ??
"http://localhost:8080/v1/graphql"
]: {
headers: {
"x-hasura-admin-secret": process.env.HASURA_ADMIN_SECRET ?? "",
},
},
},
],
documents: ["src/**/*.{ts,tsx,graphql}"],
generates: {
"src/generated/graphql.ts": {
plugins: ["typescript", "typescript-operations", "typed-document-node"],
config: {
fetcher: "graphql-request",
exposeDocument: true,
exposeQueryKeys: true,
exposeMutationKeys: true,
// hasura scalar 맵핑 필수!
scalars: {
uuid: "string",
timestamptz: "string",
jsonb: "Record<string, any>",
numeric: "number",
},
},
},
},
}
export default config;
package.json에 스크립트 추가
Root 에 둘거면 dotenv 설치 필요
{
"scripts": {
"codegen": "dotenv -e .env.local -- graphql-codegen --config codegen.ts",
}
}
3.4 GraphQL 쿼리 작성 및 Codegen 실행
예시 쿼리임.. 필요에 맞게 작성해야 함
# src/queries/users.graphql
query GetUsers {
users {
id
name
email
}
}
mutation CreateUser($name: String!, $email: String!) {
insert_users_one(object: {name: $name, email: $email}) {
id
name
email
}
}
# Codegen 실행 ✅
pnpm codegen
생성 결과:
- TypeScript 타입 자동 생성
useGetUsersQuery
,useCreateUserMutation
훅 자동 생성- 완벽한 타입 안정성 확보
3.5 환경 변수 설정
# .env.local
HASURA_ENDPOINT=http://13.125.123.456:8080/v1/graphql
HASURA_ADMIN_SECRET=your-super-secret-password-here
4. Vercel 배포
4.1 환경 변수 설정
Vercel 대시보드에서:
NEXT_PUBLIC_HASURA_ENDPOINT
HASURA_ADMIN_SECRET
4.2 배포
cli로 하든... github 연동 하든.. 알아서
pnpm vercel
5. 인프라 관리
사용 후 삭제 (비용 절약)
terraform destroy
다시 시작
terraform apply
SSH 접속 (문제 해결)
ssh -i ~/.ssh/id_rsa ubuntu@<EC2_IP>
cd ~/hasura
docker-compose logs -f
핵심 포인트 정리
✅ Terraform으로 인프라를 코드화 - Secret Manager, IAM, EC2를 한 번에 구성
⚠️ Hasura SQL 실행 시 PK 설정 명시 - uuid PRIMARY KEY
명시적 선언 필수
🔐 Permissions 필수 설정 - admin/user role 구분, 각 CRUD 작업마다 개별 권한 설정
🎯 Apollo + Codegen으로 타입 안전성 - pnpm으로 패키지 관리
📋 tfvars 파일 보안 - .gitignore
에 반드시 추가
예시 디렉터리 구조
프로젝트/
├── hasura-terraform/
│ ├── main.tf
│ ├── user_data.sh
│ ├── terraform.tfvars # ⚠️ git ignore
│ └── .gitignore
│
└── frontend/
├── src/
│ ├── queries/
│ │ └── users.graphql
│ ├── generated/
│ │ └── graphql.ts # codegen 결과
│ └── lib/
│ └── apollo-client.ts
├── codegen.yml
├── .env.local # ⚠️ git ignore
└── package.json
'TIL' 카테고리의 다른 글
[250929 TIL] ApolloClient 디버거 직접 만들기 (0) | 2025.09.29 |
---|---|
[250929 TIL] ApolloLink Next.js 설정 (0) | 2025.09.29 |
[250929 TIL] ApolloLink (0) | 2025.09.29 |
[250929 TIL] tanstack vs apollo 쿼리캐시 비교 (0) | 2025.09.29 |
[250929 TIL] (cache)typePolicies, Apollo Link (0) | 2025.09.29 |