Compare commits
128 Commits
f572da050e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c55f41408a | |||
| 7bca766247 | |||
| 120bf7c385 | |||
| 35e0f232f9 | |||
| cd9256f09c | |||
| c9e3a5cc4f | |||
| b2b444fb98 | |||
| dcc29d20f0 | |||
| 19ad30e8c4 | |||
| 99e39ee6e6 | |||
| ed83e64727 | |||
| 18e6741596 | |||
| c83b77ebdb | |||
| 6568dd10b5 | |||
| a6e4540e84 | |||
| dbdf33e78e | |||
| 74f618bcbb | |||
| 0c7fe219f7 | |||
| 6d0a15a969 | |||
| f4dd7c7d9d | |||
| 608b5ba793 | |||
| 2e45252793 | |||
| 20ba9952a1 | |||
| 69869ec3fb | |||
| cc270c8539 | |||
| 8bdcde4b90 | |||
| 2ab43e8fd3 | |||
| 5d232c7d9b | |||
| cef233b678 | |||
| b63ddbffbd | |||
| d57a1241d2 | |||
| ef0309838c | |||
| 071a74a996 | |||
| 74b3748b23 | |||
| 87216ab26a | |||
| 9e2b19e7f6 | |||
| a80c6b931b | |||
| 64c02228d8 | |||
| 55d9bef18a | |||
| 7fc945e179 | |||
| 94ab4ae6dd | |||
| 779e76974d | |||
| f3f32c163f | |||
| e00e959543 | |||
| 0fd2eacad1 | |||
| bf402adb25 | |||
| ae1c349b55 | |||
| 66d8c82e47 | |||
| ea81634ef3 | |||
| 25bd020b93 | |||
| 904f7d3c2e | |||
| 9a964cff3c | |||
| 0999e5d29f | |||
| ec903c16c2 | |||
| 155016da97 | |||
| c81f312e9e | |||
| fe0cf487ee | |||
| 81d4058c5d | |||
| 4a575bc0da | |||
| 01a345979b | |||
| c58b5d36ba | |||
| 62fcf832da | |||
| dfde1df72f | |||
| 42a68bc0b5 | |||
| 699c8537b0 | |||
| ed4d537499 | |||
| 103bbbad51 | |||
| 92a7436716 | |||
| 6aea9d018e | |||
| e2e0927291 | |||
| a5ed2be933 | |||
| d5e37dbd3f | |||
| abcebd1d9b | |||
| 3ed3e68271 | |||
| bb3dabcba7 | |||
| 8de88d96ac | |||
| c0b1308ffe | |||
| e22936ecbe | |||
| 7cdab58018 | |||
| d583015d2b | |||
| 5f2fb12436 | |||
| 92c3125773 | |||
| 6c3f4bb186 | |||
| f2f85ae236 | |||
| 256ee786b2 | |||
| c561914f49 | |||
| 96407fb57a | |||
| 45ea016aaa | |||
| 438bbccadf | |||
| 2b5d4d527d | |||
| 7fd0199e1a | |||
| 0e5b539936 | |||
| f95a3ff143 | |||
| 710222e705 | |||
| 48fd6f87fe | |||
| eb10348988 | |||
| 417fbb6ff1 | |||
| 3050bbb859 | |||
| 6f1cce8c88 | |||
| 8e6c73f82d | |||
| 85ef8ecb36 | |||
| d812ede999 | |||
| fc23e22112 | |||
| 84c9d91bcf | |||
| 96004a38c2 | |||
| cd47bce06b | |||
| d90f0179df | |||
| 27c3218784 | |||
| 1af4ec5fca | |||
| 4dee03dd86 | |||
| d1357206e8 | |||
| f36c10a5b4 | |||
| 41841f800e | |||
| 251ea6b775 | |||
| 22deecdbe8 | |||
| 46105b1f25 | |||
| 94a8df8fa1 | |||
| 102484d88c | |||
| ab1d350af3 | |||
| 26fa1be36c | |||
| 8622f9dfa0 | |||
| 0146d1f043 | |||
| d26310afb7 | |||
| 2014a82efb | |||
| 5cec1415ad | |||
| 8a18ae753d | |||
| ffbcecc09d | |||
| 39c28d49a4 |
81
CLAUDE.md
81
CLAUDE.md
@@ -25,7 +25,7 @@ Root `compose.yaml` uses Docker Compose's `include` directive to orchestrate mul
|
|||||||
- **kit**: Unified toolkit with Vert file converter and miniPaint image editor (path-routed)
|
- **kit**: Unified toolkit with Vert file converter and miniPaint image editor (path-routed)
|
||||||
- **jelly**: Jellyfin media server with hardware transcoding
|
- **jelly**: Jellyfin media server with hardware transcoding
|
||||||
- **drop**: PairDrop peer-to-peer file sharing
|
- **drop**: PairDrop peer-to-peer file sharing
|
||||||
- **ai**: AI infrastructure with Open WebUI, Crawl4AI, and pgvector (PostgreSQL)
|
- **ai**: AI infrastructure with Open WebUI, ComfyUI proxy, Crawl4AI, and pgvector (PostgreSQL)
|
||||||
- **asciinema**: Terminal recording and sharing platform (PostgreSQL)
|
- **asciinema**: Terminal recording and sharing platform (PostgreSQL)
|
||||||
- **restic**: Backrest backup system with restic backend
|
- **restic**: Backrest backup system with restic backend
|
||||||
- **netdata**: Real-time infrastructure monitoring
|
- **netdata**: Real-time infrastructure monitoring
|
||||||
@@ -451,11 +451,13 @@ AI infrastructure with Open WebUI, Crawl4AI, and dedicated PostgreSQL with pgvec
|
|||||||
- User signup enabled
|
- User signup enabled
|
||||||
- Data persisted in `ai_webui_data` volume
|
- Data persisted in `ai_webui_data` volume
|
||||||
|
|
||||||
- **crawl4ai**: Crawl4AI web scraping service (internal API, no public access)
|
- **comfyui**: ComfyUI reverse proxy exposed at `comfy.ai.pivoine.art:80`
|
||||||
- Optimized web scraper for LLM content preparation
|
- Nginx-based proxy to ComfyUI running on RunPod GPU server
|
||||||
- Internal API on port 11235 (not exposed via Traefik)
|
- Node-based UI for Flux.1 Schnell image generation workflows
|
||||||
- Designed for integration with Open WebUI and n8n workflows
|
- Proxies to RunPod via Tailscale VPN (100.121.199.88:8188)
|
||||||
- Data persisted in `ai_crawl4ai_data` volume
|
- Protected by Authelia SSO authentication
|
||||||
|
- WebSocket support for real-time updates
|
||||||
|
- Stateless architecture (no data persistence on VPS)
|
||||||
|
|
||||||
**Configuration**:
|
**Configuration**:
|
||||||
- **Claude Integration**: Uses Anthropic API with OpenAI-compatible endpoint
|
- **Claude Integration**: Uses Anthropic API with OpenAI-compatible endpoint
|
||||||
@@ -476,11 +478,71 @@ AI infrastructure with Open WebUI, Crawl4AI, and dedicated PostgreSQL with pgvec
|
|||||||
4. Use web search feature for current information
|
4. Use web search feature for current information
|
||||||
5. Integrate with n8n workflows for automation
|
5. Integrate with n8n workflows for automation
|
||||||
|
|
||||||
|
**Flux Image Generation** (`functions/flux_image_gen.py`):
|
||||||
|
Open WebUI function for generating images via Flux.1 Schnell on RunPod GPU:
|
||||||
|
- Manifold function adds "Flux.1 Schnell (4-5s)" model to Open WebUI
|
||||||
|
- Routes requests through LiteLLM → Orchestrator → RunPod Flux
|
||||||
|
- Generates 1024x1024 images in 4-5 seconds
|
||||||
|
- Returns images as base64-encoded markdown
|
||||||
|
- Configuration via Valves (API base, timeout, default size)
|
||||||
|
- **Automatically loaded via Docker volume mount** (`./functions:/app/backend/data/functions:ro`)
|
||||||
|
|
||||||
|
**Deployment**:
|
||||||
|
- Function file tracked in `ai/functions/` directory
|
||||||
|
- Automatically available after `pnpm arty up -d ai_webui`
|
||||||
|
- No manual import required - infrastructure as code
|
||||||
|
|
||||||
|
See `ai/FLUX_SETUP.md` for detailed setup instructions and troubleshooting.
|
||||||
|
|
||||||
|
**ComfyUI Image Generation**:
|
||||||
|
ComfyUI provides a professional node-based interface for creating Flux image generation workflows:
|
||||||
|
|
||||||
|
**Architecture**:
|
||||||
|
```
|
||||||
|
User → Traefik (VPS) → Authelia SSO → ComfyUI Proxy (nginx) → Tailscale → ComfyUI (RunPod:8188) → Flux Model (GPU)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Access**:
|
||||||
|
1. Navigate to https://comfy.ai.pivoine.art
|
||||||
|
2. Authenticate via Authelia SSO
|
||||||
|
3. Create node-based workflows in ComfyUI interface
|
||||||
|
4. Use Flux.1 Schnell model from HuggingFace cache at `/workspace/ComfyUI/models/huggingface_cache`
|
||||||
|
|
||||||
|
**RunPod Setup** (via Ansible):
|
||||||
|
ComfyUI is installed on RunPod using the Ansible playbook at `/home/valknar/Projects/runpod/playbook.yml`:
|
||||||
|
- Clone ComfyUI from https://github.com/comfyanonymous/ComfyUI
|
||||||
|
- Install dependencies from `models/comfyui/requirements.txt`
|
||||||
|
- Create model directory structure (checkpoints, unet, vae, loras, clip, controlnet)
|
||||||
|
- Symlink Flux model from HuggingFace cache
|
||||||
|
- Start service via `models/comfyui/start.sh` on port 8188
|
||||||
|
|
||||||
|
**To deploy ComfyUI on RunPod**:
|
||||||
|
```bash
|
||||||
|
# Run Ansible playbook with comfyui tag
|
||||||
|
ssh -p 16186 root@213.173.110.150
|
||||||
|
cd /workspace/ai
|
||||||
|
ansible-playbook playbook.yml --tags comfyui --skip-tags always
|
||||||
|
|
||||||
|
# Start ComfyUI service
|
||||||
|
bash models/comfyui/start.sh &
|
||||||
|
```
|
||||||
|
|
||||||
|
**Proxy Configuration**:
|
||||||
|
The VPS runs an nginx proxy (`ai/comfyui-nginx.conf`) that:
|
||||||
|
- Listens on port 80 inside container
|
||||||
|
- Forwards to RunPod via Tailscale (100.121.199.88:8188)
|
||||||
|
- Supports WebSocket upgrades for real-time updates
|
||||||
|
- Handles large file uploads (100M limit)
|
||||||
|
- Uses extended timeouts for long-running generations (300s)
|
||||||
|
|
||||||
|
**Note**: ComfyUI runs directly on RunPod GPU server, not in a container. All data is stored on RunPod's `/workspace` volume.
|
||||||
|
|
||||||
**Integration Points**:
|
**Integration Points**:
|
||||||
- **n8n**: Workflow automation with AI tasks (scraping, RAG ingestion, webhooks)
|
- **n8n**: Workflow automation with AI tasks (scraping, RAG ingestion, webhooks)
|
||||||
- **Mattermost**: Can send AI-generated notifications via webhooks
|
- **Mattermost**: Can send AI-generated notifications via webhooks
|
||||||
- **Crawl4AI**: Internal API for advanced web scraping
|
- **Crawl4AI**: Internal API for advanced web scraping
|
||||||
- **Claude API**: Primary LLM provider via Anthropic
|
- **Claude API**: Primary LLM provider via Anthropic
|
||||||
|
- **Flux via RunPod**: Image generation through orchestrator (GPU server) or ComfyUI
|
||||||
|
|
||||||
**Future Enhancements**:
|
**Future Enhancements**:
|
||||||
- GPU server integration (IONOS A10 planned)
|
- GPU server integration (IONOS A10 planned)
|
||||||
@@ -659,7 +721,7 @@ Backrest backup system with restic backend:
|
|||||||
- Retention: 7 daily, 4 weekly, 3 monthly
|
- Retention: 7 daily, 4 weekly, 3 monthly
|
||||||
|
|
||||||
16. **ai-backup** (3 AM daily)
|
16. **ai-backup** (3 AM daily)
|
||||||
- Paths: `/volumes/ai_postgres_data`, `/volumes/ai_webui_data`, `/volumes/ai_crawl4ai_data`
|
- Paths: `/volumes/ai_postgres_data`, `/volumes/ai_webui_data`
|
||||||
- Retention: 7 daily, 4 weekly, 6 monthly, 2 yearly
|
- Retention: 7 daily, 4 weekly, 6 monthly, 2 yearly
|
||||||
|
|
||||||
17. **asciinema-backup** (11 AM daily)
|
17. **asciinema-backup** (11 AM daily)
|
||||||
@@ -670,8 +732,7 @@ Backrest backup system with restic backend:
|
|||||||
All Docker volumes are mounted read-only to `/volumes/` with prefixed names (e.g., `backup_core_postgres_data`) to avoid naming conflicts with other compose stacks.
|
All Docker volumes are mounted read-only to `/volumes/` with prefixed names (e.g., `backup_core_postgres_data`) to avoid naming conflicts with other compose stacks.
|
||||||
|
|
||||||
**Configuration Management**:
|
**Configuration Management**:
|
||||||
- `config.json` template in repository defines all backup plans
|
- `core/backrest/config.json` in repository defines all backup plans (bind-mounted to container)
|
||||||
- On first run, copy config into volume: `docker cp restic/config.json restic_app:/config/config.json`
|
|
||||||
- Config version must be `4` for Backrest 1.10.1 compatibility
|
- Config version must be `4` for Backrest 1.10.1 compatibility
|
||||||
- Backrest manages auth automatically (username: `valknar`, password set via web UI on first access)
|
- Backrest manages auth automatically (username: `valknar`, password set via web UI on first access)
|
||||||
|
|
||||||
@@ -709,7 +770,7 @@ Each service uses named volumes prefixed with project name:
|
|||||||
- `vault_data`: Vaultwarden password vault (SQLite database)
|
- `vault_data`: Vaultwarden password vault (SQLite database)
|
||||||
- `joplin_data`: Joplin note-taking data
|
- `joplin_data`: Joplin note-taking data
|
||||||
- `jelly_config`: Jellyfin media server configuration
|
- `jelly_config`: Jellyfin media server configuration
|
||||||
- `ai_postgres_data`, `ai_webui_data`, `ai_crawl4ai_data`: AI stack databases and application data
|
- `ai_postgres_data`, `ai_webui_data`: AI stack databases and application data
|
||||||
- `netdata_config`: Netdata monitoring configuration
|
- `netdata_config`: Netdata monitoring configuration
|
||||||
- `restic_data`, `restic_config`, `restic_cache`, `restic_tmp`: Backrest backup system
|
- `restic_data`, `restic_config`, `restic_cache`, `restic_tmp`: Backrest backup system
|
||||||
- `proxy_letsencrypt_data`: SSL certificates
|
- `proxy_letsencrypt_data`: SSL certificates
|
||||||
|
|||||||
@@ -406,11 +406,10 @@ THE FALCON (falcon_network)
|
|||||||
│ ├─ vaultwarden [vault.pivoine.art] → Password Manager
|
│ ├─ vaultwarden [vault.pivoine.art] → Password Manager
|
||||||
│ └─ tandoor [tandoor.pivoine.art] → Recipe Manager
|
│ └─ tandoor [tandoor.pivoine.art] → Recipe Manager
|
||||||
│
|
│
|
||||||
├─ 🤖 AI STACK (5 services)
|
├─ 🤖 AI STACK (4 services)
|
||||||
│ ├─ ai_postgres [Internal] → pgvector Database
|
│ ├─ ai_postgres [Internal] → pgvector Database
|
||||||
│ ├─ webui [ai.pivoine.art] → Open WebUI (Claude)
|
│ ├─ webui [ai.pivoine.art] → Open WebUI (Claude)
|
||||||
│ ├─ litellm [llm.ai.pivoine.art] → API Proxy
|
│ ├─ litellm [llm.ai.pivoine.art] → API Proxy
|
||||||
│ ├─ crawl4ai [Internal:11235] → Web Scraper
|
|
||||||
│ └─ facefusion [facefusion.ai.pivoine.art] → Face AI
|
│ └─ facefusion [facefusion.ai.pivoine.art] → Face AI
|
||||||
│
|
│
|
||||||
├─ 🛡️ NET STACK (4 services)
|
├─ 🛡️ NET STACK (4 services)
|
||||||
@@ -435,7 +434,7 @@ THE FALCON (falcon_network)
|
|||||||
├─ Core: postgres_data, redis_data, backrest_*
|
├─ Core: postgres_data, redis_data, backrest_*
|
||||||
├─ Sexy: directus_uploads, directus_bundle
|
├─ Sexy: directus_uploads, directus_bundle
|
||||||
├─ Util: pairdrop_*, joplin_data, linkwarden_*, mattermost_*, vaultwarden_data, tandoor_*
|
├─ Util: pairdrop_*, joplin_data, linkwarden_*, mattermost_*, vaultwarden_data, tandoor_*
|
||||||
├─ AI: ai_postgres_data, ai_webui_data, ai_crawl4ai_data, facefusion_*
|
├─ AI: ai_postgres_data, ai_webui_data, facefusion_*
|
||||||
├─ Net: letsencrypt_data, netdata_*
|
├─ Net: letsencrypt_data, netdata_*
|
||||||
├─ Media: jelly_config, jelly_cache, filestash_data
|
├─ Media: jelly_config, jelly_cache, filestash_data
|
||||||
└─ Dev: gitea_*, coolify_data, n8n_data, asciinema_data
|
└─ Dev: gitea_*, coolify_data, n8n_data, asciinema_data
|
||||||
|
|||||||
294
ai/compose.yaml
294
ai/compose.yaml
@@ -15,7 +15,7 @@ services:
|
|||||||
- ai_postgres_data:/var/lib/postgresql/data
|
- ai_postgres_data:/var/lib/postgresql/data
|
||||||
- ./postgres/init:/docker-entrypoint-initdb.d
|
- ./postgres/init:/docker-entrypoint-initdb.d
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD-SHELL', 'pg_isready -U ${AI_DB_USER}']
|
test: ["CMD-SHELL", "pg_isready -U ${AI_DB_USER}"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
@@ -38,6 +38,10 @@ services:
|
|||||||
OPENAI_API_BASE_URLS: http://litellm:4000
|
OPENAI_API_BASE_URLS: http://litellm:4000
|
||||||
OPENAI_API_KEYS: ${AI_LITELLM_API_KEY}
|
OPENAI_API_KEYS: ${AI_LITELLM_API_KEY}
|
||||||
|
|
||||||
|
# Disable Ollama (we only use LiteLLM)
|
||||||
|
ENABLE_OLLAMA_API: false
|
||||||
|
OLLAMA_BASE_URLS: ""
|
||||||
|
|
||||||
# WebUI configuration
|
# WebUI configuration
|
||||||
WEBUI_NAME: ${AI_WEBUI_NAME:-Pivoine AI}
|
WEBUI_NAME: ${AI_WEBUI_NAME:-Pivoine AI}
|
||||||
WEBUI_URL: https://${AI_TRAEFIK_HOST}
|
WEBUI_URL: https://${AI_TRAEFIK_HOST}
|
||||||
@@ -62,100 +66,87 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- ai_webui_data:/app/backend/data
|
- ai_webui_data:/app/backend/data
|
||||||
|
- ./functions:/app/backend/data/functions:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- ai_postgres
|
- ai_postgres
|
||||||
- litellm
|
- litellm
|
||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=${AI_TRAEFIK_ENABLED}'
|
- "traefik.enable=${AI_TRAEFIK_ENABLED}"
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.rule=Host(`${AI_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.rule=Host(`${AI_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.entrypoints=web'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web.entrypoints=web"
|
||||||
# HTTPS router
|
# HTTPS router
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${AI_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${AI_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true'
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file"
|
||||||
# Service
|
# Service
|
||||||
- 'traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=8080'
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=8080"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# LiteLLM - Proxy to convert Anthropic API to OpenAI-compatible format
|
# LiteLLM - Proxy to convert Anthropic API to OpenAI-compatible format
|
||||||
litellm:
|
litellm:
|
||||||
image: ghcr.io/berriai/litellm:main-latest
|
image: ghcr.io/berriai/litellm:main-latest
|
||||||
container_name: ${AI_COMPOSE_PROJECT_NAME}_litellm
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_litellm
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 100.100.100.100
|
||||||
|
- 8.8.8.8
|
||||||
environment:
|
environment:
|
||||||
TZ: ${TIMEZONE:-Europe/Berlin}
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY}
|
||||||
LITELLM_MASTER_KEY: ${AI_LITELLM_API_KEY}
|
LITELLM_MASTER_KEY: ${AI_LITELLM_API_KEY}
|
||||||
DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/litellm
|
DATABASE_URL: postgresql://${AI_DB_USER}:${AI_DB_PASSWORD}@ai_postgres:5432/litellm
|
||||||
LITELLM_DROP_PARAMS: 'true'
|
GPU_VLLM_LLAMA_URL: ${GPU_VLLM_LLAMA_URL}
|
||||||
NO_DOCS: 'true'
|
GPU_VLLM_BGE_URL: ${GPU_VLLM_BGE_URL}
|
||||||
NO_REDOC: 'true'
|
# LITELLM_DROP_PARAMS: 'true' # DISABLED: Was breaking streaming
|
||||||
|
NO_DOCS: "true"
|
||||||
|
NO_REDOC: "true"
|
||||||
|
# Performance optimizations
|
||||||
|
LITELLM_LOG: "DEBUG" # Enable detailed logging for debugging streaming issues
|
||||||
|
LITELLM_MODE: "PRODUCTION" # Production mode for better performance
|
||||||
volumes:
|
volumes:
|
||||||
- ./litellm-config.yaml:/app/litellm-config.yaml:ro
|
- ./litellm-config.yaml:/app/litellm-config.yaml:ro
|
||||||
command:
|
command:
|
||||||
[
|
[
|
||||||
'--config',
|
"--config",
|
||||||
'/app/litellm-config.yaml',
|
"/app/litellm-config.yaml",
|
||||||
'--host',
|
"--host",
|
||||||
'0.0.0.0',
|
"0.0.0.0",
|
||||||
'--port',
|
"--port",
|
||||||
'4000',
|
"4000",
|
||||||
'--detailed_debug',
|
|
||||||
'--drop_params'
|
|
||||||
]
|
]
|
||||||
depends_on:
|
depends_on:
|
||||||
- ai_postgres
|
- ai_postgres
|
||||||
networks:
|
|
||||||
- compose_network
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
disable: true
|
disable: true
|
||||||
labels:
|
|
||||||
- 'traefik.enable=${AI_TRAEFIK_ENABLED}'
|
|
||||||
# HTTP to HTTPS redirect
|
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure.redirectscheme.scheme=https'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.entrypoints=web'
|
|
||||||
# HTTPS router
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.tls.certresolver=resolver'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.entrypoints=web-secure'
|
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress.compress=true'
|
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress,security-headers@file'
|
|
||||||
# Service
|
|
||||||
- 'traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.loadbalancer.server.port=4000'
|
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
|
||||||
# Watchtower
|
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
|
||||||
|
|
||||||
# Crawl4AI - Web scraping for LLMs (internal API, no public access)
|
|
||||||
crawl4ai:
|
|
||||||
image: ${AI_CRAWL4AI_IMAGE:-unclecode/crawl4ai:latest}
|
|
||||||
container_name: ${AI_COMPOSE_PROJECT_NAME}_crawl4ai
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
TZ: ${TIMEZONE:-Europe/Berlin}
|
|
||||||
# API configuration
|
|
||||||
PORT: ${AI_CRAWL4AI_PORT:-11235}
|
|
||||||
volumes:
|
|
||||||
- ai_crawl4ai_data:/app/.crawl4ai
|
|
||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
# No Traefik exposure - internal only
|
- "traefik.enable=${AI_TRAEFIK_ENABLED}"
|
||||||
- 'traefik.enable=false'
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web.entrypoints=web"
|
||||||
|
# HTTPS router
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.rule=Host(`${AI_LITELLM_TRAEFIK_HOST}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress.compress=true"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure-compress,security-headers@file"
|
||||||
|
# Service
|
||||||
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-litellm-web-secure.loadbalancer.server.port=4000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Facefusion - AI face swapping and enhancement
|
# Facefusion - AI face swapping and enhancement
|
||||||
facefusion:
|
facefusion:
|
||||||
build:
|
build:
|
||||||
@@ -165,7 +156,7 @@ services:
|
|||||||
container_name: ${AI_COMPOSE_PROJECT_NAME}_facefusion
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_facefusion
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
tty: true
|
tty: true
|
||||||
command: ['python', '-u', 'facefusion.py', 'run']
|
command: ["python", "-u", "facefusion.py", "run"]
|
||||||
environment:
|
environment:
|
||||||
TZ: ${TIMEZONE:-Europe/Berlin}
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
GRADIO_SERVER_NAME: "0.0.0.0"
|
GRADIO_SERVER_NAME: "0.0.0.0"
|
||||||
@@ -175,32 +166,175 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=${AI_FACEFUSION_TRAEFIK_ENABLED}'
|
- "traefik.enable=${AI_FACEFUSION_TRAEFIK_ENABLED}"
|
||||||
# HTTP Basic Auth middleware
|
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-auth.basicauth.users=${AUTH_USERS}'
|
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.entrypoints=web'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web.entrypoints=web"
|
||||||
# HTTPS router with auth
|
# HTTPS router with Authelia
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.rule=Host(`${AI_FACEFUSION_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress.compress=true'
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress.compress=true"
|
||||||
- 'traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-auth,${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress,security-headers@file'
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure-compress,net-authelia,security-headers@file"
|
||||||
# Service
|
# Service
|
||||||
- 'traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.loadbalancer.server.port=7860'
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-facefusion-web-secure.loadbalancer.server.port=7860"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower - disabled for custom local image
|
# Watchtower - disabled for custom local image
|
||||||
- 'com.centurylinklabs.watchtower.enable=false'
|
- "com.centurylinklabs.watchtower.enable=false"
|
||||||
|
|
||||||
|
# ComfyUI - Node-based UI for Flux image generation (proxies to RunPod GPU)
|
||||||
|
comfyui:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_comfyui
|
||||||
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 100.100.100.100
|
||||||
|
- 8.8.8.8
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST:-runpod-ai-orchestrator}
|
||||||
|
GPU_SERVICE_PORT: ${COMFYUI_BACKEND_PORT:-8188}
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
|
||||||
|
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=${AI_COMFYUI_TRAEFIK_ENABLED:-true}"
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web.entrypoints=web"
|
||||||
|
# HTTPS router with Authelia SSO
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.rule=Host(`${AI_COMFYUI_TRAEFIK_HOST:-comfy.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress.compress=true"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure-compress,net-authelia,security-headers@file"
|
||||||
|
# Service
|
||||||
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-comfyui-web-secure.loadbalancer.server.port=80"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
|
audiocraft:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_audiocraft
|
||||||
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 100.100.100.100
|
||||||
|
- 8.8.8.8
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST:-runpod-ai-orchestrator}
|
||||||
|
GPU_SERVICE_PORT: ${AUDIOCRAFT_BACKEND_PORT:-7860}
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
|
||||||
|
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=${AI_AUDIOCRAFT_TRAEFIK_ENABLED:-true}"
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web.entrypoints=web"
|
||||||
|
# HTTPS router with Authelia SSO
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.rule=Host(`${AI_AUDIOCRAFT_TRAEFIK_HOST:-audiocraft.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress.compress=true"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure-compress,net-authelia,security-headers@file"
|
||||||
|
# Service
|
||||||
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-audiocraft-web-secure.loadbalancer.server.port=80"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
|
upscale:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_upscale
|
||||||
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 100.100.100.100
|
||||||
|
- 8.8.8.8
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
GPU_SERVICE_HOST: ${GPU_TAILSCALE_HOST:-runpod-ai-orchestrator}
|
||||||
|
GPU_SERVICE_PORT: ${UPSCALE_BACKEND_PORT:-8080}
|
||||||
|
volumes:
|
||||||
|
- ./nginx.conf.template:/etc/nginx/nginx.conf.template:ro
|
||||||
|
command: /bin/sh -c "envsubst '$${GPU_SERVICE_HOST},$${GPU_SERVICE_PORT}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf && exec nginx -g 'daemon off;'"
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=${AI_UPSCALE_TRAEFIK_ENABLED:-true}"
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-upscale-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-upscale-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.rule=Host(`${AI_UPSCALE_TRAEFIK_HOST:-upscale.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web.entrypoints=web"
|
||||||
|
# HTTPS router with Authelia SSO
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.rule=Host(`${AI_UPSCALE_TRAEFIK_HOST:-upscale.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure-compress.compress=true"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure-compress,net-authelia,security-headers@file"
|
||||||
|
# Service
|
||||||
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-upscale-web-secure.loadbalancer.server.port=80"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
|
# Supervisor UI - Modern web interface for RunPod process management
|
||||||
|
supervisor:
|
||||||
|
image: dev.pivoine.art/valknar/supervisor-ui:latest
|
||||||
|
container_name: ${AI_COMPOSE_PROJECT_NAME}_supervisor_ui
|
||||||
|
restart: unless-stopped
|
||||||
|
dns:
|
||||||
|
- 100.100.100.100
|
||||||
|
- 8.8.8.8
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
NODE_ENV: production
|
||||||
|
# Connect to RunPod Supervisor via Tailscale (host Tailscale provides DNS)
|
||||||
|
SUPERVISOR_HOST: ${GPU_TAILSCALE_HOST:-runpod-ai-orchestrator}
|
||||||
|
SUPERVISOR_PORT: ${SUPERVISOR_BACKEND_PORT:-9001}
|
||||||
|
# No auth needed - Supervisor has auth disabled (protected by Authelia)
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=${AI_SUPERVISOR_TRAEFIK_ENABLED:-true}"
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-redirect-web-secure"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web.entrypoints=web"
|
||||||
|
# HTTPS router with Authelia SSO
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.rule=Host(`${AI_SUPERVISOR_TRAEFIK_HOST:-supervisor.ai.pivoine.art}`)"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.entrypoints=web-secure"
|
||||||
|
- "traefik.http.middlewares.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress.compress=true"
|
||||||
|
- "traefik.http.routers.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.middlewares=${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure-compress,net-authelia,security-headers@file"
|
||||||
|
# Service (port 3000 for Next.js app)
|
||||||
|
- "traefik.http.services.${AI_COMPOSE_PROJECT_NAME}-supervisor-web-secure.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
ai_postgres_data:
|
ai_postgres_data:
|
||||||
name: ${AI_COMPOSE_PROJECT_NAME}_postgres_data
|
name: ${AI_COMPOSE_PROJECT_NAME}_postgres_data
|
||||||
ai_webui_data:
|
ai_webui_data:
|
||||||
name: ${AI_COMPOSE_PROJECT_NAME}_webui_data
|
name: ${AI_COMPOSE_PROJECT_NAME}_webui_data
|
||||||
ai_crawl4ai_data:
|
|
||||||
name: ${AI_COMPOSE_PROJECT_NAME}_crawl4ai_data
|
|
||||||
ai_facefusion_data:
|
ai_facefusion_data:
|
||||||
name: ${AI_COMPOSE_PROJECT_NAME}_facefusion_data
|
name: ${AI_COMPOSE_PROJECT_NAME}_facefusion_data
|
||||||
|
|
||||||
|
networks:
|
||||||
|
compose_network:
|
||||||
|
name: ${NETWORK_NAME}
|
||||||
|
external: true
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ model_list:
|
|||||||
litellm_params:
|
litellm_params:
|
||||||
model: anthropic/claude-sonnet-4-5-20250929
|
model: anthropic/claude-sonnet-4-5-20250929
|
||||||
api_key: os.environ/ANTHROPIC_API_KEY
|
api_key: os.environ/ANTHROPIC_API_KEY
|
||||||
drop_params: true
|
|
||||||
additional_drop_params: ["prompt_cache_key"]
|
|
||||||
|
|
||||||
- model_name: claude-3-5-sonnet
|
- model_name: claude-3-5-sonnet
|
||||||
litellm_params:
|
litellm_params:
|
||||||
@@ -26,24 +24,63 @@ model_list:
|
|||||||
model: anthropic/claude-3-haiku-20240307
|
model: anthropic/claude-3-haiku-20240307
|
||||||
api_key: os.environ/ANTHROPIC_API_KEY
|
api_key: os.environ/ANTHROPIC_API_KEY
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# SELF-HOSTED MODELS - DIRECT vLLM SERVERS (GPU Server via Tailscale VPN)
|
||||||
|
# ===========================================================================
|
||||||
|
# Direct connections to dedicated vLLM servers (no orchestrator)
|
||||||
|
|
||||||
|
# Text Generation - Llama 3.1 8B (Port 8001)
|
||||||
|
- model_name: llama-3.1-8b
|
||||||
|
litellm_params:
|
||||||
|
model: hosted_vllm/meta-llama/Llama-3.1-8B-Instruct # hosted_vllm/openai/ prefix for proper streaming
|
||||||
|
api_base: os.environ/GPU_VLLM_LLAMA_URL # Direct to vLLM Llama server
|
||||||
|
api_key: "EMPTY" # vLLM doesn't validate API keys
|
||||||
|
rpm: 1000
|
||||||
|
tpm: 100000
|
||||||
|
timeout: 600 # 10 minutes for generation
|
||||||
|
stream_timeout: 600
|
||||||
|
supports_system_messages: true # Llama supports system messages
|
||||||
|
stream: true # Enable streaming by default
|
||||||
|
|
||||||
|
# Embeddings - BGE Large (Port 8002)
|
||||||
|
- model_name: bge-large-en
|
||||||
|
litellm_params:
|
||||||
|
model: openai/BAAI/bge-large-en-v1.5
|
||||||
|
api_base: os.environ/GPU_VLLM_BGE_URL
|
||||||
|
api_key: "EMPTY"
|
||||||
|
rpm: 1000
|
||||||
|
tpm: 500000
|
||||||
|
|
||||||
litellm_settings:
|
litellm_settings:
|
||||||
drop_params: true
|
drop_params: false # DISABLED: Was breaking streaming
|
||||||
set_verbose: true
|
set_verbose: true # Enable verbose logging for debugging streaming issues
|
||||||
# Disable prompt caching features
|
# Enable caching now that streaming is fixed
|
||||||
cache: false
|
cache: true
|
||||||
|
cache_params:
|
||||||
|
type: redis
|
||||||
|
host: core_redis
|
||||||
|
port: 6379
|
||||||
|
ttl: 3600 # Cache for 1 hour
|
||||||
# Force strip specific parameters globally
|
# Force strip specific parameters globally
|
||||||
allowed_fails: 0
|
allowed_fails: 0
|
||||||
# Modify params before sending to provider
|
# Modify params before sending to provider
|
||||||
modify_params: true
|
modify_params: false # DISABLED: Was breaking streaming
|
||||||
# Drop prompt_cache_key globally for all models
|
# Enable success and failure logging but minimize overhead
|
||||||
additional_drop_params: ["prompt_cache_key"]
|
success_callback: [] # Disable all success callbacks to reduce DB writes
|
||||||
|
failure_callback: [] # Disable all failure callbacks
|
||||||
|
|
||||||
router_settings:
|
router_settings:
|
||||||
allowed_fails: 0
|
allowed_fails: 0
|
||||||
|
|
||||||
# Drop unsupported parameters
|
# Drop unsupported parameters
|
||||||
default_litellm_params:
|
default_litellm_params:
|
||||||
drop_params: true
|
drop_params: false # DISABLED: Was breaking streaming
|
||||||
|
|
||||||
general_settings:
|
general_settings:
|
||||||
disable_responses_id_security: true
|
disable_responses_id_security: true
|
||||||
|
# Disable spend tracking to reduce database overhead
|
||||||
|
disable_spend_logs: true
|
||||||
|
# Disable tag tracking
|
||||||
|
disable_tag_tracking: true
|
||||||
|
# Disable daily spend updates
|
||||||
|
disable_daily_spend_logs: true
|
||||||
|
|||||||
60
ai/nginx.conf.template
Normal file
60
ai/nginx.conf.template
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
# MIME types
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# DNS resolver for Tailscale MagicDNS
|
||||||
|
resolver 100.100.100.100 8.8.8.8 valid=30s;
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
|
# Proxy settings
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# WebSocket support
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
# Timeouts for long-running audio/image generation
|
||||||
|
proxy_connect_timeout 600;
|
||||||
|
proxy_send_timeout 600;
|
||||||
|
proxy_read_timeout 600;
|
||||||
|
send_timeout 600;
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
# Increase client body size for image uploads
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
# Proxy to service on RunPod via Tailscale
|
||||||
|
# Use variable to force runtime DNS resolution (not startup)
|
||||||
|
set $backend http://${GPU_SERVICE_HOST}:${GPU_SERVICE_PORT};
|
||||||
|
proxy_pass $backend;
|
||||||
|
|
||||||
|
# WebSocket upgrade
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
|
||||||
|
# Proxy headers
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Disable buffering for real-time updates
|
||||||
|
proxy_buffering off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
arty.yml
59
arty.yml
@@ -78,7 +78,7 @@ envs:
|
|||||||
UTIL_JOPLIN_DB_NAME: joplin
|
UTIL_JOPLIN_DB_NAME: joplin
|
||||||
# PairDrop
|
# PairDrop
|
||||||
UTIL_DROP_TRAEFIK_HOST: drop.pivoine.art
|
UTIL_DROP_TRAEFIK_HOST: drop.pivoine.art
|
||||||
# Media Stack (Jellyfin, Filestash)
|
# Media Stack (Jellyfin, Filestash, Pinchflat)
|
||||||
MEDIA_TRAEFIK_ENABLED: true
|
MEDIA_TRAEFIK_ENABLED: true
|
||||||
MEDIA_COMPOSE_PROJECT_NAME: media
|
MEDIA_COMPOSE_PROJECT_NAME: media
|
||||||
MEDIA_JELLYFIN_IMAGE: jellyfin/jellyfin:latest
|
MEDIA_JELLYFIN_IMAGE: jellyfin/jellyfin:latest
|
||||||
@@ -86,6 +86,8 @@ envs:
|
|||||||
MEDIA_FILESTASH_IMAGE: machines/filestash:latest
|
MEDIA_FILESTASH_IMAGE: machines/filestash:latest
|
||||||
MEDIA_FILESTASH_TRAEFIK_HOST: filestash.media.pivoine.art
|
MEDIA_FILESTASH_TRAEFIK_HOST: filestash.media.pivoine.art
|
||||||
MEDIA_FILESTASH_CANARY: true
|
MEDIA_FILESTASH_CANARY: true
|
||||||
|
MEDIA_PINCHFLAT_IMAGE: ghcr.io/kieraneglin/pinchflat:latest
|
||||||
|
MEDIA_PINCHFLAT_TRAEFIK_HOST: pinchflat.media.pivoine.art
|
||||||
# Dev (Gitea + Coolify)
|
# Dev (Gitea + Coolify)
|
||||||
DEV_TRAEFIK_ENABLED: true
|
DEV_TRAEFIK_ENABLED: true
|
||||||
DEV_COMPOSE_PROJECT_NAME: dev
|
DEV_COMPOSE_PROJECT_NAME: dev
|
||||||
@@ -133,7 +135,6 @@ envs:
|
|||||||
AI_COMPOSE_PROJECT_NAME: ai
|
AI_COMPOSE_PROJECT_NAME: ai
|
||||||
AI_POSTGRES_IMAGE: pgvector/pgvector:pg16
|
AI_POSTGRES_IMAGE: pgvector/pgvector:pg16
|
||||||
AI_WEBUI_IMAGE: ghcr.io/open-webui/open-webui:main
|
AI_WEBUI_IMAGE: ghcr.io/open-webui/open-webui:main
|
||||||
AI_CRAWL4AI_IMAGE: unclecode/crawl4ai:latest
|
|
||||||
AI_FACEFUSION_IMAGE: facefusion/facefusion:3.5.0-cpu
|
AI_FACEFUSION_IMAGE: facefusion/facefusion:3.5.0-cpu
|
||||||
AI_FACEFUSION_TRAEFIK_ENABLED: true
|
AI_FACEFUSION_TRAEFIK_ENABLED: true
|
||||||
AI_FACEFUSION_TRAEFIK_HOST: facefusion.ai.pivoine.art
|
AI_FACEFUSION_TRAEFIK_HOST: facefusion.ai.pivoine.art
|
||||||
@@ -261,3 +262,57 @@ scripts:
|
|||||||
docker restart sexy_api &&
|
docker restart sexy_api &&
|
||||||
echo "✓ Directus API restarted"
|
echo "✓ Directus API restarted"
|
||||||
net/create: docker network create "$NETWORK_NAME"
|
net/create: docker network create "$NETWORK_NAME"
|
||||||
|
# Setup iptables NAT for Docker containers to reach Tailscale network
|
||||||
|
# Requires Tailscale installed on host: curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
|
tailscale/setup: |
|
||||||
|
echo "Setting up iptables for Docker-to-Tailscale routing..."
|
||||||
|
|
||||||
|
# Enable IP forwarding
|
||||||
|
sudo sysctl -w net.ipv4.ip_forward=1
|
||||||
|
grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf || echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
|
||||||
|
|
||||||
|
# Get Docker network CIDR
|
||||||
|
DOCKER_CIDR=$(docker network inspect ${NETWORK_NAME} --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || echo "172.18.0.0/16")
|
||||||
|
echo "Docker network CIDR: $DOCKER_CIDR"
|
||||||
|
|
||||||
|
# Add NAT rule (check if already exists)
|
||||||
|
if ! sudo iptables -t nat -C POSTROUTING -s "$DOCKER_CIDR" -o tailscale0 -j MASQUERADE 2>/dev/null; then
|
||||||
|
sudo iptables -t nat -A POSTROUTING -s "$DOCKER_CIDR" -o tailscale0 -j MASQUERADE
|
||||||
|
echo "✓ iptables NAT rule added"
|
||||||
|
else
|
||||||
|
echo "✓ iptables NAT rule already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Persist rules
|
||||||
|
sudo netfilter-persistent save 2>/dev/null || echo "Install iptables-persistent to persist rules: sudo apt install iptables-persistent"
|
||||||
|
|
||||||
|
echo "✓ Tailscale routing configured"
|
||||||
|
|
||||||
|
# Install and configure Tailscale on host with persistent state
|
||||||
|
tailscale/install: |
|
||||||
|
echo "Installing Tailscale..."
|
||||||
|
|
||||||
|
# Install Tailscale if not present
|
||||||
|
if ! command -v tailscale &> /dev/null; then
|
||||||
|
curl -fsSL https://tailscale.com/install.sh | sh
|
||||||
|
else
|
||||||
|
echo "✓ Tailscale already installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create state directory for persistence
|
||||||
|
TAILSCALE_STATE="/var/lib/tailscale"
|
||||||
|
sudo mkdir -p "$TAILSCALE_STATE"
|
||||||
|
|
||||||
|
# Start and enable tailscaled service
|
||||||
|
sudo systemctl enable --now tailscaled
|
||||||
|
|
||||||
|
# Connect to Tailscale network
|
||||||
|
echo "Connecting to Tailscale..."
|
||||||
|
sudo tailscale up --authkey="$TAILSCALE_AUTHKEY" --hostname=vps
|
||||||
|
|
||||||
|
# Show status
|
||||||
|
echo ""
|
||||||
|
tailscale status
|
||||||
|
echo ""
|
||||||
|
echo "✓ Tailscale installed and connected"
|
||||||
|
echo " Run 'arty tailscale/setup' to configure iptables routing for Docker"
|
||||||
|
|||||||
368
core/backrest/config.json
Normal file
368
core/backrest/config.json
Normal file
@@ -0,0 +1,368 @@
|
|||||||
|
{
|
||||||
|
"modno": 1,
|
||||||
|
"version": 4,
|
||||||
|
"instance": "falcon",
|
||||||
|
"repos": [
|
||||||
|
{
|
||||||
|
"id": "hidrive-backup",
|
||||||
|
"uri": "/repos",
|
||||||
|
"guid": "df03886ea215b0a3ff9730190d906d7034032bf0f1906ed4ad00f2c4f1748215",
|
||||||
|
"password": "falcon-backup-2025",
|
||||||
|
"prunePolicy": {
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 2 * * 0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"checkPolicy": {
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 3 * * 0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoUnlock": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"plans": [
|
||||||
|
{
|
||||||
|
"id": "ai-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/ai_postgres_data",
|
||||||
|
"/volumes/ai_webui_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 3 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "asciinema-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/asciinema_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 11 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "coolify-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/dev_coolify_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 0 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "directus-bundle-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/directus_bundle"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 4 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "directus-uploads-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/directus_uploads"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 4 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "filestash-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/filestash_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 7 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gitea-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/dev_gitea_config",
|
||||||
|
"/volumes/dev_gitea_data",
|
||||||
|
"/volumes/dev_gitea_runner_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 11 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jellyfin-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/jelly_config"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 9 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "joplin-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/joplin_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 2 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "letsencrypt-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/letsencrypt_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 8 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 12,
|
||||||
|
"yearly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "linkwarden-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/linkwarden_data",
|
||||||
|
"/volumes/linkwarden_meili_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 7 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mattermost-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/mattermost_config",
|
||||||
|
"/volumes/mattermost_data",
|
||||||
|
"/volumes/mattermost_plugins"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 5 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "n8n-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/n8n_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 6 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "netdata-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/netdata_config"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 10 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "postgres-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/core_postgres_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 2 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6,
|
||||||
|
"yearly": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "redis-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/core_redis_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 3 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "scrapy-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/scrapy_code",
|
||||||
|
"/volumes/scrapyd_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 6 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tandoor-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/tandoor_mediafiles",
|
||||||
|
"/volumes/tandoor_staticfiles"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 5 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vaultwarden-backup",
|
||||||
|
"repo": "hidrive-backup",
|
||||||
|
"paths": [
|
||||||
|
"/volumes/vaultwarden_data"
|
||||||
|
],
|
||||||
|
"schedule": {
|
||||||
|
"cron": "0 8 * * *"
|
||||||
|
},
|
||||||
|
"retention": {
|
||||||
|
"policyTimeBucketed": {
|
||||||
|
"daily": 7,
|
||||||
|
"weekly": 4,
|
||||||
|
"monthly": 12,
|
||||||
|
"yearly": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
# Backrest application data
|
# Backrest application data
|
||||||
- backrest_data:/data
|
- backrest_data:/data
|
||||||
- backrest_config:/config
|
- ./backrest/config.json:/config/config.json
|
||||||
- backrest_cache:/cache
|
- backrest_cache:/cache
|
||||||
- backrest_tmp:/tmp
|
- backrest_tmp:/tmp
|
||||||
|
|
||||||
@@ -84,7 +84,6 @@ services:
|
|||||||
- backup_netdata_config:/volumes/netdata_config:ro
|
- backup_netdata_config:/volumes/netdata_config:ro
|
||||||
- backup_ai_postgres_data:/volumes/ai_postgres_data:ro
|
- backup_ai_postgres_data:/volumes/ai_postgres_data:ro
|
||||||
- backup_ai_webui_data:/volumes/ai_webui_data:ro
|
- backup_ai_webui_data:/volumes/ai_webui_data:ro
|
||||||
- backup_ai_crawl4ai_data:/volumes/ai_crawl4ai_data:ro
|
|
||||||
- backup_asciinema_data:/volumes/asciinema_data:ro
|
- backup_asciinema_data:/volumes/asciinema_data:ro
|
||||||
- backup_dev_gitea_data:/volumes/dev_gitea_data:ro
|
- backup_dev_gitea_data:/volumes/dev_gitea_data:ro
|
||||||
- backup_dev_gitea_config:/volumes/dev_gitea_config:ro
|
- backup_dev_gitea_config:/volumes/dev_gitea_config:ro
|
||||||
@@ -124,8 +123,6 @@ volumes:
|
|||||||
name: ${CORE_COMPOSE_PROJECT_NAME}_redis_data
|
name: ${CORE_COMPOSE_PROJECT_NAME}_redis_data
|
||||||
backrest_data:
|
backrest_data:
|
||||||
name: ${CORE_COMPOSE_PROJECT_NAME}_backrest_data
|
name: ${CORE_COMPOSE_PROJECT_NAME}_backrest_data
|
||||||
backrest_config:
|
|
||||||
name: ${CORE_COMPOSE_PROJECT_NAME}_backrest_config
|
|
||||||
backrest_cache:
|
backrest_cache:
|
||||||
name: ${CORE_COMPOSE_PROJECT_NAME}_backrest_cache
|
name: ${CORE_COMPOSE_PROJECT_NAME}_backrest_cache
|
||||||
backrest_tmp:
|
backrest_tmp:
|
||||||
@@ -192,9 +189,6 @@ volumes:
|
|||||||
backup_ai_webui_data:
|
backup_ai_webui_data:
|
||||||
name: ai_webui_data
|
name: ai_webui_data
|
||||||
external: true
|
external: true
|
||||||
backup_ai_crawl4ai_data:
|
|
||||||
name: ai_crawl4ai_data
|
|
||||||
external: true
|
|
||||||
backup_asciinema_data:
|
backup_asciinema_data:
|
||||||
name: dev_asciinema_data
|
name: dev_asciinema_data
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ services:
|
|||||||
GITEA__mailer__FROM: ${EMAIL_FROM}
|
GITEA__mailer__FROM: ${EMAIL_FROM}
|
||||||
GITEA__service__DISABLE_REGISTRATION: false
|
GITEA__service__DISABLE_REGISTRATION: false
|
||||||
GITEA__service__REQUIRE_SIGNIN_VIEW: false
|
GITEA__service__REQUIRE_SIGNIN_VIEW: false
|
||||||
|
GITEA__service__ENABLE_NOTIFY_MAIL: true
|
||||||
|
GITEA__service__DEFAULT_EMAIL_NOTIFICATIONS: enabled
|
||||||
GITEA__packages__ENABLED: true
|
GITEA__packages__ENABLED: true
|
||||||
GITEA__actions__ENABLED: true
|
GITEA__actions__ENABLED: true
|
||||||
GITEA__ui__THEMES: gitea-auto,gitea-light,gitea-dark,arc-green,edge-auto,edge-dark,edge-light,everforest-auto,everforest-dark,everforest-light,gruvbox-auto,gruvbox-dark,gruvbox-light,gruvbox-material-auto,gruvbox-material-dark,gruvbox-material-light,nord,palenight,soft-era,sonokai,sonokai-andromeda,sonokai-atlantis,sonokai-espresso,sonokai-maia,sonokai-shusia
|
GITEA__ui__THEMES: gitea-auto,gitea-light,gitea-dark,arc-green,edge-auto,edge-dark,edge-light,everforest-auto,everforest-dark,everforest-light,gruvbox-auto,gruvbox-dark,gruvbox-light,gruvbox-material-auto,gruvbox-material-dark,gruvbox-material-light,nord,palenight,soft-era,sonokai,sonokai-andromeda,sonokai-atlantis,sonokai-espresso,sonokai-maia,sonokai-shusia
|
||||||
@@ -86,6 +88,9 @@ services:
|
|||||||
DOCKER_HOST: unix:///var/run/docker.sock
|
DOCKER_HOST: unix:///var/run/docker.sock
|
||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
|
labels:
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Coolify - Self-hosted deployment platform
|
# Coolify - Self-hosted deployment platform
|
||||||
coolify:
|
coolify:
|
||||||
@@ -93,8 +98,8 @@ services:
|
|||||||
container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify
|
container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
coolify_soketi:
|
coolify_realtime:
|
||||||
condition: service_started
|
condition: service_healthy
|
||||||
volumes:
|
volumes:
|
||||||
- coolify_data:/data/coolify
|
- coolify_data:/data/coolify
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
@@ -117,7 +122,7 @@ services:
|
|||||||
- DB_PASSWORD=${DB_PASSWORD}
|
- DB_PASSWORD=${DB_PASSWORD}
|
||||||
- REDIS_HOST=${CORE_REDIS_HOST}
|
- REDIS_HOST=${CORE_REDIS_HOST}
|
||||||
- REDIS_PORT=${CORE_REDIS_PORT}
|
- REDIS_PORT=${CORE_REDIS_PORT}
|
||||||
- PUSHER_HOST=coolify-realtime.${DEV_COOLIFY_TRAEFIK_HOST}
|
- PUSHER_HOST=realtime.${DEV_COOLIFY_TRAEFIK_HOST}
|
||||||
- PUSHER_PORT=443
|
- PUSHER_PORT=443
|
||||||
- PUSHER_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID}
|
- PUSHER_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID}
|
||||||
- PUSHER_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY}
|
- PUSHER_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY}
|
||||||
@@ -128,50 +133,68 @@ services:
|
|||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=${DEV_TRAEFIK_ENABLED}"
|
- "traefik.enable=${DEV_TRAEFIK_ENABLED}"
|
||||||
# HTTP to HTTPS redirect
|
# Main web interface - HTTP to HTTPS redirect
|
||||||
- "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure.redirectscheme.scheme=https"
|
- "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-redirect-web-secure"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.entrypoints=web"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.entrypoints=web"
|
||||||
# HTTPS router
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web.service=${DEV_COMPOSE_PROJECT_NAME}-coolify"
|
||||||
|
# Main web interface - HTTPS router
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.tls.certresolver=resolver"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.tls.certresolver=resolver"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.entrypoints=web-secure"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.entrypoints=web-secure"
|
||||||
- "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress.compress=true"
|
- "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress.compress=true"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress,security-headers@file"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure-compress,security-headers@file"
|
||||||
# Service
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-coolify"
|
||||||
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.loadbalancer.server.port=8080"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-coolify-web-secure.priority=1"
|
||||||
|
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-coolify.loadbalancer.server.port=8080"
|
||||||
|
# Network
|
||||||
- "traefik.docker.network=${NETWORK_NAME}"
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Coolify Soketi (WebSocket server)
|
# Coolify Realtime (WebSocket server for realtime AND terminal)
|
||||||
coolify_soketi:
|
coolify_realtime:
|
||||||
image: quay.io/soketi/soketi:1.0-16-alpine
|
image: ${DEV_COOLIFY_REALTIME_IMAGE:-ghcr.io/coollabsio/coolify-realtime:1.0.10}
|
||||||
container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_soketi
|
container_name: ${DEV_COMPOSE_PROJECT_NAME}_coolify_realtime
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- /data/coolify/ssh:/var/www/html/storage/app/ssh
|
||||||
environment:
|
environment:
|
||||||
|
- APP_NAME=Coolify
|
||||||
|
- SOKETI_DEBUG=${SOKETI_DEBUG:-false}
|
||||||
- SOKETI_DEFAULT_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID}
|
- SOKETI_DEFAULT_APP_ID=${DEV_COOLIFY_PUSHER_APP_ID}
|
||||||
- SOKETI_DEFAULT_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY}
|
- SOKETI_DEFAULT_APP_KEY=${DEV_COOLIFY_PUSHER_APP_KEY}
|
||||||
- SOKETI_DEFAULT_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET}
|
- SOKETI_DEFAULT_APP_SECRET=${DEV_COOLIFY_PUSHER_APP_SECRET}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:6001/ready"]
|
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:6001/ready && wget -qO- http://127.0.0.1:6002/ready"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 2s
|
||||||
retries: 10
|
retries: 10
|
||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=${DEV_TRAEFIK_ENABLED}"
|
- "traefik.enable=${DEV_TRAEFIK_ENABLED}"
|
||||||
# HTTP router
|
# Realtime (port 6001) - HTTP router
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web.rule=Host(`coolify-realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web.rule=Host(`realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web.entrypoints=web"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web.entrypoints=web"
|
||||||
# HTTPS router
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web.service=${DEV_COMPOSE_PROJECT_NAME}-realtime"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.rule=Host(`coolify-realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
# Realtime (port 6001) - HTTPS router
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.tls.certresolver=resolver"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web-secure.rule=Host(`realtime.${DEV_COOLIFY_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.entrypoints=web-secure"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web-secure.tls.certresolver=resolver"
|
||||||
# Service
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web-secure.entrypoints=web-secure"
|
||||||
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-soketi-web-secure.loadbalancer.server.port=6001"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-realtime-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-realtime"
|
||||||
|
# Realtime service
|
||||||
|
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-realtime.loadbalancer.server.port=6001"
|
||||||
|
# Terminal WebSocket (port 6002) - /terminal/ws path on main domain (PRIORITY 100)
|
||||||
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal-ws.rule=Host(`${DEV_COOLIFY_TRAEFIK_HOST}`) && PathPrefix(`/terminal/ws`)"
|
||||||
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal-ws.tls.certresolver=resolver"
|
||||||
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal-ws.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal-ws.service=${DEV_COMPOSE_PROJECT_NAME}-terminal"
|
||||||
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-terminal-ws.priority=100"
|
||||||
|
# Terminal service
|
||||||
|
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-terminal.loadbalancer.server.port=6002"
|
||||||
|
# Network
|
||||||
- "traefik.docker.network=${NETWORK_NAME}"
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
@@ -269,12 +292,11 @@ services:
|
|||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.entrypoints=web"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.entrypoints=web"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin"
|
||||||
# Admin interface - HTTPS router with Basic Auth
|
# Admin interface - HTTPS router with Authelia
|
||||||
- "traefik.http.middlewares.${DEV_COMPOSE_PROJECT_NAME}-asciinema-auth.basicauth.users=${AUTH_USERS}"
|
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.rule=Host(`admin.${DEV_ASCIINEMA_TRAEFIK_HOST}`)"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.tls.certresolver=resolver"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.tls.certresolver=resolver"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.entrypoints=web-secure"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.entrypoints=web-secure"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-auth,${DEV_COMPOSE_PROJECT_NAME}-asciinema-compress,security-headers@file"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.middlewares=${DEV_COMPOSE_PROJECT_NAME}-asciinema-compress,net-authelia,security-headers@file"
|
||||||
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin"
|
- "traefik.http.routers.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin-web-secure.service=${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin"
|
||||||
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin.loadbalancer.server.port=4002"
|
- "traefik.http.services.${DEV_COMPOSE_PROJECT_NAME}-asciinema-admin.loadbalancer.server.port=4002"
|
||||||
# Network
|
# Network
|
||||||
|
|||||||
@@ -63,6 +63,38 @@ services:
|
|||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||||
|
|
||||||
|
# Pinchflat - YouTube download manager
|
||||||
|
pinchflat:
|
||||||
|
image: ${MEDIA_PINCHFLAT_IMAGE:-ghcr.io/kieraneglin/pinchflat:latest}
|
||||||
|
container_name: ${MEDIA_COMPOSE_PROJECT_NAME}_pinchflat
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- pinchflat_config:/config
|
||||||
|
- /mnt/hidrive/users/valknar/Downloads/pinchflat:/downloads
|
||||||
|
environment:
|
||||||
|
TZ: ${TIMEZONE:-Europe/Berlin}
|
||||||
|
JOURNAL_MODE: delete
|
||||||
|
networks:
|
||||||
|
- compose_network
|
||||||
|
labels:
|
||||||
|
- 'traefik.enable=${MEDIA_TRAEFIK_ENABLED}'
|
||||||
|
# HTTP to HTTPS redirect
|
||||||
|
- 'traefik.http.middlewares.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-redirect-web-secure.redirectscheme.scheme=https'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web.middlewares=${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-redirect-web-secure'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web.rule=Host(`${MEDIA_PINCHFLAT_TRAEFIK_HOST}`)'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web.entrypoints=web'
|
||||||
|
# HTTPS router with Authelia SSO protection
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure.rule=Host(`${MEDIA_PINCHFLAT_TRAEFIK_HOST}`)'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure.tls.certresolver=resolver'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure.entrypoints=web-secure'
|
||||||
|
- 'traefik.http.middlewares.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure-compress.compress=true'
|
||||||
|
- 'traefik.http.routers.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure.middlewares=${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure-compress,net-authelia,security-headers@file'
|
||||||
|
# Service
|
||||||
|
- 'traefik.http.services.${MEDIA_COMPOSE_PROJECT_NAME}-pinchflat-web-secure.loadbalancer.server.port=8945'
|
||||||
|
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||||
|
# Watchtower
|
||||||
|
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
jellyfin_config:
|
jellyfin_config:
|
||||||
name: ${MEDIA_COMPOSE_PROJECT_NAME}_jellyfin_config
|
name: ${MEDIA_COMPOSE_PROJECT_NAME}_jellyfin_config
|
||||||
@@ -70,6 +102,8 @@ volumes:
|
|||||||
name: ${MEDIA_COMPOSE_PROJECT_NAME}_jellyfin_cache
|
name: ${MEDIA_COMPOSE_PROJECT_NAME}_jellyfin_cache
|
||||||
filestash_data:
|
filestash_data:
|
||||||
name: ${MEDIA_COMPOSE_PROJECT_NAME}_filestash_data
|
name: ${MEDIA_COMPOSE_PROJECT_NAME}_filestash_data
|
||||||
|
pinchflat_config:
|
||||||
|
name: ${MEDIA_COMPOSE_PROJECT_NAME}_pinchflat_config
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
compose_network:
|
compose_network:
|
||||||
|
|||||||
@@ -71,30 +71,29 @@ access_control:
|
|||||||
- "scrapy.pivoine.art"
|
- "scrapy.pivoine.art"
|
||||||
- "restic.pivoine.art"
|
- "restic.pivoine.art"
|
||||||
- "proxy.pivoine.art"
|
- "proxy.pivoine.art"
|
||||||
|
- "admin.asciinema.dev.pivoine.art"
|
||||||
|
- "facefusion.ai.pivoine.art"
|
||||||
|
- "pinchflat.media.pivoine.art"
|
||||||
|
- "comfy.ai.pivoine.art"
|
||||||
|
- "supervisor.ai.pivoine.art"
|
||||||
|
- "audiocraft.ai.pivoine.art"
|
||||||
|
- "upscale.ai.pivoine.art"
|
||||||
policy: one_factor
|
policy: one_factor
|
||||||
|
|
||||||
# Development services
|
|
||||||
- domain:
|
|
||||||
- "dev.pivoine.art"
|
|
||||||
- "n8n.pivoine.art"
|
|
||||||
- "asciinema.pivoine.art"
|
|
||||||
- "coolify.pivoine.art"
|
|
||||||
policy: two_factor
|
|
||||||
|
|
||||||
# session secret set via environment variable: AUTHELIA_SESSION_SECRET
|
# session secret set via environment variable: AUTHELIA_SESSION_SECRET
|
||||||
session:
|
session:
|
||||||
name: 'authelia_session'
|
name: "authelia_session"
|
||||||
same_site: 'lax'
|
same_site: "lax"
|
||||||
expiration: '1h'
|
expiration: "1h"
|
||||||
inactivity: '5m'
|
inactivity: "15m"
|
||||||
remember_me: '1M'
|
remember_me: "1M"
|
||||||
cookies:
|
cookies:
|
||||||
- domain: 'pivoine.art'
|
- domain: "pivoine.art"
|
||||||
authelia_url: 'https://auth.pivoine.art'
|
authelia_url: "https://auth.pivoine.art"
|
||||||
same_site: 'lax'
|
same_site: "lax"
|
||||||
expiration: '1h'
|
expiration: "1h"
|
||||||
inactivity: '5m'
|
inactivity: "5m"
|
||||||
remember_me: '1M'
|
remember_me: "1M"
|
||||||
|
|
||||||
regulation:
|
regulation:
|
||||||
max_retries: 3
|
max_retries: 3
|
||||||
|
|||||||
180
net/compose.yaml
180
net/compose.yaml
@@ -6,49 +6,49 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command:
|
command:
|
||||||
# API & Dashboard
|
# API & Dashboard
|
||||||
- '--api.dashboard=true'
|
- "--api.dashboard=true"
|
||||||
- '--api.insecure=false'
|
- "--api.insecure=false"
|
||||||
|
|
||||||
# Ping endpoint for healthcheck
|
# Ping endpoint for healthcheck
|
||||||
- '--ping=true'
|
- "--ping=true"
|
||||||
|
|
||||||
# Experimental plugins
|
# Experimental plugins
|
||||||
- '--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier'
|
- "--experimental.plugins.sablier.modulename=github.com/acouvreur/sablier"
|
||||||
- '--experimental.plugins.sablier.version=v1.8.0'
|
- "--experimental.plugins.sablier.version=v1.8.0"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
- '--log.level=${NET_PROXY_LOG_LEVEL:-INFO}'
|
- "--log.level=${NET_PROXY_LOG_LEVEL:-INFO}"
|
||||||
- '--accesslog=true'
|
- "--accesslog=true"
|
||||||
|
|
||||||
# Global
|
# Global
|
||||||
- '--global.sendAnonymousUsage=false'
|
- "--global.sendAnonymousUsage=false"
|
||||||
- '--global.checkNewVersion=true'
|
- "--global.checkNewVersion=true"
|
||||||
|
|
||||||
# Docker Provider
|
# Docker Provider
|
||||||
- '--providers.docker=true'
|
- "--providers.docker=true"
|
||||||
- '--providers.docker.exposedbydefault=false'
|
- "--providers.docker.exposedbydefault=false"
|
||||||
- '--providers.docker.network=${NETWORK_NAME}'
|
- "--providers.docker.network=${NETWORK_NAME}"
|
||||||
|
|
||||||
# File Provider for dynamic configuration
|
# File Provider for dynamic configuration
|
||||||
- '--providers.file.directory=/etc/traefik/dynamic'
|
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||||
- '--providers.file.watch=true'
|
- "--providers.file.watch=true"
|
||||||
|
|
||||||
# Entrypoints
|
# Entrypoints
|
||||||
- '--entrypoints.web.address=:${NET_PROXY_PORT_HTTP:-80}'
|
- "--entrypoints.web.address=:${NET_PROXY_PORT_HTTP:-80}"
|
||||||
- '--entrypoints.web-secure.address=:${NET_PROXY_PORT_HTTPS:-443}'
|
- "--entrypoints.web-secure.address=:${NET_PROXY_PORT_HTTPS:-443}"
|
||||||
|
|
||||||
# Global HTTP to HTTPS redirect
|
# Global HTTP to HTTPS redirect
|
||||||
- '--entrypoints.web.http.redirections.entryPoint.to=web-secure'
|
- "--entrypoints.web.http.redirections.entryPoint.to=web-secure"
|
||||||
- '--entrypoints.web.http.redirections.entryPoint.scheme=https'
|
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
||||||
- '--entrypoints.web.http.redirections.entryPoint.permanent=true'
|
- "--entrypoints.web.http.redirections.entryPoint.permanent=true"
|
||||||
|
|
||||||
# Security Headers (applied globally)
|
# Security Headers (applied globally)
|
||||||
- '--entrypoints.web-secure.http.middlewares=security-headers@file'
|
- "--entrypoints.web-secure.http.middlewares=security-headers@file"
|
||||||
|
|
||||||
# Let's Encrypt
|
# Let's Encrypt
|
||||||
- '--certificatesresolvers.resolver.acme.tlschallenge=true'
|
- "--certificatesresolvers.resolver.acme.tlschallenge=true"
|
||||||
- '--certificatesresolvers.resolver.acme.email=${ADMIN_EMAIL}'
|
- "--certificatesresolvers.resolver.acme.email=${ADMIN_EMAIL}"
|
||||||
- '--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json'
|
- "--certificatesresolvers.resolver.acme.storage=/letsencrypt/acme.json"
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
test: ["CMD", "traefik", "healthcheck", "--ping"]
|
||||||
@@ -74,20 +74,20 @@ services:
|
|||||||
- ./dynamic:/etc/traefik/dynamic:ro
|
- ./dynamic:/etc/traefik/dynamic:ro
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=true'
|
- "traefik.enable=true"
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-traefik-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.entrypoints=web'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web.entrypoints=web"
|
||||||
# HTTPS router with auth
|
# HTTPS router with auth
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.rule=Host(`${NET_PROXY_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.service=api@internal'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.service=api@internal"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file"
|
||||||
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.loadbalancer.server.port=8080'
|
- "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-traefik-web-secure.loadbalancer.server.port=8080"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
|
||||||
# Netdata - Real-time monitoring
|
# Netdata - Real-time monitoring
|
||||||
netdata:
|
netdata:
|
||||||
@@ -128,23 +128,23 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
|
- "traefik.enable=${NET_TRAEFIK_ENABLED}"
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.entrypoints=web'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web.entrypoints=web"
|
||||||
# HTTPS router
|
# HTTPS router
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.rule=Host(`${NET_NETDATA_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-compress.compress=true'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-netdata-compress.compress=true"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-compress,${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-netdata-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-netdata-compress,${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file"
|
||||||
# Service
|
# Service
|
||||||
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-netdata.loadbalancer.server.port=19999'
|
- "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-netdata.loadbalancer.server.port=19999"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Watchtower - Automatic container updates
|
# Watchtower - Automatic container updates
|
||||||
watchtower:
|
watchtower:
|
||||||
@@ -154,6 +154,8 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
environment:
|
environment:
|
||||||
|
# Docker API version negotiation
|
||||||
|
DOCKER_API_VERSION: "1.44"
|
||||||
# Check for updates every 5 minutes (300 seconds)
|
# Check for updates every 5 minutes (300 seconds)
|
||||||
WATCHTOWER_POLL_INTERVAL: ${WATCHTOWER_POLL_INTERVAL:-300}
|
WATCHTOWER_POLL_INTERVAL: ${WATCHTOWER_POLL_INTERVAL:-300}
|
||||||
# Only update containers with the watchtower label
|
# Only update containers with the watchtower label
|
||||||
@@ -200,7 +202,8 @@ services:
|
|||||||
- compose_network
|
- compose_network
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
|
test:
|
||||||
|
["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -208,18 +211,21 @@ services:
|
|||||||
|
|
||||||
labels:
|
labels:
|
||||||
# Traefik Configuration
|
# Traefik Configuration
|
||||||
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
|
- "traefik.enable=${NET_TRAEFIK_ENABLED}"
|
||||||
|
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-umami-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.entrypoints=web'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web.entrypoints=web"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.rule=Host(`${NET_TRACK_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.loadbalancer.server.port=3000'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.middlewares=security-headers@file"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-umami-web-secure.loadbalancer.server.port=3000"
|
||||||
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
|
# Watchtower
|
||||||
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Mailpit - SMTP server with web UI
|
# Mailpit - SMTP server with web UI
|
||||||
mailpit:
|
mailpit:
|
||||||
@@ -245,22 +251,22 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
|
- "traefik.enable=${NET_TRAEFIK_ENABLED}"
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-mailpit-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.entrypoints=web'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web.entrypoints=web"
|
||||||
# HTTPS router with auth
|
# HTTPS router with auth
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.rule=Host(`${NET_MAILPIT_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia,security-headers@file"
|
||||||
# Service
|
# Service
|
||||||
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.loadbalancer.server.port=8025'
|
- "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-mailpit-web-secure.loadbalancer.server.port=8025"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
# Authelia - SSO and authentication portal
|
# Authelia - SSO and authentication portal
|
||||||
authelia:
|
authelia:
|
||||||
@@ -280,27 +286,27 @@ services:
|
|||||||
networks:
|
networks:
|
||||||
- compose_network
|
- compose_network
|
||||||
labels:
|
labels:
|
||||||
- 'traefik.enable=${NET_TRAEFIK_ENABLED}'
|
- "traefik.enable=${NET_TRAEFIK_ENABLED}"
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure.redirectscheme.scheme=https'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure.redirectscheme.scheme=https"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.middlewares=${NET_COMPOSE_PROJECT_NAME}-authelia-redirect-web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.entrypoints=web'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web.entrypoints=web"
|
||||||
# HTTPS router
|
# HTTPS router
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.rule=Host(`${NET_AUTHELIA_TRAEFIK_HOST}`)"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.tls.certresolver=resolver'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.tls.certresolver=resolver"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.entrypoints=web-secure'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.entrypoints=web-secure"
|
||||||
- 'traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.middlewares=security-headers@file'
|
- "traefik.http.routers.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.middlewares=security-headers@file"
|
||||||
# Service
|
# Service
|
||||||
- 'traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.loadbalancer.server.port=9091'
|
- "traefik.http.services.${NET_COMPOSE_PROJECT_NAME}-authelia-web-secure.loadbalancer.server.port=9091"
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- "traefik.docker.network=${NETWORK_NAME}"
|
||||||
# ForwardAuth middleware for other services
|
# ForwardAuth middleware for other services
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.address=http://net_authelia:9091/api/authz/forward-auth'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.address=http://net_authelia:9091/api/authz/forward-auth"
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.trustForwardHeader=true'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.trustForwardHeader=true"
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"
|
||||||
- 'traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeadersRegex=^Remote-'
|
- "traefik.http.middlewares.${NET_COMPOSE_PROJECT_NAME}-authelia.forwardAuth.authResponseHeadersRegex=^Remote-"
|
||||||
# Watchtower
|
# Watchtower
|
||||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
- "com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
letsencrypt_data:
|
letsencrypt_data:
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ services:
|
|||||||
- 'traefik.http.routers.${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure.middlewares=${SEXY_COMPOSE_PROJECT_NAME}-api-strip,${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure-compress'
|
- 'traefik.http.routers.${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure.middlewares=${SEXY_COMPOSE_PROJECT_NAME}-api-strip,${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure-compress'
|
||||||
- 'traefik.http.services.${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure.loadbalancer.server.port=8055'
|
- 'traefik.http.services.${SEXY_COMPOSE_PROJECT_NAME}-api-web-secure.loadbalancer.server.port=8055'
|
||||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||||
|
# Watchtower
|
||||||
|
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||||
|
|
||||||
sexy_frontend:
|
sexy_frontend:
|
||||||
image: ${SEXY_FRONTEND_IMAGE}
|
image: ${SEXY_FRONTEND_IMAGE}
|
||||||
|
|||||||
@@ -127,6 +127,9 @@ services:
|
|||||||
MEILI_NO_ANALYTICS: ${UTIL_LINKS_MEILI_NO_ANALYTICS:-true}
|
MEILI_NO_ANALYTICS: ${UTIL_LINKS_MEILI_NO_ANALYTICS:-true}
|
||||||
volumes:
|
volumes:
|
||||||
- linkwarden_meili_data:/meili_data
|
- linkwarden_meili_data:/meili_data
|
||||||
|
labels:
|
||||||
|
# Watchtower
|
||||||
|
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||||
|
|
||||||
# Mattermost - Team collaboration
|
# Mattermost - Team collaboration
|
||||||
mattermost:
|
mattermost:
|
||||||
|
|||||||
Reference in New Issue
Block a user