Run fully isolated Chrome browser profiles in Docker containers — managed from a native GNOME desktop app.
Each browser profile lives in its own Docker container. Profiles are completely isolated from each other and from your host browser — no shared cookies, history, sessions, or fingerprints.
The app is a native Electron desktop application for GNOME/Wayland Linux. No web server, no Flask, no localhost port — the UI talks directly to the backend via a secure stdio IPC bridge.
Chrome that opens via this manager reads your host's fonts, icons, GTK theme, and dark/light mode preference (read-only) so it feels native — while remaining fully isolated at the data and identity level.
- Full profile isolation — Docker container per profile, separate data directories
- Wayland-native — runs on Wayland via
--ozone-platform=wayland, no X11 needed - Stealth mode — each profile presents as its own machine: stable per-profile CPU core count, browser language, GPU backend (real GPU or software), timezone, user-agent, hostname, and window size
- Host files read-only — your home directory (or a per-profile custom folder) is mounted read-only into each container at
/home/chrome/host - Per-profile proxy — route a profile's traffic through a SOCKS5/HTTP proxy for a different egress IP; manage a shared proxy list in the app (sidebar → Proxies), pick one per profile from a dropdown, or enter a custom URL; loopback addresses are rewritten to the host automatically, WebRTC is forced through the proxy, and authenticated proxies (
socks5://user:pass@host:port) are handled by an in-container auth wrapper - Dark / Light mode — follows host GNOME colour scheme; toggle in titlebar
- Host preferences inherited — fonts, icons, GTK theme, cursor theme all mounted read-only
- No localhost attack surface — all IPC is over stdio JSON, no HTTP server
- Profile import / export — safe ZIP/TAR archive with path-traversal protection
- GNOME integration —
.desktopentry, app icon,chrome-isolation --profile <name>CLI - Hardened security — no
--privileged, noSYS_ADMIN, no--ipc=host;/.dockerenvmasked
GNOME App (Electron)
└── electron/main.js — BrowserWindow, IPC handlers, window controls
└── electron/preload.js — contextBridge (narrow API only)
└── electron/renderer/ — UI (HTML + CSS + JS, no Node access)
└── index.html
└── style.css — dark/light design system
└── app.js
│ stdio JSON (newline-delimited)
▼
Python Backend (bridge.py)
└── bridge.py — stdin/stdout JSON-RPC dispatcher
└── profile_service.py — high-level profile operations
└── docker_manager.py — Docker container lifecycle
└── registry.py — profile path registry (JSON)
└── archive.py — safe import/export
└── validator.py — input validation (path traversal prevention)
└── desktop_manager.py — .desktop entry generation
└── config.py — paths & constants
│ docker run / docker stop
▼
Docker Container (isolated-chrome image)
└── Alpine Linux + Chromium
└── scripts/docker/stealth-launch.sh — entrypoint
└── scripts/docker/hardware-spoof.sh — stable fingerprint
└── scripts/docker/user-agent-spoof.sh — stable UA
| Dependency | Version | Notes |
|---|---|---|
| Linux (GNOME + Wayland) | Any modern | Arch, Fedora, Ubuntu 22.04+ |
| Node.js | 18+ | nodejs.org |
| npm | 8+ | Bundled with Node |
| Python | 3.10+ | Usually pre-installed |
| Docker | 24+ | docs.docker.com |
python-docker |
latest | pip install docker |
Download the latest .AppImage from the Releases page. It runs on any Linux distribution — Node.js, Python, and npm are bundled inside; no compilation or package managers needed. The only system requirement is Docker (the app runs one container per profile — first launch offers to install it if missing).
# Download, make executable, run
wget https://github.com/MuhammadUsamaMX/chrome-isolation/releases/latest/download/chrome-isolation-1.1.0-linux-x64.AppImage
chmod +x chrome-isolation-1.1.0-linux-x64.AppImage
./chrome-isolation-1.1.0-linux-x64.AppImageFirst launch: the app checks for Docker, and builds the isolated-chrome container image automatically (one-time, a few minutes).
# Debian / Ubuntu
sudo dpkg -i chrome-isolation-1.1.0-linux-x64.deb && sudo apt-get install -f
# Fedora / RHEL
sudo dnf install chrome-isolation-1.1.0-linux-x64.rpm# 1. Clone
git clone https://github.com/MuhammadUsamaMX/chrome-isolation.git
cd chrome-isolation
# 2. Install npm deps
npm install
# 3. Install Python dep
pip install docker
# 4. Run the installer (copies app, builds Docker image, creates .desktop entry)
bash install.shThe installer:
- Copies the app to
~/.local/share/chrome-isolation-manager/ - Builds the
isolated-chromeDocker image - Creates
~/.local/bin/chrome-isolationlauncher - Installs
.desktopentry for the GNOME app grid - Stops and disables the old
chrome-manager.serviceif present
After install, launch from the GNOME app grid or:
chrome-isolationClick New Profile in the sidebar. Give it a name (letters, numbers, dash, underscore). Optionally set a custom storage path, a Host Folder — a directory from your machine mounted read-only into the container at /home/chrome/host (leave empty to mount your home directory; use Browse… to pick it with the file manager) — and a Proxy chosen from the saved list or entered as a custom URL such as socks5://127.0.0.1:1080 or socks5://user:pass@proxy.example.com:1080.
Click Proxies in the sidebar to add, view, and delete named proxies shared by all profiles (e.g. tunnel-alan1 → socks5://127.0.0.1:10080). Profiles reference them by name, so updating a proxy in the list updates every profile using it.
Click Edit on any profile card to change the read-only host folder, proxy, and machine timezone after creation. Changes apply the next time the profile is launched.
Click Launch on any profile card. A Docker container starts and Chromium opens on your Wayland display. The container uses your host fonts, icons, and GTK theme (read-only), and presents the profile's own machine fingerprint (CPU cores, language, GPU backend, timezone, user-agent, hostname, window size).
Click Stop on the card.
Use Export to save a profile as a ZIP archive. Use Import in the sidebar to restore from an archive. Archives are validated for path traversal and symlink attacks before extraction.
After creating a profile, a .desktop entry is added to GNOME so you can launch it directly:
chrome-isolation --profile WorkClick the moon/sun icon in the titlebar. Preference is saved across sessions.
| Issue | Fix |
|---|---|
| S1 — Path traversal in profile names | validator.py — regex allowlist + os.path.realpath prefix check |
| S2 — Archive extraction traversal | archive.py — member-by-member validation, temp-dir staging, tarfile filter="data" |
| S3 — Localhost HTTP attack surface | Eliminated — no Flask, all IPC via stdio JSON bridge |
| S4 — Orphaned custom-path profiles | registry.py — JSON registry tracks all profiles with actual paths |
| S5 — Container over-privilege | No --privileged, no SYS_ADMIN; /.dockerenv masked; realistic shm_size, ulimits. The container entrypoint uses --no-sandbox because Docker's default seccomp profile blocks unprivileged user namespaces — the container is the security boundary |
| S6 — Flask dev server in production | Eliminated — Electron replaces Flask entirely |
| S7 — Host files exposed to container | Home directory (or per-profile folder) mounted read-only at /home/chrome/host — the container can read host files but never write to them |
| S8 — Per-profile proxy | Optional SOCKS5/HTTP proxy per profile; loopback rewritten to host.docker.internal (host-gateway alias), WebRTC forced through the proxy to prevent IP leaks, and user:pass@ credentials handled by an in-container auth wrapper (Chromium ignores credentials in proxy URLs) |
chrome-isolation/
├── electron/ # Electron frontend
│ ├── main.js # Main process
│ ├── preload.js # contextBridge API
│ └── renderer/ # UI
│ ├── index.html
│ ├── style.css
│ └── app.js
├── backend/ # Python backend
│ ├── bridge.py # stdio JSON-RPC
│ ├── profile_service.py
│ ├── docker_manager.py
│ ├── registry.py
│ ├── archive.py
│ ├── validator.py
│ ├── desktop_manager.py
│ └── config.py
├── tests/ # Backend tests
├── scripts/
│ ├── build/after-pack.js # electron-builder post-pack hook
│ └── docker/ # Container entrypoint scripts
│ ├── stealth-launch.sh
│ ├── hardware-spoof.sh
│ └── user-agent-spoof.sh
├── assets/icons/icon.png
├── bridge.spec # PyInstaller spec for the Python bridge
├── Dockerfile
├── build.sh # AppImage / .deb / .rpm build script
├── install.sh # Desktop app installer
├── uninstall.sh # Full uninstaller (all install methods)
├── setup.sh # Dev environment setup
├── package.json
└── requirements.txt
# Run without installing
npm start
# Watch bridge stderr (Python tracebacks) in terminal
npm start 2>&1The renderer has zero Node.js access — all calls go through window.api (contextBridge) → IPC → main process → Python bridge → Docker.
bash <(curl -s https://raw.githubusercontent.com/MuhammadUsamaMX/chrome-isolation/main/uninstall.sh)
# or, from a clone:
bash uninstall.shThe script confirms first, then removes: profile containers + the isolated-chrome Docker image, all profile data (~/Chrome), the app data dir (registry, proxies, signatures), launcher, .desktop entry, icon, and the .deb/.rpm package if installed.
rm -rf ~/.local/share/chrome-isolation-manager
rm ~/.local/bin/chrome-isolation
rm ~/.local/share/applications/chrome-isolation.desktop
rm ~/.local/share/icons/hicolor/256x256/apps/chrome-isolation.png
rm -rf ~/Chrome # profile data — back it up first!
docker rmi isolated-chrome
# .deb: sudo dpkg -r chrome-isolation
# .rpm: sudo dnf remove chrome-isolationNon-Commercial — All rights reserved by MuhammadUsamaMX. See LICENSE for full terms.