Como hospedar o sandboxd no seu próprio VPS
Veja como instalar o sandboxd com versão fixada, configurar chaves de modelo e HTTPS, além dos mínimos de RAM e disco e da limpeza de sandboxes antigas.
O que é o sandboxd e o que obtém ao executá-lo por conta própria
Para alojar o sandboxd por conta própria, precisa de um servidor Linux com Docker e de um nome de domínio. Envia um prompt, um agente de programação cria uma aplicação real dentro de um contentor isolado e essa aplicação fica disponível no seu próprio URL de pré-visualização. Os construtores de aplicações a partir de prompts são a categoria alojada mais visível de 2026, e o sandboxd é a opção que corre no seu VPS, sob a licença MIT, com o código gerado armazenado no seu próprio disco.
A arquitetura é pequena de propósito. Um plano de controlo Go controla o Docker, o Traefik v3 encaminha cada hostname de pré-visualização, o SQLite armazena o estado e cada aplicação corre dentro de um contentor. Não existe Kubernetes nem um servidor de base de dados separado. Por isso, uma máquina com 2 vCPU consegue executá-lo.
Quatro objetos representam todo o modelo. Uma app é o projeto persistente. Contém o nome, os metadados do git e os segredos. Uma sandbox é o contentor Docker onde essa app corre, e uma app aponta para uma sandbox de cada vez. Um workspace são os ficheiros da app. Estes ficam no host e persistem depois de o contentor terminar. Uma task é um prompt enviado ao agente dentro da sandbox. Parar uma sandbox liberta memória e preserva os ficheiros. Destruí-la elimina o contentor, e a app pode iniciar uma nova sandbox.
Como o sandboxd difere do Dify e do OpenHands?
Estes três projetos são frequentemente confundidos porque todos executam um LLM (modelo de linguagem de grande escala) no seu servidor, mas produzem resultados diferentes. O Dify cria aplicações com LLM: interfaces de chat, pipelines de recuperação e workflows que chamam um modelo sempre que alguém os utiliza. O modelo faz parte do produto final. O OpenHands trabalha num repositório que já existe: indique-lhe o seu código e ele lê ficheiros, executa comandos e propõe alterações. O sandboxd começa do zero. Cria a estrutura de um projeto a partir de um preset, compila-o num contentor novo e fornece um URL para o consultar. O resultado é uma aplicação React ou FastAPI comum que não precisa de um modelo para funcionar.
Por isso, escolha com base no resultado que pretende obter. O sandboxd serve para começar com uma frase e manter o código depois. Os outros dois servem para situações em que o repositório ou o produto baseado em modelos já existe.
A outra diferença é a idade. É o fator que deve ponderar antes de criar algo real com base nele.
Os dados por trás deste gráfico
[
{
"tool": "sandboxd",
"github_stars": "875",
"forks": "50"
},
{
"tool": "OpenHands",
"github_stars": "83,091",
"forks": "10,711"
},
{
"tool": "Dify",
"github_stars": "151,320",
"forks": "23,886"
}
]O sandboxd tem 875 estrelas, contra 83,091 do OpenHands e 151,320 do Dify. O repositório foi criado em 3 de junho de 2026, por isso tinha dois meses em agosto de 2026. O OpenHands data de março de 2024 e o Dify de abril de 2023. A release v0.1.0 foi lançada em 6 de junho de 2026 e a v0.3.6 em 1 de agosto de 2026. O projeto identifica-se como beta e informa que as releases 0.x podem quebrar a compatibilidade. Interprete estes números como um indicador de risco das dependências, não como uma avaliação da qualidade: um projeto com dois meses de existência só teve dois meses para que outras pessoas encontrassem os seus bugs.
O que o servidor precisa e o que falha quando faltam recursos
O projeto indica 2 vCPU e 4 GB de RAM como suficientes para começar. Isso é correto para o plano de controlo e uma sandbox pequena, mas não é suficiente para duas pessoas compilarem ao mesmo tempo. Distribua a memória por componentes. O Traefik e o plano de controlo em Go consomem poucos recursos. Cada sandbox em execução inclui uma toolchain completa de Node ou Python, e o pico ocorre durante um npm install seguido de uma compilação de produção. Planeie 8 GB para um servidor que manterá algumas aplicações ativas. Considere a swap uma rede de segurança, não capacidade adicional, porque uma compilação que usa swap demora minutos em vez de segundos.
Quando a memória se esgota, ocorrem duas falhas diferentes, que têm comportamentos completamente distintos. Dentro de uma sandbox, o contentor atinge o limite rígido de --memory definido pelo sandboxd e o kernel termina o processo maior. A compilação falha sem uma mensagem útil do agente. docker ps -a mostra o código de saída 137 desse contentor e docker inspect apresenta "OOMKilled": true. Uma compilação de Node que falha dessa forma costuma apresentar JavaScript heap out of memory primeiro.
A segunda falha ocorre no host. O sandboxd executa um processo de recuperação sob pressão que para as sandboxes quando a memória do host fica reduzida. Num servidor pequeno, uma sandbox pode desaparecer enquanto observa a respetiva pré-visualização. Os ficheiros permanecem seguros e o pedido seguinte ao URL de pré-visualização volta a iniciá-la, mas uma tarefa que estava em execução quando o contentor parou não é retomada.
O disco é o problema mais silencioso. Cada aplicação mantém o seu próprio workspace no host, e um projeto JavaScript inclui uma árvore node_modules com centenas de megabytes. Dez aplicações ocupam vários gigabytes com dependências, sem contar as imagens. Comece com 40 GB e monitorize:
docker system df
sudo du -sh /var/lib/sandboxed/workspacesNa v0.3.6, a versão fixada neste guia, o diretório de dados predefinido é /var/lib/sandboxed, escrito com o e adicional. Executar /var/lib/sandboxd nesse local não produz resultados e pode levar a cinco minutos de diagnóstico confuso. Isto mudou na v0.3.9 (25 August 2026). Os instaladores mais recentes colocam as instalações novas em /var/lib/sandboxd e mantêm /var/lib/sandboxed apenas para uma instalação que já esteja nesse local. Num servidor configurado pela primeira vez com uma versão posterior, use o caminho sem o e em todos os comandos abaixo.
Instalar uma versão fixada do sandboxd
O Docker Engine com o plugin Compose, além do git, tem de estar instalado no sistema. Instalar o Docker numa VPS explica essa parte.
docker compose version
git --versionAmbos têm de imprimir uma versão. docker: 'compose' is not a docker command significa que o plugin Compose v2 está em falta. O instalador prefere o plugin, mas recorre a um binário docker-compose autónomo se existir um instalado. O instalador só termina com Docker Compose not found quando nenhum dos dois está disponível. Os comandos deste guia usam docker compose, por isso instalar o plugin é a correção mais simples.
O instalador é um script shell obtido através da rede. Leia-o antes de o executar e fixe a versão.
curl -fsSL https://raw.githubusercontent.com/tastyeffectco/sandboxd/v0.3.6/install.sh -o install-sandboxd.sh
less install-sandboxd.sh
SANDBOXD_REF=v0.3.6 bash install-sandboxd.shSANDBOXD_REF é a referência git que o instalador obtém em $HOME/.sandboxd/src. Por predefinição, usa main. Se a deixar indefinida, a instalação corresponde ao que tiver sido integrado nessa manhã. Isto é relevante num projeto que lançou seis versões apenas em julho de 2026. Fixe a versão e atualize-a deliberadamente depois de ler o changelog. Em 12 de outubro de 2026, a versão mais recente é a v0.3.22, dezasseis versões depois da v0.3.6 fixada aqui.
O script clona o código-fonte, cria as imagens, inicia a stack com docker compose up -d e imprime no fim o URL da consola e um token de API. Guarde esse token num local seguro. É a credencial de uma API que controla o Docker como root.
curl http://127.0.0.1:9090/healthzIsto imprime ok quando o plano de controlo está ativo. Se não imprimir nada, a stack não iniciou: execute docker compose ps a partir de ~/.sandboxd/src para ver qual o serviço que está parado. Em seguida, execute docker compose logs sandboxd para saber porquê.
Aceder à consola num servidor remoto
A consola é disponibilizada através do Traefik em HTTP_PORT, que por predefinição é 80, no hostname http://console.localhost. O Traefik encaminha as ligações com base no hostname. Por isso, introduzir o endereço IP do servidor no browser não corresponde a nenhuma regra e devolve 404. Até configurar um domínio real, encaminhe a porta e mantenha o hostname:
ssh -L 8080:127.0.0.1:80 you@your-vpsEm seguida, abra http://console.localhost:8080 no portátil. No Linux e no macOS, qualquer nome terminado em .localhost é resolvido para 127.0.0.1. Assim, o pedido segue pelo túnel com o cabeçalho Host correto. Defina a palavra-passe da consola no primeiro acesso.
Dê um modelo ao agente
A imagem base inclui dois agentes de codificação: OpenCode e Claude Code. SANDBOXD_DEFAULT_AGENT decide qual deles executa uma tarefa que não especifica um agente, e o padrão é opencode. Sem nenhuma chave configurada, as tarefas usam os modelos gratuitos sem chave do OpenCode Zen. Assim, a primeira build não tem custo e pode testar todo o ciclo antes de gastar.
Ligue a sua própria chave quando quiser um modelo mais potente. As chaves vão para o plano de controlo, nunca para a sandbox. São armazenadas de forma encriptada no diretório de dados e injetadas na rede por um proxy de credenciais. Assim, nem o agente nem o código que este escreve podem lê-las.
export API=http://127.0.0.1:9090
export SANDBOXD_TOKEN=sk_... # printed by the installer
export AUTH="Authorization: Bearer $SANDBOXD_TOKEN"
curl -s -XPOST $API/v1/agents/claude-code/api-key -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"api_key":"sk-ant-..."}'A consola faz o mesmo em Settings, AI Agents, incluindo um fluxo OAuth guiado se quiser usar uma subscrição Claude em vez de uma chave de API. O modelo predefinido de cada agente fica no mesmo painel, e uma tarefa individual pode substituí-lo.
Crie uma aplicação pequena de ponta a ponta
Crie a aplicação, inicialize o sandbox e envie um prompt. Os IDs são devolvidos como JSON, e o quickstart extrai-os com sed, portanto não é necessário ter jq instalado.
APP=$(curl -s -XPOST $API/v1/apps -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"name":"todo","runtime_preset":"react-vite"}' \
| sed -E 's/.*"id":"([^"]+)".*/\1/')
SB=$(curl -s -XPOST $API/v1/apps/$APP/sandbox -H "$AUTH" \
-H 'content-type: application/json' -d '{"ports":[3000]}' \
| sed -E 's/.*"id":"([^"]+)".*/\1/')
echo "app=$APP sandbox=$SB"As duas variáveis devem conter um ID. Um $SB vazio significa que o sandbox nunca foi inicializado. A causa habitual é a imagem base ainda estar a ser criada ou o host estar sem memória. Um 401 no lugar de um ID significa que o bearer token está incorreto.
curl -s -XPOST $API/v1/sandboxes/$SB/tasks -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"prompt":"Add a todo list with a text input, an add button, and a delete button on each row. Keep the list in localStorage.","agent":"opencode"}'A resposta contém um ID de tarefa. GET /v1/sandboxes/$SB/tasks/<task id> devolve o resultado, e o caminho /events na mesma tarefa é um fluxo SSE (eventos enviados pelo servidor) em tempo real do que o agente está a fazer. A consola mostra o mesmo fluxo como uma conversa.
A aplicação fica disponível em http://s-<sandbox id>-3000.preview.localhost, onde 3000 é a porta solicitada. Se o sandbox estiver adormecido, o primeiro pedido chega ao catch-all do Traefik. O sandboxd inicia o contentor, aguarda até a porta responder e apresenta uma página curta de inicialização que é atualizada para a aplicação. Uma pré-visualização que nunca abandona essa página significa que o processo dentro do contentor não está a escutar na porta declarada no sandbox.yaml da aplicação.
Coloque as pré-visualizações num domínio real com HTTPS
Cada sandbox recebe o seu próprio hostname, por isso um único registo DNS wildcard abrange todos eles. Aponte *.preview.yourdomain.com para o endereço IP do servidor com um registo A. Depois, defina as variáveis das pré-visualizações em .env dentro de ~/.sandboxd/src:
PREVIEW_DOMAIN=yourdomain.com
PREVIEW_ENTRYPOINT=websecure
PREVIEW_TLS=true
SANDBOXD_API_AUTH_DISABLED=falseO Traefik precisa da parte correspondente: ative o entrypoint websecure em traefik/traefik.yml e adicione um resolver de certificados. Use o desafio DNS-01, porque um único certificado wildcard abrange todos os hostnames das pré-visualizações. Com HTTP-01, cada sandbox nova precisaria da sua própria emissão, e uma tarde movimentada de builds atingiria rapidamente os limites de taxa do Let's Encrypt. Certificados wildcard através do desafio DNS-01 explica a configuração do DNS.
cd ~/.sandboxd/src
docker compose up -dOs URLs das pré-visualizações passam a ser https://s-<id>-3000.preview.yourdomain.com. Abra as portas 80 e 443 na firewall e mantenha a porta 9090 fechada para a Internet: consulte regras básicas da firewall ufw. Lembre-se de que qualquer pessoa que consiga adivinhar um hostname de pré-visualização pode carregar a aplicação. Trate as pré-visualizações como públicas.
Se preferir ignorar completamente o domínio, o DNS e os certificados, os responsáveis pelo projeto disponibilizam agora o sandboxd Cloud. Este serviço fornece ao seu servidor um endereço HTTPS público em sandboxd.io por 9.99 dólares por servidor e por mês, ou 4.99 com o desconto de lançamento, em outubro de 2026. Confirme qual release é necessário antes de depender do serviço, fixando a versão v0.3.6.
Onde fica o código gerado e é possível exportá-lo?
No host, dentro do diretório de dados. Cada workspace é um diretório comum em /var/lib/sandboxed/workspaces/<id>/ numa instalação v0.3.6, montado por bind no container, e os ficheiros da aplicação ficam em /home/sandbox/workspace/app dentro do sandbox. O estado do control plane está num único ficheiro SQLite em state/sandboxd.db, e as credenciais encriptadas do agente estão em agent-auth/. Nada fica oculto numa camada do container. Por isso, uma cópia de segurança consiste em copiar o diretório e esse ficheiro de base de dados. cópias de segurança restic num VPS trata dos dois.
sudo ls /var/lib/sandboxed/workspaces
sudo du -sh /var/lib/sandboxed/workspaces/*A exportação para Git está integrada, em vez de ser acrescentada posteriormente. A API disponibiliza o estado e o diff para leitura, seguidos de commit e push:
curl -s $API/v1/apps/$APP/git/status -H "$AUTH"
curl -s -XPOST $API/v1/apps/$APP/git/commit -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"message":"todo list, first pass"}'
curl -s -XPOST $API/v1/apps/$APP/git/push -H "$AUTH" \
-H 'content-type: application/json' -d '{"branch":"todo-first-pass"}'O push é sempre feito para uma branch nova. Se omitir branch, o valor predefinido é sandboxd/<slug>-<shortsha>. main, master e a branch de origem da importação são rejeitados. Faça o merge no lado remoto.
Um remote privado precisa de um personal access token, configurado uma vez na consola, em Settings, Git credentials. O token é armazenado de forma encriptada e fica fora do sandbox. Assim, o agente não o pode ler nem fazer push com ele sem o seu conhecimento. Faça push cedo e com frequência. Até isso acontecer, o diretório do workspace é a única cópia do código, e DELETE /v1/apps/<id> elimina-o sem possibilidade de recuperação.
Qual é o custo de uma compilação em tokens do modelo?
O sandboxd não mede os seus gastos. Por isso, o número relevante está no console do seu provedor. Os modelos gratuitos do OpenCode Zen não têm custo. São mais lentos e menos eficientes do que um modelo pago. Isso aparece como mais rodadas de correção em qualquer aplicação que ultrapasse um protótipo simples.
O formato da cobrança acompanha o funcionamento de um loop de agente. A cada turno, o contexto necessário é enviado novamente. Por isso, o custo acompanha o número de turnos, não o número de aplicações. Um prompt que funciona à primeira é barato. Quinze rodadas de "agora corrija o espaçamento" num projeto com cinquenta ficheiros não são baratas, porque o conteúdo dos ficheiros é enviado novamente a cada turno. Os tokens de entrada e de saída têm preços diferentes, e o custo de um agente de programação por sessão apresenta um intervalo realista. Defina um limite máximo de gastos no provedor antes de entregar as credenciais a um loop executado sem supervisão.
Limpando sandboxes obsoletos
O mecanismo de remoção de inativos interrompe qualquer sandbox que esteja inativo por mais de SANDBOXD_IDLE_THRESHOLD_SECONDS, cujo valor padrão é 2100 segundos, ou 35 minutos. Isso libera a RAM e mantém os ficheiros. O próximo pedido à URL de pré-visualização reativa o contentor. Reduza esse valor num servidor pequeno, porque 35 minutos de contentores inativos representam 35 minutos de memória que não pode utilizar.
Interromper não é eliminar, e é assim que os discos ficam cheios sem chamar atenção. Um sandbox interrompido ainda mantém o seu workspace e o seu contentor. Remover o sandbox, mas manter a aplicação, é um DELETE no sandbox. Essa operação remove o contentor e o workspace. Remover a aplicação elimina tudo permanentemente.
curl -s -XPOST $API/v1/sandboxes/$SB/stop -H "$AUTH" # frees RAM, keeps files
curl -s -XDELETE $API/v1/sandboxes/$SB -H "$AUTH" # container and workspace gone
curl -s -XDELETE $API/v1/apps/$APP -H "$AUTH" # app and everything under itDepois de algumas semanas de experiências, docker system df mostrará mais espaço de imagens recuperável do que espera, porque cada aplicação que obteve o seu próprio toolchain deixou camadas para trás. docker image prune limpa as camadas sem referência. Verifique GET /v1/apps primeiro, porque uma imagem ainda referenciada por um sandbox em espera não é lixo.
O que o limite do contentor oferece e o que não oferece
Cada sandbox é executada com um utilizador sem privilégios, um sistema de ficheiros raiz apenas de leitura, todas as capacidades Linux removidas, no-new-privileges definido, um limite de memória e um limite de processos. O projeto é claro quanto a essa limitação: um contentor Linux com kernel partilhado oferece um limite de isolamento forte, mas um limite de segurança fraco. Uma vulnerabilidade no kernel pode comprometer o host.
Dois factos exigem ação. A saída de rede de uma sandbox está aberta na compilação self-hosted, pelo que o código gerado pode aceder à Internet, à sua rede local e aos endpoints de metadados da cloud. Existe um subsistema de saída nftables no código-fonte, mas está desativado na compilação portátil do Docker Compose. Por isso, os limites têm de ser impostos pela firewall do host. Além disso, a API do plano de controlo equivale efetivamente a root no host, porque controla o socket do Docker. Por predefinição, liga-se a 127.0.0.1:9090, SANDBOXD_API_AUTH_DISABLED tem de permanecer false e nunca deve ser publicada na Internet.
Se pretende permitir que outras pessoas enviem prompts para o seu servidor, esse modelo é demasiado fraco por si só. O projeto aponta para o gVisor com SANDBOXD_RUNTIME=runsc, que coloca um kernel em espaço de utilizador entre a sandbox e o host. Segundo as medições do próprio projeto, isto torna as instalações de pacotes aproximadamente 1.7 vezes mais lentas e o trabalho intensivo em chamadas de sistema aproximadamente 4 vezes mais lento. A opção mais segura é usar uma máquina por tenant, pelo mesmo motivo que executar agentes de programação numa VM descartável.
Deve criar algo com base num projeto com dois meses?
Para uma máquina de desenvolvimento pessoal, sim, com as precauções óbvias: fixe SANDBOXD_REF, faça uma cópia de segurança do diretório de dados (/var/lib/sandboxed no v0.3.6, /var/lib/sandboxd numa instalação nova do v0.3.9 ou posterior) e envie todas as aplicações importantes para um repositório git remoto. Para qualquer aplicação utilizada por clientes, espere pela versão 1.0 ou reserve tempo e orçamento para corrigir problemas, porque os responsáveis afirmam claramente que a versão 0.x pode sofrer alterações incompatíveis. Os responsáveis também comercializam uma instalação gerida, por 199 dólares de configuração e 79 dólares por mês de operação em outubro de 2026. Esta informação é útil para avaliar se o projeto tem motivos para continuar a existir.
O risco é tolerável por causa do resultado. sandboxd produz uma aplicação normal num repositório git normal. Se o projeto ficar parado, conserva o código e perde apenas o wrapper. Esta é uma posição muito melhor do que a de um construtor alojado que controla o seu projeto. Para uma visão mais ampla do que merece um lugar no seu servidor este ano, consulte o que vale a pena alojar por conta própria em 2026.
FAQ
Quais são as especificações mínimas do servidor para o sandboxd?
O projeto indica que 2 vCPU e 4 GB de RAM são suficientes para começar. Isso inclui o plano de controlo, o Traefik e um sandbox pequeno. Use 8 GB e 40 GB de disco se quiser manter várias aplicações ativas ao mesmo tempo, porque cada sandbox em execução contém uma toolchain completa de Node ou Python e cada workspace mantém a sua própria árvore de dependências no disco. Quando o host fica sem memória suficiente, o pressure reaper do sandboxd para sandboxes para libertar memória. Se uma build exceder o limite de memória do seu contentor, o kernel termina o processo: docker ps -a mostra o código de saída 137.
Em que difere o sandboxd do Dify ou do OpenHands?
Produzem artefactos diferentes. O Dify cria aplicações que chamam um modelo durante a execução, como interfaces de chat e pipelines de retrieval. O OpenHands edita um repositório que já existe, executa comandos e propõe alterações ao código existente. O sandboxd cria a estrutura de um projeto novo a partir de um prompt, faz a build dentro do seu próprio contentor e publica-o num URL de preview. O resultado é uma aplicação web normal que não precisa de um modelo para funcionar.
Onde fica efetivamente o código escrito pelo agente?
Fica no sistema de ficheiros do host, não dentro de uma imagem de contentor. Cada aplicação recebe um diretório em /var/lib/sandboxed/workspaces/<id>/ numa instalação v0.3.6 (/var/lib/sandboxd/workspaces/<id>/ numa instalação nova da v0.3.9 ou posterior). Esse diretório é montado como bind mount no respetivo sandbox, e os ficheiros ficam disponíveis em /home/sandbox/workspace/app dentro do sandbox. O estado do plano de controlo é armazenado num único ficheiro SQLite em state/, no mesmo diretório de dados. Pode fazer commit e push para um novo branch num remote git a partir do separador Git da consola ou através dos endpoints /v1/apps/<id>/git/commit e /git/push. Um token para remotes privados é armazenado de forma cifrada pelo plano de controlo, em vez de ser entregue ao sandbox.
É seguro expor o sandboxd à Internet?
Exponha os URLs de preview e a consola, mas nunca a API do plano de controlo. Essa API controla o Docker no host, pelo que equivale a acesso root. Por esse motivo, está ligada a 127.0.0.1:9090 por predefinição. Os sandboxes também têm egress de rede aberto na build self-hosted. Isso significa que o código escrito pelo agente pode aceder à sua rede local e a endpoints de metadados da cloud. Adicione regras de firewall no host se a máquina estiver numa rede com outros sistemas que precisem de proteção. Para prompts enviados por pessoas em quem não confia, use um host por tenant em vez de depender do isolamento do contentor.