Multistage Dockerfile (FrankenPHP + Octane + Horizon + Reverb) with
docker-compose wiring 6 services: app, mariadb, qdrant, ollama, redis,
traefik. All data mounts to .core/vm/mnt/{config,data,log}. Traefik
routes *.lthn.sh with self-signed TLS. Setup script handles first-run
bootstrap including cert generation and embedding model pull.
Co-Authored-By: Virgil <virgil@lethean.io>
138 lines
4.3 KiB
YAML
138 lines
4.3 KiB
YAML
# Core Agent — Local Development Stack
|
|
# Usage: docker compose up -d
|
|
# Data: .core/vm/mnt/{config,data,log}
|
|
|
|
services:
|
|
app:
|
|
build:
|
|
context: ..
|
|
dockerfile: docker/Dockerfile
|
|
container_name: core-app
|
|
env_file: .env
|
|
volumes:
|
|
- ../.core/vm/mnt/log/app:/app/storage/logs
|
|
networks:
|
|
- core-net
|
|
depends_on:
|
|
mariadb:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
qdrant:
|
|
condition: service_started
|
|
restart: unless-stopped
|
|
labels:
|
|
- "traefik.enable=true"
|
|
# Main app
|
|
- "traefik.http.routers.app.rule=Host(`lthn.sh`) || Host(`api.lthn.sh`) || Host(`mcp.lthn.sh`) || Host(`docs.lthn.sh`) || Host(`lab.lthn.sh`)"
|
|
- "traefik.http.routers.app.entrypoints=websecure"
|
|
- "traefik.http.routers.app.tls=true"
|
|
- "traefik.http.routers.app.service=app"
|
|
- "traefik.http.services.app.loadbalancer.server.port=8088"
|
|
# WebSocket (Reverb)
|
|
- "traefik.http.routers.app-ws.rule=Host(`lthn.sh`) && PathPrefix(`/app`)"
|
|
- "traefik.http.routers.app-ws.entrypoints=websecure"
|
|
- "traefik.http.routers.app-ws.tls=true"
|
|
- "traefik.http.routers.app-ws.service=app-ws"
|
|
- "traefik.http.routers.app-ws.priority=10"
|
|
- "traefik.http.services.app-ws.loadbalancer.server.port=8080"
|
|
|
|
mariadb:
|
|
image: mariadb:11
|
|
container_name: core-mariadb
|
|
environment:
|
|
MARIADB_ROOT_PASSWORD: ${DB_PASSWORD:-core_local_dev}
|
|
MARIADB_DATABASE: ${DB_DATABASE:-core_agent}
|
|
MARIADB_USER: ${DB_USERNAME:-core}
|
|
MARIADB_PASSWORD: ${DB_PASSWORD:-core_local_dev}
|
|
volumes:
|
|
- ../.core/vm/mnt/data/mariadb:/var/lib/mysql
|
|
networks:
|
|
- core-net
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
qdrant:
|
|
image: qdrant/qdrant:v1.17
|
|
container_name: core-qdrant
|
|
volumes:
|
|
- ../.core/vm/mnt/data/qdrant:/qdrant/storage
|
|
networks:
|
|
- core-net
|
|
restart: unless-stopped
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.qdrant.rule=Host(`qdrant.lthn.sh`)"
|
|
- "traefik.http.routers.qdrant.entrypoints=websecure"
|
|
- "traefik.http.routers.qdrant.tls=true"
|
|
- "traefik.http.services.qdrant.loadbalancer.server.port=6333"
|
|
|
|
ollama:
|
|
image: ollama/ollama:latest
|
|
container_name: core-ollama
|
|
volumes:
|
|
- ../.core/vm/mnt/data/ollama:/root/.ollama
|
|
networks:
|
|
- core-net
|
|
restart: unless-stopped
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.ollama.rule=Host(`ollama.lthn.sh`)"
|
|
- "traefik.http.routers.ollama.entrypoints=websecure"
|
|
- "traefik.http.routers.ollama.tls=true"
|
|
- "traefik.http.services.ollama.loadbalancer.server.port=11434"
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: core-redis
|
|
volumes:
|
|
- ../.core/vm/mnt/data/redis:/data
|
|
networks:
|
|
- core-net
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
traefik:
|
|
image: traefik:v3
|
|
container_name: core-traefik
|
|
command:
|
|
- "--api.dashboard=true"
|
|
- "--api.insecure=false"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
|
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--providers.docker.network=core-net"
|
|
- "--providers.file.directory=/etc/traefik/config"
|
|
- "--providers.file.watch=true"
|
|
- "--log.level=INFO"
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ../.core/vm/mnt/config/traefik:/etc/traefik/config
|
|
- ../.core/vm/mnt/log/traefik:/var/log/traefik
|
|
networks:
|
|
- core-net
|
|
restart: unless-stopped
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.traefik.rule=Host(`traefik.lthn.sh`)"
|
|
- "traefik.http.routers.traefik.entrypoints=websecure"
|
|
- "traefik.http.routers.traefik.tls=true"
|
|
- "traefik.http.routers.traefik.service=api@internal"
|
|
|
|
networks:
|
|
core-net:
|
|
name: core-net
|