23 min read

Self-Host Auto Browser with Docker and Reach noVNC Remotely

Install auto-browser with Docker Compose, verify the dashboard, MCP endpoint and noVNC takeover locally, then reach it securely over a Localtonet HTTP tunnel.

Self-Hosting ยท Auto Browser ยท Localtonet ยท 2026

Run Auto Browser locally with Docker, verify its controller, and understand the remote-access security boundary

Auto Browser gives an agent and a human operator access to a shared Playwright browser. This guide covers a local Docker deployment, authenticated REST checks, local noVNC takeover, and practical maintenance. It does not provide a validated remote noVNC or MCP-client deployment: the available documentation does not establish the complete public-host, gateway, Origin, and WebSocket configuration. We explain where a Localtonet HTTP tunnel fits, but keep both application ports unpublished until that security boundary is established.

๐Ÿ”’ Authenticated controller checks ๐Ÿ–ฅ๏ธ Local noVNC verification ๐Ÿ“ฆ Pinned historical lab baseline

What this guide establishes, and what it does not

This article concerns LvcidPsyche/auto-browser on GitHub, not the similarly named Chrome extension. The Docker project combines a browser controller with a browser-node component. Its local interface includes a dashboard, REST API, an HTTP MCP endpoint, and a noVNC page for human takeover.

A real browser can render JavaScript applications, retain login state, and allow a person to recover a workflow that automation cannot complete. That flexibility also makes the deployment sensitive. A controller credential can grant authority over a browser, while a takeover connection can expose whatever is visible in its desktop. Use a disposable browser session and a harmless page during installation, not an account containing production data.

โš™๏ธ Controller Port 8000 serves the dashboard and API. This guide tests session creation and observation with bearer authentication.
๐Ÿ–ฅ๏ธ Human takeover Port 6080 serves the local noVNC interface. Loading its HTML is not the same as establishing its desktop connection.
๐ŸŒ Remote connectivity With Localtonet, a connected client can expose a reachable HTTP service through a public HTTPS address. Application authorization remains a separate responsibility.
Self-hosted machine with an illustrated tunnel connecting it to a laptop and phone
Remote connectivity is the eventual design goal, not a validated Auto Browser deployment in this guide. The executable procedure below stays on localhost.

Why the scope stops at localhost

noVNC uses WebSockets to carry desktop traffic. Auto Browser's security release also describes an Origin check at this boundary. The available evidence does not establish Localtonet HTTP-tunnel WebSocket behavior for this application, the project's supported public-Origin configuration, its public takeover URL settings, or the complete gateway recommendations. A successful HTTP page load would therefore be insufficient evidence for a working, protected takeover connection.

The same caution applies to publishing the controller. A forwarding client on the Docker host may reach the application over loopback even when the original caller is remote. A loopback deployment setting must not become an authorization shortcut for those callers. We do not supply an off-box configuration or a remote MCP-client recipe without the missing primary documentation.

Local tutorial, not a production exposure recipe

Do not create tunnels to ports 8000 or 6080 as part of this procedure. Do not disable Origin checks, enable tokenless access, or restore raw VNC publishing to make remote access work. The remote-access section is an acceptance checklist, not an instruction to publish an unverified deployment.

Prerequisites and release selection

Use a machine you control with Docker Engine or Docker Desktop, the Docker Compose plugin, Git, and a browser that can reach the Docker host's localhost ports. The command examples use Bash. They also use curl, jq, and standard Unix utilities. On Windows, run them in an appropriate Bash environment with Docker access rather than pasting Bash arrays into PowerShell.

docker version
docker compose version
git --version
curl --version
jq --version

Docker must be running, and your account must be permitted to use it. Access to the Docker daemon is powerful host access; use a trusted machine and do not grant it to untrusted users just to complete this tutorial. Ports 8000 and 6080 must be available. Installation needs network access to fetch the repository, container dependencies, and the example web page.

The supplied evidence does not establish a supported operating-system matrix, minimum memory, or a required Docker version. The published-image workflow described in the existing project material targets linux/amd64. Do not assume ARM support or emulation compatibility. A source build is not, by itself, proof that every browser dependency supports another architecture.

A reproducible baseline is not a current security recommendation

The primary release evidence supplied for this revision verifies Auto Browser v1.11.2, a historical security release. It does not identify today's stable release. Accordingly, the commands below pin that known tag for a disposable, local-only lab. We do not label it current, recommend it for production, or imply it contains all later fixes.

For any ongoing deployment, select a current stable version from the project's releases, review intervening security notes, and record its exact commit and image digests. If you cannot establish a supported current release, stop before putting sensitive accounts into the browser. Neither an unpinned main checkout nor a floating latest image solves that verification problem.

The historical v1.11.2 fixes matter because they span both components: the controller receives application fixes, the browser-node image receives the VNC fix, and the Compose configuration stops publishing port 5900. Updating only a client library or MCP bridge does not deploy those server-side protections.

Install a local-only Docker lab

Installation flow showing a terminal, environment file, Docker Compose services, and running containers
Fetch a pinned checkout, inspect its configuration, and start the local stack before attempting any integration.

The basic project workflow is clone, configure if needed, optionally run diagnostics, and build with Compose. Here we add an explicit release pin and configuration inspection before startup. The repository's base Compose file and environment example are useful contextual references, but the files in your pinned checkout govern the deployment you actually run.

1

Fetch the historical lab release

Clone the repository at v1.11.2 and record the resulting commit. Keep this lab separate from an existing installation.

2

Prepare and inspect the environment

Copy the example environment file, keep tokenless mode disabled, and retain loopback-only published ports. Do not add a tunnel or a gateway overlay.

3

Run the optional diagnostic check

If Make is installed, run make doctor from a normal terminal with Docker access and permission to open localhost sockets.

4

Build and start the stack

Start the services from the pinned checkout. Inspect their state and logs before proceeding.

5

Confirm the controller credential exists

With the default authenticated loopback setup and no explicit bearer token, the controller generates data/api-token. Treat that file as a secret.

git clone --branch v1.11.2 --depth 1 \
  https://github.com/LvcidPsyche/auto-browser.git auto-browser-lab
cd auto-browser-lab
git rev-parse HEAD

umask 077
cp .env.example .env
chmod 600 .env

# Inspect locally. Resolved configuration may contain secrets.
docker compose config

# Optional, if Make is available:
make doctor

docker compose up --build -d
docker compose ps
docker compose logs --tail=100

# Check without printing the token.
test -s data/api-token && printf 'API token file exists\n'

Review the resolved port mappings before startup. Published application ports should bind to 127.0.0.1, not 0.0.0.0 or a LAN address. There should be no published port 5900. A browser-node service may use internal container networking without making that service available on the host; distinguish internal ports from published host ports.

Do not copy resolved Compose output into a public ticket. It can contain environment values, credentials, filesystem paths, and other operational details. If the token file does not appear, inspect startup errors and whether an explicit API_BEARER_TOKEN or alternate token file is configured.

Prebuilt-image alternative

The project also describes a GHCR image overlay. To reproduce the historical lab with that path, use the same pinned repository checkout and explicitly select the matching image tag instead of accepting the floating default:

export AUTO_BROWSER_IMAGE_TAG=1.11.2

docker compose -f docker-compose.yml \
  -f docker-compose.images.yml pull

docker compose -f docker-compose.yml \
  -f docker-compose.images.yml up -d

Choose either the source-build path or the image-overlay path and keep using that configuration for status, shutdown, updates, and recovery. The controller's prebuilt image omits agent command-line tools; the documented source-build alternative for CLI authentication uses INSTALL_AGENT_CLIS=true. That optional integration is outside this local REST tutorial.

Optional isolated sessions introduce another image dependency. In that workflow, docker-compose.images.yml must come after docker-compose.isolation.yml, otherwise the isolation overlay can select a stale or nonexistent local browser-node image. Isolation is not needed for the basic lab here.

Verify authentication, the browser, and local takeover

Illustrated local dashboard, noVNC browser viewport, and endpoint response
Verify the controller and desktop locally. An endpoint response alone does not prove an MCP-client integration or remote takeover path.
InterfaceLocal addressVerification goal
API documentationhttp://127.0.0.1:8000/docsInspect the local API; authorize requests with the controller token.
Dashboardhttp://127.0.0.1:8000/dashboardEnter the token when requested and inspect the operator interface.
MCP endpointhttp://127.0.0.1:8000/mcpEndpoint location only. This guide does not configure or validate an MCP client.
noVNChttp://127.0.0.1:6080/vnc.html?autoconnect=true&resize=scaleConnect to the desktop and observe the test browser session.

Use a credential without putting it in shell history

A literal bearer token in a shell command can remain in history. Expanding a token into curl's command-line arguments can also expose it through process inspection. The following Bash example stores the header in a private temporary file and tells curl to read it. It avoids printing the credential, although the file still needs protection and cleanup.

# Run from the project directory in Bash.
# Do not run with shell tracing enabled.
set +x
umask 077
AUTH_FILE=$(mktemp)
trap 'rm -f "$AUTH_FILE"; unset TOKEN' EXIT

# For the default generated-token setup:
TOKEN=$(cat data/api-token)

# If you configured your own token, use this instead:
# IFS= read -r -s -p 'API token: ' TOKEN
# printf '\n'

printf 'Authorization: Bearer %s\n' "$TOKEN" > "$AUTH_FILE"
unset TOKEN

On a shared host, a private temporary file does not protect secrets from an administrator or a compromised account. Do not record the terminal session, enable curl tracing, or upload diagnostic bundles containing credentials.

Check refusal before creating a session

Use the observation path with a deliberately nonexistent session ID to test authentication without requesting a browser action:

curl -sS -o /dev/null -w 'No credential: %{http_code}\n' \
  http://127.0.0.1:8000/sessions/auth-check-nonexistent/observe

curl -sS -o /dev/null -w 'Wrong credential: %{http_code}\n' \
  -H 'Authorization: Bearer deliberately-invalid' \
  http://127.0.0.1:8000/sessions/auth-check-nonexistent/observe

Expect an authentication refusal, normally 401, rather than an authorized observation. A generic error alone is not proof that authentication is enforced. If the application accepts unauthenticated protected requests, stop and inspect tokenless mode and the resolved environment before continuing.

Create and observe a harmless session

curl --fail-with-body -sS \
  --header @"$AUTH_FILE" \
  -H 'Content-Type: application/json' \
  -X POST http://127.0.0.1:8000/sessions \
  -d '{"name":"local-demo","start_url":"https://example.com"}' | jq

Copy the session ID from the JSON response. Then request an observation:

read -r -p 'Session ID from the response: ' SESSION_ID

curl --fail-with-body -sS \
  --header @"$AUTH_FILE" \
  "http://127.0.0.1:8000/sessions/$SESSION_ID/observe" | jq

A successful result verifies more than a listening socket: the credential was accepted, the controller created a session, and the browser node could produce an observation. If your curl version lacks --fail-with-body, use --fail and inspect errors separately.

Verify local noVNC separately

Open the local noVNC URL from the table. Confirm that the desktop connects and that you can see the browser showing the test page. The historical release notes state that noVNC requests VNC_PASSWORD when one is configured. Set a separate value through the checkout's environment configuration if you want to verify that behavior, recreate the affected containers, and test both an incorrect and the correct password.

The supplied evidence does not establish the password backend's length rules or a complete public-host configuration. Do not treat this password as authorization to publish the desktop. A local successful connection validates only the local path and its configured password behavior.

When finished with the API checks, remove the temporary header file:

rm -f "$AUTH_FILE"
unset AUTH_FILE SESSION_ID
trap - EXIT

Understand the authentication and exposure boundaries

Locked gate separating a private Docker host from the public internet
Network reachability, API authorization, and desktop access are distinct controls. A tunnel does not replace application authentication.

The available production-hardening specification states that API_BIND_SCOPE=exposed requires an API bearer token of at least 32 characters, with an alternate token-file mechanism available. The base Compose deployment declares loopback scope to match its loopback publishing and can generate a token automatically.

These are two different ideas: a Docker host binding controls where a socket is reachable, while application bind scope controls application security behavior. Keeping the Docker mapping on localhost does not make tunneled traffic local in the security sense. Conversely, changing an application setting does not automatically change Docker's published addresses.

Never use tokenless loopback mode for forwarded traffic

API_ALLOW_TOKENLESS_LOOPBACK=true removes the credential requirement in the described local mode. Other containers can then drive the browser, and a forwarding process may make remote requests arrive from a locally trusted address. Keep authentication enabled even in the lab.

For a future exposed deployment, a long random API token, explicit exposed semantics, and preserved authorization headers are necessary requirements, not a complete hardened configuration. The supplied hardening excerpt is truncated, and the full gateway configuration has not been established here. Merely placing a variable in .env is also insufficient if the Compose service does not consume it or overrides it.

Keep credentials out of URL fragments, screenshots, chat messages, and repositories. Although a fragment is not normally sent in an HTTP request, it can still appear in history or screen captures. Paste the dashboard credential into its prompt instead of bookmarking a token-bearing URL.

Approvals are not a replacement for authentication

The v1.11.2 release explains that an approval is spent when a call claims it, before the action runs. If the action subsequently fails, do not assume it had no effect. Observe the page or check the external outcome before approving another attempt. Retrying with the same spent approval is intentionally refused.

Only qualifying browser actions that stop before beginning return approval, and the response identifies this with approval_given_back. If the session has closed, request a new action in a live session rather than attempting to reuse that session's approval. A rejection after the action begins is too late to cancel it and is refused.

When crossing the v1.11.2 upgrade boundary, old governed-tool approvals must be requested again. Old pending entries shown as takeover requests should be rejected. The release also describes subtleties with AUTONOMOUS_APPROVALS=true; keep autonomous approval disabled unless you deliberately accept those semantics. The project's MCP-client and approval documentation is the relevant integration reference, but this guide does not claim a configured MCP client.

What must be established before remote access

Our platform uses a client on a device that can reach the target service. That client establishes an outbound connection to a Localtonet relay, avoiding inbound router port forwarding. HTTP tunnels provide a public HTTPS address. They are available only while the chosen device is connected and the tunnel is running.

Conceptual request path from a remote browser through a Localtonet endpoint to a local service
Conceptual HTTP forwarding only. This diagram does not establish Auto Browser gateway settings, WebSocket compatibility, Origin acceptance, or authentication behavior.

A client running directly on the Docker host can reach host-loopback ports. A client in a separate container cannot use its own 127.0.0.1 to reach the host. Moving the client to another LAN machine also does not make a loopback-only service reachable. Do not broaden the application's binding as an improvised fix.

For general HTTP setup, our HTTP tunnel documentation is the authoritative workflow. Process Types include Random Sub Domain, Custom Sub Domain, and Custom Domain; available device tokens and relay servers come from the current dashboard. Creating a tunnel is separate from pressing Start. We do not reproduce an exact field-by-field sequence here because the current HTTP setup page was not included in the supplied evidence and this narrowed guide does not create a tunnel.

Required acceptance checks for a future deployment

  • Controller configuration: establish how the selected release declares exposed scope while retaining a strong API credential and protected endpoints.
  • Gateway behavior: incorporate the supported recommendations from the project's deployment documentation, including relevant forwarded-header and public-host handling.
  • Negative authentication: prove that missing and incorrect credentials fail through the public path, not just on localhost.
  • Desktop transport: verify the complete noVNC WebSocket upgrade, sustained interaction, and reconnect behavior through the selected tunnel.
  • Origin enforcement: verify that the supported public Origin succeeds and an unapproved Origin fails. Do not remove the check.
  • Password behavior: verify incorrect-password refusal and correct-password success through the complete desktop path.
  • Public links: establish supported takeover URL configuration rather than distributing localhost links or inventing environment variables.
  • MCP integration: validate one named client's documented configuration, authentication, initialization, tool discovery, and actual operation.

Until those requirements are satisfied, neither a second tunnel to 6080 nor a controller tunnel to 8000 is part of this tutorial. Our McpNet Gateway guide describes a separate integration; it is not evidence that Auto Browser's MCP server or noVNC path has been validated.

Routine operation, updates, rollback, and secrets

Start, inspect, and stop

# Source-build configuration:
docker compose up -d
docker compose ps
docker compose logs --tail=100

# Stop without removing containers:
docker compose stop

# Remove the stack's containers and networks:
docker compose down

For the prebuilt workflow, include the same two -f arguments and selected image tag every time. Do not add down -v casually: it can delete Compose-managed volumes. Ordinary shutdown is not a backup, and the exact storage inventory must be checked before destructive operations.

The data directory contains sensitive state, including the generated token in the default workflow. Saved authentication profiles can represent signed-in sessions. Restrict access, encrypt backups appropriately, and avoid public synchronization destinations. Do not assume that ignoring a file in Git protects it from backup tools or local users.

Use explicit manual startup until boot behavior is verified

This tutorial uses manual startup. After a host reboot, start Docker, enter the same checkout, select the same configuration, run up -d, and repeat the local checks. Do not promise automatic availability without testing an actual reboot.

The repository includes ops/systemd, but the available evidence does not establish its unit names, installation commands, or service dependencies. We therefore do not invent a systemd installation. An unattended deployment requires review of those units, persistent storage, restart policy, and secret availability before it can be considered operationally complete.

Update both server components

Before updating, stop new work, close active sessions, record the current commit and image identifiers, and take a consistent backup with the stack stopped. Include the configuration and all configured persistent storage, not just the source checkout. Protect that backup as carefully as the live credentials.

git rev-parse HEAD
docker compose images
docker compose stop

# Fetch release tags without switching to an unpinned branch.
git fetch --tags
read -r -p 'Reviewed release tag to deploy: ' TARGET_RELEASE
git checkout --detach "$TARGET_RELEASE"

# Source-build path: rebuild both components from the selected checkout.
docker compose build --pull
docker compose up -d --force-recreate
docker compose ps

The tag prompt is intentional: no current stable release has been verified in the supplied evidence. Select a reviewed release, not an arbitrary tag. For prebuilt deployments, select its matching AUTO_BROWSER_IMAGE_TAG, pull with the image overlay, and recreate the services using the same overlay. Record the pulled digests; a version label alone is not necessarily immutable.

Review changes to Compose and environment files during the upgrade. If ISOLATED_BROWSER_IMAGE is explicitly set, update it to the matching reviewed browser-node image. Close old isolated sessions and recreate their containers so they cannot continue using a vulnerable image. Re-run both authenticated and rejected-request tests after the upgrade.

Rollback means restoring a compatible set

Keep the previous reviewed source commit or image digests, configuration, and pre-upgrade data snapshot together. If the new version fails, stop it first. Restore that compatible set, recreate the stack, and verify locally before resuming work. Do not assume a new release's data is backward-compatible with an older controller.

No automatic migration reversal or project-specific rollback command is established here. If release notes do not confirm downgrade compatibility, restore the pre-upgrade snapshot rather than running old code against modified state. Never roll back to a release with a known security flaw simply to restore remote connectivity.

Rotate credentials after suspected exposure

First stop any existing tunnels and stop the application. Replace an explicitly configured bearer token using a protected editor or your secret-management process, not a literal shell command. Recreate the services that consume it, update authorized callers, and verify that the old token fails and the new one succeeds. Update a configured VNC password separately and test it locally.

The supplied evidence does not establish a hot-rotation API or the complete generated-token replacement procedure. Do not assume deleting data/api-token while the service runs revokes an in-memory credential. Keep the service stopped until the selected release's credential source and restart behavior are understood. If browser session state may have leaked, revoke affected website sessions as well; changing the controller token does not revoke website cookies.

For any separately validated Localtonet deployment, stopping or deleting its tunnel belongs to lifecycle operations, not creation. Stop the tunnel when remote work ends. Stopping public forwarding does not stop the local containers or erase their data.

Troubleshooting without weakening controls

SymptomLikely areaSafe next step
Docker commands failDaemon or permissionsConfirm Docker is running and the terminal has authorized Docker access.
make doctor fails in a sandboxLocal socket restrictionsRun from a normal terminal on the Docker host. Do not disable host security globally.
8000 or 6080 is already in usePort conflictIdentify the owner and stop the conflicting service if appropriate. Avoid improvised remapping.
Protected API calls return 401Credential mismatchCheck whether the deployment uses a generated file or an explicit bearer token. Recreate the temporary header file from the correct source.
Unauthenticated protected calls succeedAuthentication configurationStop the stack and inspect tokenless settings and resolved configuration. Do not publish it.
Controller refuses startupConfiguration or secret validationRead local logs. Exposed scope requires a bearer token of at least 32 characters.
Documentation page is blankSwagger asset loadingThe described UI loads assets from cdn.jsdelivr.net. Check browser access or use curl for the local tests.
Session creation works but observation failsBrowser-node or target accessInspect both services' logs and verify the harmless target page is reachable.
Raw VNC on 5900 refuses connectionsIntentional security changeUse local noVNC on 6080. Do not republish 5900.
noVNC HTML loads but desktop does notDesktop transport or authenticationCheck local password behavior and service logs. HTML delivery alone does not validate WebSockets.
Prebuilt image fails on ARMImage architectureUse a supported image architecture; ARM compatibility is not established here.
An approved action cannot be retriedSpent approvalCheck whether the action already took effect before requesting another approval.

Debug in layers: container startup, listening ports, authentication, session creation, observation, and desktop interaction. Record the first failing layer. Do not add a tunnel to fix a service that fails locally, and do not interpret a gateway or transport error as a reason to remove authorization.

Frequently asked questions

Does this guide provide working remote noVNC access?

No. It validates local controller and desktop behavior. The complete public-host, Origin, password, gateway, and WebSocket path is not established by the available evidence, so remote noVNC publication is excluded.

Is v1.11.2 the recommended current release?

No. It is a verified historical security release used as a reproducible disposable-lab baseline. A current stable release was not established here. Review current releases before any ongoing or sensitive deployment.

Does localhost binding make a tunneled controller private?

No. A forwarding process can make a loopback service remotely reachable. Preserve application authentication and establish the supported exposed-scope and gateway configuration before publication.

Where is the default controller token?

In the described default authenticated loopback deployment, the controller generates data/api-token. An explicitly configured bearer token or alternate token file changes the credential source. Do not print the token into logs or place it in command history.

Does a successful REST request validate an MCP client?

No. It validates that REST path and its credential. MCP requires a supported client configuration and protocol-level testing. This guide deliberately does not promise a completed MCP integration.

Is a Localtonet HTTP tunnel a VPN?

No. An HTTP tunnel publishes an individual HTTP service. Our VPN Manager is the separate private mesh VPN feature. Neither connectivity model removes the need to secure a browser controller and desktop.

Establish the local boundary before adding remote connectivity

Finish the local authentication and browser checks first. When your application's supported gateway and public-host configuration is established, use our HTTP tunnel documentation to plan a controlled Localtonet deployment without inbound router port forwarding.

Explore HTTP tunnel configuration โ†’

Corrections & updates

Substantive changes approved by the Localtonet editorial team are listed transparently below.

Validate the complete noVNC path through a Localtonet HTTP tunnel, including WebSocket transport, Origin enforcement, password behavior, and the supported public-host configuration. If that cannot be established, remove the remote-noVNC promise from the title and clearly limit the tutorial to the verified controller or MCP path. Replace the bind-scope uncertainty with an evidence-backed hardened configuration that uses a strong API token and preserves authentication for tunneled requests. Add at least one complete supported MCP-client

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support