docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# LLMSwapper en contenedor.
#
# docker compose up -d y abre http://127.0.0.1:7373
#
# Antes de usarlo, lee "Docker" en el README: dentro de un contenedor el panel pierde la
# detección de procesos y los targets de WSL, y en macOS solo puede tocar las credenciales si
# están en fichero y no en el Llavero. No es un bug, es la frontera del contenedor.
#
# NO LEVANTES ESTO Y `node server.js` A LA VEZ. El suelo que mantiene la app dentro del cupo del
# endpoint de uso (unas 5 peticiones por 5 minutos) se lleva POR PROCESO, así que dos instancias
# doblan el ritmo de salida y se rate-limitan la una a la otra. Una u otra, no las dos.
services:
llmswapper:
build: .
image: llmswapper:latest
# Reconstruye en cada `up`. Sin esto, tras un `git pull`, `docker compose up -d` arranca la
# imagen ANTERIOR sin avisar y el arreglo que acabas de bajar no corre. Con caché tarda un
# par de segundos; no hay npm install que repetir.
pull_policy: build
container_name: llmswapper
# 127.0.0.1: en el lado del HOST. El servidor escucha en 0.0.0.0 dentro del contenedor
# porque no le queda otra, así que el loopback tiene que imponerse aquí. Quitar el
# "127.0.0.1:" publicaría en todas las interfaces de la máquina un panel que maneja
# credenciales de pago; no lo hagas para "verlo desde el móvil".
ports:
- "127.0.0.1:${SWAPPER_PORT:-7373}:7373"
environment:
PORT: 7373
SWAPPER_BIND: 0.0.0.0
SWAPPER_IN_CONTAINER: "1"
NO_OPEN: "1"
volumes:
# Las cuentas guardadas y la caché de uso, compartidas con una instalación local del
# repo. Es lo que se quiere casi siempre: das de alta una cuenta con `node server.js` y
# el contenedor la ve, y al revés. Un volumen con nombre (`llmswapper-data:/app/data`)
# daría un almacén SEPARADO y vacío - correcto para un servidor que solo usa Docker,
# desconcertante en una máquina donde ya tenías cuentas dadas de alta.
#
# En un host Linux, CREA data/ antes del primer `up` (`mkdir -p data`; `node server.js` ya
# lo hizo si arrancaste el panel alguna vez). Docker crea un origen de bind mount que no
# existe como root, y el servidor corre como uid 1000: EACCES al arrancar (mkdir /app/data/backups). El chown
# del Dockerfile no ayuda aquí, solo siembra volúmenes con nombre.
- ./data:/app/data
# La configuración REAL de Claude Code en tu máquina: sin esto el swap no tiene nada que
# cambiar y el panel queda en modo mirón. CLAUDE_HOME por defecto es $HOME, que resuelve
# solo en Linux y macOS; en Windows (PowerShell) define antes:
# $env:CLAUDE_HOME = $env:USERPROFILE
#
# Se monta el directorio home ENTERO, no ~/.claude y ~/.claude.json por separado, porque
# ~/.claude.json va suelto en el home y Claude Code lo reescribe creando un fichero nuevo y
# renombrándolo encima: en Linux nativo un bind mount de UN fichero se queda con el inode
# viejo, el contenedor lee una copia congelada y sus escrituras nunca llegan al host. Con el
# directorio montado el rename ocurre dentro del mount y todo sigue siendo atómico. El
# contenedor ve todo tu home; ya tenía tus credenciales de Claude, que es lo valioso.
#
# Solo en Docker Desktop (Windows, macOS), que resuelve por ruta y no por inode, puedes
# cambiar esta línea por las dos de siempre y exponer menos:
# - ${CLAUDE_HOME:-${HOME}}/.claude:/home/node/.claude
# - ${CLAUDE_HOME:-${HOME}}/.claude.json:/home/node/.claude.json
- ${CLAUDE_HOME:-${HOME}}:/home/node
restart: unless-stopped