SSD Nodes Learn 🎉 VPS da $5.50/mese
Guide Matt ConnorDi Matt Connor · Aggiornato 2026-08-13

Jail FreeBSD o container Docker: differenze

Confronto tra jail FreeBSD e container Docker: userland completo contro immagini a livelli, con differenze pratiche su software, stato, rete e limiti.

Jail FreeBSD e container Docker, in un solo paragrafo

I jail FreeBSD e i container Docker risolvono lo stesso problema secondo due modelli diversi. Entrambi eseguono userland isolati su un unico kernel condiviso, quindi nessuno dei due è una macchina virtuale. La differenza riguarda ciò che viene eseguito all'interno. Un container Docker esegue un processo a partire da un'immagine a livelli scaricata da un registry. Un jail esegue un userland FreeBSD completo: il proprio /etc, i propri script di avvio rc, il proprio database pkg e tutti i processi necessari. Quasi tutte le altre differenze descritte in questa pagina derivano da questa sola caratteristica.

SSD Nodes non offre immagini FreeBSD. Su questa piattaforma non è possibile noleggiare un server FreeBSD e quanto segue non è una guida all'installazione per una macchina acquistabile qui. Si tratta di un confronto tra due modelli di isolamento, scritto per aiutarti a stabilire quale modello sia effettivamente adatto a un determinato carico di lavoro e per consentirti di leggere la configurazione di un team FreeBSD senza dover procedere per tentativi.

Che cos'è realmente un jail

I jail sono stati introdotti in FreeBSD 4.0 nel marzo 2000, quindi precedono i cgroup e risalgono a circa un decennio prima di Docker. Il meccanismo consiste in una chiamata al kernel. jail(8) prende un albero di directory e avvia al suo interno i processi associando loro un jail ID; il kernel rifiuta quindi un insieme predefinito di operazioni per ogni processo che porta quell'ID. Un processo in jail non può vedere i processi esterni al proprio jail, non può montare o smontare filesystem, non può caricare moduli del kernel e non può associarsi a indirizzi di rete non assegnati al jail. Non esiste un tipo separato di namespace da imparare e non è necessario abilitare singolarmente ogni funzionalità: le restrizioni vengono applicate come un'unica unità e vengono modificate tramite i parametri nella configurazione del jail.

Sull'host, jls elenca i jail in esecuzione e jexec web sh apre una shell all'interno del jail denominato web.

Per creare un jail, inserisci un userland FreeBSD in una directory. Il sistema base esegue questa operazione al posto tuo:

sudo bsdinstall jail /usr/local/jails/containers/web

Questo comando scarica il set di distribuzione base per la tua release ed esegue le normali procedure post-installazione. Puoi quindi impostare la password di root e scegliere il fuso orario esattamente come su un nuovo server. Il risultato è un'installazione FreeBSD contenuta in una directory. Devi poi descriverla in /etc/jail.conf:

web {
  host.hostname = "web.example.internal";
  path = "/usr/local/jails/containers/web";
  ip4.addr = "10.0.0.10";
  exec.start = "/bin/sh /etc/rc";
  exec.stop = "/bin/sh /etc/rc.shutdown";
  mount.devfs;
}

Avvialo, quindi controllane lo stato:

sudo service jail start web
jls

A questo punto jls dovrebbe elencare web con un JID, il relativo hostname e il relativo indirizzo IP. Se il jail non compare, esegui direttamente sudo jail -c web. Applica la stessa configurazione in primo piano e stampa il parametro che non è stato possibile accettare, invece di lasciare l'errore nell'output del servizio.

La riga da leggere con particolare attenzione è exec.start = "/bin/sh /etc/rc". L'avvio di un jail esegue al suo interno il normale script di boot di FreeBSD. Di conseguenza, il jail avvia ogni servizio abilitato nel proprio /etc/rc.conf. Un container Docker non ha un passaggio equivalente, perché esegue il processo entrypoint dell'immagine e si arresta quando quel processo termina.

Come si ottiene il software: immagini e registry a confronto con un userland da riempire

Questa è la differenza che si nota dal primo giorno.

Con Docker si indica il software e lo si riceve. docker pull nginx scarica un'immagine stratificata e indirizzata in base al contenuto, compilata e testata da altri, mentre docker compose up -d la avvia con i relativi volumi e la rete collegata. Il registry è il prodotto. Gran parte del valore di un flusso di lavoro Docker deriva dal fatto che migliaia di progetti pubblicano un'immagine funzionante. Per questo eseguire Docker su un VPS richiede poco tempo invece di diventare un progetto.

FreeBSD non fornisce un registry pubblico predefinito di immagini per jail. Si crea un userland vuoto e vi si installa il software, come si configurerebbe un server senza applicazioni. Questo richiede più comandi. È anche più trasparente, perché nella jail viene eseguito ciò che pkg vi ha installato, usando lo stesso set di pacchetti del sistema host.

Gli strumenti riducono il lavoro. BastilleBSD è il gestore di jail più usato ed è disponibile come pacchetto:

sudo pkg install bastille
sudo sysrc bastille_enable=YES
sudo bastille setup
sudo bastille bootstrap 15.1-RELEASE

bastille setup configura rete, storage e firewall. bastille bootstrap scarica una release una sola volta, dopodiché ogni jail creata riutilizza quella release. FreeBSD 15.1 è la release attuale per la produzione, pubblicata a giugno 2026; sostituiscila con la release in uso.

A questo punto, per creare una jail serve un comando e per installarvi il software ne serve un altro:

sudo bastille create web 15.1-RELEASE 10.17.89.10/24
sudo bastille pkg web install nginx
sudo bastille service web nginx start
sudo bastille console web

bastille console web fornisce una shell di login all'interno della jail, mentre bastille list mostra ciò che esiste sull'host. Per ripetere una build, i template di Bastille contengono i passaggi in un file e li applicano a una jail. Sono l'equivalente più vicino a un Dockerfile in questo contesto. Un template viene rieseguito su ogni jail. Nulla è preinstallato.

Il riepilogo corretto è quindi semplice. Docker fornisce build realizzate da altri. Le jail richiedono installazioni gestite da te. Se il software presente nell'elenco è distribuito come immagine container e non in altro modo, la scelta è già determinata prima di valutare qualsiasi altro criterio.

Stato e aggiornamenti: la parte che ZFS modifica

Docker separa intenzionalmente lo stato. Il filesystem del container è usa e getta, i dati risiedono in un volume denominato o in un bind mount e un aggiornamento consiste in docker compose pull seguito da docker compose up -d. Il container viene sostituito e tutto ciò che non è stato inserito in un volume viene eliminato. Questo è un vantaggio se si segue la regola, ma diventa un incidente con perdita di dati se la si dimentica. Per questo la scelta tra bind mount e volumi denominati è così importante in uno stack Compose.

Un jail non separa lo stato. È ZFS a rendere possibile questo approccio. L'intero jail è un dataset:

sudo zfs snapshot zroot/jails/containers/web@pre-upgrade
sudo pkg -j web upgrade
sudo zfs rollback zroot/jails/containers/web@pre-upgrade

Verificare il nome effettivo del dataset con zfs list prima di eseguire questo comando. Il percorso precedente corrisponde alla struttura usata dall'handbook. Lo snapshot richiede circa un secondo e occupa quasi nessuno spazio finché il contenuto del jail non cambia. Se l'aggiornamento interrompe il funzionamento del servizio, il rollback ripristina l'intero userland allo stato precedente, inclusi il database dei pacchetti e i file di configurazione modificati manualmente alle 2 di notte. Docker non offre un equivalente integrato, perché il suo modello presuppone che non sia mai necessario.

zfs clone è l'altra parte. Un clone di uno snapshot è un nuovo jail scrivibile che condivide con il parent i blocchi invariati. Per questo una copia di staging di un jail da 3 GB occupa quasi nessuno spazio su disco finché non si iniziano ad apportare modifiche. È così che un amministratore FreeBSD crea un jail "uguale alla produzione" per provare un aggiornamento.

L'aggiornamento del sistema di base è separato da quello dei pacchetti. Per un jail che contiene una propria copia dell'userland:

sudo freebsd-update -b /usr/local/jails/containers/web fetch install

I thin jail evitano di ripetere questa operazione. Montano una base condivisa in sola lettura tramite nullfs e assegnano a ogni jail un proprio piccolo livello scrivibile. In questo modo si applica la patch alla base una sola volta e tutti i jail vedono il risultato. Bastille crea per impostazione predefinita thin jail.

Rete: porte pubblicate e scelta del modello di indirizzamento

Docker gestisce automaticamente la rete e richiede di pubblicare soltanto le eccezioni. I container vengono collegati a un bridge, comunicano tra loro tramite il nome del servizio su una rete definita dall'utente e -p 8080:80 espone uno di essi sull'host. Docker scrive le proprie regole di filtraggio dei pacchetti per ottenere questo comportamento. È anche il motivo per cui una porta pubblicata del container aggira direttamente ufw.

Un jail richiede di scegliere il modello in anticipo. I modelli sono due.

IP condiviso. ip4.addr = "10.0.0.10" aggiunge quell'indirizzo a un'interfaccia esistente dell'host e limita il jail a utilizzarlo. Il jail non dispone di uno stack di rete autonomo e quindi non può eseguire il proprio firewall. Inoltre, non può realmente eseguire il bind su ogni indirizzo: un socket nel jail che richiede 0.0.0.0 viene riscritto dal kernel usando l'indirizzo del jail. Due jail non possono restare entrambi in ascolto sulla porta 80 dello stesso indirizzo. È quindi necessario assegnare un indirizzo a ciascuno oppure utilizzare un reverse proxy.

VNET. Aggiungi vnet; al jail per assegnargli uno stack di rete completo: interfacce proprie, tabella di routing propria e regole firewall proprie. Collegalo all'host tramite un epair, cioè un cavo virtuale con un'estremità su ciascun lato, e collega l'estremità dell'host a un bridge. Questo è il modello più simile a quello fornito da Docker ed è alla base dei tipi di jail -V e -B di Bastille.

L'inoltro di una porta dell'host verso un jail è una regola di redirect pf. Bastille la gestisce tramite:

sudo bastille rdr web tcp 80 80

Non esistono EXPOSE né la pubblicazione automatica delle porte. Una connessione raggiunge un jail soltanto se il suo indirizzo o una regola di redirect lo consente. L'avvio richiede più configurazione, ma il firewall è molto più prevedibile e silenzioso.

Limiti delle risorse: cgroups e rctl

Docker limita un container tramite cgroups e i limiti risiedono nel punto in cui il container è definito: --memory=1g --cpus=1.5 nella riga di comando oppure nelle chiavi corrispondenti di un file Compose. Se lo stack è già gestito tramite un file Docker Compose su un VPS, il limite si trova accanto al servizio a cui si applica e viene versionato insieme a esso in git.

FreeBSD usa rctl, un sottosistema che deve essere attivato. La contabilizzazione delle risorse è disabilitata per impostazione predefinita perché introduce un piccolo costo a ogni allocazione. Aggiungi il tunable a /boot/loader.conf e riavvia il sistema:

kern.racct.enable=1

Quindi imposta una regola e monitorala:

sudo rctl -a jail:web:vmemoryuse:deny=1g
rctl -hu jail:web

rctl -hu jail:web mostra l'utilizzo corrente del jail in unità leggibili, così puoi verificare quanto si avvicina al limite prima che si verifichi un errore. L'azione deny fa fallire l'allocazione oltre il limite all'interno del jail, mostrando l'errore di allocazione dell'applicazione invece di un messaggio di terminazione sul sistema host.

Le regole aggiunte con rctl -a vengono rimosse al riavvio successivo. Il servizio rctl di FreeBSD le ricarica da /etc/rctl.conf, quindi scrivi la regola in quel file e abilita il servizio:

sudo sysrc rctl_enable=YES

Questo è l'aspetto in cui Docker è chiaramente più pratico. Un limite in un file Compose viene esaminato insieme al servizio a cui si applica. Una regola rctl è una riga in un file separato che identifica un jail definito altrove.

Quando la risposta è una macchina virtuale: bhyve

Un jail condivide il kernel dell'host, quindi alcune funzionalità restano permanentemente indisponibili. Non può eseguire una versione diversa del kernel, caricare un modulo del kernel né eseguire binari Linux come fa un container Linux. FreeBSD include un livello di compatibilità Linux, il linuxulator, ma questo implementa un sottoinsieme delle system call Linux e non costituisce una soluzione generale per immagini Linux arbitrarie.

bhyve è l'hypervisor di FreeBSD ed è lo strumento corretto quando serve un isolamento a livello di macchina: un sistema operativo diverso, un kernel diverso oppure un tenant con cui si preferisce non condividere il kernel. Il costo consiste nella memoria riservata anziché condivisa e nella necessità di applicare le patch anche a un secondo kernel. È la stessa scelta che si fa su Linux tra container e macchine virtuali complete e determina se serve un VPS che supporti la virtualizzazione annidata sottostante.

L’ecosistema, cioè il motivo concreto per cui la maggior parte dei team usa Docker

Tutto quanto detto finora riguarda il modello. Per la maggior parte dei team, la scelta dipende dalle dimensioni dell’ecosistema che circonda ciascuna soluzione.

Docker offre Docker Hub e GHCR, docker compose, Kubernetes quando un solo server non è più sufficiente, runner CI con il supporto per i container già integrato e una procedura di avvio rapido eseguibile con un solo comando nella README di quasi ogni progetto. I jail offrono il ports tree di FreeBSD, ampio e gestito con attenzione, oltre a un insieme molto più ridotto di bundle applicativi pronti all’uso. Quando un progetto pubblica soltanto un’immagine container e nient’altro, su FreeBSD occorre consultare la documentazione e assemblare autonomamente i vari componenti.

I jail sono preferibili nell’altro lato di questo compromesso. Sono indicati quando usi già ZFS e vuoi eseguire snapshot e rollback di un intero servizio, quando i tuoi servizi sono nativi FreeBSD, quando vuoi un userland completo per ogni tenant invece di un singolo processo oppure quando vuoi che kernel, packet filter, filesystem e documentazione siano gestiti insieme come un unico sistema. È questo che si intende quando si definisce FreeBSD coerente. Il tema è trattato più ampiamente in il confronto generale tra Linux e FreeBSD come piattaforme server e in le novità introdotte da FreeBSD 15 per l’uso sui server.

Un’ultima valutazione. Se il tuo team conosce già Docker, il costo della migrazione è concreto e il vantaggio deve essere specifico. Non cambiare per la qualità dell’isolamento: i due modelli sono abbastanza simili e la configurazione conta di più. Cambia perché vuoi eseguire rollback di interi servizi basati su ZFS oppure perché usi già FreeBSD.

FAQ

È possibile eseguire immagini Docker su FreeBSD?

Non immagini Linux, almeno non con un percorso supportato. FreeBSD supporta i container OCI: sudo pkg install -y podman-suite installa Podman, che esegue i container tramite ocijail, un runtime che crea jail reali a un livello sottostante. Per il monitor dei container è necessario montare fdescfs su /dev/fd, mentre pf serve per il NAT dei container (Network Address Translation). Le immagini OCI native per FreeBSD funzionano meglio. Le immagini Linux richiedono inoltre il layer di compatibilità Linux e, ad agosto 2026, la port di FreeBSD per Podman è ancora descritta come sperimentale. Se il deployment è composto da uno stack di immagini Linux, eseguilo su Linux.

Le jail di FreeBSD sono più sicure dei container Docker?

Entrambi condividono il kernel dell'host, quindi un bug del kernel rappresenta un rischio per entrambi. Nessuno dei due costituisce il confine di isolamento da scegliere per codice realmente non attendibile. La differenza sta nel punto di partenza. Una jail inizia con un insieme ampio di operazioni rifiutate e le si riabilita una alla volta tramite i parametri. Un container Docker inizia con root all'interno di un insieme di namespace, con alcune capability rimosse; l'hardening aggiuntivo è facoltativo. In pratica, la configurazione conta più del modello: una jail con allow.mount e allow.raw_sockets abilitati non è più sicura di un container configurato correttamente.

Come si esegue il backup di una jail?

Crea uno snapshot del dataset e trasferiscilo. sudo zfs snapshot zroot/jails/containers/web@backup, quindi zfs send quello snapshot su un altro pool o in un file da copiare fuori dal server. Poiché una jail conserva l'intero userland in un unico dataset, lo snapshot acquisisce i pacchetti installati e i dati in un unico punto coerente, insieme a tutti i file di configurazione modificati manualmente. È l'opposto dell'approccio Docker, in cui si esegue il backup dei volumi denominati e del file Compose e si ricostruisce il resto dall'immagine.

Servono BastilleBSD o il sistema di base è sufficiente?

Il sistema di base è sufficiente ed è il punto di partenza migliore. jail.conf, jls, jexec e service jail start coprono l'intero modello e, una volta appresi, consentono di comprendere qualsiasi host FreeBSD senza dover prima imparare gli strumenti specifici di quell'host. Bastille è un livello di convenienza costruito sopra questi strumenti: prepara le release, crea jail thin, applica template e scrive per te le regole di redirect pf. Impara prima i comandi di base, quindi aggiungi Bastille quando il numero di jail rende la digitazione ripetitiva.