Files
wecom_it_smart_desk/docker-compose.yml
Simon 21830d507d fix(nginx): 移除 /itportal/ 静态前端块(portal 源码已下线)
P0 修复 — /itportal/ HTTP 500(连续 3+ 天阻塞)

根因分析:
- portal 源码 frontend-portal/ 在 commit bea288e4 (2026-07-11) 被误删
- portal dist 不存在(前端目录已不存在)
- backend/app/api/portal.py 也已删除
- /api/portal/* API 不再在 router.py 注册
- 但 nginx 配置 + docker-compose 仍引用 portal dist → try_files 指向空目录 → 500
- nginx-split.conf 还有根路径重定向 / → /itportal/ → 用户访问根域名直接 500

修复(最小集、最安全):
1. nginx 6 个配置(nginx/nginx.conf + 5 个 deploy-server 历史变体):
   - 删除 location /itportal/ { alias ... } 静态块
   - 保留 location /itportal/meetingroom/ API 块(最长前缀仍命中)
   - nginx-split.conf / nginx-full.conf / nginx-green-upstream.conf 根重定向
     /itportal/ → /itdesk/
2. docker-compose 4 个配置(+split):
   - 删除 ./frontend-portal/dist 或 ./html/itportal 卷挂载
3. deploy-server/deploy.sh:
   - 删除 portal dist 备份/解压步骤
   - 部署完成提示去掉 /itportal/ 入口

预期效果:
- /itportal/ → nginx 404(不再 500)
- /itportal/meetingroom/ → API 仍工作(终端+H5 共用会议室预定)
- /itdesk/ /itagent/ /itadmin/ /itterminal/ 不受影响
- 根域名访问 → 重定向到 /itdesk/(H5 入口)

文件改动:
- nginx/nginx.conf(双 server block)
- deploy-server/nginx.conf(双 server block)
- deploy-server/nginx-full.conf + green-upstream.conf + nginx.conf + nginx-split.conf
- docker-compose.yml + 3 个 deploy-server 变体
- deploy-server/deploy.sh

⚠️ 待部署(无 jumpserver/VPN):本地已就绪,需在 jumpserver-V2 流程下
   scp 上述 11 个文件到 /opt/wecom-it-desk/ 覆盖 + docker compose restart nginx 验证
   验证命令:curl -I https://itsupport.servyou.com.cn/itportal/ 期望返回 404(或 301/302)
            curl -I https://itsupport.servyou.com.cn/itportal/meetingroom/... 期望 200/401/403
            curl -I https://itsupport.servyou.com.cn/ 期望 302 → /itdesk/

Refs: 滴答清单任务 6a6bfc29e4b06440c36701e1 (P0 逾期 1 天)
2026-08-03 20:02:52 +08:00

250 lines
9.4 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# =============================================================================
# 企微IT智能服务台 — Docker Compose(公司内网服务器版)
# =============================================================================
# 目标服务器:10.90.5.110
# 域名:itsupport.servyou.com.cn
#
# 用法:
# 1. 上传部署包到服务器
# 2. cp .env.example .env && vim .env # 填入真实配置
# 3. docker compose up -d # 启动所有服务
# 4. docker compose logs -f # 查看日志
#
# 架构:
# 客户端浏览器 → Nginx:80 → { /itdesk/, /itagent/, /itadmin/, /api/, /ws/ }
# =============================================================================
services:
# --------------------------------------------------------------------------
# PostgreSQL 16 — 持久化数据库
# --------------------------------------------------------------------------
postgres:
image: postgres:16-alpine
container_name: wecom_it_postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-wecom}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-wecom_secret}
POSTGRES_DB: ${POSTGRES_DB:-wecom_it_desk}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-wecom}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- it-desk-internal
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# --------------------------------------------------------------------------
# Redis 7 — 缓存服务(token、会话、员工信息)
# --------------------------------------------------------------------------
redis:
image: redis:7-alpine
container_name: wecom_it_redis
restart: unless-stopped
command: redis-server --appendonly yes --save 900 1 --save 300 10 --requirepass "${REDIS_PASSWORD:?REDIS_PASSWORD must be set in .env}"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
networks:
- it-desk-internal
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# --------------------------------------------------------------------------
# Neo4j 5 — 知识图谱存储(社区版)
# --------------------------------------------------------------------------
neo4j:
image: neo4j:5-community
container_name: wecom_it_neo4j
restart: unless-stopped
environment:
NEO4J_AUTH: neo4j/${NEO4J_PASSWORD}
NEO4J_PLUGINS: '["apoc"]'
volumes:
- neo4j_data:/data
- neo4j_logs:/logs
healthcheck:
test: ["CMD-SHELL", "cypher-shell -u neo4j -p ${NEO4J_PASSWORD} 'RETURN 1'"]
interval: 10s
timeout: 5s
retries: 10
networks:
- it-desk-internal
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# --------------------------------------------------------------------------
# FastAPI 后端 — 核心业务服务
# --------------------------------------------------------------------------
backend:
build:
context: ./src/backend
dockerfile: Dockerfile
image: wecom-it-desk-backend:latest
container_name: wecom_it_backend
restart: unless-stopped
environment:
# 企微凭证
- WECOM_CORP_ID=${WECOM_CORP_ID}
- WECOM_AGENT_ID=${WECOM_AGENT_ID}
- WECOM_SECRET=${WECOM_SECRET}
- WECOM_APPROVAL_SECRET=${WECOM_APPROVAL_SECRET:-}
- WECOM_TOKEN=${WECOM_TOKEN}
- WECOM_ENCODING_AES_KEY=${WECOM_ENCODING_AES_KEY}
# 企微 SSO 回调地址(扫码登录用)
- WECOM_SSO_CALLBACK_BASE=${WECOM_SSO_CALLBACK_BASE:-https://itsupport.servyou.com.cn}
# ITSM 运维平台(app_id/app_secret 待申请,先占位)
- ITSM_APP_ID=${ITSM_APP_ID:-}
- ITSM_APP_SECRET=${ITSM_APP_SECRET:-}
# 数据库(Docker 内部网络,用容器名通信)
- DATABASE_URL=postgresql://${POSTGRES_USER:-wecom}:${POSTGRES_PASSWORD:-wecom_secret}@postgres:5432/${POSTGRES_DB:-wecom_it_desk}
# RedisDocker 内部网络)
# v4.0 P1-7:密码改为 .env 注入(原硬编码已入 git 历史,2026-07-18 轮换)
# 新密码为 32 位字母数字,无需 URL 编码;若含特殊字符必须用 REDIS_PASSWORD_ENCODED
- REDIS_URL=redis://:${REDIS_PASSWORD_ENCODED:-${REDIS_PASSWORD}}@redis:6379/0
# 应用环境(v4.0 P1-7 修复:生产 UA 校验和 IP 白名单依赖此变量,此前未传入容器)
- APP_ENV=${APP_ENV:-production}
# CORS
- CORS_ORIGINS=${CORS_ORIGINS:-http://itsupport.servyou.com.cn}
# AI 服务(Dify
- DIFY_API_URL=${DIFY_API_URL}
- DIFY_API_KEY=${DIFY_API_KEY}
- DIFY_TIMEOUT=${DIFY_TIMEOUT:-30}
# Dify 原生直连(优先于 dify2openai 代理,修复 [object Object] bug
- DIFY_NATIVE_BASE_URL=${DIFY_NATIVE_BASE_URL:-}
- DIFY_NATIVE_API_KEY=${DIFY_NATIVE_API_KEY:-}
# Dify 双路径超时预算切分(v4.0 P0-620+20 < wait_for 30s
# 2026-07-20: 12→20,用户反馈高峰期超时较多
- DIFY_NATIVE_TIMEOUT=${DIFY_NATIVE_TIMEOUT:-20}
- DIFY_PROXY_TIMEOUT=${DIFY_PROXY_TIMEOUT:-20}
# AI Wingman(留空禁用)
- DIFY_WINGMAN_API_URL=${DIFY_WINGMAN_API_URL:-}
- DIFY_WINGMAN_API_KEY=${DIFY_WINGMAN_API_KEY:-}
- DIFY_WINGMAN_TIMEOUT=${DIFY_WINGMAN_TIMEOUT:-30}
# 百度语音识别(ASR
- BAIDU_ASR_APP_ID=${BAIDU_ASR_APP_ID:-}
- BAIDU_ASR_API_KEY=${BAIDU_ASR_API_KEY:-}
- BAIDU_ASR_SECRET_KEY=${BAIDU_ASR_SECRET_KEY:-}
# Neo4j 知识图谱
- NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687}
- NEO4J_USER=${NEO4J_USER:-neo4j}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
- NEO4J_DATABASE=${NEO4J_DATABASE:-neo4j}
- NEO4J_MAX_CONNECTION_LIFETIME=${NEO4J_MAX_CONNECTION_LIFETIME:-3600}
- NEO4J_MAX_CONNECTION_POOL_SIZE=${NEO4J_MAX_CONNECTION_POOL_SIZE:-50}
# Mock 登录(生产环境默认关闭,如需临时调试请在 .env 中显式设置为 true)
- MOCK_LOGIN_ENABLED=${MOCK_LOGIN_ENABLED:-false}
# 终端页面基础URL(用于NE2005等终端生成二维码)
- TERMINAL_BASE_URL=${TERMINAL_BASE_URL:-https://itsupport.servyou.com.cn/itterminal/}
# 服务配置
- BACKEND_HOST=0.0.0.0
- BACKEND_PORT=8000
# 上传文件目录(持久化)
- UPLOAD_DIR=/app/uploads
# 运行期日志目录(供"运行期日志"管理页面读取,需与下方 volumes 挂载一致)
- RUNTIME_LOG_DIR=/app/logs
# 安全告警(企微机器人 webhook)
- CONTENT_AUDIT_WEBHOOK=${CONTENT_AUDIT_WEBHOOK}
volumes:
# 代码热更新(生产环境:宿主机 ./src/backend/app → 容器 /app/app
- ./src/backend/app:/app/app
- backend-uploads:/app/uploads
- ${RUNTIME_LOG_HOST_DIR:-/var/log/wecom-it-desk}:/app/logs
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
neo4j:
condition: service_healthy
command: >
/bin/sh -c "
echo '>>> 启动 API 服务 (跳过迁移)...' &&
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 1
"
networks:
- it-desk-internal
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"
# --------------------------------------------------------------------------
# Nginx — 反向代理 + 静态文件服务
# --------------------------------------------------------------------------
nginx:
image: nginx:1.27-alpine
container_name: wecom_it_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- ./src/frontend-h5/dist:/usr/share/nginx/html/itdesk:ro
- ./src/frontend-h5/dist:/usr/share/nginx/html/h5:ro
- ./src/frontend-agent/dist:/usr/share/nginx/html/itagent:ro
- ./src/frontend-admin/dist:/usr/share/nginx/html/itadmin:ro
- ./src/frontend-terminal/dist:/usr/share/nginx/html/itterminal:ro
depends_on:
- backend
networks:
- it-desk-internal
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:80/itdesk/health || exit 1"]
interval: 15s
timeout: 5s
retries: 3
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# =============================================================================
# 网络
# =============================================================================
networks:
it-desk-internal:
driver: bridge
# =============================================================================
# 数据卷 — 持久化存储
# =============================================================================
volumes:
postgres_data:
name: wecom_it_postgres_data
redis_data:
name: wecom_it_redis_data
neo4j_data:
name: wecom_it_neo4j_data
neo4j_logs:
name: wecom_it_neo4j_logs
backend-uploads:
name: wecom_it_backend_uploads