tailchat

https://github.com/msgbyte/tailchat

语音/视频

https://github.com/livekit/livekit

拉取并生成镜像

docker pull moonrailgun/tailchat # 从公共镜像库拉取 tailchat镜像
docker tag moonrailgun/tailchat tailchat # 将下载的镜像改名为tailchat(和源码编译保持一致,如果不改的话会走源码编译流程)

docker-compose

version: "3"

x-common: &common
  logging:
    driver: json-file #仅在 json-file 驱动程序下,可以使用以下参数,限制日志得数量和大小。
    options:
      max-size: "200m" # 单个文件大小为200m
      max-file: "1" # 最多1个文件

services:
  livekit-server:
    <<: *common
    ports:
      - 7880:7880
      - 7881:7881
      - 7882:7882/udp
    volumes:
      - /opt/livekit/livekit.yaml:/livekit.yaml
    image: livekit/livekit-server
    command: --config /livekit.yaml --node-ip=10.27.0.9
    # node-ip 为 客户端可访问 ip

  # livekit webhook receiver
  tailchat-livekit-webhook-receiver:
    build:
      context: ../
    image: tailchat
    restart: unless-stopped
    env_file: stack.env
    environment:
      LIVEKIT_WEBHOOK_PORT: 3000
    depends_on:
      - mongo
      - redis
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.livekit.rule=PathPrefix(`/livekit/webhook`)"
      - "traefik.http.services.livekit.loadbalancer.server.port=3000"
    networks:
      - internal
    command: node server/dist/plugins/com.msgbyte.livekit/webhook/index.js

  # Tailchat Core Services
  service-core:
    build:
      context: .
    image: tailchat
    restart: unless-stopped
    env_file: stack.env
    environment:
      SERVICES: core/gateway,core/user/*.service.js,core/group/*.service.js,core/chat/*.service.js,core/file,core/plugin/registry,core/config
      PORT: 3000
    depends_on:
      - mongo
      - redis
      - minio
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.api-gw.rule=PathPrefix(`/`)"
      - "traefik.http.services.api-gw.loadbalancer.server.port=3000"
    networks:
      - internal

  # 后台应用
  tailchat-admin:
    build:
      context: ../
    image: tailchat
    restart: unless-stopped
    env_file: stack.env
    depends_on:
      - mongo
      - redis
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.admin.rule=PathPrefix(`/admin`)"
      - "traefik.http.services.admin.loadbalancer.server.port=3000"
    networks:
      - internal
    command: pnpm start:admin

  # Open Platform
  service-openapi:
    build:
      context: .
    image: tailchat
    restart: unless-stopped
    env_file: stack.env
    environment:
      SERVICES: openapi/app,openapi/bot,openapi/integration,openapi/oidc/oidc
      OPENAPI_PORT: 3003
      OPENAPI_UNDER_PROXY: "true"
    depends_on:
      - mongo
      - redis
      - minio
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.openapi-oidc.rule=PathPrefix(`/open`)"
      - "traefik.http.services.openapi-oidc.loadbalancer.server.port=3003"
    networks:
      - internal

  # Plugin Service (All Plugins)
  service-all-plugins:
    build:
      context: .
    image: tailchat
    restart: unless-stopped
    env_file: stack.env
    environment:
      SERVICEDIR: plugins
    depends_on:
      - mongo
      - redis
      - minio
    networks:
      - internal

  # Database
  mongo:
    image: mongo:4
    restart: on-failure
    volumes:
      - /opt/tailchat/data:/data/db
    networks:
      - internal

  # Data cache and Transporter
  redis:
    image: redis:alpine
    restart: on-failure
    networks:
      - internal

  # Persist Storage
  minio:
    image: minio/minio
    restart: on-failure
    networks:
      - internal
    environment:
      MINIO_ROOT_USER: [用户名]
      MINIO_ROOT_PASSWORD: [密码]
    volumes:
      - /opt/tailchat/storage:/data
    command: minio server /data --console-address ":9001"

  # Router
  traefik:
    image: traefik:v2.1
    restart: unless-stopped
    command:
      - "--api.insecure=true" # Don't do that in production!
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entryPoints.web.address=:80"
      - "--entryPoints.web.forwardedHeaders.insecure" # Not good
    ports:
      - 11000:80
#       - 127.0.0.1:11001:8080
      - 11001:8080
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - internal
      - default

networks:
  internal:
    name: tailchat-internal

env

LOGGER=true
LOGLEVEL=info
SERVICEDIR=services

TRANSPORTER=redis://redis:6379

REDIS_URL=redis://redis:6379
MONGO_URL=mongodb://mongo/tailchat
SECRET=

# file
API_URL=https://xx.xx.xx:11111
# 50M
FILE_LIMIT=52428800

# minio
MINIO_URL=minio:9000
MINIO_USER=[用户名]
MINIO_PASS=[密码]

# SMTP
SMTP_SENDER=[SMTP账号]
SMTP_URI=smtps://[SMTP账号]:[SMTP密码]@[SMTP服务地址]/?pool=true

# metrics
PROMETHEUS=1

# Admin
ADMIN_USER=[用户名]
ADMIN_PASS=[密码]

#livekit
LIVEKIT_URL=wss://xx.xx.xx.xx:11111/7880/
LIVEKIT_API_KEY=[LIVEKIT_API_KEY]
LIVEKIT_API_SECRET=[LIVEKIT_API_SECRET]

caddy 反向代理

https://chat.skcks.cn:11111 {
	tls /opt/caddy2/config/ssl/xx.xx.crt /opt/caddy2/config/ssl/xx.xx.key

	handle /_proxy/* {
		#uri strip_prefix _proxy/
		#vars target {path}

		uri strip_prefix /{http.request.uri.path.0}

		respond {query}
		#reverse_proxy {path} {
		#	header_up X-Forwarded-For {remote_host}
		#	header_up X-Real-IP {remote_host}
		#	header_down Access-Control-Allow-Headers *
		#	header_down Access-Control-Allow-Origin *
		#}
	}

	handle /7880/* {
	 	uri strip_prefix /7880
		reverse_proxy http://127.0.0.1:7880  {
			header_up X-Forwarded-For {remote_host}
			header_up  X-Real-IP {remote_host}
    	}
	}

	handle / {
	 	#uri strip_prefix /media
		reverse_proxy http://127.0.0.1:11000  {
			header_up X-Forwarded-For {remote_host}
			header_up  X-Real-IP {remote_host}
    	}
	}

	handle /* {
	 	#uri strip_prefix /media
		reverse_proxy http://127.0.0.1:11000  {
			header_up X-Forwarded-For {remote_host}
			header_up  X-Real-IP {remote_host}
    	}
	}
}