Skip to main content

Dev Environment Setup

이 문서는 surfai-vivid의 dev 환경 구축 기준을 정리합니다.

확정 기준

항목
AWS accountlocal과 같은 계정
Regionap-northeast-2
Domaindev.surfai.org
RuntimeEC2 1대 + Docker Compose
EC2 instancet3.medium부터 시작
DatabaseEC2 내부 PostgreSQL container
RedisEC2 내부 Redis container
QueueSQS
StorageS3 private media bucket

초기 dev는 비용을 우선하여 backend, frontend, PostgreSQL, Redis, ComfyUI, ai-node-agent, post-processing-worker를 같은 EC2에서 Docker Compose로 실행합니다. SQS/S3만 AWS managed service로 둡니다.

dev.surfai.org
-> nginx
-> frontend container
-> backend container
-> postgres container
-> redis container
-> SQS computation queue
-> S3 media bucket
-> ai-node-agent + ComfyUI
-> post-processing-worker

AWS 리소스

S3

surfai-vivid-dev-media

Bucket 설정은 local media bucket과 동일하게 둡니다.

설정
Regionap-northeast-2
Block Public Access4개 항목 모두 ON
Object OwnershipBucket owner enforced
VersioningOFF로 시작
EncryptionSSE-S3

Prefix 구조:

raw/
temp/
uploads/original/
generation/source/
generation/work-input/
creations/
post-processing/failed/
exports/user-downloads/

초기 CORS:

[
{
"AllowedOrigins": [
"http://localhost:4000",
"https://dev.surfai.org"
],
"AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": [
"ETag",
"x-amz-request-id",
"x-amz-id-2",
"x-amz-checksum-crc32"
],
"MaxAgeSeconds": 3000
}
]

Lifecycle 기준은 S3 media bucket 설정을 따릅니다.

SQS

다음 queue를 생성합니다.

surfai-computation-queue-dev
surfai-computation-queue-dev-dlq

surfai-post-processing-worker-queue-dev
surfai-post-processing-worker-queue-dev-dlq

surfai-email-dev
surfai-email-dev-dlq

권장값:

항목
TypeStandard
Receive message wait time20초
Visibility timeoutgeneration/post-processing은 900초부터 시작
DLQ maxReceiveCount3

ai-node-agentpost-processing-worker가 처리 중 timeout보다 오래 걸릴 수 있으므로 visibility timeout은 짧게 잡지 않습니다.

PostgreSQL

dev는 DB 초기화가 허용되는 환경이므로 초기에는 EC2 내부 PostgreSQL container를 사용합니다.

항목
EnginePostgreSQL 16 container
NetworkDocker internal network
Porthost 외부 공개 금지
Volumenamed volume 또는 EBS 경로 bind mount
Backup필수 아님. 필요 시 pg_dump cron 추가

dev 데이터를 보존해야 하는 요구가 생기면 RDS surfai-vivid-dev-postgres로 분리합니다.

Redis

dev는 EC2 내부 Redis container를 사용합니다.

항목
EngineRedis 7 Alpine container
NetworkDocker internal network
Porthost 외부 공개 금지
PersistenceAOF on

dev Redis 상태는 재구성 가능해야 합니다. 장기 보존이 필요한 상태를 Redis에만 두지 않습니다.

EC2

surfai-vivid-dev-app

권장 초기값:

항목
AMIUbuntu 22.04 LTS 또는 24.04 LTS
Instancet3.medium
EBSgp3 50GB
IAMEC2 instance profile 사용
Public IPElastic IP 할당 권장

Security group:

PortSource용도
22관리자 IPSSH
800.0.0.0/0HTTP challenge/redirect
4430.0.0.0/0HTTPS

다음 포트는 외부 공개하지 않습니다.

3000 backend
4000 frontend
8188 ComfyUI
5432 PostgreSQL container
6379 Redis container

IAM Role

dev EC2에는 access key 대신 IAM role을 붙이는 것을 기본으로 합니다.

예시 이름:

surfai-vivid-dev-ec2-role

필요 권한:

S3:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
- s3:ListBucket

SQS:
- sqs:SendMessage
- sqs:SendMessageBatch
- sqs:ReceiveMessage
- sqs:DeleteMessage
- sqs:ChangeMessageVisibility
- sqs:GetQueueAttributes

SES:
- ses:SendEmail
- ses:SendRawEmail

권한 범위는 dev bucket과 dev queue ARN으로 제한합니다. 같은 AWS 계정을 쓰더라도 local/prod 리소스까지 열지 않습니다.

SES 발송은 verified identity의 From 주소로 제한합니다.

{
"Sid": "DevSesSend",
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"ses:FromAddress": "noreply@surfai.org"
}
}
}

SES sandbox 상태에서는 dev에서도 verified recipient에게만 발송됩니다. 일반 사용자 대상 발송은 SES production access 승인 후 활성화합니다.

Domain And Reverse Proxy

초기 dev는 별도 API subdomain을 두지 않고 dev.surfai.org 단일 origin으로 운영합니다.

https://dev.surfai.org/      -> frontend
https://dev.surfai.org/api -> backend API
https://dev.surfai.org/api/socket.io/ -> backend websocket

장점:

  • frontend CORS 구성이 단순합니다.
  • cookie 인증 정책이 단순합니다.
  • NEXT_PUBLIC_API_URL=https://dev.surfai.org/api 하나로 충분합니다.

Route53:

dev.surfai.org A record -> dev EC2 Elastic IP

EC2 host에 nginx를 설치하고 TLS는 certbot으로 발급합니다. ALB/ACM을 붙이는 방식도 가능하지만 초기 dev에는 비용과 운영 복잡도가 더 큽니다.

nginx proxy 기준:

server {
listen 80;
server_name dev.surfai.org;
return 301 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name dev.surfai.org;

location /api/socket.io/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api/v1/agent-relay/ws {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location /api-docs {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}

location / {
proxy_pass http://127.0.0.1:4000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

Environment Variables

backend

NODE_ENV=development
PORT=3000

POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_USER=<dev-db-user>
POSTGRES_PASSWORD=<dev-db-password>
POSTGRES_DB=<dev-db-name>
POSTGRES_SSL_ENABLED=false

REDIS_HOST=redis
REDIS_PORT=6379
REDIS_TLS_ENABLED=false

AWS_REGION=ap-northeast-2

SQS_COMPUTATION_QUEUE_URL=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-computation-queue-dev
SQS_POST_PROCESSING_QUEUE_URL=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-post-processing-worker-queue-dev
SQS_EMAIL_QUEUE_URL=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-email-dev
SQS_EMAIL_DLQ_URL=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-email-dev-dlq

S3_TEMP_BUCKET_NAME=surfai-vivid-dev-media
S3_PERMANENT_BUCKET_NAME=surfai-vivid-dev-media

EMAIL_FROM=noreply@surfai.org
EMAIL_DELIVERY_MODE=ses
EMAIL_DISPATCH_INTERVAL_MS=3000
EMAIL_WORKER_POLL_INTERVAL_MS=5000
EMAIL_DISPATCH_BATCH_SIZE=10
EMAIL_DISPATCH_MAX_BATCHES_PER_TICK=5
EMAIL_DISPATCH_LEASE_MS=60000
# 설정한 SES configuration set이 있을 때만 추가한다.
# SES_CONFIGURATION_SET_NAME=surfai-dev-email

CORS_ORIGIN=https://dev.surfai.org
PUBLIC_FRONTEND_URL=https://dev.surfai.org
SECURE_COOKIES=true

EC2 IAM role을 사용할 경우 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY는 설정하지 않습니다.

frontend

Docker build arg로 주입합니다.

NEXT_PUBLIC_APP_ENV=dev
NEXT_PUBLIC_API_URL=https://dev.surfai.org/api

Next standalone 서버는 dev EC2에서 PORT=4000으로 실행합니다. backend도 3000을 사용하므로 frontend를 4000으로 분리합니다.

ai-server

AI_AGENT_ENV=dev
AWS_REGION=ap-northeast-2

SQS_COMPUTATION_QUEUE_DEV=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-computation-queue-dev
SQS_POST_PROCESSING_QUEUE_DEV=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-post-processing-worker-queue-dev

S3_TEMP_BUCKET_DEV_NAME=surfai-vivid-dev-media
S3_SYSTEM_CONFIGURATION_BUCKET_NAME=<dev-system-configuration-bucket>

COMFY_API_URL=http://127.0.0.1:8188/prompt
COMFY_WS_URL=ws://127.0.0.1:8188/ws
COMFY_OUTPUT_DIR=/app/temp
COMFY_HTTP_TIMEOUT_SECONDS=15

COMFY_ORG_API_KEY=<server-only>
COMFY_USAGE_SOURCE=surfai-vivid-dev

AI_AGENT_RELAY_HTTP_URL=https://dev.surfai.org/api/v1/agent-relay
AI_AGENT_RELAY_WS_URL=wss://dev.surfai.org/api/v1/agent-relay/ws
AI_AGENT_RELAY_TOKEN=<dev-relay-token>
NODE_ID=dev-ai-node-01

post-processing-worker

TARGET_ENV=dev
AWS_REGION=ap-northeast-2

SQS_POST_PROCESSING_QUEUE_DEV=https://sqs.ap-northeast-2.amazonaws.com/<account-id>/surfai-post-processing-worker-queue-dev

S3_TEMP_BUCKET_DEV_NAME=surfai-vivid-dev-media
S3_PERMANENT_BUCKET_DEV_NAME=surfai-vivid-dev-media

BACKEND_API_URL=http://127.0.0.1:3000/api

POST_PROCESSING_MAX_WORKERS=2
SQS_VISIBILITY_TIMEOUT_SECONDS=900
FFMPEG_TIMEOUT_SECONDS=300

Docker Compose 배치 원칙

현재 각 repository에 compose 파일이 나뉘어 있으므로 dev EC2에서는 다음 중 하나를 선택합니다.

  1. 서버 배포용 통합 docker-compose.dev.yml을 별도로 만든다.
  2. 각 repository 디렉터리에서 개별 compose/build/run 스크립트를 실행한다.

초기 운영은 1번이 낫습니다. 단일 EC2에서 컨테이너 생명주기를 한 번에 볼 수 있기 때문입니다.

주의:

  • backend와 frontend 모두 기본 포트가 3000입니다. frontend container는 PORT=4000으로 실행합니다.
  • PostgreSQL과 Redis는 같은 compose network 안에서만 접근하게 하고 외부 공개하지 않습니다.
  • ComfyUI의 8188은 외부 공개하지 않습니다.
  • ai-node-agent와 ComfyUI는 input/output/temp volume을 공유해야 합니다.
  • post-processing-worker는 backend API에 내부 주소로 접근합니다.

GitHub Actions 자동 배포

dev는 root repository가 아니라 각 서브모듈 repository의 development 브랜치 push를 기준으로 자동 배포합니다.

backend-vivid-ai development push
-> EC2 backend-vivid-ai 갱신
-> docker compose build backend
-> docker compose up -d --no-deps --force-recreate backend

frontend-vivid-ai development push
-> EC2 frontend-vivid-ai 갱신
-> docker compose build frontend
-> docker compose up -d --no-deps --force-recreate frontend

post-processing-worker development push
-> EC2 post-processing-worker 갱신
-> docker compose build post-processing-worker
-> docker compose up -d --no-deps --force-recreate post-processing-worker

ai-server development push
-> EC2 ai-server 갱신
-> docker compose build ai-node-agent
-> docker compose up -d --no-deps --force-recreate ai-node-agent

ComfyUI container는 build 시간이 길고 모델/output/input 디렉터리 영향이 크므로 기본 자동 배포에서는 rebuild하지 않습니다. ComfyUI Dockerfile 또는 custom node 변경을 dev에 반영해야 할 때는 ai-server repository의 Deploy AI Server to Dev EC2 workflow를 수동 실행하면서 rebuild_comfyui=true를 선택합니다.

각 서브모듈 repository에 동일하게 설정할 GitHub secret:

DEV_EC2_HOST=<dev EC2 public IP 또는 dev.surfai.org>
DEV_EC2_SSH_KEY=<EC2 접속용 private key>
DEV_EC2_KNOWN_HOSTS=<선택, ssh-keyscan 결과>

각 서브모듈 repository에 동일하게 설정할 GitHub variable:

DEV_APP_DIR=/srv/surfai/vivid-ai
DEV_EC2_USER=ubuntu
DEV_EC2_PORT=22

DEV_EC2_KNOWN_HOSTS를 엄격하게 설정하려면 로컬에서 다음 값을 복사해 secret에 넣습니다.

ssh-keyscan -p 22 dev.surfai.org

EC2 전제 조건:

/srv/surfai/vivid-ai 에 root repository clone 완료
.env.dev 파일 배치 완료
각 서브모듈이 development 브랜치로 checkout 가능
EC2의 GitHub SSH key가 root repo와 모든 private submodule에 접근 가능
Docker/Compose 설치 완료
ubuntu 사용자가 docker 그룹 소속

각 workflow는 EC2에서 /tmp/surfai-dev-deploy.lock을 사용해 동시 배포를 직렬화합니다. backend와 frontend push가 동시에 발생해도 EC2에서는 한 번에 하나의 compose 작업만 실행됩니다.

구축 순서

  1. S3 dev media bucket 생성 및 CORS/lifecycle 설정
  2. SQS dev queue/DLQ 생성
  3. EC2 t3.medium 생성, IAM role 연결
  4. Route53 dev.surfai.org를 EC2 Elastic IP로 연결
  5. EC2에 Docker, Docker Compose, nginx, certbot 설치
  6. 통합 Docker Compose에 PostgreSQL/Redis/backend/frontend/ai-server/post-processing-worker 구성
  7. .env 파일 작성
  8. backend migration 실행
  9. 컨테이너 실행
  10. nginx TLS 설정
  11. smoke test 수행

Smoke Test

순서대로 확인합니다.

1. https://dev.surfai.org 접속
2. https://dev.surfai.org/api/health 또는 backend health endpoint 확인
3. backend -> PostgreSQL container 연결 확인
4. backend -> Redis container 연결 확인
5. backend -> SQS SendMessage 확인
6. ai-node-agent -> SQS ReceiveMessage 확인
7. ai-node-agent -> ComfyUI prompt 호출 확인
8. ai-node-agent -> S3 raw/ 업로드 확인
9. post-processing-worker -> SQS receive 확인
10. post-processing-worker -> S3 creations/ 업로드 확인
11. backend creation result update 확인
12. frontend realtime progress 확인

운영 기준

  • dev도 local/prod와 queue, bucket, DB를 반드시 분리합니다.
  • dev credential 또는 EC2 role은 prod resource에 접근하지 못해야 합니다.
  • dev PostgreSQL/Redis는 EC2 내부 container로 두며, 데이터 초기화 가능성을 전제로 운영합니다.
  • Comfy API node concurrency limit을 고려해 dev ai-node-agent는 초기에 1 job씩 처리합니다.
  • t3.medium에서 memory pressure가 보이면 t3.large로 올립니다.
  • EC2 하나에서 감당하기 어려워지는 시점까지 dev는 Kubernetes를 사용하지 않습니다.