환경 변수
자체 호스팅 Melso에서 자주 사용하는 서버, 저장소, 연동, 런타임 설정입니다.
Melso는 프로세스를 시작할 때 환경 변수를 읽습니다. 수정 후에는 보통 해당 API, Web 또는 데몬을 다시 시작해야 합니다. Docker Compose의 docker compose restart는 .env를 다시 읽지 않으므로 up -d로 컨테이너를 다시 만들어야 적용됩니다.
이 페이지에는 배포자를 위한 설정만 나열하며 테스트 변수와 내부 태스크 변수는 다루지 않습니다. 여기서는 그룹별 참조를 제공하고 전체 배포 단계는 자체 호스팅 빠른 시작을 참고하세요.
프로덕션 최소 설정
DATABASE_URL=postgres://user:password@postgres:5432/multica?sslmode=require
JWT_SECRET=<long-random-secret>
APP_ENV=production
FRONTEND_ORIGIN=https://multica.example.com
MULTICA_APP_URL=https://multica.example.com
MULTICA_PUBLIC_URL=https://api.multica.example.com이메일 서비스도 하나 선택해야 합니다. 설정하지 않으면 인증 코드와 초대가 서버 로그에만 기록됩니다.
프로덕션 환경에서 기본 JWT_SECRET을 사용하거나 MULTICA_DEV_VERIFICATION_CODE를 설정하지 마세요.
API와 데이터베이스
| 변수 | 기본값 | 설명 |
|---|---|---|
DATABASE_URL | 로컬 multica 데이터베이스 | PostgreSQL 연결 주소 |
DATABASE_MAX_CONNS | 25 | API 프로세스 하나의 최대 데이터베이스 연결 수 |
DATABASE_MIN_CONNS | 5 | API 프로세스 하나가 유지하는 최소 연결 수 |
PORT | 8080 | API listen port |
JWT_SECRET | 개발용 고정값 | 로그인 JWT와 일부 서명 절차에서 사용하는 키 |
APP_ENV | 비어 있음 | 프로덕션 환경에서는 production으로 설정 |
AUTH_TOKEN_TTL | 720h(30일) | 브라우저 JWT와 cookie 유효 기간. Go duration 또는 양의 정수 초 허용 |
LOG_LEVEL | 앱 기본값 | 로그 수준 |
MULTICA_SHUTDOWN_HOLD_DURATION | 0 | 종료 신호를 받은 뒤 graceful shutdown을 시작하기 전 대기 시간 |
Kubernetes에서 shutdown hold를 설정하면 terminationGracePeriodSeconds가 hold와 실제 종료에 필요한 시간의 합보다 커야 합니다.
공개 주소와 브라우저 접근
| 변수 | 기본값 | 설명 |
|---|---|---|
FRONTEND_ORIGIN | 비어 있음 | 사용자가 접근하는 프런트엔드 origin. CORS, cookie, 초대 링크에 사용 |
MULTICA_APP_URL | FRONTEND_ORIGIN으로 fallback | 사용자가 접근할 수 있는 Web 주소. CLI 로그인과 계정 연결 링크에 사용 |
MULTICA_PUBLIC_URL | 비어 있음 | 공개 API 주소. webhook URL과 런타임 연결 안내에 사용 |
CORS_ALLOWED_ORIGINS | 비어 있음 | 추가로 허용할 HTTP origin, 쉼표로 구분 |
ALLOWED_ORIGINS | CORS 또는 프런트엔드 주소로 fallback | WebSocket origin allowlist, 쉼표로 구분 |
COOKIE_DOMAIN | 비어 있음 | 프런트엔드와 backend의 host가 다르고 브라우저가 API 도메인에 직접 접근할 때 필수. 단일 도메인 배포에서는 비워 둠 |
프런트엔드와 API가 서로 다른 host를 사용하고 브라우저가 API 도메인에 직접 접근한다면 COOKIE_DOMAIN을 설정해야 합니다. 설정하지 않으면 브라우저가 CSRF cookie를 읽지 못해 모든 쓰기 요청이 403 CSRF validation failed를 반환하고 읽기 요청만 정상 작동합니다. 두 host를 모두 포함하는 가장 좁은 상위 도메인을 사용하세요(.example.com보다 .agent.example.com이 더 적합). 이 설정은 로그인 세션 cookie를 해당 도메인의 모든 host로 확장하므로 모든 host를 같은 신뢰 주체가 운영할 때만 사용할 수 있습니다. 수정 후 두 host에서 이전 cookie를 삭제하고 다시 로그인해야 합니다. 자체 호스팅 빠른 시작의 same-origin 구성을 사용해 브라우저가 app 도메인에만 접근한다면 비워 두세요. IP 주소는 입력하지 마세요. 브라우저가 IP Domain이 포함된 cookie를 무시합니다.
자체 호스팅 배포에서는 FRONTEND_ORIGIN을 설정해야 합니다. 없으면 초대 링크, cookie 보안 속성, WebSocket origin 검증이 실제 도메인과 맞지 않을 수 있습니다.
이메일과 로그인
Resend
| 변수 | 기본값 | 설명 |
|---|---|---|
RESEND_API_KEY | 비어 있음 | 설정하면 Resend 활성화 |
RESEND_FROM_EMAIL | noreply@melso.ai | 발신 주소. 인증된 도메인에 속해야 함 |
SMTP
SMTP_HOST가 비어 있지 않으면 SMTP가 Resend보다 우선합니다.
| 변수 | 기본값 | 설명 |
|---|---|---|
SMTP_HOST | 비어 있음 | SMTP host. 설정하면 SMTP 활성화 |
SMTP_PORT | 25 | 일반적인 값: 25, 587, 465 |
SMTP_USERNAME | 비어 있음 | 사용자 이름. 익명 relay에서는 비워 둠 |
SMTP_PASSWORD | 비어 있음 | 비밀번호 |
SMTP_FROM_EMAIL | RESEND_FROM_EMAIL로 fallback | Envelope From과 이메일 From |
SMTP_TLS | starttls | implicit, smtps, ssl은 암시적 TLS를 의미하며 465에서는 자동 활성화 |
SMTP_TLS_INSECURE | false | 인증서 검증 건너뛰기. 신뢰할 수 있는 내부 네트워크에서만 사용 |
SMTP_EHLO_NAME | host 이름 | 엄격한 relay에서 요구하는 EHLO/FQDN |
Google OAuth
| 변수 | 기본값 | 설명 |
|---|---|---|
GOOGLE_CLIENT_ID | 비어 있음 | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | 비어 있음 | Google OAuth client secret |
GOOGLE_REDIRECT_URI | http://localhost:3000/auth/callback | Google Console의 callback 주소와 완전히 같아야 함 |
가입 범위
| 변수 | 기본값 | 설명 |
|---|---|---|
ALLOW_SIGNUP | true | allowlist가 없을 때 새 계정 생성 허용 여부 |
ALLOWED_EMAILS | 비어 있음 | 가입을 허용할 전체 이메일 주소, 쉼표로 구분 |
ALLOWED_EMAIL_DOMAINS | 비어 있음 | 가입을 허용할 이메일 도메인, 쉼표로 구분 |
DISABLE_WORKSPACE_CREATION | false | 모든 사용자의 새 워크스페이스 생성을 금지. owner/admin 예외 없음 |
MULTICA_DEV_VERIFICATION_CODE | 비어 있음 | production이 아닌 환경에서 사용하는 고정 6자리 테스트 인증 코드 |
allowlist의 정확한 판단 순서는 로그인과 가입을 참고하세요.
첨부 파일 저장소
S3_BUCKET을 설정하지 않으면 Melso가 로컬 디스크를 사용합니다.
S3 또는 호환 저장소
| 변수 | 기본값 | 설명 |
|---|---|---|
S3_BUCKET | 비어 있음 | Bucket 이름. 전체 hostname을 입력하지 않음 |
S3_REGION | us-west-2 | Bucket region |
AWS_ACCESS_KEY_ID | SDK 기본 자격 증명 chain | 정적 access key |
AWS_SECRET_ACCESS_KEY | SDK 기본 자격 증명 chain | 정적 secret key |
AWS_ENDPOINT_URL | 비어 있음 | MinIO 같은 S3 호환 endpoint |
S3_USE_PATH_STYLE | 사용자 지정 endpoint에서는 true | path-style 주소 사용 여부 |
ATTACHMENT_DOWNLOAD_MODE | auto | auto, cloudfront, presign, proxy 중 하나 |
ATTACHMENT_DOWNLOAD_URL_TTL | 30m | 서명된 다운로드 주소의 유효 기간 |
내부 네트워크의 MinIO처럼 브라우저에서 endpoint에 직접 접근할 수 없다면 ATTACHMENT_DOWNLOAD_MODE=proxy를 사용하세요.
로컬 디스크
| 변수 | 기본값 | 설명 |
|---|---|---|
LOCAL_UPLOAD_DIR | ./data/uploads | 파일과 metadata를 저장할 디렉터리. persistent volume 필요 |
LOCAL_UPLOAD_BASE_URL | 비어 있음 | 선택적인 공개 base URL. 비워 두면 사이트 내부 상대 주소 반환 |
CloudFront
| 변수 | 설명 |
|---|---|
CLOUDFRONT_DOMAIN | CDN 도메인 |
CLOUDFRONT_KEY_PAIR_ID | CloudFront key pair ID |
CLOUDFRONT_PRIVATE_KEY | 전체 private key |
CLOUDFRONT_PRIVATE_KEY_SECRET | Secrets Manager에서 private key를 읽을 때 사용 |
Redis와 rate limit
| 변수 | 기본값 | 설명 |
|---|---|---|
REDIS_URL | 비어 있음 | 공유 rate limit, 실시간 이벤트, token cache에 사용. 설정하지 않으면 실시간 이벤트와 초대 제한은 프로세스 메모리로 fallback하고 인증 rate limit은 비활성화 |
REDIS_DISABLE_CLIENT_NAME | false | 관리형 Redis가 CLIENT SETNAME을 금지하면 true로 설정 |
RATE_LIMIT_AUTH | 5 | IP당 1분에 인증 코드 전송 또는 Google 로그인 시작 허용 횟수 |
RATE_LIMIT_AUTH_VERIFY | 20 | IP당 1분에 인증 코드 검증 허용 횟수 |
RATE_LIMIT_INVITATION_ACTOR_10M | 10 | 초대자별 10분 슬라이딩 윈도 내 워크스페이스 초대 생성 횟수. 0이면 이 제한을 비활성화 |
RATE_LIMIT_INVITATION_WORKSPACE_24H | 50 | 워크스페이스의 모든 관리자가 24시간 슬라이딩 윈도 내 생성할 수 있는 총 초대 수. 0이면 이 제한을 비활성화 |
RATE_LIMIT_INVITATION_RECIPIENT_24H | 6 | 정규화된 동일 수신 이메일이 워크스페이스 전체에서 24시간 슬라이딩 윈도 내 받을 수 있는 초대 수. 0이면 이 제한을 비활성화 |
RATE_LIMIT_TRUSTED_PROXIES | 비어 있음 | X-Forwarded-For를 제공하도록 허용할 proxy CIDR, 쉼표로 구분 |
MULTICA_TRUSTED_PROXIES | 비어 있음 | 자동화 webhook과 실시간 연결에서 사용할 신뢰 proxy CIDR |
reverse proxy 뒤에 배포한다면 실제 proxy 네트워크를 입력해야 합니다. 모든 출처를 그대로 신뢰하지 마세요. 클라이언트가 전달 IP를 위조할 수 있습니다.
인증 rate limit에는 REDIS_URL이 필요하며, 설정하지 않으면 시작 로그에 인증 rate limit이 비활성화되었다고 표시됩니다. 초대 제한은 Redis 없이도 프로세스 메모리에서 동작하고, Redis를 설정하면 여러 replica가 할당량을 공유합니다. 설정된 Redis를 일시적으로 사용할 수 없으면 인증 rate limit은 fail-open하지만, 초대 생성은 보호 없이 이메일을 보내지 않고 재시도 가능한 503을 반환합니다.
외부 연동
| 연동 | 변수 | 설명 |
|---|---|---|
| GitHub | GITHUB_APP_SLUG | GitHub App slug |
| GitHub | GITHUB_WEBHOOK_SECRET | Webhook HMAC 및 연결 state 서명 키 |
| GitHub | GITHUB_APP_ID | PR 카드의 CI 상태, merge 가능 여부, "GitHub에서 선택" 저장소에 필요 |
| GitHub | GITHUB_APP_PRIVATE_KEY | App ID와 짝을 이루는 전체 PEM private key. 용도는 위와 같음 |
| Feishu | MULTICA_LARK_SECRET_KEY | base64로 인코딩한 32바이트 자격 증명 암호화 키 |
| Slack | MULTICA_SLACK_SECRET_KEY | base64로 인코딩한 32바이트 token 암호화 키 |
| Composio | COMPOSIO_API_KEY | Composio 도구 연결 활성화 |
| Composio | COMPOSIO_CALLBACK_BASE_URL | callback API 주소. MULTICA_PUBLIC_URL로 fallback 가능 |
| Composio | COMPOSIO_STATE_SECRET | OAuth state 서명 키. JWT_SECRET에서 파생 가능 |
| 자체 호스팅 Git | MULTICA_VCS_INTEGRATION_ENABLED | Forgejo/Gitea/GitLab 연동 스위치. compose에서는 기본 활성화 |
| 자체 호스팅 Git | MULTICA_VCS_SECRET_KEY | base64로 인코딩한 32바이트 암호화 키(openssl rand -base64 32). 없으면 전체 기능을 사용할 수 없음 |
GITHUB_APP_ID와 private key를 설정하지 않아도 PR 연결, 미러링, merge 시 done 전환은 정상적으로 작동합니다. 다만 카드에 CI와 merge 가능 상태가 표시되지 않고 "GitHub에서 선택" 저장소 메뉴도 비활성화됩니다.
설정 단계는 GitHub 연동, Feishu Bot, Slack Bot을 참고하세요.
서버 측 LLM
이 설정 그룹은 대화 제목 같은 서버 측 보조 생성 기능에 사용됩니다. 에이전트가 태스크를 실행할 때 사용하는 AI 코딩 도구의 자격 증명이 아닙니다.
| 변수 | 기본값 | 설명 |
|---|---|---|
MULTICA_LLM_API_KEY | 비어 있음 | OpenAI 호환 API key |
MULTICA_LLM_BASE_URL | 비어 있음 | OpenAI 호환 endpoint |
MULTICA_LLM_DEFAULT_MODEL | gpt-5.6-luna | 요청에 모델이 지정되지 않았을 때 사용 |
API key와 base URL이 모두 비어 있으면 서버 측 LLM 생성이 꺼지고 호출자가 로컬 fallback 로직을 사용합니다.
데몬 설정
아래 변수는 API 컨테이너가 아니라 에이전트를 실행하는 컴퓨터에서 읽습니다.
| 변수 | 기본값 | 설명 |
|---|---|---|
MULTICA_SERVER_URL | ws://localhost:8080/ws | Melso API / WebSocket 주소. http(s)도 허용 |
MULTICA_DAEMON_DEVICE_NAME | host 이름 | 런타임 목록의 기기 이름 |
MULTICA_AGENT_RUNTIME_NAME | Local Agent | 런타임 표시 이름 |
MULTICA_DAEMON_POLL_INTERVAL | 30s | wakeup 이벤트가 없을 때 실행 태스크 polling 간격 |
MULTICA_DAEMON_HEARTBEAT_INTERVAL | 15s | heartbeat 간격 |
MULTICA_DAEMON_MAX_CONCURRENT_TASKS | 20 | 데몬 하나의 동시 실행 태스크 상한 |
MULTICA_AGENT_TIMEOUT | 0 | 단일 실행의 절대 시간 제한. 0은 제한 없음 |
MULTICA_AGENT_IDLE_WATCHDOG | 30m | 출력과 도구 실행이 모두 없을 때의 무응답 상한 |
MULTICA_AGENT_TOOL_WATCHDOG | 2h | 단일 도구 호출이 계속 무응답인 시간 상한 |
MULTICA_OPENCODE_IDLE_WATCHDOG | 10m | OpenCode 전용 무응답 기준값 |
MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUT | 10m | Codex 의미 활동 없음 기준값 |
MULTICA_CODEX_FIRST_TURN_TIMEOUT | 0 | Codex 첫 턴 무진행 상한의 명시적 재정의; 0 은 기본값 유지. 실제 첫 턴 대기는 여전히 MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUT 및 전체 실행 타임아웃으로 제한됨 — MULTICA_CODEX_SEMANTIC_INACTIVITY_TIMEOUT 을 이 값보다 엄격히 크게(여유를 두고) 설정해야 하며, 그렇지 않으면 대기가 그 값으로 잘리고 모델 카탈로그 시작 재시도가 건너뛰어짐. 값이 같으면 충분하지 않음: 의미 타이머가 먼저 시작되므로 값이 같을 때도 재시도가 손실될 수 있음 |
MULTICA_CODEX_HANDSHAKE_TIMEOUT | 30s | Codex app-server 시작 handshake 상한 |
MULTICA_DAEMON_AUTO_UPDATE | Cloud true, 자체 호스팅 false | CLI 자동 확인 및 업데이트 여부 |
MULTICA_DAEMON_AUTO_UPDATE_INTERVAL | 6h | 업데이트 확인 간격 |
MULTICA_DAEMON_AUTO_RELOAD | true | 외부에서 교체된 multica 바이너리(brew upgrade, 재다운로드, 로컬 빌드)로 재시작할지 여부. MULTICA_DAEMON_AUTO_UPDATE와 독립적 |
MULTICA_WORKSPACES_ROOT | ~/multica_workspaces | 실행 태스크 작업 디렉터리의 루트 |
MULTICA_AGENT_TEMP_BASE | /tmp(Linux/macOS) | Linux/macOS 전용. 작업별 비공개 임시 디렉터리의 상위 디렉터리입니다. 기존의 쓰기 가능한 절대 경로여야 하며, 값이 잘못되면 /tmp로 대체하지 않고 작업 시작에 실패합니다. 짧은 경로를 선택하세요. 하위 도구가 그 아래에 AF_UNIX 소켓을 만들 수 있으며 sun_path 제한은 Linux에서 108바이트, macOS에서 104바이트입니다 |
MULTICA_KEEP_ENV_AFTER_TASK | false | 디버깅을 위해 실행 태스크 디렉터리 유지 |
각 AI 코딩 도구는 MULTICA_<PROVIDER>_PATH와 MULTICA_<PROVIDER>_MODEL로 명령 경로와 기본 모델을 덮어쓸 수 있습니다. QwenPaw만 예외로, Melso가 모델을 전달하지 않기 때문에 MULTICA_QWENPAW_MODEL이 없습니다. 자세한 내용은 AI 코딩 도구 비교를 참고하세요. DeepSeek Harness는 MULTICA_DSH_PATH와 MULTICA_DSH_MODEL을 지원합니다(값은 dsh 모델 카탈로그의 모델 ID, 예: deepseek-official/deepseek-chat). 컴퓨터 전체 기본 인수 MULTICA_<PROVIDER>_ARGS는 현재 Claude Code, Codex, CodeBuddy, Qwen Code, QwenPaw 다섯 도구를 지원합니다. 해당 변수는 MULTICA_CLAUDE_ARGS, MULTICA_CODEX_ARGS, MULTICA_CODEBUDDY_ARGS, MULTICA_QWEN_ARGS, MULTICA_QWENPAW_ARGS입니다. 예시:
MULTICA_CLAUDE_PATH=/opt/bin/claude
MULTICA_CLAUDE_ARGS=--max-turns 40우선순위는 명령줄 flag → 환경 변수 → ~/.multica/config.json → 내장 기본값입니다. watchdog 동작은 데몬과 런타임을 참고하세요.
데몬 설정 영속화
자주 사용하는 데몬 측 설정은 shell 환경 변수에 의존하지 않고 ~/.multica/config.json에 기록할 수도 있습니다. 이름 있는 profile의 설정 파일은 ~/.multica/profiles/<name>/config.json에 있습니다.
melso config set poll_interval 10s
melso config show지원되는 key:
| key | 기본값 | 설명 |
|---|---|---|
server_url | ws://localhost:8080/ws | Melso API / WebSocket 주소 |
app_url | 비어 있음 | 브라우저 로그인에 사용할 Web 주소 |
workspace_id | 비어 있음 | 기본 워크스페이스 |
device_name | host 이름 | 런타임 목록의 기기 이름 |
runtime_name | Local Agent | 런타임 표시 이름 |
workspaces_root | ~ 아래 profile별 경로 | 실행 태스크 작업 디렉터리의 루트 |
max_concurrent_tasks | 20 | 동시 실행 태스크 상한. 0 또는 빈 값은 설정되지 않음을 의미 |
poll_interval | 30s | 실행 태스크 polling 간격 |
heartbeat_interval | 15s | heartbeat 간격 |
agent_timeout | 제한 없음 | 단일 실행의 절대 시간 제한 |
codex_semantic_inactivity_timeout | 10m | Codex 의미 활동 없음 기준값 |
codex_handshake_timeout | 30s | Codex app-server handshake 상한 |
disable_auto_update | 환경을 따름 | true는 자동 업데이트를 끔. false는 로컬 덮어쓰기를 지우고 환경 변수 또는 기본값으로 복귀 |
auto_update_check_interval | 6h | 업데이트 확인 간격 |
disable_auto_reload | 환경을 따름 | true는 디스크에서 교체된 바이너리 추적을 끔. false는 로컬 덮어쓰기를 지움. disable_auto_update와 별도로 해석됨 |
값에는 다음 규칙이 적용됩니다.
- duration key는 양의 Go duration(예:
10s,2h)을 허용하며0s와 음수는 거부합니다. 유일한 예외는agent_timeout입니다.0s가 유효하며 실행 시간 제한을 명시적으로 끕니다. - 빈 문자열을 전달하면 저장된 값을 지우고 환경 변수 또는 내장 기본값으로 돌아갑니다. 예:
melso config set poll_interval "" max_concurrent_tasks는 0 이상의 정수여야 합니다.- 상대
workspaces_root값은 저장할 때 절대 경로로 변환됩니다.
관측과 통계
| 변수 | 기본값 | 설명 |
|---|---|---|
ANALYTICS_DISABLED | false | true로 설정하면 PostHog 전송 비활성화 |
POSTHOG_API_KEY | 비어 있음 | 설정하지 않으면 통계 전송 비활성화. 자체 PostHog 프로젝트 연결 시 입력 |
POSTHOG_HOST | https://us.i.posthog.com | PostHog 주소 |
METRICS_ADDR | 비어 있음 | Prometheus metrics listen 주소. 비어 있으면 시작하지 않음 |
REALTIME_METRICS_TOKEN | 비어 있음 | /health/realtime을 보호하는 bearer token |