Cambia tema

Dev Sandbox self-hosted con Docker e Go: preview URL senza Kubernetes

Easton editorial illustration: code bundle entering an isolated Docker sandbox and exiting through a guarded preview-URL portal

"Il README di sandboxed descrive control plane Go, Docker, Traefik, SQLite, preview URL, idle stop e confini di hardening in produzione."

"La documentazione Docker sulle resource constraints spiega che i container non hanno limiti CPU o memory senza configurazione esplicita."

"La documentazione Docker Sandboxes usa microVM, Docker daemon indipendente, isolamento di rete e isolamento delle credential come modello di sicurezza più forte."

"Il Docker provider di Traefik può leggere la configurazione di routing dai Docker labels e instradare con Host rule verso servizi container."

Aprire un ambiente di preview per ogni PR di solito significa usare Vercel o Netlify. Se però contano di più costo, dati in rete privata o controllo dell’infrastruttura, un singolo host Docker con un control plane Go può coprire la stessa esigenza iniziale. Ogni sandbox ha la propria preview URL, le risorse hanno limiti e il confine di sicurezza è esplicito. Niente Kubernetes, niente multi-node.

Tabella decisionale: quando usare quale opzione

Quando arriva la richiesta di “ambienti di preview self-hosted”, molti pensano subito a script shell pieni di docker run, oppure al salto diretto su Kubernetes. Meglio partire da una tabella decisionale.

ScenarioSoluzione consigliataMotivo
Team interno con meno di 10 preview concorrenti, confine di fiducia dentro il teamDocker su singolo host + control plane GoLa densità di risorse è gestibile, l’architettura resta semplice e non devi gestire un cluster K8s
Team interno con più di 20 preview concorrenti o richiesta di alta disponibilità multi-nodeK8s + isolamento tramite NamespaceUn singolo host non basta; servono scheduling su più node e rolling upgrade
Utenti esterni o esecuzione di codice non fidato, compresi autonomous agentmicroVM, come Docker Sandboxes o FirecrackerDocker socket equivale a potere root sul host e non va mescolato con workload non fidati
Preview statica semplice senza persistenzaShell script + porta casualePuò funzionare, ma la preview URL non è stabile e mancano limiti di risorse e confine di sicurezza

I criteri sono tre.

Dimensione del team: un singolo host è adatto a circa 10 preview interne concorrenti. Stima pratica: 512 MB RAM + 0,5 CPU per sandbox. Un host con 16 GB di memoria può reggere circa 20 sandbox, poi il margine diventa sottile. Oltre questa densità servono scheduling K8s o capacità separata con microVM.

Confine di fiducia: membri del team e utenti fidati possono girare in container Docker. Se utenti esterni o autonomous agent eseguono codice arbitrario, il design con Docker socket non è abbastanza sicuro. Docker Sandboxes usa isolamento microVM: ogni sandbox ha Docker daemon, filesystem e rete propri.

Percorso di upgrade: parti da Docker su singolo host per validare loop di prodotto e densità. Se la concorrenza supera l’host o serve alta disponibilità multi-node, passa a Kubernetes. Se il confine di fiducia passa da “team interno” a “utenti esterni”, passa a microVM.

Il README di tastyeffectco/sandboxes è chiaro: questo modello è pensato per AI app builder, agent platform e coding playground su un singolo Docker host. Non è isolamento da microVM; è un control plane Go che crea container su un Docker host e pubblica preview URL.

Architettura scomposta: i componenti centrali del control plane

Un ambiente di preview Docker single-host non è un semplice docker run ripetuto. Serve un control plane per lifecycle, registrazione delle route e recupero risorse. L’architettura di tastyeffectco/sandboxes si divide in sei moduli.

Control plane Go (sandboxd): gira in un container e monta il Docker socket del host più una directory dati. Gestisce il lifecycle dei sandbox container tramite Docker CLI: create, start, stop, delete. Tutti i metadata delle sandbox finiscono in SQLite come source of truth.

Mount del Docker socket: è l’ingresso del control plane nel Docker daemon. Montando /var/run/docker.sock, sandboxd ottiene il permesso di creare e gestire container. Qui sta anche il confine di privilegi: con il Docker socket, il control plane ha poteri molto elevati sul host.

Registrazione con Traefik labels: quando un sandbox container parte, il control plane inietta la configurazione di routing Traefik tramite Docker labels. Traefik fa da reverse proxy, scopre le route dai labels e inoltra le richieste *.preview.example.com al container corretto.

Storage metadata in SQLite: ogni sandbox ha un ID unico e una directory associata. I metadata vengono salvati in SQLite. I workspace stanno sotto SANDBOXED_DATA_DIR/workspaces/, con una sottodirectory per sandbox per codice sorgente, configurazione e artefatti.

Idle reaper e pressure reaper: l’idle reaper controlla quanto tempo un sandbox container è rimasto inattivo e lo ferma oltre la soglia per liberare RAM. Il pressure reaper osserva la pressione di memoria del host e ferma alcune sandbox prima dell’OOM. Questi due reaper sono il cuore del recupero risorse.

Wake path: dopo che l’idle reaper ferma un sandbox container, la prima visita alla preview URL deve risvegliarlo. Un catch-all di Traefik passa la richiesta al control plane; il control plane avvia il container e restituisce una warming page finché l’app è pronta.

La versione minima utile è: container del control plane Go, mount del Docker socket, Traefik, SQLite e idle reaper. Il quick start locale richiede Docker Engine e il plugin Compose.

Implementazione delle preview URL

Il punto chiave di una preview URL è un dominio stabile, non una porta casuale. Ogni sandbox ha un host indipendente {sandbox_id}.preview.example.com.

Configurazione del Docker provider di Traefik

Traefik può scoprire la configurazione di routing dai labels dei container tramite Docker provider. Configurazione minima:

# traefik.yml
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

exposedByDefault: false significa che Traefik scopre solo container esplicitamente marcati con labels.

Host rule e Docker labels

Il control plane inietta labels quando crea un sandbox container. Esempio:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.sandbox123.rule=Host(`sandbox123.preview.example.com`)"
  - "traefik.http.routers.sandbox123.entrypoints=websecure"
  - "traefik.http.services.sandbox123.loadbalancer.server.port=3000"

La Host rule instrada le richieste per sandbox123.preview.example.com verso quel container. loadbalancer.server.port indica il port interno su cui ascolta l’applicazione.

Percorso wake-on-request

Dopo che l’idle reaper ferma il sandbox container, la prima richiesta alla preview URL attiva il wake flow:

  1. DNS risolve verso Traefik; serve wildcard DNS come *.preview.example.com
  2. Traefik conosce la route della sandbox, ma il container è stopped
  3. Il catch-all di Traefik inoltra la richiesta al wake handler del control plane
  4. Il control plane avvia il sandbox container e restituisce una warming page
  5. Quando il container è ready, Traefik inoltra le richieste successive direttamente al container

Il catch-all deve avere priorità più bassa di tutte le route sandbox:

labels:
  - "traefik.http.routers.catch-all.rule=HostRegexp(`{subdomain:[a-z0-9-]+}.preview.example.com`)"
  - "traefik.http.routers.catch-all.priority=1"
  - "traefik.http.routers.catch-all.service=wake-service"

Le richieste non abbinate a una route sandbox viva cadono sul catch-all, e il control plane gestisce la logica di wake.

Confine di sicurezza: permessi del Docker socket

Montare il Docker socket dà al control plane potere di livello host. È il tradeoff di sicurezza di questa architettura: adatta a team interni e utenti fidati, non a codice non affidabile.

Rischi del Docker socket

La documentazione Docker avverte che il daemon ha una superficie di attacco. Se l’API Docker viene esposta in modo insicuro, un utente remoto non-root può ottenere accesso root al host. Un container con /var/run/docker.sock montato può usare Docker CLI per creare, modificare e cancellare container. Può anche raggiungere filesystem e rete del host attraverso container creati da lui.

Questo significa:

  • Il container del control plane ha permessi molto elevati sul host
  • Non eseguire control plane e workload non fidati sullo stesso host
  • Il codice nei sandbox container può influenzare indirettamente il host se può influenzare il control plane

Limite per scenari non fidati

Docker single-host + control plane Go è adatto a:

  • Ambienti di preview per membri del team interno
  • Coding playground per utenti fidati
  • Ambienti interni di validazione per AI app builder o agent platform

Non è adatto a:

  • Esecuzione di codice arbitrario di utenti esterni sconosciuti
  • Esecuzione production di autonomous agent quando il host non è fidato
  • Piattaforme multi-tenant che richiedono isolamento forte

Se il confine di fiducia passa da “team interno” a “utenti esterni”, passa a Docker Sandboxes ufficiali o a microVM stile Firecracker. Docker Sandboxes include isolamento hypervisor, rete indipendente, Docker daemon indipendente, filesystem indipendente e isolamento delle credential. Ogni sandbox è una microVM completa, non un container che condivide il Docker daemon del host.

Checklist di hardening production

Prima della produzione aggiungi questi confini:

  • Isolamento di rete: control plane e sandbox container girano su reti dedicate, non sulla rete business
  • API authentication: i quick start locali possono essere senza auth; in produzione serve token o altro meccanismo di autenticazione
  • Superficie minima: esponi le preview URL via Traefik, non la porta dell’API Docker
  • TLS: le preview URL devono usare un certificato TLS wildcard, non HTTP in chiaro
  • Logs e monitoring: registra richieste API del control plane ed eventi lifecycle dei container, poi attiva alert

Per confini più forti, confronta gVisor, Firecracker e Kubernetes in un design di sandbox per AI agent.

Limiti di risorse: memory / CPU / PIDs

I container Docker non hanno limiti di risorse di default. Senza limiti, un sandbox container può consumare RAM e CPU del host e impattare altre sandbox e processi host. Un ambiente di preview multi-tenant richiede limiti rigidi per container.

Comportamento predefinito di Docker

La documentazione Docker spiega che i container possono usare le risorse del host secondo quanto consente il kernel scheduler. Senza --memory o --cpus, un container può prendere le risorse host disponibili.

Limite rigido di memory

--memory imposta la memory massima disponibile per il container. Esempio:

docker run --memory="512m" --memory-swap="512m" sandbox-image

--memory-swap imposta il limite combinato di memory + swap. Se --memory-swap è uguale a --memory, il container non usa swap.

Se il container supera il limite memory, l’OOM killer può terminare processi del container. Un OOM a livello host può colpire anche altri container e processi host.

Limite di quota CPU

--cpus imposta quanta capacità CPU può usare un container. Esempio:

docker run --cpus="0.5" sandbox-image

Il container può usare al massimo 0,5 CPU. Con molte sandbox concorrenti, il limite CPU impedisce a un container di occupare tutta la capacità di calcolo.

Limite al numero di processi

--pids-limit aiuta a prevenire fork bomb. Esempio:

docker run --pids-limit=100 sandbox-image

Il container può creare al massimo 100 processi. Dopo, fork() fallisce.

Esempio di configurazione Compose

Con Docker Compose, configura i limiti in deploy.resources.limits:

services:
  sandbox:
    image: sandbox-image
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
          pids: 100

deploy.resources di Compose vale in Docker Swarm mode. Su un host Docker singolo passa --memory, --cpus e --pids-limit manualmente, oppure usa docker-compose --compatibility.

Il control plane dovrebbe iniettare questi parametri quando crea i sandbox container, non dipendere dalla configurazione manuale degli utenti.

Operazioni: image cache e Docker Hub rate limit

Quando molte sandbox vengono create e distrutte spesso, gli image pull diventano un collo di bottiglia. Docker Hub ha pull rate limit e abuse rate limit, con policy che variano in base ad account e piano. In produzione non conviene affidare ogni image pull al Docker Hub pubblico.

Limiti di Docker Hub

La documentazione Docker spiega che utenti anonimi, utenti autenticati e account team hanno policy diverse per i pull. Superato il limite, le richieste vengono rifiutate. I numeri cambiano con le policy: controlla Docker Hub usage and limits invece di fissarli nel testo.

In scenari multi-sandbox questo pesa perché:

  • La creazione frequente di sandbox può tirare un’immagine a ogni avvio
  • Dopo uno stop dell’idle reaper, il riavvio può richiedere di nuovo l’immagine
  • Più sandbox possono tirare ripetutamente la stessa immagine

Image pre-warming e strategia di cache

In produzione servono alcune contromisure.

Image pre-warming: scarica le immagini comuni sul host prima di avviare il control plane. Riduci l’attesa all’avvio della sandbox.

Registry privato: spingi le immagini comuni in un registry privato, come Harbor, AWS ECR o Google Artifact Registry. Il control plane tira da lì invece che da Docker Hub.

Login Docker Hub: se devi tirare da Docker Hub, usa un account autenticato per ottenere il pull allowance adatto. Docker consiglia il login in produzione invece dei pull anonimi.

Image cache: il Docker daemon mette già in cache i layer scaricati. Se i sandbox container vengono cancellati e ricreati spesso, evita che i job di cleanup rimuovano layer utili in modo troppo aggressivo.

Accelerazione di registry interno

Se il host sta in una rete privata, configura registry mirror o proxy per i timeout di Docker pull. Trattalo come parte della piattaforma, non come un intervento dopo il primo outage.

Checklist di troubleshooting: preview URL non raggiungibile

Quando una preview URL non si apre, controlla questi cinque punti in ordine.

1. Il DNS punta a Traefik?

Verifica il wildcard DNS. Il record A o CNAME di *.preview.example.com dovrebbe puntare all’IP del host dove gira Traefik.

Usa dig o nslookup:

dig sandbox123.preview.example.com

L’IP restituito deve essere l’IP del host Traefik, non un altro indirizzo.

2. Traefik ha scoperto i labels del container?

Controlla la configurazione del Docker provider di Traefik e i labels del container.

Usa dashboard o logs di Traefik:

docker logs traefik-container | grep "sandbox123"

I logs di Traefik dovrebbero mostrare la route per sandbox123. In caso contrario, verifica:

  • Che il label traefik.enable=true esista
  • Che exposedByDefault: false sia configurato correttamente
  • Che Traefik monti correttamente il Docker socket

3. Il container è in esecuzione?

Controlla lo stato del sandbox container.

Usa docker ps:

docker ps | grep sandbox123

Se il container è fermo, potrebbe averlo fermato l’idle reaper o il wake path potrebbe non averlo riavviato. Visitando la preview URL, il wake handler del control plane dovrebbe avviare il container e restituire una warming page. Se fallisce, controlla i logs del control plane.

4. Indirizzo di ascolto dell’applicazione

Controlla indirizzo e port su cui ascolta l’app dentro il container.

Entra nel container e controlla i port:

docker exec sandbox123 netstat -tuln

L’app deve ascoltare su 0.0.0.0:3000, non solo su 127.0.0.1:3000. La documentazione Docker spiega che le porte bound a 127.0.0.1 o ::1 sono raggiungibili solo dal Docker host, quindi le richieste esterne non arrivano.

Se l’app ascolta solo su localhost, cambia la configurazione dell’app o usa il network mode adatto.

5. Controllo del port binding

Confronta il port configurato in Traefik con quello su cui ascolta davvero l’app.

Il label Traefik potrebbe essere:

- "traefik.http.services.sandbox123.loadbalancer.server.port=3000"

L’app dentro il container deve ascoltare sulla porta 3000. Se Traefik punta a 3000 ma l’app ascolta su 8080, le richieste falliranno.

Quando le porte non coincidono, correggi i labels Traefik o la configurazione dell’app.

Conclusione

Docker su singolo host più un control plane Go può sostenere un ambiente di preview self-hosted: ogni sandbox ha la propria preview URL, le risorse sono limitate e il tradeoff di sicurezza è esplicito. L’uso corretto resta circoscritto: team interni, utenti fidati, piccola concorrenza. Se il confine di fiducia si apre a sconosciuti esterni o la concorrenza supera un host, passa a microVM o Kubernetes.

I moduli principali sono lineari: la tabella decisionale mantiene onesto lo scope; control plane, Traefik, SQLite e reaper spiegano le parti in movimento; le preview URL dipendono da Host rule Traefik e Docker labels; la sicurezza tratta il Docker socket come potere di livello host; i limiti di risorse sono la base multi-tenant; la image cache riduce il rischio Docker Hub; la checklist di troubleshooting dà un percorso quando le preview URL si rompono.

Prossimi passi:

  • Preview piccole per team interno: parti con Docker single-host + control plane Go e misura la densità di risorse
  • Utenti esterni o workload ad alto rischio: passa a Docker Sandboxes, Firecracker o un altro confine microVM
  • Self-hosted CI Runner: leggi la guida GitHub Actions self-hosted runner per completare l’infrastruttura privata
  • App dentro l’ambiente di preview: usa la guida Next.js Docker self-hosting per eseguire l’app nella sandbox

Creare un MVP di Dev Sandbox self-hosted

Dal singolo host Docker a un ambiente di preview interno con limiti di risorse e controllo degli accessi.

⏱️ Estimated time: 4 hr

  1. 1

    Step 1: Scegliere il modello di isolamento

    Usa Docker su un singolo host per team fidati e piccoli workload di preview. Per utenti sconosciuti o codice non affidabile, scegli microVM, host separati o Kubernetes.
  2. 2

    Step 2: Preparare il control plane

    Esegui un piccolo servizio Go che gestisce metadata delle sandbox, lifecycle operation, reaper e wake-on-request.
  3. 3

    Step 3: Configurare la discovery di Traefik

    Abilita il Docker provider con `exposedByDefault: false` e aggiungi labels solo ai container sandbox che devono ricevere traffico.
  4. 4

    Step 4: Assegnare preview URL stabili

    Usa wildcard DNS come `*.preview.example.com` e instrada ogni host `{sandbox_id}.preview.example.com` verso il port del container che serve l'app.
  5. 5

    Step 5: Rendere persistenti i workspace

    Salva ogni sandbox sotto `SANDBOXED_DATA_DIR/workspaces/` o in una directory equivalente del host, così `docker stop` non elimina i file dell'utente.
  6. 6

    Step 6: Aggiungere limiti di risorse

    Imposta limiti di memory, CPU e PIDs su ogni sandbox. Una build fuori controllo non deve prosciugare il host.
  7. 7

    Step 7: Chiudere gli ingressi di produzione

    Non esporre l'API Docker. Aggiungi API auth, TLS, controllo di accesso per i preview link, separazione di rete e audit log.
  8. 8

    Step 8: Pianificare immagini e registry

    Pre-riscalda le immagini comuni, fai login su Docker Hub quando serve e usa un registry privato o una cache se crei sandbox di frequente.

FAQ

In cosa un Dev Sandbox è diverso da Docker Compose?
Compose è ideale per un insieme fisso di servizi di lunga durata. Un control plane per Dev Sandbox crea, avvia, ferma, risveglia e distrugge ambienti on demand, assegna a ciascuno una preview URL stabile e registra lo stato per un backend di prodotto.
Perché non usare Kubernetes fin dall'inizio?
Kubernetes è più adatto quando servono scheduling multi-node, alta disponibilità, network policy standard e governance di piattaforma. Per validare il loop di prodotto con un team interno fidato, spesso basta un singolo host Docker.
L'isolamento dei container Docker può eseguire codice arbitrario di sconosciuti?
Non va trattato come confine forte per quel caso. Un control plane basato su Docker socket è adatto a utenti fidati. Il codice arbitrario non affidabile dovrebbe andare su microVM, VM dedicate, gVisor, Kata, Firecracker o almeno host separati per tenant.
Una preview URL deve usare HTTPS?
I test locali con `*.localhost` possono partire da HTTP. I domini pubblici di preview dovrebbero usare HTTPS, soprattutto se gli utenti inseriscono token, form o dati di business. Un certificato wildcard evita di emettere un certificato per sandbox.
I file spariscono dopo un idle stop?
No, se il workspace è salvato in una directory persistente del host. `docker stop` libera risorse ma mantiene i file. Tieni separate le operazioni destroy e purge, così è chiaro se elimini solo il container o anche il workspace.
I rate limit di Docker Hub possono influire?
Sì. Creare molte sandbox aumenta gli image pull. In produzione conviene autenticarsi su Docker Hub quando serve, pre-riscaldare le immagini comuni e valutare un registry privato o una cache.

13 min di lettura · Pubblicato il: 5 giu 2026 · Aggiornato il: 14 lug 2026

Percorso di lettura della serieParte 1 di 1

Guida pratica Docker

Stai leggendo il primo articolo di questa serie. Continua con il successivo o apri l’hub della serie.

Vedi hub della serie

Precedente

Sei all’inizio di questa serie.

Successivo

Questo è l’articolo più recente della serie per ora.

Commenti

Accedi con GitHub per lasciare un commento

Easton BlogEaston Blog