SSD Nodes Learn 🎉 VPS desde $4.99/mês
Guias Matt ConnorPor Matt Connor

Como hospedar o Octop com Docker em um VPS

Veja como implantar o Octop v0.9.19 com Docker Compose, isolamento por usuário, backend compatível com OpenAI e TLS, sem usar o instalador curl.

O que é o Octop e por que o deve alojar por conta própria

O Octop é um assistente de IA autoalojado para uma família ou uma pequena equipa. A razão para alojar o Octop por conta própria, em vez de usar apenas um frontend de chat, é manter os utilizadores separados. O Open WebUI fornece uma interface de navegador à frente de um modelo. O Octop acrescenta contas com uma função de administrador, um espaço de trabalho privado e um conjunto de credenciais para cada utilizador, além de uma biblioteca de agentes especializados que cada utilizador pode selecionar conforme a tarefa. Essa é a diferença que permite a um único VPS servir cinco pessoas em vez de uma.

O projeto está disponível em github.com/TencentCloud/Octop. É um único processo que fornece um dashboard web, uma interface de linha de comandos, canais de chat (Feishu, DingTalk, QQ, Discord, WeCom) e tarefas agendadas, tudo suportado por uma única base de dados SQLite em ~/.octop/. Tudo o que se segue refere-se à tag v0.9.19, lançada em 5 August 2026. Se ainda estiver a decidir entre plataformas, a comparação de alternativas ao Open WebUI que pode executar num VPS abrange as principais opções.

Há um ponto que deve ficar claro antes de lhe dedicar uma noite. O Octop é software anterior à versão 1.0, publicado a partir da organização GitHub de um fornecedor, com cerca de 900 estrelas em August 2026. O desenvolvimento é rápido, como mostram os números das versões, e nada aqui constitui uma garantia de um processo de atualização estável. Fixe uma tag, leia o changelog e mantenha cópias de segurança.

O que você precisa antes de começar

  • Uma VPS com Ubuntu 24.04, Docker Engine e o plugin Compose. Não conhece o Compose? Comece por conceitos básicos do Docker Compose para uma VPS.
  • git, porque você vai obter uma tag de release em vez de baixar uma imagem.
  • Um nome de domínio apontado para a VPS, porque você quer TLS (transport layer security) na frente deste serviço.
  • Um backend de modelo compatível com a API da OpenAI: um Ollama local, um gateway auto-hospedado ou uma chave paga.

O Octop é leve. É um processo Python e um ficheiro SQLite. O peso está no backend do modelo. Se você pretende executar o modelo no mesmo servidor, dimensione o servidor para o modelo.

Por que não recomendamos o instalador via curl

O README começa com uma instalação de uma linha:

curl -fsSL https://finnie-1258344699.cos.ap-guangzhou.myqcloud.com/octop/install.sh | bash

Não recomendamos este método num servidor importante, por um motivo concreto: esse script não está no repositório. Ele é servido a partir de um bucket do Tencent Cloud Object Storage. Nada relacionado a ele é coberto por uma tag ou por um commit do git. Portanto, não é possível comparar o script de hoje com o da semana passada, e não existe um histórico que explique uma alteração. O bucket pode servir bytes diferentes amanhã, sem que nada no projeto registe essa mudança. Encaminhar diretamente o resultado para bash também faz com que a máquina execute o script antes de você ler qualquer linha dele.

O instalador também grava dados no host, em vez de usar um container. Ele usa uv para obter o Python 3.12 e criar um ambiente que o seu gestor de pacotes desconhece. Por isso, removê-lo mais tarde exige um procedimento manual.

Há duas opções melhores. Obtenha o script, leia-o e depois execute-o. Isso demora trinta segundos: curl -fsSL <url> -o install.sh, depois less install.sh e, por fim, bash install.sh. Ou use Docker, que é o restante deste guia. O pacote PyPI (pip install octop) é pelo menos um artefacto versionado que você pode fixar numa release.

Implantar o Octop com Docker Compose, fixado na v0.9.19

Não existe uma imagem publicada para obter em agosto de 2026. O ficheiro Compose fornecido cria a imagem a partir do repositório. Por isso, fixar uma versão significa fazer checkout de uma tag git.

git clone https://github.com/TencentCloud/Octop.git
cd Octop
git checkout v0.9.19

Este é o serviço definido pelo ficheiro, reduzido às 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 o bloco build:. image: octop:latest é o nome da build local, não uma referência de registry. Portanto, latest aqui significa o que foi compilado mais recentemente. Defina explicitamente o caminho dos dados, em vez de o deixar ao valor predefinido. Defina também uma palavra-passe real para a conta de administrador antes do primeiro arranque. Coloque isto em docker/.env:

OCTOP_PORT=8088
OCTOP_ADMIN_USERNAME=admin
OCTOP_DEFAULT_PASSWORD=<a long random password>
OCTOP_DATA=/srv/octop-data

Há uma armadilha importante neste ficheiro. O Compose lê docker/.env apenas para interpolar os marcadores ${...} no YAML. Uma chave adicionada a esse ficheiro não chega ao contentor, a menos que também esteja listada em environment: no ficheiro Compose. Adicionar OCTOP_ACCESS_TOKEN_TTL apenas a .env não produz efeito algum, silenciosamente. A alternativa é escrever as mesmas chaves em ~/.octop/env dentro do diretório de dados montado. O Octop carrega esse ficheiro no arranque. O guia sobre ficheiros de ambiente e secrets no Docker Compose explica por que estes dois mecanismos não são equivalentes.

Crie e inicie o serviço:

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/health

Uma instância saudável responde à verificação de estado com {"status":"ok","version":"..."}. Se devolver qualquer outra coisa, consulte docker compose -f docker/docker-compose.yml logs -f octop antes de abrir o browser.

Agora atribua um nome significativo à imagem que acabou de criar, porque o próximo --build vai substituir octop:latest e deixará de ser possível distinguir as duas:

docker image tag octop:latest octop:0.9.19

No primeiro arranque, é executado octop init e as credenciais iniciais são gravadas no volume de dados:

docker exec -it octop cat /data/.octop/credential.txt

Os valores predefinidos são admin / octop e são aplicados apenas na primeira inicialização. É por isso que surge uma pergunta frequente: alterar OCTOP_DEFAULT_PASSWORD depois de o contentor já ter iniciado uma vez não produz efeito, porque a conta já existe. Altere a palavra-passe no painel de administração.

Não publique a porta 8088

A linha ports: acima associa todas as interfaces da VPS. Assim que o contentor arranca, o dashboard fica disponível na Internet pública em texto simples, com uma palavra-passe predefinida. O valor predefinido de OCTOP_BIND_HOST no Octop é 127.0.0.1; o ficheiro Compose substitui-o por 0.0.0.0 porque o processo tem de aceitar tráfego fora do seu próprio namespace de rede. Essa substituição está correta. É a porta publicada que o expõe.

Edite a linha ports: em docker/docker-compose.yml para que o mapeamento escute apenas na interface de loopback:

    ports:
      - "127.0.0.1:${OCTOP_PORT:-8088}:${OCTOP_PORT:-8088}"

Não tente corrigir isto com um simples ficheiro de substituição. O Compose concatena as listas ports de vários ficheiros em vez de as substituir. Assim, acaba por publicar ambos os mapeamentos, e o segundo falha ao associar-se à porta. Se quiser manter o ficheiro upstream inalterado, use a etiqueta !override na sequência. Essa é a forma documentada de substituir os valores em vez de os acrescentar. A explicação sobre como o Compose combina vários ficheiros apresenta as restantes regras de combinação.

A associação à interface de loopback também resolve um problema que surgiria de outra forma com a firewall. O Docker escreve as regras das portas publicadas na tabela nat, antes das cadeias geridas pelo ufw. Por isso, ufw deny 8088 não impede o acesso a uma porta publicada do contentor. Uma porta associada a 127.0.0.1 nunca pode ser alcançada a partir do exterior, independentemente da configuração do ufw. É por isso que esta é a correção adequada, e não apenas uma alternativa secundária.

Coloque o TLS à frente com um reverse proxy

Caddy é a opção mais simples, porque solicita o certificado através do ACME (ambiente de gestão automática de certificados) por conta própria e faz proxy de WebSockets sem configuração adicional:

octop.example.com {
    reverse_proxy 127.0.0.1:8088
}

nginx exige mais atenção, porque o Octop transmite o chat através de um 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 linha tem uma função. O chat usa WS /agents/{id}/chat/ws, por isso, sem proxy_http_version 1.1 e os dois cabeçalhos de upgrade, o nginx responde à tentativa de upgrade com 400 Bad Request: o dashboard carrega normalmente e cada mensagem enviada fica bloqueada indefinidamente, sem erro na página. proxy_buffering off é importante porque o endpoint de retoma human-in-the-loop devolve text/event-stream, e os SSE (eventos enviados pelo servidor) retidos num buffer do proxy chegam todos de uma vez no fim, em vez de serem transmitidos progressivamente. proxy_read_timeout abrange execuções longas de ferramentas, porque o valor predefinido de 60 segundos interrompe um agente a meio da tarefa e regista upstream timed out (110: Connection timed out).

Como funciona a autenticação JWT atrás do proxy

O Octop autentica com um token bearer, não com um cookie. POST /api/auth/login devolve {access_token, role, user, ...} e as chamadas seguintes transportam Authorization: Bearer <access_token>. Para um reverse proxy, isto é uma vantagem: não há domínio de cookie, nem a flag Secure, nem uma regra SameSite que possa ser configurada incorretamente. Assim, uma sessão que funcionou em http://127.0.0.1:8088 comporta-se da mesma forma em https://octop.example.com.

Vale a pena conhecer duas consequências antes de disponibilizar o serviço a utilizadores reais.

O WebSocket transporta o token no URL. O endpoint é WS /agents/{id}/chat/ws?token=<jwt>, porque o JavaScript do browser não pode definir um cabeçalho Authorization durante o handshake de um WebSocket. O TLS protege esse token durante o transporte. Não o protege dos seus próprios logs: por predefinição, o nginx escreve a linha de pedido completa, incluindo a query string, em access_log. Assim, um token válido de um utilizador real acaba num ficheiro de texto simples no servidor. Registe o caminho sem os argumentos. $uri é o caminho normalizado, já sem a query string. Coloque isto no bloco http e faça referência a ele a partir do server:

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;

Não existe logout por sessão. OCTOP_ACCESS_TOKEN_TTL usa 86400 por predefinição, pelo que um token permanece válido durante 24 horas após o login. A única forma documentada de invalidar um token é octop admin rotate-jwt-secret. Esse comando roda a chave de assinatura armazenada em ~/.octop/secrets/jwt_secret e invalida imediatamente todos os tokens ainda válidos, para todos os utilizadores. Assim, quando alguém sair da equipa, a ordem é: eliminar o utilizador, rodar o segredo e pedir aos restantes utilizadores que iniciem sessão novamente. Se isso for demasiado pesado, reduza o tempo de vida. Lembre-se de adicionar também a variável à lista environment:, além de .env:

OCTOP_ACCESS_TOKEN_TTL=28800

A proteção contra brute force já está incluída: OCTOP_LOGIN_MAX_ATTEMPTS permite 5 falhas por predefinição e OCTOP_LOGIN_LOCKOUT_SECONDS usa 900. Por isso, um utilizador bloqueado está simplesmente a aguardar quinze minutos, em vez de assumir que a instalação está avariada. O Octop tem o seu próprio armazenamento de utilizadores e não tem suporte OIDC documentado na versão v0.9.19. Se precisar de single sign-on verdadeiro, coloque um proxy de autenticação à frente dele. É essa a finalidade de um servidor Authentik autoalojado.

Indicar um backend de modelo ao Octop

Os provedores são configurados por agente no dashboard, e octop provider list mostra o que está definido. O Octop inclui predefinições para APIs compatíveis com OpenAI, DashScope (Qwen) e Ollama. As credenciais são armazenadas na tabela providers da sua própria base de dados SQLite. A escolha altera o que paga e o que sai do servidor.

Um modelo local com Ollama. Nada sai do servidor, e o custo é em RAM em vez de tokens. O detalhe de ligação que causa problemas: um container não consegue aceder ao Ollama do host em 127.0.0.1:11434, porque esse endereço é o loopback do próprio container. Adicione uma entrada de gateway do host ao serviço:

    extra_hosts:
      - "host.docker.internal:host-gateway"

Depois, defina o URL base do provedor como http://host.docker.internal:11434/v1, que é o caminho compatível com OpenAI do Ollama, e introduza qualquer string não vazia no campo da API key. O Ollama ignora esse valor, mas os clientes OpenAI recusam-se a enviar uma chave vazia. O Ollama também tem de escutar além do loopback para isto funcionar, o que significa OLLAMA_HOST=0.0.0.0:11434 na unidade systemd. Essa é a parte arriscada: o Ollama não tem autenticação. Portanto, uma porta 11434 aberta num IP público transforma o servidor num servidor de modelos gratuito para quem o encontrar primeiro. Permita apenas o intervalo privado do Docker, sudo ufw allow from 172.16.0.0/12 to any port 11434 proto tcp, e bloqueie o restante. Executar o Ollama numa VPS aborda o dimensionamento do modelo, e a comparação entre Ollama e vLLM explica quando o Ollama deixa de ser o servidor adequado.

Mais um aviso sobre modelos locais, porque isto parece um bug no Octop, mas não é. Os agentes funcionam através da chamada de ferramentas, e o prompt do sistema, as definições das ferramentas e o histórico formam um prompt grande. O Ollama disponibiliza os modelos com uma janela de contexto predefinida modesta. Assim, o início do prompt, onde ficam as definições das ferramentas, sai da janela. O modelo deixa então de chamar ferramentas ou inventa ferramentas que não existem. Aumente num_ctx para 16k ou 32k e escolha um modelo que seja realmente bom a chamar funções.

Um gateway autoalojado. Coloque um gateway LiteLLM autoalojado entre o Octop e todos os restantes serviços. Assim, terá um único URL base, uma key separada por utilizador, limites de gastos e um único log. Também pode trocar o modelo por trás do gateway sem editar nada no Octop.

Uma API paga. É a opção com melhor qualidade, mas com uma contrapartida clara: o conteúdo das conversas sai do seu servidor e chega ao provedor. Isso corresponde a grande parte do motivo para usar self-hosting. A key é definida em docker/.env como OPENAI_API_KEY, e o ficheiro Compose já a transmite.

Independentemente da escolha, o ficheiro Compose também transporta OCTOP_LANGFUSE_ENABLED, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY e LANGFUSE_BASE_URL. Assim, pode enviar traces para a sua própria instância do Langfuse e ver o que os agentes estão realmente a fazer, em vez de tentar adivinhar a partir da janela de chat.

Usuários, funções e a biblioteca compartilhada de agentes

A conta de administrador criada na primeira inicialização cria e gere as restantes. Cada usuário tem os seus próprios agentes, espaço de trabalho e credenciais. Esse isolamento é transportado pelo token mantido pelo navegador. Além disso, existe um conjunto compartilhado de habilidades e subagentes que qualquer pessoa pode usar. Esse é o recurso que torna a execução útil para uma família: uma pessoa cria um bom agente de pesquisa uma vez, e as outras não precisam recriá-lo.

Tenha cuidado com as ferramentas. O Octop anuncia aprovação de ferramentas e proteções para comandos shell, e ambas existem. No entanto, um agente que executa comandos shell executa-os dentro do contêiner do Octop, com o seu volume de dados montado. As proteções reduzem o que um prompt descuidado pode fazer. Elas não constituem uma barreira de sandbox. Portanto, mantenha a aprovação de ferramentas ativada para qualquer pessoa a quem você não entregaria acesso a um shell. Se estiver comparando esta opção com outras, o comparativo de agentes de IA auto-hospedados explica como cada uma lida com isso.

Atualizar um projeto que lança versões a este ritmo

ChartDays between Octop releases, v0.9.16 to v0.9.19 (repository tags, 7 August 2026)
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 são as datas das tags do repositório, contabilizadas até 7 de agosto de 2026. 4 versões com tag foram lançadas em nove dias, com um intervalo mínimo de 1 dia, e v0.9.19 chegou 3 dias depois da tag anterior. Este ritmo é um bom sinal sobre o projeto e um mau motivo para executar latest. Leia as alterações antes de as aplicar:

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"

Faça sempre uma cópia de segurança primeiro, porque as migrações da base de dados são executadas no arranque e uma migração falhada num projeto anterior à versão 1.0 é um problema que terá de resolver:

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 start

Depois, faça checkout da nova tag e volte a compilar com docker compose -f docker/docker-compose.yml up -d --build. Se algo correr mal, fazer checkout da tag anterior e voltar a compilar repõe o código, mas só o tarball repõe a base de dados.

Esse tarball contém octop.db, config.json, o segredo de assinatura JWT e credential.txt, pelo que é tão sensível como o próprio servidor. Mantenha-o com o modo 600 e guarde uma cópia fora do servidor. Numa instalação maior, o projeto também fornece docker/docker-compose.postgres.yml, que executa PostgreSQL com pgvector em vez de SQLite.

Modos de falha e as mensagens que verá

A verificação de saúde nunca responde. curl http://127.0.0.1:8088/api/health bloqueia ou recusa a ligação. Consulte docker compose -f docker/docker-compose.yml logs -f octop. Um contentor que termina durante a inicialização inicial normalmente não consegue escrever no diretório de dados. Verifique a propriedade do diretório definido em OCTOP_DATA.

O dashboard carrega, mas o chat bloqueia. Não aparece nenhum erro na página e nunca há resposta. Abra a consola do navegador e procure uma ligação falhada a wss://octop.example.com/agents/.../chat/ws. O proxy não está a encaminhar a atualização da ligação. Adicione os cabeçalhos proxy_http_version 1.1 e Upgrade e Connection.

A resposta inteira aparece de uma vez, vários segundos depois. O streaming funciona, mas o buffering está ativo. Defina proxy_buffering off.

bind: address already in use. Algo já está a usar a porta 8088. sudo ss -tlnp | grep 8088 identifica o processo. Isto também acontece quando adiciona uma segunda entrada ports num ficheiro de override em vez de editar a entrada original.

A palavra-passe correta é rejeitada. Cinco tentativas incorretas ativam um bloqueio de 900 segundos. Aguarde o fim do bloqueio em vez de reinstalar.

A nova palavra-passe em .env não teve efeito. Essas credenciais só se aplicam durante a inicialização inicial. Altere a palavra-passe no dashboard.

O agente responde, mas nunca executa uma ferramenta. Quase sempre é um problema do modelo local: a janela de contexto é demasiado pequena para as definições das ferramentas ou o modelo tem pouca capacidade para chamadas de funções. Aumente num_ctx e experimente um modelo concebido para utilizar ferramentas.

FAQ

O Octop substitui o Open WebUI?

Apenas se precisar do que ele acrescenta. O Open WebUI é uma interface de chat para um modelo e cumpre bem essa função para uma pessoa ou para uma família de confiança. O Octop acrescenta contas com uma função de administrador, áreas de trabalho e credenciais por utilizador, além de uma biblioteca selecionável de agentes especializados. Assim, várias pessoas podem partilhar um servidor sem partilharem o mesmo histórico. Se uma única conta for suficiente, o Open WebUI é a opção mais simples e muito mais madura.

Por que não devo usar o script de instalação curl do Octop?

O script é disponibilizado a partir de um bucket do Tencent Cloud Object Storage, e não do repositório. Por isso, não é abrangido por qualquer tag ou commit do git. Não pode comparar o que ele faz hoje com o que fazia na semana passada, e ao encaminhá-lo para bash ele é executado antes de o ler. O script também instala o Octop no host com o seu próprio ambiente Python 3.12, fora do gestor de pacotes. Transfira-o e leia-o primeiro, ou faça a implementação com Docker Compose a partir de uma tag obtida do repositório.

O Octop pode usar um modelo local em vez de uma API paga?

Sim. O Octop usa APIs compatíveis com OpenAI e inclui uma predefinição para Ollama. Por isso, apontá-lo para http://host.docker.internal:11434/v1 funciona depois de adicionar extra_hosts: ["host.docker.internal:host-gateway"] ao contentor e definir OLLAMA_HOST=0.0.0.0:11434 no host. Restrinja a porta 11434 ao intervalo de endereços do Docker na firewall, porque o Ollama não tem autenticação própria. Conte com a necessidade de aumentar num_ctx do Ollama para 16k ou mais, porque os prompts dos agentes com definições de ferramentas excedem a janela de contexto predefinida. Nesse caso, o modelo deixa de chamar as ferramentas.

Preciso de um reverse proxy ou posso abrir a porta 8088?

Precisa do proxy. O ficheiro Compose fornecido pelo Octop publica a porta 8088 em todas as interfaces, sem TLS. Assim, as palavras-passe e os bearer tokens atravessariam a Internet em texto simples. Altere a porta publicada para 127.0.0.1:8088:8088 e coloque o Caddy ou o nginx à frente, com um certificado. Com nginx, encaminhe os cabeçalhos de upgrade do WebSocket e defina proxy_buffering off. Caso contrário, a página será carregada, mas o chat nunca responderá e o problema poderá não ser evidente.

O Octop está pronto para produção?

O Octop ainda está antes da versão 1.0 e, em agosto de 2026, disponibilizava várias releases etiquetadas por semana. Por isso, considere-o promissor, mas ainda não estabilizado. Pode ser uma opção adequada para uma família ou uma pequena equipa interna se fixar uma tag exata, ler o log de commits antes de cada atualização e fazer uma cópia de segurança do volume de dados antes de cada reconstrução. Não o execute em latest e não armazene nele dados de clientes por enquanto.