Skip to content

Instantly share code, notes, and snippets.

@metasikander
Created April 6, 2026 07:20
Show Gist options
  • Select an option

  • Save metasikander/0f2430b11f2da22a00b9c771fb0b9bdd to your computer and use it in GitHub Desktop.

Select an option

Save metasikander/0f2430b11f2da22a00b9c771fb0b9bdd to your computer and use it in GitHub Desktop.
LLM Stack
services:
litellm:
container_name: "litellm"
environment:
- "PROXY_MASTER_KEY=${LITELLM_PROXY_MASTER_KEY}"
- "LITELLM_SALT_KEY=${LITELLM_SALT_KEY}"
- "LITELLM_MASTER_KEY=${LITELLM_MASTER_KEY}"
- "PROXY_ADMIN_ID=${LITELLM_PROXY_ADMIN_ID}"
- "STORE_MODEL_IN_DB=${LITELLM_STORE_MODEL_IN_DB}"
- "UI_USERNAME=${LITELLM_UI_USERNAME}"
- "UI_PASSWORD=${LITELLM_UI_PASSWORD}"
- "DATABASE_URL=${LITELLM_DATABASE_URL}"
mem_limit: 2g
image: "ghcr.io/berriai/litellm:main-stable"
networks:
- "marvin_default"
- proxy
expose:
- "4000/tcp"
restart: "always"
labels:
- "traefik.enable=true"
- "traefik.http.routers.litellm.rule=Host(`litellm.public.cc`)"
- "traefik.http.routers.litellm.entrypoints=websecure"
- "traefik.http.routers.litellm.tls.certresolver=cloudflare"
- "traefik.http.services.litellm.loadbalancer.server.port=4000"
- "homepage.group=Tools"
- "homepage.name=LiteLLM"
- "homepage.icon=ollama.png"
- "homepage.href=https://litellm.public.cc/ui"
marvin_cf:
command:
- "tunnel"
- "--no-autoupdate"
- "run"
- "--token"
- "${CF_TUNNEL_TOKEN}"
container_name: "marvin_cf"
image: "cloudflare/cloudflared:latest"
networks:
- "marvin_default"
restart: "always"
marvin_db:
container_name: "marvin_db"
environment:
- "POSTGRES_USER=${POSTGRES_USER}"
- "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}"
- "POSTGRES_DB=${POSTGRES_DB}"
expose:
- "5432/tcp"
image: "postgres:17"
networks:
- "marvin_default"
restart: "always"
volumes:
- "./postgres_data:/var/lib/postgresql/data:z"
marvin_redis:
container_name: "marvin_redis"
image: "redis:latest"
expose:
- "6379/tcp"
networks:
- "marvin_default"
restart: "always"
llama-cpp:
image: ghcr.io/ggml-org/llama.cpp:server-cuda
container_name: llama-cpp
restart: unless-stopped
expose:
- "8080"
volumes:
- "./llama-models:/models:ro"
networks:
- "marvin_default"
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
command:
- "-m"
- "/models/Qwen3.5-9B-Q4_K_M.gguf"
- "--verbose"
- "-ngl"
- "99"
- "-c"
- "131072"
- "-np"
- "1"
- "-fa"
- "on"
- "--cache-type-k"
- "q4_0"
- "--cache-type-v"
- "q4_0"
- "--host"
- "0.0.0.0"
- "--port"
- "8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
bitnet:
build:
context: ./bitnet
dockerfile: Dockerfile
image: bitnet-server:latest
container_name: bitnet-server
restart: unless-stopped
cpuset: "0-15"
expose:
- "8080"
networks:
- "marvin_default"
environment:
OMP_PLACES: "cores"
OMP_PROC_BIND: "close"
command:
- "-m"
- "/models/ggml-model-i2_s.gguf"
- "-a"
- "bitnet"
- "--host"
- "0.0.0.0"
- "--port"
- "8080"
- "-t"
- "8"
- "-c"
- "2048"
- "-n"
- "4096"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
open-webui:
container_name: "open-webui"
expose:
- "8080/tcp"
image: "ghcr.io/open-webui/open-webui:main"
mem_limit: 2g
networks:
- "marvin_default"
restart: "always"
volumes:
- "./open-webui:/app/backend/data:z"
hermes-agent:
container_name: "hermes-agent"
build:
context: ./hermes
dockerfile: Dockerfile
entrypoint: ["hermes", "gateway"]
environment:
- "HOME=/home/hermes"
- "API_SERVER_ENABLED=true"
- "API_SERVER_HOST=0.0.0.0"
- "API_SERVER_PORT=8642"
- "API_SERVER_KEY=${HERMES_API_KEY}"
- "OPENAI_API_BASE=http://litellm:4000/v1"
- "OPENAI_API_KEY=${HERMES_OPENAI_API_KEY}"
expose:
- "8642/tcp"
networks:
- "marvin_default"
restart: "always"
volumes:
- "./hermes/config:/home/hermes/.hermes:z"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8642/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
hermes-workspace:
container_name: "hermes-workspace"
build:
context: ./hermes-workspace
dockerfile: Dockerfile
depends_on:
hermes-agent:
condition: service_healthy
environment:
- "HERMES_API_URL=http://hermes-agent:8642"
- "HERMES_PASSWORD=${HERMES_PASSWORD}"
- "HERMES_API_KEY=${HERMES_API_KEY}"
expose:
- "3000/tcp"
networks:
- "marvin_default"
- proxy
restart: "always"
labels:
- "traefik.enable=true"
- "traefik.http.routers.hermes.rule=Host(`hermes.public.cc`)"
- "traefik.http.routers.hermes.entrypoints=websecure"
- "traefik.http.routers.hermes.tls.certresolver=cloudflare"
- "traefik.http.services.hermes.loadbalancer.server.port=3000"
- "homepage.group=Tools"
- "homepage.name=Hermes Workspace"
- "homepage.icon=hermes.png"
- "homepage.href=https://hermes.public.cc"
searxng:
container_name: "searxng"
image: "docker.io/searxng/searxng:latest"
restart: "always"
networks:
- "marvin_default"
- "proxy"
expose:
- "8080/tcp"
volumes:
- "./searxng:/etc/searxng:rw"
environment:
- "SEARXNG_BASE_URL=https://searxng.public.cc/"
labels:
- "traefik.enable=true"
- "traefik.http.routers.searxng.rule=Host(`searxng.public.cc`)"
- "traefik.http.routers.searxng.entrypoints=websecure"
- "traefik.http.routers.searxng.tls.certresolver=cloudflare"
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
- "homepage.group=Tools"
- "homepage.name=SearXNG"
- "homepage.icon=searxng.png"
- "homepage.href=https://searxng.public.cc"
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
networks:
marvin_default:
name: "marvin_default"
proxy:
external: true
FROM node:22-alpine
WORKDIR /app
# Install dependencies
RUN apk add --no-cache curl git
# Cache-busting layer — forces re-clone when main branch updates
ADD https://github.com/outsourc-e/hermes-workspace/commits/main.atom /tmp/latest_commit
# Clone the repository
RUN git clone --depth 1 https://github.com/outsourc-e/hermes-workspace.git .
# Install pnpm and dependencies
RUN npm install -g pnpm && pnpm install --no-frozen-lockfile
# Build the app
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
RUN pnpm build
# Runtime environment
ENV NODE_ENV=production
EXPOSE 3000
CMD ["node", "server-entry.js"]
FROM ubuntu:latest
# Install updates and dependencies
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y \
curl \
ca-certificates \
git \
sudo \
npm \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Create a non-root user (handle pre-existing GID/UID gracefully)
ARG USERNAME=hermes
ARG USER_UID=1000
ARG USER_GID=1000
RUN if getent group ${USER_GID} > /dev/null 2>&1; then \
existing_group=$(getent group ${USER_GID} | cut -d: -f1); \
groupmod -n ${USERNAME} "$existing_group"; \
else \
groupadd --gid ${USER_GID} ${USERNAME}; \
fi && \
if getent passwd ${USER_UID} > /dev/null 2>&1; then \
existing_user=$(getent passwd ${USER_UID} | cut -d: -f1); \
usermod -l ${USERNAME} -d /home/${USERNAME} -m "$existing_user"; \
else \
useradd --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME}; \
fi && \
echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Switch to non-root user
USER ${USERNAME}
WORKDIR /home/${USERNAME}
# Set environment variables
ENV HOME=/home/${USERNAME}
ENV PATH="/home/${USERNAME}/.local/bin:/home/${USERNAME}/.cargo/bin:${PATH}"
# ── Step 1: Install uv ──
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
# ── Step 2: Check for repo changes ──
ADD https://github.com/NousResearch/hermes-agent/commits/main.atom /tmp/latest_commit
# ── Step 3: Clone the repository and init submodules ──
RUN git clone --depth 1 https://github.com/NousResearch/hermes-agent.git
WORKDIR /home/${USERNAME}/hermes-agent
RUN git submodule update --init --recursive --depth 1
# ── Step 4: Create venv with Python 3.11 ──
RUN uv venv venv --python 3.11
# ── Step 5: Install Python dependencies ──
ENV VIRTUAL_ENV=/home/${USERNAME}/hermes-agent/venv
RUN uv pip install -e ".[all]"
# ── Step 6: Install submodule packages (optional) ──
RUN uv pip install -e "./tinker-atropos"
# ── Step 7: Install Node.js dependencies (browser tools & WhatsApp) ──
RUN npm install
# ── Step 8: Create configuration directory structure ──
RUN mkdir -p ~/.hermes/{cron,sessions,logs,memories,skills,pairing,hooks,image_cache,audio_cache,whatsapp/session} && \
cp cli-config.yaml.example ~/.hermes/config.yaml && \
touch ~/.hermes/.env
# ── Step 9: Symlink hermes to PATH ──
RUN mkdir -p ~/.local/bin && \
ln -sf "$(pwd)/venv/bin/hermes" ~/.local/bin/hermes
# Expose default port
EXPOSE 8080
# Persistent volumes for config and data
VOLUME ["/home/hermes/.hermes"]
# Default entrypoint
ENTRYPOINT ["hermes-agent"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment