129 lines
7.0 KiB
YAML
129 lines
7.0 KiB
YAML
services:
|
|
|
|
# ─── Claude Max API Proxy (fuer Hermes) ─────────────────
|
|
# Gleicher Trick wie beim ARIA-Proxy (/root/ARIA-AGENT/docker-compose.yml,
|
|
# Service "proxy"): das npm-Paket claude-max-api-proxy wrappt die Claude
|
|
# Code CLI (angemeldet mit Claude-Max-Subscription) als OpenAI-kompatiblen
|
|
# /v1/chat/completions-Endpoint. Die Sed-Patches unten sind identisch zu
|
|
# ARIA — noetig damit:
|
|
# - der Server auf 0.0.0.0 bindet (sonst nur localhost im Container)
|
|
# - Claude ohne interaktive Permission-Prompts laeuft (--dangerously-skip-permissions,
|
|
# zwingend fuer non-interactive Container-Betrieb als root)
|
|
# - der System-Prompt komplett ersetzt wird (--system-prompt) statt nur
|
|
# angehaengt — sonst gewinnt Claude Codes eigene "You are Claude Code"-
|
|
# Identitaet bei duennem Kontext
|
|
# - lange Agent-Loops nicht nach 5min timeouten (DEFAULT_TIMEOUT -> 24h)
|
|
# - der Prompt via stdin statt CLI-Arg uebergeben wird (Arg-Laengenlimit/
|
|
# Escaping-Probleme bei langen Konversationen)
|
|
#
|
|
# Adapter-Patches (proxy-patches/*.js) sind 1:1 aus dem ARIA-Proxy
|
|
# uebernommen — sie sind generisch (implementieren nur die
|
|
# OpenAI-tools <-> <tool_call>-Text-Bridge, kein ARIA-Code drin):
|
|
# - openai-to-cli.js: haengt `tools`-Definitionen als Anleitung in den
|
|
# System-Prompt ("gib <tool_call name=X>{json}</tool_call> aus")
|
|
# - cli-to-openai.js: parsed genau dieses Format aus Claudes Antwort
|
|
# wieder raus und baut daraus OpenAI-konforme tool_calls[]
|
|
#
|
|
# BEWUSST NICHT uebernommen: ARIAs routes.js-Patch. Der haengt zusaetzlich
|
|
# an aria-bridge:8090 (Live-Tool-Stream + Not-Aus-Killswitch) und liest
|
|
# /shared/config/models.json — beides ARIA-Bridge-spezifisch. Hier laeuft
|
|
# die NPM-Stock-Version von routes.js (macht die Kern-Route trotzdem,
|
|
# nur ohne die Bridge-Extras). Falls Hermes spaeter auch Live-Stream/
|
|
# Killswitch braucht: sag Bescheid, dann bauen wir das nach.
|
|
hermes-proxy:
|
|
image: node:22-alpine
|
|
container_name: hermes-proxy
|
|
command: >-
|
|
sh -c "apk add --no-cache bash curl &&
|
|
npm install -g @anthropic-ai/claude-code claude-max-api-proxy &&
|
|
DIST=$$(find /usr/local/lib -path '*/claude-max-api-proxy/dist' -type d | head -1) &&
|
|
sed -i 's/startServer({ port })/startServer({ port, host: process.env.HOST || \"127.0.0.1\" })/' $$DIST/server/standalone.js &&
|
|
sed -i 's/\"--no-session-persistence\",/\"--no-session-persistence\",\"--dangerously-skip-permissions\",/' $$DIST/subprocess/manager.js &&
|
|
sed -i 's/\"--dangerously-skip-permissions\",/\"--dangerously-skip-permissions\",\"--system-prompt\",options.systemPrompt,/' $$DIST/subprocess/manager.js &&
|
|
sed -i 's/const DEFAULT_TIMEOUT = 300000;/const DEFAULT_TIMEOUT = 86400000;/' $$DIST/subprocess/manager.js &&
|
|
sed -i '/prompt, \\/\\/ Pass prompt as argument/d' $$DIST/subprocess/manager.js &&
|
|
sed -i 's|this\\.process\\.stdin?\\.end();|this.process.stdin?.end(prompt);|' $$DIST/subprocess/manager.js &&
|
|
cp /proxy-patches/openai-to-cli.js $$DIST/adapter/openai-to-cli.js &&
|
|
cp /proxy-patches/cli-to-openai.js $$DIST/adapter/cli-to-openai.js &&
|
|
claude-max-api"
|
|
volumes:
|
|
# WICHTIG: eigenes, von ARIA getrenntes Volume fuer die Claude-CLI-Session.
|
|
# Einmalig `docker exec -it hermes-proxy claude` fuer den Browser-Login
|
|
# mit der Claude-Max-Subscription (kann derselbe Account wie ARIA sein —
|
|
# es ist ja dieselbe Subscription, nur eine eigene CLI-Session dafuer).
|
|
- ./hermes-data/claude-config:/root/.claude
|
|
# optional: nur noetig falls Hermes Dateien mit Dir austauschen soll
|
|
- ./hermes-shared:/shared
|
|
- ./proxy-patches:/proxy-patches:ro
|
|
tmpfs:
|
|
# wie bei ARIA: Claude Codes eigenes Auto-Memory nicht persistieren
|
|
- /root/.claude/projects
|
|
environment:
|
|
- HOST=0.0.0.0
|
|
- SHELL=/bin/bash
|
|
- CLAUDE_CODE_BUBBLEWRAP=1 # erlaubt --dangerously-skip-permissions als root
|
|
restart: unless-stopped
|
|
networks:
|
|
- hermes-net
|
|
# Bewusst KEIN ports:-Mapping nach aussen — genau wie bei ARIAs Proxy.
|
|
# Nur Container im selben Docker-Netz (hier: hermes-gateway) sollen ihn
|
|
# erreichen koennen. Das eigentliche Netzwerk-Exposing + Auth macht das
|
|
# Gateway unten, damit hier niemals ein unauthentifizierter Endpoint
|
|
# offen im Netz haengt.
|
|
# Zum manuellen Testen direkt im Container: docker exec -it hermes-proxy curl -s localhost:3456/v1/chat/completions ...
|
|
|
|
# ─── Hermes Gateway (Auth + Netzwerk-Expose) ───────────────
|
|
# Stefan deployt den eigentlichen Hermes-Agent-Client (Nous Research,
|
|
# https://github.com/NousResearch/hermes-agent, CLI/Desktop-App) SELBST
|
|
# auf einer ANDEREN Maschine — hier steht daher kein hermes-agent-Service,
|
|
# nur die Proxy-Seite, die Hermes von aussen ansprechen kann.
|
|
#
|
|
# Weil "von aussen" heisst: der Proxy braucht einen echten Netzwerk-Port.
|
|
# hermes-proxy selbst hat aber keine Authentifizierung eingebaut (siehe
|
|
# Kommentar oben) — ein offener Port waere ein frei nutzbarer Claude-Max-
|
|
# Zugang fuer jeden der ihn erreicht. Deshalb dieses schlanke Gateway
|
|
# (proxy-patches/gateway.js, pure Node, keine Extra-Deps): prueft den
|
|
# Authorization: Bearer <TOKEN> Header, leitet nur bei Match an
|
|
# hermes-proxy weiter. Alles andere -> 401.
|
|
#
|
|
# In Hermes' ~/.hermes/config.yaml traegst du ein:
|
|
# model:
|
|
# provider: custom
|
|
# model: "sonnet" # oder "opus" / "haiku" — siehe MODEL_MAP
|
|
# # in proxy-patches/openai-to-cli.js
|
|
# base_url: "http://<diese-maschine>:${HERMES_GATEWAY_PORT:-8447}/v1"
|
|
# api_key: "<HERMES_GATEWAY_TOKEN aus .env>"
|
|
# OpenAI-kompatible Clients schicken api_key automatisch als
|
|
# "Authorization: Bearer <api_key>" — genau das prueft das Gateway, kein
|
|
# Extra-Schritt auf Hermes-Seite noetig.
|
|
hermes-gateway:
|
|
image: node:22-alpine
|
|
container_name: hermes-gateway
|
|
command: ["node", "/gateway/gateway.js"]
|
|
depends_on:
|
|
- hermes-proxy
|
|
volumes:
|
|
- ./proxy-patches:/gateway:ro
|
|
environment:
|
|
- TOKEN=${HERMES_GATEWAY_TOKEN:?HERMES_GATEWAY_TOKEN muss in .env gesetzt sein - siehe .env.example}
|
|
- UPSTREAM_HOST=hermes-proxy
|
|
- UPSTREAM_PORT=3456
|
|
- LISTEN_PORT=8080
|
|
ports:
|
|
# Bindet auf ALLE Interfaces, damit Hermes von der anderen Maschine
|
|
# rankommt. HERMES_GATEWAY_PORT in .env setzen (Default 8447).
|
|
# WICHTIG (lies auch README "Sicherheitshinweis"): wenn diese Maschine
|
|
# direkt im Internet haengt statt in einem vertrauenswuerdigen
|
|
# LAN/VPN, den Port zusaetzlich per Firewall auf Hermes' IP
|
|
# einschraenken oder per VPN/SSH-Tunnel statt direktem Expose fahren
|
|
# — Bearer-Token schuetzt vor Fremdnutzung, aber der Traffic selbst
|
|
# laeuft hier unverschluesselt (HTTP, kein TLS).
|
|
- "${HERMES_GATEWAY_PORT:-8447}:8080"
|
|
restart: unless-stopped
|
|
networks:
|
|
- hermes-net
|
|
|
|
networks:
|
|
hermes-net:
|
|
driver: bridge
|