
Esegui Firefox in un contenitore Podman rootless con capabilities rimosse, rete isolata e storage effimero per contenere le evasioni dalla sandbox e prevenire il compromesso dell'host.
Esegui Firefox in un contenitore Podman rootless per l'isolamento di sicurezza. Il tuo browser viene eseguito con quasi nessuna capacità Linux, nel proprio namespace utente e di rete, isolato dall'host — pur mantenendo piena accelerazione GPU, audio e supporto DRM.
Firefox ha già una sandbox multi-processo che isola i renderer dei contenuti web utilizzando namespace Linux e seccomp-bpf. Per la maggior parte delle minacce, questo è efficace. foxcage aggiunge una seconda barriera: se un attaccante sfrutta una vulnerabilità che elude la sandbox di Firefox (cosa che accade — esistono CVE per questo), finisce in un contenitore bloccato invece che nella tua intera sessione utente.
~/.ssh, ~/.gnupg, profili browser per altri browser, database di gestori di password, documenti, codice sorgente. In foxcage, l'attaccante vede solo ciò che hai montato esplicitamente.@tmp lascia zero tracce su disco dopo la chiusura della finestra — incluse estensioni, stato HSTS, cache delle sessioni TLS e cache DNS che la Navigazione Privata di Firefox persiste comunque. Più gabbie @tmp vengono eseguite contemporaneamente senza interferire tra loro.~/.config/autostart, ~/.bashrc, cron o altrove per sopravvivere a un riavvio. Il contenitore effimero di foxcage (--rm) significa che nulla persiste a meno che tu non lo abbia montato con bind.localhost. Su Firefox nudo, una fuga dalla sandbox ha pieno accesso alla rete. (Usa [network] mode = "host" se una gabbia necessita di accesso a localhost, ad es. per lo sviluppo locale — ma vedi l'avvertenza sotto "Rete": la modalità host espone anche i socket Unix astratti dell'host.)CAP_SYS_CHROOT e blocca l'acquisizione di nuovi privilegi. I binari setuid, gli exploit del kernel tramite syscall oscure e percorsi di escalation simili sono tagliati fuori.profile, downloads_dir, bind mount aggiuntivi) è pienamente accessibile a un browser compromesso. Se monti una directory del profilo host, un attaccante può manometterla proprio come su Firefox nudo.Il contenitore viene eseguito con:
CAP_SYS_CHROOT aggiunta per la sandbox dei contenuti di Firefox; CAP_SETUID/CAP_SETGID aggiunte temporaneamente quando init.root è configurato)no-new-privileges per prevenire l'escalation dei privilegi--userns keep-id)/dev/shm privato (non condiviso con l'host) — dimensione configurabile tramite shm_sizenetwork.dns)XDG_RUNTIME_DIR sono montati con bind (Wayland, PulseAudio, PipeWire e il proxy D-Bus filtrato) — la directory runtime completa dell'host non viene mai espostaxdg-dbus-proxy filtrato in esecuzione sull'host. Solo , , e (per i fork) il namespace del fork stesso (ad es. ) sono raggiungibili — i servizi di sessione come il portachiavi e l'agente SSH/GPG sono bloccatiOgni opzione [network] e [mounts] che abiliti scambia un po' di isolamento per comodità. Le impostazioni predefinite sono la configurazione più restrittiva che ti dà comunque un browser utilizzabile.
sudo apt install passt) — a meno che network.mode = "host"sudo apt install xdg-dbus-proxy)/dev/dri foxcage avvisa e Firefox esegue il rendering in software. I driver VA-API per Intel, AMD e nouveau sono installati nell'immagine, quindi la decodifica video hardware funziona senza pacchetti driver host — vedi Decodifica video hardwareEsegui foxcage come tuo normale utente desktop, non come root o tramite sudo — la sandbox mappa il tuo utente nel contenitore, e l'esecuzione come root rimuove l'isolamento per cui foxcage esiste. Rifiuta di avviarsi come root.
Ambiente testato: Debian 13 (Trixie) con GNOME 3. Altre distribuzioni Linux e compositor Wayland potrebbero funzionare ma non sono stati testati.
foxcage è un singolo script Python senza dipendenze al di fuori della libreria standard Python. Copialo in una directory nel tuo PATH:```sh
sudo cp foxcage /usr/local/bin/foxcage
Oppure per un'installazione locale dell'utente:```sh
cp foxcage ~/.local/bin/foxcage
Assicurati che lo script sia eseguibile (chmod +x foxcage).
Controlla quale revisione hai con foxcage --version — utile quando segnali un problema, poiché foxcage viene installato copiando un singolo file.
./foxcage
Al primo avvio lo script crea l'immagine del container (scarica Firefox da Mozilla, installa le dipendenze Debian minime) e poi avvia Firefox. Alle esecuzioni successive, foxcage verifica la presenza di aggiornamenti di Firefox e ricostruisce l'immagine automaticamente quando è disponibile una nuova versione. L'immagine viene inoltre ricostruita periodicamente (ogni 7 giorni per impostazione predefinita) per recepire gli aggiornamenti dei pacchetti di sistema. Se il controllo degli aggiornamenti fallisce (errore di rete, timeout), viene registrato un avviso e viene utilizzata l'immagine esistente — l'avvio non viene mai bloccato.
Passa gli argomenti a Firefox:```sh
./foxcage https://example.com
Combina una gabbia nominata con i flag di Firefox:```sh ./foxcage @work --kiosk https://example.com
Se una gabbia è già in esecuzione, l'URL si apre in una nuova scheda del browser esistente invece di avviare un secondo contenitore. Eseguire `foxcage` (o `foxcage @cage`) senza URL contro una gabbia in esecuzione termina correttamente con un messaggio "la gabbia è già in esecuzione" — foxcage non può sollevare una finestra Wayland esistente dall'esterno del contenitore, quindi non ci prova.
I flag per singolo avvio **non** si applicano quando una gabbia è già in esecuzione. `--dns`, `--ipv4-only`, `--lifetime`, `--color` e `--fork` vengono consumati all'avvio del contenitore, e le impostazioni di un contenitore in esecuzione non possono essere modificate dall'esterno, quindi vengono ignorati con un avviso. Chiudi la gabbia e riesegui per applicarli.
> Usa la chiave di configurazione `private_browsing` per le sessioni in modalità privata — *non* il flag CLI grezzo `--private-window` di Firefox. La chiave di configurazione imposta la modalità privata a livello di sessione (`browser.privatebrowsing.autostart`), così le successive invocazioni `foxcage @cage URL` possono riaprire in schede. `--private-window` come pass-through di Firefox renderebbe privata solo la prima finestra e romperebbe il comportamento di riapertura in scheda descritto sopra.
>
> **Attenzione:** le sessioni abilitate tramite `private_browsing = true` non mostrano i consueti segnali UI della finestra privata di Firefox (barra di accento viola, icona maschera, "(Private Browsing)" nel titolo). Questo perché ogni finestra della sessione è privata, quindi Firefox non ha alcuna finestra non privata con cui creare un contrasto visivo — sopprime l'indicatore. La sessione *è* genuinamente privata; verifica se vuoi visitando `about:privatebrowsing` nella gabbia (mostra la pagina informativa standard sulla navigazione privata) o `about:config` e controllando `browser.privatebrowsing.autostart = true`.
### Navigazione effimera con `@tmp`
Per link monouso che non devono lasciare traccia, usa la gabbia riservata `tmp`:```sh
./foxcage @tmp https://somewhere-suspicious.example
Ogni avvio con @tmp è un Firefox nuovo e usa-e-getta, senza profilo persistente. Quando la finestra si chiude, tutto sparisce — cookie, cache, cronologia, estensioni, stato HSTS, cache delle sessioni TLS, cache DNS, stato delle schede salvate. Questo va oltre la Navigazione Privata di Firefox, che conserva comunque le estensioni e una buona parte dello stato su disco.
Più gabbie @tmp vengono eseguite contemporaneamente, ciascuna isolata dalle altre. La barra dei menu mostra FoxCage - tmp (<id breve>) così puoi distinguere le finestre effimere simultanee.
Le gabbie effimere aprono una pagina vuota all'avvio e nuove schede vuote — la home page predefinita di Firefox e il contenuto delle nuove schede (siti principali, consigli di Pocket, activity stream) sono puro rumore su un profilo nuovo che sta per essere buttato via, quindi vengono soppressi. Le gabbie persistenti mantengono le impostazioni predefinite di Firefox.
Se vuoi un nome significativo su una sessione usa-e-getta (ad esempio, un percorso di ricerca che vorrai riaprire in una nuova scheda), usa @tmp-<nome>:```sh
./foxcage @tmp-research https://example.com # first call → new window
./foxcage @tmp-research https://another.example # second call → new tab in the existing window
`@tmp-<name>` è ancora effimero: quando chiudi la finestra, tutto sparisce. La differenza rispetto al semplice `@tmp` è che i secondi avvii con lo stesso nome **riutilizzano la finestra esistente** (come le gabbie persistenti), quindi puoi aggiungere altre schede in seguito senza avviare una copia parallela. Il semplice `@tmp` mantiene il suo comportamento "ogni avvio è un nuovo usa-e-getta".
L'etichetta della barra dei menu mostra il nome che hai scelto (`FoxCage - tmp-research`), così la finestra è etichettata in modo significativo.
#### Personalizzare le impostazioni predefinite effimere
Crea `~/.config/foxcage/tmp.toml` per impostare le predefinite per tutte le gabbie effimere (sia il semplice `@tmp` che ogni `@tmp-<name>`). Ad esempio:```toml
private_browsing = true
lifetime = "30m"
extensions = ["ublock-origin"]
[network]
dns = "cloudflare"
Ogni avvio effimero ora ottiene una finestra privata, uBlock Origin, Cloudflare DoH e si chiude automaticamente dopo 30 minuti — con piena effimerità intatta. Gli effimeri nominati ereditano tmp.toml per impostazione predefinita; se vuoi sovrascrivere per nome, crea ~/.config/foxcage/tmp-<name>.toml. Quel file viene quindi applicato al posto di tmp.toml — nessuna fusione, il file più specifico vince del tutto. Copia le impostazioni predefinite condivise al suo interno se le vuoi.
Tutto ciò che puoi impostare nella configurazione di una gabbia regolare funziona qui, tranne la chiave che sconfiggerebbe l'effimerità stessa:
profile — errore grave.Punta a una directory di profilo persistente sull'host, che contraddice direttamente lo scopo di @tmp. Se vuoi una gabbia sandbox con un profilo persistente, usa una gabbia nominata regolare (@work, @research, ecc.) che non inizi con tmp-.
Una gabbia può avere estensioni integrate nella sua immagine e installate forzatamente a ogni avvio:```toml extensions = ["ublock-origin"]
Metti questo in `~/.config/foxcage/tmp.toml` e **ogni cage usa e getta parte con uBlock Origin già attivo** — il che conta, perché una cage effimera è altrimenti il browser meno protetto che hai, usato proprio sui link di cui ti fidi meno. Un profilo `@tmp` nuovo non ha alcuna estensione, e installarne una a mano è inutile in una sessione che si distrugge alla chiusura.
Ogni voce può essere il nome breve dall'URL dell'add-on su addons.mozilla.org, l'URL della pagina stessa, oppure l'ID dell'add-on:```toml
extensions = [
"ublock-origin",
"https://addons.mozilla.org/firefox/addon/noscript/",
"[email protected]",
]
Add-ons vengono risolti tramite l'API di addons.mozilla.org all'avvio, scaricati durante la build dell'immagine e verificati rispetto allo SHA-256 pubblicato da AMO. La versione risolta fa parte del Containerfile, quindi una nuova release di un'estensione cambia l'hash dell'immagine e attiva una rebuild — le estensioni si aggiornano nello stesso modo di Firefox, e per lo stesso motivo: nulla viene installato a runtime, quindi un profilo effimero fresco non scarica mai nulla di nuovo.
Poiché vengono installati tramite policy aziendale e non manualmente:
about:addons li mostra come installati dalla tua organizzazione).private_browsing = true. Questo richiede Firefox 136 o ESR 128.8; le versioni precedenti ignorano l'impostazione e lasciano l'add-on inerte nelle finestre private.Limitazioni:
.xpi nudo viene rifiutato.@tmp e ogni @tmp-<name> costruiscono una singola immagine foxcage-tmp, quindi dare a un'effimera nominata una lista extensions diversa da tmp.toml fa sì che le due si ricostruiscano a vicenda ad avvii alternati. Tieni le liste di estensioni effimere in tmp.toml.Il flag --dns (e la chiave di configurazione equivalente network.dns) accetta tre forme:```sh
./foxcage @tmp --dns 1.1.1.1 https://example.com # IP
./foxcage @tmp --dns cloudflare https://example.com # alias
./foxcage @tmp --dns https://dns.nextdns.io/ # custom DoH URI
**Quando il valore corrisponde a un provider noto (per alias o per IP), foxcage abilita automaticamente il DNS over HTTPS forzato verso quel provider.** Il TRR di Firefox viene impostato alla modalità 3 (strict, nessun fallback in chiaro) con l'indirizzo bootstrap compilato, così non c'è alcuna perdita di risoluzione non crittografata all'avvio. Vedi una notifica su una riga su stderr come `Enabling DNS over HTTPS via Cloudflare`.
Alias integrati:
| Alias | IP | Filtraggio |
|-------|------|-----------|
| `cloudflare` | 1.1.1.1 | nessuno |
| `cloudflare-security` | 1.1.1.2 | blocca malware |
| `cloudflare-family` | 1.1.1.3 | blocca malware + adulti |
| `google` | 8.8.8.8 | nessuno |
| `quad9` | 9.9.9.9 | blocca malware (predefinito Quad9) |
| `quad9-unfiltered` | 9.9.9.10 | nessuno |
| `adguard` | 94.140.14.14 | blocca annunci + tracker |
| `adguard-family` | 94.140.14.15 | annunci + tracker + adulti |
| `opendns` | 208.67.222.222 | alcuni |
Un IP che non è nella tabella (ad es. il Pi-hole della tua LAN) rimane solo in chiaro — nessun DoH viene abilitato, poiché foxcage non conosce l'endpoint DoH corrispondente. Usa la forma URI per quello: `--dns https://pi.hole/dns-query` (con un certificato valido) abilita DoH e lascia invariato il DNS del container.
La forma URI salta l'impostazione del DNS in chiaro del container, quindi qualsiasi cosa all'interno del container che non sia Firefox usa ancora il DNS dell'host. Questo è intenzionale — `--dns URI` significa "fai usare a Firefox questo resolver DoH", punto.
`--dns` è incompatibile con `network.mode = "host"`, che ha già pieno accesso alla rete dell'host.
### Identificazione visiva della gabbia
Ogni gabbia nominata riceve un colore di accento nella barra dei menu così puoi distinguere le finestre a colpo d'occhio. **Non devi configurare nulla** — il colore è derivato deterministicamente dal nome della gabbia (hash SHA256 in una tonalità, con saturazione e luminosità fisse). `@banking`, `@work`, `@personal`, `@tmp-research` ottengono tutti colori distinti e stabili senza che tu muova un dito.
La gabbia predefinita (anonima) mantiene l'arancione integrato.
Se vuoi sovrascrivere il colore derivato automaticamente, impostalo esplicitamente:```toml
# ~/.config/foxcage/banking.toml
color = "#dc2626" # red — overrides the auto-derived colour
I'm ready to translate the Kitploit tool content from English to Italian. Please provide the Markdown content you'd like me to translate.```sh ./foxcage @experiment --color "#10b981" https://example.com # teal, one-off
Accepts standard CSS hex: `#rgb`, `#rrggbb`, o `#rrggbbaa` (con alpha). I colori derivati automaticamente sono calibrati per essere visibili sia su menubar chiari che scuri (luminosità fissata al 55%, saturazione al 75%), quindi non dovresti aver bisogno di sovrascriverli per motivi di tema.
### Gabbie con durata limitata
Il flag `--lifetime` (e la chiave di configurazione equivalente `lifetime`) chiude automaticamente una gabbia dopo una durata prestabilita. Il formato è `<numero><unità>` con unità `s`, `m` o `h`:```sh
./foxcage @tmp --lifetime 10m https://example.com
./foxcage @work --lifetime 2h
Il conto alla rovescia inizia quando Firefox si avvia effettivamente all'interno della gabbia — il tempo di avvio del container e di build dell'immagine non incide sul tuo budget. L'etichetta della barra dei menu della gabbia mostra il conto alla rovescia insieme all'identità della gabbia — es. FoxCage - tmp (a3f2b1) | 9m — aggiornata una volta al minuto finché manca più di un minuto, e una volta al secondo nell'ultimo minuto. Quando il conto alla rovescia arriva a zero, Firefox si chiude da solo e il container esce. Se chiudi Firefox manualmente prima della scadenza della durata, non succede nulla di insolito.
Imposta una durata predefinita per ogni gabbia nella sua configurazione:```toml
lifetime = "15m" private_browsing = true
`--lifetime` sulla riga di comando ha la precedenza su qualsiasi valore di configurazione.
Forza una ricostruzione completa dell'immagine (riscarica Firefox e tutti i pacchetti di sistema):```sh
./foxcage --rebuild
Un contenitore in esecuzione mantiene l'immagine da cui è stato avviato, anche dopo che foxcage ricostruisce il tag dell'immagine. Se provi ad aprire una scheda in una cage la cui immagine è stata nel frattempo aggiornata (tramite --rebuild, un aggiornamento di Firefox o la ricostruzione programmata), foxcage rifiuta con un errore (segnalato anche come notifica desktop) e ti chiede di uscire da Firefox e rilanciarlo — che avvia un nuovo contenitore sull'immagine corrente. Con --rebuild su una cage attiva, foxcage avvisa in anticipo, esegue la build e poi applica lo stesso controllo.
foxcage verifica la presenza di nuove versioni del browser a ogni avvio — l'API di rilascio di Mozilla per Firefox, l'endpoint dei rilasci di GitLab per LibreWolf. Se è disponibile un aggiornamento, l'immagine del contenitore viene ricostruita automaticamente. L'immagine viene inoltre ricostruita periodicamente (ogni 7 giorni per impostazione predefinita) per recepire gli aggiornamenti di sicurezza di Debian. L'auto-aggiornamento integrato del browser è disabilitato poiché gli aggiornamenti sono gestiti a livello di immagine.
Se il controllo degli aggiornamenti fallisce (nessuna rete, timeout dell'API), viene stampato un avviso e viene utilizzata l'immagine esistente — puoi sempre navigare.
La cadenza degli aggiornamenti si trova al livello superiore della configurazione; il blocco di versione e canale si trova nella sezione per-fork:```toml rebuild_days = 14 # rebuild for base-image updates every 14 days (0 to disable)
[firefox] channel = "beta" # track the beta channel instead of stable (firefox only) version = "149" # pin to Firefox 149.x (latest patch release)
**Per fissare una versione ESR serve anche il canale.** L'indice delle versioni di Mozilla elenca le release ESR senza il suffisso `esr` che i loro download portano, quindi un semplice `version = "140"` sul canale predefinito risolve a una release che non esiste. Imposta entrambi:```toml
[firefox]
channel = "esr"
version = "140" # → 140.13.0esr
Un pin che non corrisponde a nessuna release ora è un errore che indica il pin, invece di ripiegare silenziosamente sull'ultima release. Un guasto temporaneo nel raggiungere l'API di Mozilla avvisa comunque e prosegue con l'immagine esistente, quindi una rete instabile non blocca mai l'avvio.
I pin con suffisso devono essere completamente qualificati — "140.13.0esr" e "150.0b9" funzionano, "140esr" e "150b9" vengono rifiutati al caricamento della configurazione perché nessuna release potrà mai corrispondervi. Lo stesso vale per le revisioni di LibreWolf: "146.0.1-1" funziona, "146-1" no.
Per forzare una ricostruzione completa immediata: ./foxcage --rebuild
foxcage rifiuta di installare una build del browser la cui firma è stata creata da una sottochiave di firma che il progetto upstream ha revocato come compromessa (motivo di revoca RFC 4880 0x02). gpg --verify non fa questo da solo: stampa un avviso ed esce con 0, quindi senza il controllo aggiuntivo una chiave di firma trapelata autenticherebbe comunque un download manomesso.
Un rifiuto si presenta così e fa fallire la build invece di installare:``` foxcage: REFUSING /tmp/SHA512SUMS - signed by 09BEED63F3462A2DFFAB3B875ECB6497C1A20256, which its owner revoked as compromised. This build cannot be trusted; wait for upstream to re-sign this release with a current key.
Non c'è nulla da configurare e nessun override. Se si incappa in questo problema, la soluzione è a monte: o si fissa una release firmata con una chiave corrente, oppure si attende che la release interessata venga ri-firmata.
La rotazione periodica delle chiavi viene trattata diversamente. Una subchiave revocata come sostituita, ritirata o senza motivo indicato non invalida le firme effettuate *prima* della revoca, quindi quelle release si installano con un avviso. Una firma datata *dopo* qualsiasi revoca viene rifiutata qualunque sia il motivo dichiarato.
**Rotazione delle chiavi di Mozilla dell'agosto 2026.** Mozilla ha revocato la subchiave di firma `09BEED63…C1A20256` il 2026-08-06 dopo che una copia non cifrata era stata committata in un repository GitHub privato, sostituendola con `827E6586…76767AA3`. Le release di Firefox firmate con la vecchia subchiave — tutto ciò che va dal 2025-03-13 al 2026-08-06, che al momento della scrittura include ancora l'attuale ESR (`140.13.0esr`) e qualsiasi pin `version` in quella finestra — vengono rifiutate dal controllo sopra indicato. I canali release e beta non sono interessati. foxcage recupera le chiavi da `keys.openpgp.org` anziché da `keyserver.ubuntu.com` perché quest'ultimo non ha servito né la subchiave sostitutiva né la revoca per giorni dopo la rotazione; un keyserver obsoleto romperebbe le build all'istante e ridurrebbe silenziosamente il controllo di revoca a un no-op.
### Fork di Firefox (LibreWolf)
foxcage può eseguire un fork di Firefox orientato alla privacy al posto del Firefox upstream:```toml
fork = "librewolf" # default is "firefox"
[librewolf]
version = "146.0.1-1" # optional pin; partial pins ("146", "146.0.1") also work
Oppure per avvio singolo tramite CLI:```sh foxcage @tmp --fork librewolf https://example.com
**LibreWolf**: fork di Firefox con privacy irrobustita — protezione dal tracciamento rigorosa, DoH, RFP, telemetria disattivata per impostazione predefinita. Tarball Linux firmato da GitLab (`librewolf-community/browser/bsys6`), verificato con GPG contro la chiave dei Maintainers di LibreWolf `662E 3CDD 6FE3 2900 2D0C A5BB 4033 9DD8 2B12 EF16` con un controllo incrociato `.sha256sum` associato, sotto le stesse [regole di revoca](#revoked-signing-keys) di Firefox. Il `librewolf.cfg` incluso in LibreWolf viene preservato; foxcage aggiunge le proprie preferenze sopra senza sovrascriverle. I maintainers hanno ruotato la loro sottochiave di firma il 2026-04-25 senza indicarne il motivo; i tarball attuali sono stati firmati prima di quella data, quindi si installano con un avviso anziché essere rifiutati.
**Il canale è solo Firefox**: `firefox.channel = "beta" | "esr"` viene rifiutato quando `fork` è diverso da `"firefox"`. LibreWolf ha un unico canale di rilascio.
Cambiare `fork` (tramite config o `--fork`) modifica l'hash del Containerfile, il che attiva una ricostruzione al prossimo avvio — nessun `--rebuild` manuale necessario.
#### Compatibilità dei profili
> **Usa un profilo dedicato per ogni fork.** L'impostazione predefinita più sicura è lasciare che foxcage fornisca il proprio profilo (ometti `profile` dalla config), oppure punta `profile` a una directory che non apri anche dall'host.
- **LibreWolf**: *di solito* va bene condividerlo con il tuo profilo Firefox dell'host — LibreWolf segue le versioni di Firefox entro pochi giorni, quindi i conflitti di schema `compatibility.ini` sono rari. Rischi: (1) è sicuro solo l'uso sequenziale (il file di blocco di Firefox impedisce aperture simultanee); (2) nella breve finestra dopo una release stabile di Firefox, avviare prima Firefox e poi LibreWolf può attivare una finestra di migrazione "usato da una versione più recente"; (3) le funzionalità che LibreWolf rimuove (Sync, Pocket, account Mozilla) non funzionano silenziosamente ma non corrompono i dati.
### Gabbie con nome
Esegui istanze sandbox separate con la propria config e il proprio profilo Firefox:```sh
./foxcage @work
Questo carica ~/.config/foxcage/work.toml e utilizza un'immagine separata (foxcage-work), un container (foxcage-work) e un volume (foxcage-work-profile). Il file di configurazione deve esistere per le gabbie con nome. I nomi delle gabbie possono contenere solo lettere, cifre, trattini e trattini bassi.
I file di configurazione si trovano in $XDG_CONFIG_HOME/foxcage/ (per impostazione predefinita ~/.config/foxcage/).
config.toml — gabbia predefinita (opzionale, con impostazioni predefinite sensate senza di esso)<name>.toml — gabbia con nome, caricata con @<name> (obbligatorio)Le chiavi di configurazione sconosciute vengono rifiutate con un errore. Consulta config.toml.example per tutte le opzioni disponibili con i valori predefiniti.
profile = "~/.mozilla/firefox/xxxxxxxx.default-release"
downloads_dir = "~/Downloads"
[firefox]
[librewolf]
[network]
[mounts]
bind = [ "~/Documents:ro", ]
[init]
### Profilo Firefox dell'host
Per condividere un profilo Firefox dell'host con la gabbia, imposta `profile` sulla directory del profilo. Trova il percorso del tuo profilo visitando `about:profiles` in Firefox sull'host — oppure punta semplicemente a una nuova directory vuota se vuoi che la gabbia inizi con un profilo pulito che persiste sull'host.```toml
profile = "~/.mozilla/firefox/xxxxxxxx.default-release"
Solo questa directory viene montata tramite bind nella gabbia. I profili adiacenti sotto ~/.mozilla/firefox/ e il registro profiles.ini non sono esposti — una gabbia compromessa non può manometterli.
Se profile non è impostato, un volume Podman con nome memorizza il profilo Firefox (vedi "Cosa persiste" più sotto). Se lo stesso profilo è già aperto in Firefox sull'host, il file di blocco per profilo di Firefox causerà un conflitto — usa un profilo dedicato per ogni gabbia.
Per impostazione predefinita, il contenitore usa pasta con loopback dell'host bloccato e DNS dell'host. pasta richiede podman 4.4 o successivo (è il default rootless dalla versione 5.0 di podman).
Rete host rimuove completamente l'isolamento di rete. Usala quando la gabbia deve raggiungere servizi sul localhost dell'host (ad es. un server di sviluppo locale, un database su 127.0.0.1):```toml
[network]
mode = "host"
`dns` non può essere combinato con `mode = "host"` — la rete host utilizza già il resolver del sistema.
> **La modalità host rinuncia a più del solo localhost.** Colloca la gabbia nel namespace di rete dell'host, e i socket Unix astratti sono limitati a quel namespace piuttosto che al filesystem. Quindi una gabbia in modalità host può raggiungere direttamente i socket a indirizzo astratto sull'host — incluso `@/tmp/.X11-unix/X0` di Xwayland se esegui X11 o Xwayland (registrazione degli input, nonostante foxcage sia solo Wayland), e un bus di sessione configurato con `unix:abstract=…`, che aggirerebbe il proxy D-Bus filtrato. Questo è intrinseco alla condivisione dello stack di rete, non qualcosa che foxcage può filtrare. Usa la modalità host quando ti serve, e preferisci una gabbia nominata che avvii solo per quello scopo.
**Gabbie solo IPv4** disabilitano completamente IPv6:```toml
[network]
ipv4_only = true
Or per launch with the --ipv4-only flag (short form -4, as in ssh/curl/pasta):```sh
./foxcage @tmp -4 https://example.com
Questo esegue pasta in modalità solo IPv4 (`-4`), quindi il container non ha alcuno stack IPv6, e imposta inoltre `network.dns.disableIPv6` in Firefox così da non risolvere i record AAAA — cosa che conta quando DoH è abilitato, poiché le risposte DoH bypassano il resolver del container. `ipv4_only` non può essere combinato con `mode = "host"` — il networking host utilizza direttamente lo stack di rete dell'host, quindi disabilita IPv6 sull'host invece.
### Comandi di init
Esegui comandi personalizzati al momento della build o all'avvio del container tramite `[init]`:
- **`build`** — viene eseguito al momento della build dell'immagine come root. Usalo per installare pacchetti o altre configurazioni lente. Le modifiche ai comandi di build attivano automaticamente una ricostruzione dell'immagine.
- **`root`** — viene eseguito all'avvio del container come root, prima di Firefox. Usalo per attività root rapide a runtime (regolazione dei permessi, scrittura di file di configurazione).
- **`user`** — viene eseguito all'avvio del container come tuo utente, prima di Firefox. Usalo per creare directory, impostare lo stato a livello utente.```toml
[init]
build = [
"apt-get update && apt-get install -y --no-install-recommends fonts-noto-cjk",
"rm -rf /var/lib/apt/lists/*",
]
root = ["chmod 777 /tmp/shared"]
user = ["mkdir -p ~/workspace"]
Tutte e tre le chiavi sono liste di stringhe di comandi shell. Se un qualsiasi comando fallisce, il container esce senza avviare Firefox.
Nota di sicurezza: Quando init.root è impostato, il container si avvia come root con CAP_SETUID e CAP_SETGID aggiunte (oltre alla CAP_SYS_CHROOT predefinita) così da poter tornare all'utente regolare. Queste capacità sono mantenute solo durante la fase di init come root — dopo l'abbassamento dei privilegi, il processo dell'utente regolare non ha capacità aggiuntive. Senza init.root, il container viene eseguito con il set di capacità minimo predefinito.
Senza configurazione, un volume Podman nominato memorizza il profilo Firefox (segnalibri, impostazioni, estensioni, plugin Widevine DRM). Tutto il resto è effimero.
foxcage-profilefoxcage-<name>-profilePer ricominciare da zero, rimuovi il volume:```sh podman volume rm foxcage-profile
Se `profile` è impostato, la directory host viene montata direttamente e non viene creato alcun volume.
Le estensioni elencate in `extensions` non fanno parte di quello stato: risiedono nell'immagine e vengono reinstallate a ogni avvio, quindi la rimozione del volume (o l'uso di una cage effimera, che non ne ha) non le fa perdere.
### Utilizzo del disco
Ogni immagine della cage è di circa 1 GB. Una ricostruzione ri-taggia l'immagine e lascia la precedente come voce `<none>` non taggata, quindi foxcage rimuove l'immagine appena sostituita dopo ogni build riuscita. Rimuove solo quella specifica immagine e mai una che una cage in esecuzione sta ancora utilizzando.
Le immagini orfane create prima dell'introduzione di questo comportamento non vengono ripulite retroattivamente. Per recuperarle:```sh
podman images --filter dangling=true # review first
podman image prune # then remove
Gli aggiornamenti di Firefox vengono rilevati automaticamente a ogni avvio. Per forzare una ricostruzione completa (ad es. per applicare immediatamente gli aggiornamenti di sicurezza di sistema):```sh ./foxcage --rebuild
## Theming
foxcage passa automaticamente quanto segue dall'host, così Firefox nel container appare e si comporta come un'applicazione nativa:
- **Font.** I font di sistema (`/usr/share/fonts`) e i font utente (`~/.local/share/fonts`) vengono montati in sola lettura. Anche la configurazione dei font da `~/.config/fontconfig` viene passata.
- **Tema GTK e modalità scura.** Rilevati tramite `GTK_THEME` o `gsettings` e passati al container. La configurazione GTK da `~/.config/gtk-3.0` e `~/.config/gtk-4.0` viene montata in sola lettura.
- **Fuso orario.** Il nome del fuso orario dell'host (rilevato da `TZ`, dal symlink `/etc/localtime` o da `/etc/timezone`) viene passato nel container come `TZ`, e `/etc/localtime` viene montato in sola lettura. Servono entrambi: Firefox deriva il fuso orario JavaScript dal *nome* della zona, non dal contenuto del file — senza `TZ`, i siti web mostrerebbero gli orari in UTC.
- **Locale.** `LANG` viene passato. La locale dell'host viene generata nell'immagine del container al momento della build.
**Etichetta Cage.** La barra dei menu di Firefox mostra "FoxCage" (o "FoxCage - nome" per le cage con nome) così puoi capire a colpo d'occhio che sei in una sessione containerizzata. La barra dei menu è sempre visibile tramite la policy aziendale.
Il container include solo il tema GTK Adwaita. Su desktop GNOME funziona subito. Su KDE o altri desktop, Firefox ripiegherà su Adwaita se il tuo tema GTK (es. Breeze) non è installato nel container. Il rilevamento della modalità scura funziona comunque purché la preferenza sia impostata tramite `gsettings` o `GTK_THEME`.
## Decodifica video hardware (VA-API)
Il container ha il proprio userland, quindi i driver VA-API installati sull'host sono
irrilevanti — l'immagine include i propri. `va-driver-all` trascina `i965-va-driver` (Intel
più vecchia) e `mesa-va-drivers` (AMD, nouveau), insieme a `intel-media-va-driver-non-free`
(Intel Gen8+, il driver iHD) e `libva2`/`libva-drm2`, che Firefox carica a runtime.
La decodifica hardware richiede il passaggio di `/dev/dri`, cosa che foxcage fa automaticamente
ogni volta che l'host lo possiede. Niente da configurare.
Il driver Intel è la build **non-free**, quindi l'immagine abilita il componente `non-free`
di Debian. Il `intel-media-va-driver` libero di Debian è un reimpacchettamento `+dfsg` con i
kernel codec non ridistribuibili rimossi, e ciò che perde è la decodifica AV1 — il formato
che YouTube ora serve di default. La build libera lascerebbe AV1 ripiegare sul software
su ogni macchina Intel.
Per verificare che funzioni davvero, esegui `vainfo` dentro una cage live:```bash
podman exec foxcage-<name> vainfo
Dovrebbe elencare il driver in uso (iHD su Intel, radeonsi su AMD) e i profili
supportati — VAProfileH264*, VAProfileVP9Profile0, VAProfileAV1Profile0 e così via.
Il controllo equivalente dall'interno del browser è about:support → Media, dove la
colonna Hardware Decoding dovrebbe indicare Supported per H264, VP8, VP9, HEVC e AV1. Con
un video in riproduzione, intel_gpu_top sull'host mostra attività sul motore Video.
La codifica hardware encoding è separata, e su Intel proviene dallo stesso driver: H264 e
HEVC dovrebbero indicare Supported in quella colonna, che è ciò che WebRTC usa per il
flusso della fotocamera in uscita nelle videochiamate e ciò che MediaRecorder usa. La codifica
VP8, VP9 e AV1 rimane Unsupported — Firefox collega solo gli encoder VA-API H264 e HEVC,
qualunque sia la capacità della GPU.
I codec audio (AAC, MP3, Opus, Vorbis, FLAC, Wave) indicano Unsupported sotto Hardware
Decoding su ogni macchina — nessuna GPU consumer ha un blocco di decodifica audio. Quella riga
non è una configurazione errata.
Se vainfo riporta failed to initialize display, il container non può aprire
/dev/dri/renderD128. Su un normale desktop systemd, logind concede al tuo utente un ACL su
quel dispositivo, quindi di solito significa che foxcage viene eseguito da una sessione che non
possiede la sessione grafica (SSH, una TTY diversa).
Il DRM Widevine funziona subito. Alla prima visita a un sito protetto da DRM, Firefox scaricherà automaticamente il CDM Widevine. Potrebbe volerci un momento.
foxcage usa un proxy D-Bus filtrato per dare a Firefox accesso al XDG Desktop Portal e al demone di notifiche dell'host. Queste funzionalità sono sicure perché tutto l'accesso è mediato dall'utente — l'host mostra finestre di dialogo native con cui devi interagire. Un browser compromesso non può accedere silenziosamente alle risorse dell'host.
mailto:, link magnet, ecc. si aprono tramite il selettore di app dell'hostQuesti passano i dispositivi dell'host direttamente nel container e sono disattivati per impostazione predefinita — a differenza delle funzionalità del portal sopra, non c'è conferma lato host. Un browser compromesso potrebbe usare l'hardware silenziosamente.```toml webcam = true # /dev/video* — webcam for video calls local_printers = true # CUPS socket — USB printers (network printers work by default) security_keys = true # /dev/hidraw* — FIDO2/U2F hardware keys
## Non ancora supportato
Alcune funzionalità delle piattaforme web non funzionano nel container a causa della mancata integrazione con l'host. Queste sono elencate qui per trasparenza.
**Bluetooth, USB, seriale e NFC.** Le API Web Bluetooth, WebUSB, Web Serial e WebNFC richiedono l'accesso ai dispositivi e servizi di sistema (BlueZ, udev) che non sono disponibili nel container.
**Gamepad e MIDI.** L'API Gamepad richiede l'accesso a `/dev/input/`. Il Web MIDI richiede l'accesso al sequencer ALSA. Nessuno dei due viene inoltrato.
**Installazione PWA.** Le Progressive Web App non possono essere installate sul desktop dell'host dall'interno del container.
**Accessibilità.** Il supporto per gli screen reader tramite AT-SPI è disabilitato (`NO_AT_BRIDGE=1`) — il container non ha alcuna connessione al bus di accessibilità dell'host. La sintesi vocale dell'API Web Speech funziona: `speech-dispatcher` con il motore `espeak-ng` è installato nella cage e viene avviato automaticamente al primo utilizzo, con l'audio instradato attraverso la socket PulseAudio condivisa.
## Configurazione dell'host
### Consigliato: storage overlay
Podman rootless potrebbe ripiegare sul driver di storage `vfs`, che copia interi layer di immagini invece di utilizzare i mount overlay. Questo rende l'avvio del container dopo una build molto più lento. Controlla quale driver hai:```sh
podman info --format '{{.Store.GraphDriverName}} {{.Store.GraphStatus}}'
overlay con Native Overlay Diff:true è il percorso rapido e non richiede configurazione — su kernel 5.13 o successivi con un filesystem di supporto ext4/xfs, Podman usa overlayfs non privilegiato direttamente. Se è ciò che vedi, non c'è nulla da fare, e installare fuse-overlayfs non servirà.
Solo se ti trovi su vfs (kernel vecchio, o un filesystem di supporto che non può eseguire overlay non privilegiato) installa fuse-overlayfs e aggiungi a ~/.config/containers/storage.conf:```toml
[storage]
driver = "overlay"
[storage.options.overlay] mount_program = "/usr/bin/fuse-overlayfs"
Questo è un fallback, non un aggiornamento: FUSE instrada ogni operazione del filesystem attraverso lo spazio utente ed è più lento rispetto all'overlay nativo. Impostare `mount_program` su un sistema che supporta l'overlay nativo peggiora le cose, non le migliora.
### Impostare foxcage come browser predefinito
Prima di tutto, assicurati che lo script `foxcage` sia nella sua posizione permanente (ad es. `~/bin/foxcage` o `/usr/local/bin/foxcage`). Il comando di installazione registra il percorso corrente dello script nel file `.desktop`, quindi spostarlo successivamente romperà il launcher.
Poi esegui:```sh
foxcage --install
Questo crea un file .desktop che punta alla posizione corrente dello script, installa l'icona di foxcage e aggiorna i database del desktop e delle icone. FoxCage dovrebbe quindi apparire nel menu delle applicazioni.
Per impostare foxcage come browser web predefinito, così che i link cliccati in altre applicazioni si aprano in foxcage:```sh xdg-settings set default-web-browser foxcage.desktop
Se una gabbia è già in esecuzione, gli URL si aprono come nuova scheda nel browser esistente.
Per annullare:```sh
foxcage --uninstall
StartupNotify=true è impostato nel file .desktop, che indica al compositor di mostrare un cursore a spirale mentre foxcage si avvia. Quando è necessaria una build dell'immagine (che può richiedere diversi minuti), foxcage invia una notifica desktop così sai che Firefox sta arrivando. Qualsiasi errore di uscita anticipata (refuso nella configurazione, dipendenza mancante, nome cage malformato) viene anche mostrato come notifica desktop, così gli utenti che avviano dal desktop non restano a fissare il nulla quando foxcage fallisce senza un terminale collegato. Entrambi richiedono notify-send (da libnotify-bin su Debian/Ubuntu) — se non è installato, le notifiche vengono silenziosamente saltate e l'errore va comunque a stderr.
Se preferisci creare il file .desktop manualmente, crea ~/.local/share/applications/foxcage.desktop:```ini
[Desktop Entry]
Type=Application
Name=FoxCage
Comment=Firefox in a rootless Podman container
Exec=/path/to/foxcage %u
Icon=foxcage
MimeType=text/html;x-scheme-handler/http;x-scheme-handler/https;
Terminal=false
Categories=Network;WebBrowser;
StartupNotify=true
StartupWMClass=foxcage
Sostituisci `/path/to/foxcage` con il percorso effettivo dello script. Registralo:```sh
update-desktop-database ~/.local/share/applications
La suite di test utilizza pytest + pytest-cov, dichiarati come dipendenze solo per lo sviluppo in requirements-dev.txt.```
pip install -r requirements-dev.txt
pytest
I test sono completamente ermetici — niente podman, niente rete, niente filesystem reale oltre a `tmp_path` di pytest. La suite impone il **100% di copertura di righe e rami** (configurata in `pytest.ini` e `.coveragerc`); qualsiasi riga non coperta, o lato non eseguito di un condizionale, fa fallire l'esecuzione. La CI esegue la suite a ogni push tramite `.gitlab-ci.yml`.
## Ringraziamenti
Questo progetto è stato sviluppato da Mike Cardwell, con l'assistenza di [Claude Code](https://claude.ai/claude-code), lo strumento di codifica AI di Anthropic.
## Supporta/Apprezza il mio lavoro
- [Bitcoin](bitcoin:1PQLtWnjUi1itHLG6QCQeHM3Nxua8pRsq1): 1PQLtWnjUi1itHLG6QCQeHM3Nxua8pRsq1
- [Paypal](https://www.paypal.me/grepular)
org.freedesktop.Notificationsorg.freedesktop.portal.Desktoporg.mozilla.*org.librewolf.*org.freedesktop.portal.Desktop è consentito nel suo insieme, perché è così che funzionano il selettore file, "apri link in un'altra app" e la condivisione dello schermo. Espone anche RemoteDesktop (tastiera/mouse sintetici per l'intera sessione), Camera e Location. Questi sono controllati dai dialoghi di approvazione del tuo desktop piuttosto che da foxcage — e il prompt RemoteDesktop assomiglia al prompt di condivisione schermo, quindi leggi i dialoghi di approvazione prima di accettarli. xdg-dbus-proxy non ha una regola "nega un'interfaccia", quindi restringere questo significa enumerare ogni interfaccia di cui Firefox ha bisogno; vedi docs/DESIGN.md per il motivo per cui questo non viene fatto per impostazione predefinitaprofile, downloads_dir, [mounts] bind aggiuntivi) usano nosuid,noexecgpg --verify, che esce con 0 per una firma fatta da una chiave revocata e per qualsiasi chiave nel portachiavi. foxcage richiede inoltre che la firma si colleghi alla chiave primaria fissata e rifiuta qualsiasi release firmata da una subkey che il suo proprietario ha revocato come compromessa — vedi Chiavi di firma revocate--rm) — le scritture sul filesystem vengono perse all'uscita