From 0a7f91ba8c75842d3c46202d0545acc89ca490e2 Mon Sep 17 00:00:00 2001 From: AWESOMEDEV Date: Thu, 23 Jul 2026 12:23:50 +0900 Subject: [PATCH] =?UTF-8?q?deploy:=20=EB=A9=98=ED=86=A0=20AI=20=EC=B4=88?= =?UTF-8?q?=EC=95=88=EC=9A=A9=20ollama-proxy=20=EC=B6=94=EA=B0=80=20+=20ba?= =?UTF-8?q?ckend=20LLM=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit edu(EC2)가 워크스테이션 tailnet의 Ollama를 쓰도록 프록시를 둔다. Ollama는 DNS-rebinding 방어로 Host를 검증해 tailnet 이름 요청을 403으로 막는데, 이 프록시가 Host를 localhost로 재작성해 통과시킨다. backend는 JAVA_TOOL_OPTIONS(-Dllm.base-url)로 프록시를 가리킨다. --- deploy/docker-compose.prod.yml | 22 ++++++++++++++++++++++ deploy/ollama-proxy/Caddyfile | 9 +++++++++ 2 files changed, 31 insertions(+) create mode 100644 deploy/ollama-proxy/Caddyfile diff --git a/deploy/docker-compose.prod.yml b/deploy/docker-compose.prod.yml index 9130ab1..bd3b845 100644 --- a/deploy/docker-compose.prod.yml +++ b/deploy/docker-compose.prod.yml @@ -50,9 +50,31 @@ services: TELEGRAM_CHAT_ID: ${TELEGRAM_CHAT_ID:-} # 멘토 최초 비밀번호 (첫 부팅 시드용). 비우면 랜덤 생성돼 로그에 1회 출력된다. MENTOR_INITIAL_PASSWORD: ${MENTOR_INITIAL_PASSWORD:-} + # 멘토 피드백 AI 초안 — 아래 ollama-proxy 경유로 워크스테이션(tailnet)의 Ollama를 쓴다. + # 학습 포인트: @Value("${llm.base-url:}")는 환경변수 relaxed binding이 약해, LLM_BASE_URL을 + # 줘도 안 읽히는 경우가 있다. JVM 시스템 프로퍼티(-D)로 주면 확실하다. + # 이 값이 없으면 초안 기능만 조용히 꺼지고 앱은 정상 동작한다. + JAVA_TOOL_OPTIONS: "-Dllm.base-url=http://ollama-proxy:11434" depends_on: postgres: condition: service_healthy + ollama-proxy: + condition: service_started + restart: unless-stopped + + # 로컬 LLM 프록시 — 멘토 피드백 AI 초안이 워크스테이션(tailnet)의 Ollama를 쓰게 한다. + # 왜 프록시가 필요한가: Ollama는 DNS-rebinding 방어로 요청 Host 헤더를 검증해서, + # tailnet 이름(awesomedev.taildc21b5.ts.net)으로 오는 요청을 403으로 막는다. + # 이 프록시가 Host를 localhost로 재작성해 통과시킨다(Caddyfile 참조). + # 워크스테이션 쪽은 `tailscale serve`로 Ollama를 tailnet 전용 노출한다(Ollama는 127.0.0.1 유지). + ollama-proxy: + image: caddy:2-alpine + container_name: ollama-proxy + logging: *logging + extra_hosts: + - "awesomedev.taildc21b5.ts.net:100.67.10.124" # 워크스테이션 tailnet IP + volumes: + - ./ollama-proxy/Caddyfile:/etc/caddy/Caddyfile:ro restart: unless-stopped # 프론트 빌드 결과물을 공유 볼륨(webroot)에 복사해 주고 종료하는 일회성 컨테이너 diff --git a/deploy/ollama-proxy/Caddyfile b/deploy/ollama-proxy/Caddyfile new file mode 100644 index 0000000..a1608a6 --- /dev/null +++ b/deploy/ollama-proxy/Caddyfile @@ -0,0 +1,9 @@ +# Ollama 앞단 Host 재작성 프록시. +# Ollama는 DNS-rebinding 방어로 요청 Host를 검증해, tailnet 이름으로 오는 요청을 403으로 막는다. +# 여기서 Host를 localhost로 바꿔 통과시킨다. 업스트림은 워크스테이션의 `tailscale serve`(HTTPS, :8443). +# SNI/인증서는 실제 이름(awesomedev.taildc21b5.ts.net)으로 맺고, HTTP Host 헤더만 localhost로 보낸다. +:11434 { + reverse_proxy https://awesomedev.taildc21b5.ts.net:8443 { + header_up Host localhost:11434 + } +}