A full Chromium browser running inside Docker, accessible from any device on your local network via a web browser. Uses linuxserver/chromium with KasmVNC for streaming.
Contributions are welcome — see CONTRIBUTING.md.
- Docker and Docker Compose installed on the host machine
- Port 3000 (or your configured
PORT) open on the host firewall
Find your user and group IDs (needed for .env):
id -u # PUID
id -g # PGID-
Copy the example env file and set your credentials:
cp .env.example .env
Edit
.envand setPUID,PGID,CHROME_PASSWORD, andTZat minimum. -
Start the container:
./scripts/start.sh
-
Find your host machine's local IP:
hostname -I | awk '{print $1}'
-
Open a browser on any device on the same network and go to:
Protocol URL Notes HTTP http://<host-ip>:3000No warnings, works everywhere HTTPS https://<host-ip>:3001Self-signed cert — accept the browser warning once Log in with the credentials from your
.envfile.
| Device | Recommended Browser |
|---|---|
| Desktop/Laptop | Any modern browser |
| Android | Chrome or Firefox |
| iPad/iPhone | Safari or Chrome |
| Chromebook | Chrome |
The browser UI streams as video — no app or plugin required on the client.
Use the clipboard panel (toolbar on the left side of the KasmVNC interface) to paste text into the remote browser or copy text out of it.
All options are set in .env:
| Variable | Default | Description |
|---|---|---|
HTTP_PORT |
3000 |
Host port for HTTP access |
HTTPS_PORT |
3001 |
Host port for HTTPS access (self-signed cert) |
USE_VPN |
false |
Set to true to route all traffic through WireGuard (requires vpn/*.conf) |
CLEAN_START |
false |
Set to true to wipe all browser data on every container start |
CHROME_USER |
admin |
Login username |
CHROME_PASSWORD |
— | Login password (required, no default) |
TZ |
America/New_York |
Timezone for the container |
PUID |
1000 |
Host user ID — run id -u to get yours |
PGID |
1000 |
Host group ID — run id -g to get yours |
SHM_SIZE |
2gb |
Shared memory — do not set below 1gb |
CPU_LIMIT |
8.4 |
Max CPU cores allocated (set to ~70% of host cores) |
MEM_LIMIT |
11G |
Max RAM allocated (set to ~70% of host RAM) |
After changing .env, apply with:
docker compose up -dRoute all Chromium traffic through a WireGuard VPN — useful for accessing geo-restricted content or browsing privately. No VPN app needed on the client device.
-
Get a WireGuard config file from your VPN provider:
- ProtonVPN: Account → Downloads → WireGuard configuration
- Mullvad: Account → WireGuard configuration → Generate key
- Any provider that offers WireGuard
.confdownloads
-
Place the
.conffile in thevpn/directory:vpn/ └── wg0.conf ← your config file (any filename ending in .conf)This directory is gitignored — your config will never be committed.
-
Enable VPN in
.env:USE_VPN=true -
Start with the VPN-aware script:
./scripts/start.sh
start.sh applies docker-compose.vpn.yml as a Compose override, which starts a linuxserver/wireguard container and attaches Chromium to its network namespace. All traffic that Chromium sends exits through the WireGuard tunnel — no split-tunneling, no leak path.
Chromium waits for the tunnel to be fully established before launching (via a wg show healthcheck), so there is no window where traffic escapes unencrypted.
# VPN mode requires the override file to tear down correctly
docker compose -f docker-compose.yml -f docker-compose.vpn.yml downOr set USE_VPN=false in .env and run ./scripts/start.sh to switch back to non-VPN mode (bring down the VPN stack first with the command above).
# Confirm WireGuard interface is active
docker exec remote-wireguard wg show
# Confirm Chromium's traffic exits via the VPN server (not the host IP)
docker exec remote-chromium curl -s ifconfig.meERROR: USE_VPN=true but no .conf file found in vpn/
Place your WireGuard .conf file in the vpn/ directory and re-run ./scripts/start.sh.
WireGuard container starts but tunnel never becomes healthy
Check logs: docker compose logs wireguard. Verify the .conf file is valid and the VPN server endpoint is reachable from the host.
Ports 3000/3001 unreachable in VPN mode
In VPN mode, ports are declared on the wireguard container. Confirm both containers are running: docker compose -f docker-compose.yml -f docker-compose.vpn.yml ps
WireGuard kernel module not found
On kernels older than 5.6, install WireGuard on the host: sudo apt install wireguard (Debian/Ubuntu).
Bookmarks, history, cookies, and extensions are stored in a Docker named volume (chrome-data). Data survives container restarts and image updates.
To start with a completely clean browser every time the container starts, set CLEAN_START=true in .env:
# .env
CLEAN_START=trueThen restart: docker compose up -d. The Chromium profile is wiped before the browser launches on each start. The Docker volume itself is kept — switch back to CLEAN_START=false at any time to resume saving data.
To back up your browser profile (run from the project directory):
docker run --rm -v chrome-data:/data -v "$(pwd)":/backup alpine \
tar czf /backup/chrome-data-backup.tar.gz -C /data .To restore (run from the project directory):
docker run --rm -v chrome-data:/data -v "$(pwd)":/backup alpine \
tar xzf /backup/chrome-data-backup.tar.gz -C /datadocker compose pull
docker compose up -dYour data volume is preserved across updates.
docker compose downTo also delete saved browser data:
docker compose down -vCan't connect to the browser UI
- Confirm the container is running:
docker compose ps - Check logs for errors:
docker compose logs chromium - Verify the host IP with
hostname -Iand that port 3000 is not blocked by a firewall
Browser crashes immediately after login
SHM_SIZEis too low. Increase it to2gbin.envand restart:docker compose up -d
Blank or black screen after login
- The container is still initializing. Wait 10–15 seconds and refresh the page.
Login prompt rejects credentials
- Ensure
CHROME_PASSWORDis set in.env(not just.env.example) and restart the container.
File permission errors in logs
PUID/PGIDin.envdon't match the host user. Runid -uandid -gand update.envaccordingly.