Cómo autoalojar Octop multiusuario con Docker
Instala Octop v0.9.19 en un VPS con Docker Compose fijado a una etiqueta, aislamiento por usuario, backend compatible con OpenAI y TLS, sin usar el instalador curl.
Qué es Octop y por qué alojarlo de forma autónoma
Octop es un asistente de IA autoalojado para un hogar o un equipo pequeño. La razón para alojar Octop de forma autónoma en lugar de usar una interfaz de chat básica es que mantiene separados a los usuarios. Open WebUI proporciona una interfaz de navegador delante de un modelo. Octop añade cuentas con un rol de administrador, un espacio de trabajo privado y un conjunto de credenciales para cada usuario, además de una biblioteca de agentes especializados entre los que cada usuario puede cambiar según la tarea. Esta es la diferencia que permite que un solo VPS atienda a cinco personas en lugar de a una.
El proyecto está disponible en github.com/TencentCloud/Octop. Es un único proceso que proporciona un panel web, una interfaz de línea de comandos, canales de chat (Feishu, DingTalk, QQ, Discord, WeCom) y tareas programadas. Todo usa una única base de datos SQLite en ~/.octop/. Todo lo que sigue se basa en la etiqueta v0.9.19, publicada el 5 de agosto de 2026. Si todavía está comparando plataformas, la comparativa de alternativas a Open WebUI que puede ejecutar en un VPS cubre un conjunto más amplio de opciones.
Conviene aclarar un punto antes de dedicarle una tarde. Octop es software anterior a la versión 1.0, publicado desde la organización de GitHub de un proveedor, con unas 900 estrellas en agosto de 2026. El proyecto evoluciona rápido, como indican los números de versión, y nada de lo que se describe aquí garantiza una ruta de actualización estable. Fije una etiqueta, lea el registro de cambios y conserve copias de seguridad.
Qué necesita antes de empezar
- Un VPS con Ubuntu 24.04, Docker Engine y el plugin Compose. ¿No conoce Compose? Empiece por Conceptos básicos de Docker Compose para un VPS.
git, porque va a extraer una etiqueta de versión en lugar de descargar una imagen.- Un nombre de dominio que apunte al VPS, porque necesita TLS (seguridad de la capa de transporte) delante de este servicio.
- Un backend de modelos compatible con la API de OpenAI: un Ollama local, una gateway autogestionada o una clave de pago.
Octop consume pocos recursos. Es un proceso de Python y un archivo SQLite. El consumo principal procede del backend del modelo. Si piensa ejecutar el modelo en el mismo equipo, dimensione el equipo para ese modelo.
Por qué no recomendamos el instalador con curl
El README comienza con una instalación de una sola línea:
curl -fsSL https://finnie-1258344699.cos.ap-guangzhou.myqcloud.com/octop/install.sh | bashNo lo recomendamos en un servidor que deba mantenerse bajo control por un motivo concreto: ese script no está en el repositorio. Se sirve desde un bucket de Tencent Cloud Object Storage. Ningún tag ni commit cubre su contenido, por lo que no puede comparar el script actual con el de la semana pasada, y no existe un historial que explique los cambios. Mañana el bucket puede servir bytes diferentes y nada en el proyecto lo registrará. Enviar directamente el resultado a bash también significa que la máquina ejecuta el script antes de que usted haya leído una sola línea.
El instalador también escribe en el host en lugar de hacerlo en un contenedor. Usa uv para descargar Python 3.12 y crear un entorno que el gestor de paquetes desconoce, por lo que después tendrá que eliminarlo manualmente.
Hay dos opciones mejores. Descargue el script, léalo y ejecútelo después; sólo le llevará treinta segundos: curl -fsSL <url> -o install.sh, después less install.sh y luego bash install.sh. O use Docker, que es el resto de esta guía. El paquete de PyPI (pip install octop) es, como mínimo, un artefacto versionado que puede fijar a una release.
Implementar Octop con Docker Compose, fijado en v0.9.19
No hay una imagen publicada que se pueda descargar a fecha de agosto de 2026. El archivo Compose incluido construye la imagen desde el repositorio, por lo que fijar una versión significa cambiar a un tag de git.
git clone https://github.com/TencentCloud/Octop.git
cd Octop
git checkout v0.9.19Este es el servicio que define el archivo, reducido a las partes relevantes:
services:
octop:
build:
context: ..
dockerfile: docker/Dockerfile
image: octop:latest
container_name: octop
restart: unless-stopped
ports:
- "${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"
volumes:
- ${OCTOP_DATA:-~/.octop}:/data/.octop
environment:
- HOME=/data
- OCTOP_BIND_HOST=0.0.0.0
- OCTOP_PORT=${OCTOP_PORT:-8088}
- OCTOP_DEFAULT_PASSWORD=${OCTOP_DEFAULT_PASSWORD:-octop}
- OCTOP_ADMIN_USERNAME=${OCTOP_ADMIN_USERNAME:-admin}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}Observe el bloque build:. image: octop:latest es el nombre de su propia compilación, no una referencia de registro, por lo que latest aquí significa lo que haya compilado más recientemente. Establezca la ruta de datos de forma explícita en lugar de dejarla en manos de un valor predeterminado y asigne una contraseña real a la cuenta de administración antes del primer arranque. Coloque esto en docker/.env:
OCTOP_PORT=8088
OCTOP_ADMIN_USERNAME=admin
OCTOP_DEFAULT_PASSWORD=<a long random password>
OCTOP_DATA=/srv/octop-dataHay un problema importante que merece más atención que el resto del archivo. Compose lee docker/.env sólo para interpolar los marcadores ${...} en el YAML. Una clave que añada a ese archivo no llega al contenedor a menos que también aparezca bajo environment: en el archivo Compose. Añadir OCTOP_ACCESS_TOKEN_TTL únicamente a .env no hace nada, y además de forma silenciosa. La alternativa consiste en escribir las mismas claves en ~/.octop/env dentro del directorio de datos montado; Octop lo carga durante el arranque. La guía sobre archivos de entorno y secretos en Docker Compose explica por qué estos dos mecanismos no son equivalentes.
Constrúyalo e inícielo:
docker compose -f docker/docker-compose.yml up -d --build
docker compose -f docker/docker-compose.yml ps
curl http://127.0.0.1:8088/api/healthUna instancia en buen estado responde a la comprobación de estado con {"status":"ok","version":"..."}. Si devuelve cualquier otra cosa, lea docker compose -f docker/docker-compose.yml logs -f octop antes de abrir el navegador.
Ahora asigne un nombre significativo a la imagen que acaba de construir, porque el siguiente --build sobrescribirá octop:latest y no podrá distinguir una de otra:
docker image tag octop:latest octop:0.9.19El primer arranque ejecuta octop init y escribe las credenciales iniciales en el volumen de datos:
docker exec -it octop cat /data/.octop/credential.txtLos valores predeterminados son admin / octop y se aplican sólo durante la primera inicialización. Esto explica una pregunta muy frecuente: cambiar OCTOP_DEFAULT_PASSWORD después de que el contenedor ya se haya iniciado una vez no cambia nada, porque la cuenta ya existe. Cambie la contraseña desde el panel de control.
No publique el puerto 8088
La línea ports: anterior enlaza todas las interfaces de la VPS. En cuanto se inicia el contenedor, el panel queda expuesto en Internet sin cifrado y con una contraseña predeterminada. El valor predeterminado de OCTOP_BIND_HOST en Octop es 127.0.0.1; el archivo Compose lo sobrescribe con 0.0.0.0 porque el proceso debe aceptar tráfico desde fuera de su propio espacio de nombres de red. Esa sobrescritura es correcta. La publicación del puerto es lo que lo expone.
Edite la línea ports: en docker/docker-compose.yml para que la asignación sólo escuche en loopback:
ports:
- "127.0.0.1:${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"No intente corregirlo con un archivo de sobrescritura simple. Compose concatena las listas ports de varios archivos en lugar de reemplazarlas, por lo que termina publicando ambas asignaciones y la segunda no puede enlazarse. Si quiere mantener intacto el archivo original, use la etiqueta !override en la secuencia. Es la forma documentada de reemplazarla en lugar de añadir elementos. La explicación sobre cómo Compose combina varios archivos cubre el resto de esas reglas de combinación.
Enlazar con loopback también resuelve un problema que, de otro modo, tendría con el firewall. Docker escribe las reglas de los puertos publicados en la tabla nat antes de las cadenas que administra ufw, por lo que ufw deny 8088 no detiene un puerto de contenedor publicado. Un puerto enlazado a 127.0.0.1 nunca es accesible desde fuera, independientemente de lo que indique ufw. Por eso es la corrección adecuada y no una alternativa secundaria.
Configura TLS delante de Octop con un proxy inverso
Caddy es la opción más sencilla, porque solicita el certificado mediante ACME (entorno de gestión automática de certificados) por su cuenta y gestiona WebSockets sin configuración adicional:
octop.example.com {
reverse_proxy 127.0.0.1:8088
}nginx requiere más atención, porque Octop transmite el chat mediante un WebSocket:
server {
listen 443 ssl;
server_name octop.example.com;
ssl_certificate /etc/letsencrypt/live/octop.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/octop.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8088;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 3600s;
}
}Cada línea cumple una función. El chat usa WS /agents/{id}/chat/ws, por lo que, sin proxy_http_version 1.1 y las dos cabeceras de actualización, nginx responde al intento de actualización con 400 Bad Request: el panel se carga con normalidad, pero todos los mensajes que envías quedan bloqueados para siempre sin mostrar ningún error en la página. proxy_buffering off es importante porque el endpoint de reanudación con intervención humana devuelve text/event-stream, y los eventos SSE (eventos enviados por el servidor) retenidos en un búfer del proxy llegan todos juntos al final en lugar de transmitirse progresivamente. proxy_read_timeout cubre las ejecuciones largas de herramientas, porque el valor predeterminado de 60 segundos interrumpe el agente a mitad de la tarea y registra upstream timed out (110: Connection timed out).
Cómo funciona la autenticación JWT detrás del proxy
Octop se autentica con un token bearer, no con una cookie. POST /api/auth/login devuelve {access_token, role, user, ...} y las solicitudes posteriores incluyen Authorization: Bearer <access_token>. Para un reverse proxy, esto es una ventaja: no hay ningún dominio de cookie, ninguna marca Secure ni ninguna regla SameSite que pueda configurarse mal. Por tanto, una sesión que funciona en http://127.0.0.1:8088 se comporta igual en https://octop.example.com.
Conviene conocer dos consecuencias antes de ponerlo a disposición de usuarios reales.
WebSocket incluye el token en la URL. El endpoint es WS /agents/{id}/chat/ws?token=<jwt>, porque JavaScript del navegador no puede establecer una cabecera Authorization durante el handshake de WebSocket. TLS protege ese token durante el tránsito. No lo protege de sus propios registros: nginx escribe la línea de solicitud completa, incluida la cadena de consulta, en access_log de forma predeterminada. Por tanto, un token válido de un usuario real termina en un archivo de texto sin cifrar del servidor. Registre la ruta sin los argumentos. $uri es la ruta normalizada con la cadena de consulta ya eliminada. Incluya esto en el bloque http y haga referencia a él desde el servidor:
log_format octop_noargs '$remote_addr [$time_local] '
'"$request_method $uri $server_protocol" '
'$status $body_bytes_sent';
access_log /var/log/nginx/octop.log octop_noargs;No existe un cierre de sesión por sesión. OCTOP_ACCESS_TOKEN_TTL tiene 86400 como valor predeterminado, por lo que un token sigue siendo válido durante 24 horas después del inicio de sesión. La única forma documentada de invalidar uno es octop admin rotate-jwt-secret. Esta operación rota la clave de firma almacenada en ~/.octop/secrets/jwt_secret e invalida de inmediato todos los tokens vigentes para todos los usuarios. Por tanto, cuando alguien deja el equipo, el orden es el siguiente: elimine el usuario, rote el secreto y pida al resto de usuarios que vuelvan a iniciar sesión. Si esto resulta excesivo, reduzca la duración y recuerde añadir la variable a la lista environment:, además de .env:
OCTOP_ACCESS_TOKEN_TTL=28800La protección contra fuerza bruta ya está incluida: OCTOP_LOGIN_MAX_ATTEMPTS tiene 5 fallos como valor predeterminado y OCTOP_LOGIN_LOCKOUT_SECONDS tiene 900. Por tanto, un usuario bloqueado sólo tiene que esperar quince minutos, en lugar de enfrentarse a una instalación dañada. Octop tiene su propio almacén de usuarios y no ofrece compatibilidad documentada con OIDC en v0.9.19. Si necesita inicio de sesión único real, coloque delante un proxy de autenticación. Para eso sirve un servidor Authentik autohospedado.
Configurar Octop con un backend de modelos
Los proveedores se configuran por agente en el panel, y octop provider list muestra la configuración actual. Octop incluye ajustes predefinidos para API compatibles con OpenAI, DashScope (Qwen) y Ollama. Las credenciales se almacenan en la tabla providers de su propia base de datos SQLite. Esta elección determina cuánto paga y qué datos salen del servidor.
Un modelo local con Ollama. Nada sale del servidor y el coste se traslada a la RAM en lugar de los tokens. Hay un detalle de conexión que suele causar problemas: un contenedor no puede acceder al Ollama del host mediante 127.0.0.1:11434, porque esa dirección corresponde al loopback del propio contenedor. Añada una entrada de gateway del host al servicio:
extra_hosts:
- "host.docker.internal:host-gateway"Después, configure la URL base del proveedor como http://host.docker.internal:11434/v1, que es la ruta compatible con OpenAI de Ollama. Introduzca cualquier cadena no vacía en el campo de la API key, porque Ollama la ignora, pero los clientes de OpenAI se niegan a enviar una clave vacía. Ollama también debe escuchar fuera del loopback para que esto funcione. Esto implica configurar OLLAMA_HOST=0.0.0.0:11434 en su unidad de systemd. Esta es la parte de riesgo: Ollama no tiene autenticación. Por tanto, un puerto 11434 abierto en una IP pública permite que cualquiera que lo escanee primero use el servidor de modelos. Permita sólo el rango privado de Docker, sudo ufw allow from 172.16.0.0/12 to any port 11434 proto tcp, y deniegue el resto. Ejecutar Ollama en un VPS explica cómo dimensionar el modelo, y la comparación entre Ollama y vLLM explica cuándo Ollama deja de ser el servidor adecuado.
Hay otra advertencia sobre los modelos locales, porque parece un error de Octop, pero no lo es. Los agentes funcionan mediante llamadas a herramientas. El prompt del sistema, las definiciones de las herramientas y el historial forman un prompt grande. Ollama sirve los modelos con una ventana de contexto predeterminada relativamente pequeña, por lo que la parte inicial del prompt, donde están las definiciones de las herramientas, queda fuera de la ventana. Entonces el modelo deja de llamar a las herramientas o inventa herramientas que no existen. Aumente num_ctx a 16k o 32k y elija un modelo que sea realmente bueno para las llamadas a funciones.
Un gateway autogestionado. Coloque un gateway LiteLLM autogestionado entre Octop y el resto de los servicios. Así obtiene una única URL base, una clave independiente por usuario, límites de gasto y un único registro. También puede cambiar el modelo situado detrás del gateway sin editar nada en Octop.
Una API de pago. Ofrece la mejor calidad, con una contrapartida clara: el contenido de las conversaciones sale del servidor y llega al proveedor. Esto afecta a una de las principales razones para usar servicios autogestionados. La clave se introduce en docker/.env como OPENAI_API_KEY, y el archivo Compose ya la transmite.
Elija la opción que elija, el archivo Compose también incluye OCTOP_LANGFUSE_ENABLED, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY y LANGFUSE_BASE_URL. Así puede enviar trazas a su propia instancia de Langfuse y comprobar qué hacen realmente los agentes, en lugar de deducirlo sólo por la ventana de chat.
Usuarios, roles y biblioteca compartida de agentes
La cuenta de administrador creada durante el primer arranque crea y gestiona las demás cuentas. Cada usuario tiene sus propios agentes, espacio de trabajo y credenciales. El token que conserva el navegador mantiene ese aislamiento. Además, existe un conjunto compartido de habilidades y subagentes que cualquiera puede usar. Esta función hace que Octop sea útil para una familia: una persona configura un buen agente de investigación una sola vez y nadie más tiene que volver a configurarlo.
Tenga cuidado con las herramientas. Octop ofrece aprobación de herramientas y controles para los comandos de shell, y ambos son reales. Sin embargo, un agente que ejecuta comandos de shell los ejecuta dentro del contenedor de Octop, con el volumen de datos montado. Los controles limitan lo que puede hacer un prompt descuidado. No constituyen un límite de aislamiento. Por tanto, mantenga activada la aprobación de herramientas para cualquier persona a la que no daría acceso a un shell. Si compara esta opción con otras alternativas, la comparativa de agentes de IA autoalojados explica cómo gestiona cada una ese aspecto.
Actualizar un proyecto que publica versiones a este ritmo
The data behind this chart
[
{
"version": "v0.9.16",
"days_since_previous_release": 2
},
{
"version": "v0.9.17",
"days_since_previous_release": 3
},
{
"version": "v0.9.18",
"days_since_previous_release": 1
},
{
"version": "v0.9.19",
"days_since_previous_release": 3
}
]Estas son las fechas de las etiquetas del repositorio, contadas hasta el 7 de agosto de 2026. Se publicaron 4 versiones etiquetadas en nueve días. El intervalo más corto fue de 1 día. Además, v0.9.19 llegó 3 días después de la etiqueta anterior. Este ritmo es una buena señal sobre el proyecto, pero una mala razón para ejecutar latest. Lea los cambios antes de aplicarlos:
cd Octop
git fetch --tags
git tag --sort=-creatordate | head
NEW_TAG=$(git tag --sort=-creatordate | head -1)
git log --oneline "v0.9.19..$NEW_TAG"Haga siempre una copia de seguridad antes de actualizar. Las migraciones de la base de datos se ejecutan al iniciar el servicio. Si una migración falla en un proyecto anterior a la versión 1.0, tendrá que resolver el problema manualmente:
docker compose -f docker/docker-compose.yml stop
sudo tar czf octop-backup-$(date +%F).tgz -C /srv octop-data
docker compose -f docker/docker-compose.yml startDespués, cambie a la nueva etiqueta y vuelva a compilar con docker compose -f docker/docker-compose.yml up -d --build. Si algo falla, cambiar a la etiqueta anterior y volver a compilar restaura el código. Sin embargo, sólo el archivo tar restaura la base de datos.
Ese archivo tar contiene octop.db, config.json, el secreto de firma JWT y credential.txt, por lo que es tan sensible como el propio servidor. Manténgalo con permisos 600 y guarde una copia fuera del servidor. En instalaciones más grandes, el proyecto también publica docker/docker-compose.postgres.yml, que ejecuta PostgreSQL con pgvector en lugar de SQLite.
Modos de fallo y los mensajes que verá
La comprobación de estado nunca responde. curl http://127.0.0.1:8088/api/health se bloquea o rechaza la conexión. Lea docker compose -f docker/docker-compose.yml logs -f octop. Un contenedor que se detiene durante la primera inicialización normalmente no puede escribir en el directorio de datos, así que compruebe el propietario de la ruta que configuró en OCTOP_DATA.
El panel se carga, pero el chat se bloquea. No aparece ningún error en la página y nunca llega una respuesta. Abra la consola del navegador y busque una conexión fallida a wss://octop.example.com/agents/.../chat/ws. El proxy no está reenviando la actualización de la conexión. Añada proxy_http_version 1.1 y las cabeceras Upgrade y Connection.
La respuesta completa aparece de una vez, varios segundos tarde. La transmisión funciona, pero el almacenamiento en búfer está activado. Configure proxy_buffering off.
bind: address already in use. Ya hay otro proceso usando 8088. sudo ss -tlnp | grep 8088 identifica el proceso. Esto también ocurre si añadió una segunda entrada ports en un archivo de sobrescritura en lugar de editar la original.
Se rechaza la contraseña correcta. Cinco intentos incorrectos activan un bloqueo de 900 segundos. Espere a que termine en lugar de reinstalar.
La nueva contraseña de .env no tuvo efecto. Esas credenciales sólo se aplican durante la primera inicialización. Cámbiela en el panel.
El agente responde, pero nunca ejecuta una herramienta. Casi siempre se trata de un problema del modelo local: la ventana de contexto es demasiado pequeña para las definiciones de las herramientas o el modelo no gestiona bien las llamadas a funciones. Aumente num_ctx y pruebe un modelo diseñado para usar herramientas.
FAQ
¿Octop sustituye a Open WebUI?
Sólo si necesita lo que añade. Open WebUI es una interfaz de chat para acceder a un modelo y cumple bien esa función para una persona o un hogar de confianza. Octop añade cuentas con un rol de administrador, espacios de trabajo y credenciales por usuario, además de una biblioteca configurable de agentes especializados. Así, varias personas pueden compartir un servidor sin compartir el mismo historial. Si una sola cuenta es suficiente, Open WebUI es la opción más sencilla y mucho más madura.
¿Por qué no debería usar el script de instalación de Octop mediante curl?
El script se sirve desde un bucket de Tencent Cloud Object Storage y no desde el repositorio, por lo que no está cubierto por ninguna etiqueta ni confirmación de git. No puede comparar lo que hace hoy con lo que hacía la semana pasada, y al canalizarlo hacia bash se ejecuta antes de que pueda leerlo. Además, se instala en el host con su propio entorno de Python 3.12, fuera del gestor de paquetes. Descárguelo y léalo primero, o impleméntelo con Docker Compose desde una etiqueta previamente descargada.
¿Puede Octop usar un modelo local en lugar de una API de pago?
Sí. Octop es compatible con las API de OpenAI y proporciona un ajuste predefinido para Ollama. Por tanto, apuntarlo a http://host.docker.internal:11434/v1 funciona después de añadir extra_hosts: ["host.docker.internal:host-gateway"] al contenedor y establecer OLLAMA_HOST=0.0.0.0:11434 en el host. Restrinja el puerto 11434 al rango de direcciones de Docker, porque Ollama no incluye autenticación propia. Prepárese para aumentar num_ctx de Ollama a 16k o más, ya que las solicitudes de los agentes con definiciones de herramientas superan la ventana de contexto predeterminada y el modelo deja de llamar a las herramientas.
¿Necesito un reverse proxy o puedo abrir el puerto 8088?
Necesita el proxy. El archivo Compose incluido con Octop publica 8088 en todas las interfaces sin TLS, por lo que las contraseñas y los tokens bearer atravesarían Internet en texto sin cifrar. Cambie el puerto publicado a 127.0.0.1:8088:8088 y coloque Caddy o nginx delante con un certificado. Con nginx, reenvíe las cabeceras de actualización de WebSocket y establezca proxy_buffering off. De lo contrario, la página se cargará, pero el chat no responderá y no mostrará ningún error.
¿Octop está listo para producción?
Es anterior a la versión 1.0 y publica varias versiones etiquetadas por semana en agosto de 2026, por lo que debe considerarlo prometedor, pero todavía no consolidado. Puede funcionar para una familia o un equipo interno pequeño si fija una etiqueta exacta, lee el registro de confirmaciones antes de cada actualización y realiza una copia de seguridad del volumen de datos antes de cada reconstrucción. No lo ejecute en latest ni almacene todavía datos de clientes en él.