name: webpage services: lotto: build: context: ./lotto args: APP_VERSION: ${APP_VERSION:-dev} container_name: lotto restart: unless-stopped ports: - "18000:8000" environment: - TZ=${TZ:-Asia/Seoul} - LOTTO_ALL_URL=${LOTTO_ALL_URL:-https://smok95.github.io/lotto/results/all.json} - LOTTO_LATEST_URL=${LOTTO_LATEST_URL:-https://smok95.github.io/lotto/results/latest.json} volumes: - ${RUNTIME_PATH}/data:/app/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 stock-lab: build: context: ./stock-lab args: APP_VERSION: ${APP_VERSION:-dev} container_name: stock-lab restart: unless-stopped ports: - "18500:8000" environment: - TZ=${TZ:-Asia/Seoul} - WINDOWS_AI_SERVER_URL=${WINDOWS_AI_SERVER_URL:-http://192.168.0.5:8000} - GEMINI_API_KEY=${GEMINI_API_KEY:-} - GEMINI_MODEL=${GEMINI_MODEL:-gemini-1.5-flash} - ADMIN_API_KEY=${ADMIN_API_KEY:-} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - ANTHROPIC_MODEL=${ANTHROPIC_MODEL:-claude-haiku-4-5-20251001} - LLM_PROVIDER=${LLM_PROVIDER:-claude} - OLLAMA_URL=${OLLAMA_URL:-http://192.168.45.59:11435} - OLLAMA_MODEL=${OLLAMA_MODEL:-qwen3:14b} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} volumes: - ${RUNTIME_PATH}/data/stock:/app/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 music-lab: build: context: ./music-lab container_name: music-lab restart: unless-stopped ports: - "18600:8000" environment: - TZ=${TZ:-Asia/Seoul} - MUSIC_AI_SERVER_URL=${MUSIC_AI_SERVER_URL:-} - SUNO_API_KEY=${SUNO_API_KEY:-} - MUSIC_MEDIA_BASE=${MUSIC_MEDIA_BASE:-/media/music} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} - PEXELS_API_KEY=${PEXELS_API_KEY:-} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - OPENAI_API_KEY=${OPENAI_API_KEY:-} - YOUTUBE_OAUTH_CLIENT_ID=${YOUTUBE_OAUTH_CLIENT_ID:-} - YOUTUBE_OAUTH_CLIENT_SECRET=${YOUTUBE_OAUTH_CLIENT_SECRET:-} - YOUTUBE_OAUTH_REDIRECT_URI=${YOUTUBE_OAUTH_REDIRECT_URI:-} - CLAUDE_HAIKU_MODEL=${CLAUDE_HAIKU_MODEL:-claude-haiku-4-5-20251001} - CLAUDE_SONNET_MODEL=${CLAUDE_SONNET_MODEL:-claude-sonnet-4-6} - VIDEO_DATA_DIR=${VIDEO_DATA_DIR:-/app/data/videos} - WINDOWS_VIDEO_ENCODER_URL=${WINDOWS_VIDEO_ENCODER_URL:-} - NAS_VIDEOS_ROOT=${NAS_VIDEOS_ROOT:-/volume1/docker/webpage/data/videos} - NAS_MUSIC_ROOT=${NAS_MUSIC_ROOT:-/volume1/docker/webpage/data/music} volumes: - ${RUNTIME_PATH}/data/music:/app/data - ${RUNTIME_PATH:-.}/data/videos:/app/data/videos healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 blog-lab: build: context: ./blog-lab container_name: blog-lab restart: unless-stopped ports: - "18700:8000" environment: - TZ=${TZ:-Asia/Seoul} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - NAVER_CLIENT_ID=${NAVER_CLIENT_ID:-} - NAVER_CLIENT_SECRET=${NAVER_CLIENT_SECRET:-} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} volumes: - ${RUNTIME_PATH}/data/blog:/app/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 realestate-lab: build: context: ./realestate-lab container_name: realestate-lab restart: unless-stopped ports: - "18800:8000" environment: - TZ=${TZ:-Asia/Seoul} - DATA_GO_KR_API_KEY=${DATA_GO_KR_API_KEY:-} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} - AGENT_OFFICE_URL=${AGENT_OFFICE_URL:-http://agent-office:8000} volumes: - ${RUNTIME_PATH}/data/realestate:/app/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 agent-office: build: context: ./agent-office container_name: agent-office restart: unless-stopped ports: - "18900:8000" environment: - TZ=${TZ:-Asia/Seoul} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} - STOCK_LAB_URL=http://stock-lab:8000 - MUSIC_LAB_URL=http://music-lab:8000 - BLOG_LAB_URL=http://blog-lab:8000 - REALESTATE_LAB_URL=http://realestate-lab:8000 - REALESTATE_DASHBOARD_URL=${REALESTATE_DASHBOARD_URL:-http://localhost:8080/realestate} - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-} - TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-} - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-} - TELEGRAM_WIFE_CHAT_ID=${TELEGRAM_WIFE_CHAT_ID:-} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - CLAUDE_HAIKU_MODEL=${CLAUDE_HAIKU_MODEL:-claude-haiku-4-5-20251001} - CLAUDE_SONNET_MODEL=${CLAUDE_SONNET_MODEL:-claude-sonnet-4-6} - LOTTO_BACKEND_URL=${LOTTO_BACKEND_URL:-http://lotto:8000} - LOTTO_CURATOR_MODEL=${LOTTO_CURATOR_MODEL:-claude-sonnet-4-5} - CONVERSATION_MODEL=${CONVERSATION_MODEL:-claude-haiku-4-5-20251001} - CONVERSATION_HISTORY_LIMIT=${CONVERSATION_HISTORY_LIMIT:-20} - CONVERSATION_RATE_PER_MIN=${CONVERSATION_RATE_PER_MIN:-6} - YOUTUBE_DATA_API_KEY=${YOUTUBE_DATA_API_KEY:-} volumes: - ${RUNTIME_PATH:-.}/data/agent-office:/app/data depends_on: - stock-lab - music-lab - blog-lab - realestate-lab healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 personal: build: context: ./personal container_name: personal restart: unless-stopped ports: - "18850:8000" environment: - TZ=${TZ:-Asia/Seoul} - PORTFOLIO_EDIT_PASSWORD=${PORTFOLIO_EDIT_PASSWORD:-} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} volumes: - ${RUNTIME_PATH:-.}/data/personal:/app/data healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 packs-lab: build: context: ./packs-lab container_name: packs-lab restart: unless-stopped ports: - "18950:8000" environment: - TZ=${TZ:-Asia/Seoul} - DSM_HOST=${DSM_HOST:-} - DSM_USER=${DSM_USER:-} - DSM_PASS=${DSM_PASS:-} - DSM_VERIFY_SSL=${DSM_VERIFY_SSL:-true} - BACKEND_HMAC_SECRET=${BACKEND_HMAC_SECRET:-} - SUPABASE_URL=${SUPABASE_URL:-} - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY:-} - UPLOAD_TOKEN_TTL_SEC=${UPLOAD_TOKEN_TTL_SEC:-1800} - PACK_BASE_DIR=${PACK_BASE_DIR:-/app/data/packs} - PACK_HOST_DIR=${PACK_HOST_DIR:-${PACK_DATA_PATH:-./data/packs}} volumes: - ${PACK_DATA_PATH:-./data/packs}:${PACK_BASE_DIR:-/app/data/packs} healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 travel-proxy: build: ./travel-proxy container_name: travel-proxy restart: unless-stopped user: "${PUID}:${PGID}" ports: - "19000:8000" environment: - TZ=${TZ:-Asia/Seoul} - TRAVEL_ROOT=${TRAVEL_ROOT:-/data/travel} - TRAVEL_THUMB_ROOT=${TRAVEL_THUMB_ROOT:-/data/thumbs} - TRAVEL_MEDIA_BASE=${TRAVEL_MEDIA_BASE:-/media/travel} - TRAVEL_DB_PATH=${TRAVEL_DB_PATH:-/data/thumbs/travel.db} - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080} volumes: - ${PHOTO_PATH}:/data/travel:ro - ${RUNTIME_PATH}/travel-thumbs:/data/thumbs:rw healthcheck: test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"] interval: 30s timeout: 5s retries: 3 frontend: image: nginx:alpine container_name: frontend restart: unless-stopped depends_on: - lotto - stock-lab - music-lab - blog-lab - realestate-lab - agent-office - personal - packs-lab - travel-proxy ports: - "8080:80" volumes: - ${FRONTEND_PATH}:/usr/share/nginx/html:ro - ${RUNTIME_PATH}/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro - ${PHOTO_PATH}:/data/travel:ro - ${RUNTIME_PATH}/travel-thumbs:/data/thumbs:ro - ${RUNTIME_PATH}/data/music:/data/music:ro - ${RUNTIME_PATH}/data/videos:/data/videos:ro extra_hosts: - "host.docker.internal:host-gateway" healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/"] interval: 30s timeout: 5s retries: 3 deployer: build: ./deployer container_name: webpage-deployer restart: unless-stopped ports: - "127.0.0.1:19010:9000" environment: - TZ=${TZ:-Asia/Seoul} - WEBHOOK_SECRET=${WEBHOOK_SECRET} - PUID=${PUID:-1026} - PGID=${PGID:-100} volumes: - ${REPO_PATH}:/repo:rw - ${RUNTIME_PATH}:/runtime:rw - ${RUNTIME_PATH}/scripts:/scripts:ro - /var/run/docker.sock:/var/run/docker.sock