Distrobox — izolowane testowanie aplikacji bez ryzyka aktualizacji
Masz działającą instalację aplikacji, na której wszystko działa, a na horyzoncie pojawia się nowa wersja. Chcesz ją sprawdzić, zanim nadpiszesz pakiet na hoście. Klasyczny Docker do programów z GUI (szczególnie Electron) jest uciążliwy: X11, GPU, FUSE, logowanie. Distrobox rozwiązuje dokładnie ten problem — kontener z pełną integracją graficzną, a instalacja na hoście zostaje nietknięta.
W ostatnim czasie miałem dwa takie przypadki. Czasem muszę skorzystać z wcześniejszej wersji slicera do mojej drukarki 3D — Snapmaker potrafi zrobić rozgardiasz przy aktualizacji i jest dramat z ustawieniami. Ostatnio też widzę i słyszę o problemach z Cursor: lista to-do nie działa w 3.12, a w 3.9 jest OK; modele znacząco spowolniły na jakimś rodzaju tasków, a na wcześniejszej wersji chodzą jak wcześniej. Przydałoby się coś, co można odpalić w izolowanym środowisku…
Ten artykuł najpierw wyjaśnia, czym jest Distrobox i kiedy ma sens, a potem — na realnym przykładzie — przeprowadza przez test Cursor 3.14.x obok stabilnej instalacji 3.9.x: osobny home, AppImage, pułapki z katalogiem roboczym oraz praktyczne obejście logowania OAuth.
Czym jest Distrobox
Distrobox to warstwa nad Podmanem lub Dockerem, której celem nie jest twarde sandboxowanie (jak Flatpak), tylko integracja. Kontener dostaje:
- dostęp do X11 / Wayland (okna GUI wyglądają jak natywne),
- dźwięk, USB, dyski,
- (domyślnie) Twój katalog domowy,
- możliwość eksportu aplikacji do menu hosta.
W praktyce uruchamiasz oprogramowanie z innej dystrybucji — albo osobną kopię tego samego programu — bez dual-bootu i bez walczenia z pełnym Dockerem pod Electronem. Ten sam wzorzec działa dla IDE, slicera, edytora audio czy dowolnej apki, której nie chcesz aktualizować „na ślepo”.
Do czego się go używa
Distrobox służy głównie do uruchamiania oprogramowania „jak na innej dystrybucji”, przy zachowaniu normalnego desktopu hosta. Typowe zastosowania:
- Aplikacje niedostępne lub problematyczne na Twojej dystrybucji — paczki tylko dla Fedory/Archa, stare zależności, konflikt bibliotek.
- Izolowane środowiska deweloperskie — osobny stack (Node, Python, toolchain) bez zaśmiecania systemu.
- GUI z kontenera — duża przewaga nad zwykłym Dockerem: okna, dźwięk i pliki z home działają bez ręcznej konfiguracji.
- Starsze lub nowsze wersje programów obok siebie — test lub rollback bez aktualizacji hosta (Cursor, slicer 3D, itd.).
- Eksport apki do menu hosta (
distrobox-export) — wygląda jak zwykła aplikacja systemowa.
Czego nie jest: twardym sandboxem bezpieczeństwa. Celowo mocno integruje się z hostem (home, X11, urządzenia). Do izolacji „nieufam temu kodowi” lepszy Flatpak albo zwykły kontener z ograniczonymi mountami.
Distrobox vs zwykły Docker
| Distrobox | Klasyczny Docker | |
|---|---|---|
| Cel | środowisko deweloperskie / GUI zintegrowane z hostem | izolacja usług, CI, serwery |
| Okna GUI | działa „od ręki” (X11/Wayland) | ręczny montaż socketów, dużo tarcia |
| Home | domyślnie współdzielony z hostem | zwykle osobny volume |
| Sandbox | słaby — nie traktuj jak izolacji bezpieczeństwa | silniejszy (przy sensownej konfiguracji) |
Wymagania
- Linux z Podmanem lub Dockerem (Distrobox preferuje Podmana, jeśli oba są zainstalowane),
- pakiet
distroboxz dystrybucji albo instalacja ze skryptu upstream.
Na Kubuntu / Ubuntu zwykle wystarczy:
sudo apt install distrobox podman
Przykład: nowy Cursor bez aktualizacji hosta
Cel: przetestować najnowszy Cursor (tu: AppImage 3.14.7), nie ruszając działającego pakietu .deb (np. 3.9.16 w /usr/bin/cursor).
Strategia:
- Kontener Distrobox z osobnym katalogiem home.
- W środku — AppImage najnowszej wersji.
- Dane edytora (
~/.config/Cursor) lądują w home kontenera, nie w hostowym.
Bez osobnego home Distrobox zamontuje Twój prawdziwy ~/ i nowy Cursor może nadpisać ustawienia / bazę SQLite działającej instalacji. Tego unikamy.
Host Distrobox (cursor-test)
───── ───────────────────────
/usr/bin/cursor (3.9.x) Cursor.AppImage (3.14.x)
~/.config/Cursor ~/cursor-test-home/.config/Cursor
↑ nietknięte ↑ izolowane dane
Ten sam układ przenosisz na inne aplikacje: osobny --home, binarka / AppImage / pakiet wewnątrz kontenera, host nietknięty.
Krok 1 — osobny home i utworzenie kontenera
mkdir -p ~/cursor-test-home
distrobox create \
--name cursor-test \
--image ubuntu:24.04 \
--home ~/cursor-test-home \
--additional-packages "libfuse2t64 libgtk-3-0 libnss3 libxss1 libasound2t64"
Kluczowe jest --home ~/cursor-test-home. Distrobox i tak dodatkowo zamontuje prawdziwy /home/$USER (integracja z hostem), ale zmienna $HOME w kontenerze wskazuje na katalog testowy — i tam powinny iść pliki konfiguracyjne aplikacji respektujących $HOME / XDG.
Wejście do kontenera:
distrobox enter -nw cursor-test
Flaga -nw (no workdir) sprawia, że lądujesz od razu w $HOME kontenera. Bez niej Distrobox zachowuje bieżący katalog z hosta — jeśli wchodzisz z /home/ty, po enter nadal jesteś w /home/ty i wygląda to, jakby --home nie działało.
Sprawdzenie:
echo $HOME # /home/ty/cursor-test-home
pwd # po -nw: to samo
ls ~ # skel (.bashrc, .profile, …) — nie Twój pełny home hosta
Jeśli
pwdpokazuje/home/ty, aecho $HOMEpokazuje.../cursor-test-home, wszystko jest OK — po prostu zróbcd ~albo wchodź z-nw.
Krok 2 — pobranie Cursor (AppImage)
Endpoint https://cursor.com/api/download?platform=linux-x64&releaseTrack=stable nie zwraca pliku binarnego, tylko JSON z polami downloadUrl, debUrl, version itd.
Błędne (dostaniesz plik ~600 B z JSON-em):
curl -L "https://cursor.com/api/download?platform=linux-x64&releaseTrack=stable" -o Cursor.AppImage
Poprawne:
# w kontenerze, w $HOME
URL=$(python3 -c "import json,urllib.request; print(json.load(urllib.request.urlopen('https://cursor.com/api/download?platform=linux-x64&releaseTrack=stable'))['downloadUrl'])")
curl -fL -o Cursor.AppImage "$URL"
chmod +x Cursor.AppImage
file Cursor.AppImage # oczekuj: ELF 64-bit … (~280 MB)
Uruchomienie:
./Cursor.AppImage
# na Ubuntu 24.04+ czasem potrzeba:
./Cursor.AppImage --no-sandbox
# albo gdy brakuje FUSE:
./Cursor.AppImage --appimage-extract-and-run
Wygodny launcher (opcjonalnie):
cat > ~/run-cursor.sh <<'EOF'
#!/bin/bash
set -euo pipefail
export HOME=/home/$USER/cursor-test-home # dostosuj ścieżkę
cd "$HOME"
exec ./Cursor.AppImage --no-sandbox "$@"
EOF
chmod +x ~/run-cursor.sh
Krok 3 — pułapka: logowanie OAuth w kontenerze
Cursor loguje się przez OAuth w zewnętrznej przeglądarce (xdg-open). W Distroboxie klik „Log in” często nic nie robi.
Dlaczego
- Distrobox podmienia
xdg-opennadistrobox-host-exec. distrobox-host-execopiera się ohost-spawn, ahost-spawnwymaga na hoście Flatpaka (interfejs D-Busorg.freedesktop.Flatpak.Development).- Bez Flatpaka dostajesz
Error: Cannot download host-spawn/ exit code 127 — przeglądarka się nie otwiera.
Nawet gdy uda się otworzyć przeglądarkę, pojawia się drugi problem: po zalogowaniu callback cursor://… na hoście trafia zwykle do hostowego Cursor (handler z /usr/share/applications), a nie do instancji w kontenerze.
Do smoke-testu funkcji AI nie warto z tym walczyć. Prostsze jest skopiowanie sesji z działającej instalacji na hoście.
Krok 4 — obejście OAuth: skopiowanie sesji z hosta
Cursor trzyma tokeny w SQLite:
~/.config/Cursor/User/globalStorage/state.vscdb
Klucze m.in.:
cursorAuth/accessTokencursorAuth/refreshTokencursorAuth/cachedEmailcursorAuth/cachedTeamcursorAuth/stripeMembershipType
Zamknij testowy Cursor, potem na hoście:
import sqlite3, shutil, time
host = "/home/USER/.config/Cursor/User/globalStorage/state.vscdb"
test = "/home/USER/cursor-test-home/.config/Cursor/User/globalStorage/state.vscdb"
keys = [
"cursorAuth/accessToken",
"cursorAuth/refreshToken",
"cursorAuth/cachedEmail",
"cursorAuth/cachedScopedProfile",
"cursorAuth/cachedSignUpType",
"cursorAuth/cachedTeam",
"cursorAuth/stripeMembershipType",
]
h = sqlite3.connect(f"file:{host}?mode=ro", uri=True)
vals = {k: h.execute("SELECT value FROM ItemTable WHERE key=?", (k,)).fetchone()[0] for k in keys}
h.close()
shutil.copy2(test, test + f".bak-{int(time.time())}")
t = sqlite3.connect(test)
for k, v in vals.items():
t.execute(
"INSERT INTO ItemTable(key,value) VALUES(?,?) "
"ON CONFLICT(key) DO UPDATE SET value=excluded.value",
(k, v),
)
t.execute("DELETE FROM ItemTable WHERE key=?", ("glass.lastSignedInAuthId",))
t.commit()
t.close()
print("OK")
Po restarcie AppImage powinien być zalogowany na to samo konto co host. To świadome współdzielenie sesji — wygodne do testów, nie do „twardej” izolacji tożsamości.
Jeśli jednak chcesz iść ścieżką przeglądarki: na hoście zainstaluj
flatpak(oficjalna ścieżkahost-spawn) albo doinstaluj przeglądarkę w kontenerze. Pamiętaj wtedy o konflikcie handleracursor://.
Krok 5 — co warto przetestować przed aktualizacją hosta
- start GUI, layout, otwarcie projektu,
- Agent / Chat / terminal,
- Git, rozszerzenia, MCP,
- typowy workflow dnia codziennego,
- toole, które lubisz, czas trwania komend.
Jeśli wszystko gra — aktualizujesz .deb na hoście jak zwykle. Jeśli nie — wyrzucasz kontener i zostajesz przy starej wersji.
Sprzątanie
distrobox stop cursor-test
distrobox rm cursor-test
rm -rf ~/cursor-test-home
Hostowy Cursor pozostaje bez zmian.
Checklist — szybka ściąga
distrobox create … --home ~/cursor-test-homedistrobox enter -nw cursor-test- Pobrać prawdziwy AppImage z
downloadUrl(nie surowy JSON z API) - Skopiować tokeny z hostowego
state.vscdb(OAuth w kontenerze zwykle nie rusza) - Przetestować typowy workflow
- Po teście:
distrobox rm+ ewentualna aktualizacja.deb
Podsumowanie
Distrobox to praktyczny sposób na „drugi Linux” pod GUI bez dual-bootu i bez Dockerowego circus z Electronem. Przyda się zarówno przy slicerze 3D, jak i przy IDE: osobny --home, binarka w kontenerze, host nietknięty.
W przypadku Cursor dodatkowo warto wiedzieć, że logowanie OAuth w Distroboxie potrafi kompletnie zamilknąć — do szybkiego testu najwygodniej skopiować sesję z działającej instalacji. Dzięki temu aktualizacja hosta przestaje być skokiem na główkę: najpierw sprawdzasz, potem dopiero nadpisujesz to, co działa.