Testing Internal Web Apps with BrowserStack Local: Secure Tunnel Setup for Selenium
Set up BrowserStack Local to run Selenium tests against internal web apps without public exposure. Covers tunnel binary setup, Java capabilities config, and cleanup.
10 Jan 2026, 11:03 UTC

The Problem: Testing Private Applications on Cloud Browsers
You need to run automated Selenium tests against a web application that lives on your laptop, behind a corporate VPN, or in a staging environment with no public IP. Exposing these endpoints to the internet is not an option. BrowserStack Local solves this by creating an encrypted tunnel from your machine to BrowserStack's cloud, letting remote browsers reach localhost or any private hostname as if they were on your network.
How the Tunnel Works
The BrowserStack Local binary opens a persistent WebSocket connection over outbound TCP 443 to BrowserStack's edge. When a test session starts with the browserstack.local capability enabled, the cloud browser's HTTP/HTTPS requests for private hosts are routed back through that tunnel to your machine, where the binary resolves and forwards them to the target server. Only HTTP and HTTPS traffic is proxied; other protocols (WebSocket upgrades, raw TCP, UDP) are not supported.
Worked Example: Java Maven Project with Selenium
Prerequisites
- BrowserStack account with username and access key (found in Account Settings → Automate)
- Java 11+ and Maven 3.6+ installed locally
- A local web server running on
http://localhost:8080serving a test page (e.g.,python3 -m http.server 8080in a directory with anindex.html)
Step 1: Download and Start the Tunnel Binary
Run this on your local machine or CI agent before launching tests. The binary must stay running for the entire test suite.
# Linux/macOS
curl -O https://www.browserstack.com/browserstack-local/BrowserStackLocal-linux-x64.zip
unzip BrowserStackLocal-linux-x64.zip
chmod +x BrowserStackLocal
./BrowserStackLocal --key YOUR_ACCESS_KEY
Where to run: Terminal on the machine hosting the private application. Permissions: Execute permission on the binary; outbound internet on TCP 443. Placeholders: Replace YOUR_ACCESS_KEY with your actual key. Expected check: The process prints "Connected to BrowserStack Local" and shows a tunnel ID. Risk: If the binary is older than 6 months, TLS handshake failures may occur; always download the latest version.
Step 2: Configure Selenium Capabilities
Add the following to your test setup (JUnit 5 example shown). The capabilities tell BrowserStack to route this session through your active tunnel.
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import java.net.URL;
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("browserstack.user", "YOUR_USERNAME");
caps.setCapability("browserstack.key", "YOUR_ACCESS_KEY");
caps.setCapability("browserstack.local", true);
// Optional: name the tunnel if you run multiple concurrent tunnels
// caps.setCapability("browserstack.localIdentifier", "my-tunnel-1");
RemoteWebDriver driver = new RemoteWebDriver(
new URL("https://hub-cloud.browserstack.com/wd/hub"), caps);
Where to run: In your test code before creating the RemoteWebDriver. Placeholders: YOUR_USERNAME and YOUR_ACCESS_KEY from your BrowserStack account. Risk: Omitting browserstack.local=true causes "connection refused" when the cloud browser tries to reach localhost.
Step 3: Write a Test That Hits the Local Server
@Test
void localAppLoads() {
driver.get("http://localhost:8080");
assertEquals("Test Page", driver.getTitle());
}
The cloud browser resolves localhost through your tunnel, not its own loopback interface.
Limits and Common Mistakes
| Limitation | Impact | Workaround |
|---|---|---|
| HTTP/HTTPS only | WebSocket, gRPC, raw TCP, UDP traffic will not route | Use a local reverse proxy (nginx) to terminate WebSocket and forward as HTTP if needed |
| Concurrent session cap | Account tier limits parallel tunnels (e.g., 2 on basic plans) | Use browserstack.localIdentifier to share one tunnel across multiple test threads |
| Outbound TCP 443/80 required | Fails in air-gapped or heavily firewalled environments | Allowlist *.browserstack.com on port 443; proxy support via --proxy-host/--proxy-port flags |
| Binary version drift | Old binaries drop support for newer TLS ciphers, causing silent handshake failures | Automate binary download in CI; verify version with ./BrowserStackLocal --version |
| Orphan tunnels consume minutes | Forgotten processes bill against your tunnel quota | Always wrap binary start/stop in try/finally or CI lifecycle hooks |
Verification Checklist
- Tunnel connected: Binary output shows "Connected to BrowserStack Local" and a tunnel ID appears in Automate Dashboard → Local Testing.
- Test passes: The Selenium test opening
http://localhost:8080asserts the expected title. - Session flag: In the Automate session detail, the "local" badge is present and video/logs record normally.
- Network trace (optional): Run
./BrowserStackLocal --log-file local.log -vto capture tunnel traffic for debugging DNS resolution or certificate issues.
Cleanup: Terminate the Tunnel
Send SIGTERM (Ctrl+C) to the BrowserStackLocal process after the test suite completes. In CI, use a finally block or post step:
# Bash example
trap 'kill $TUNNEL_PID' EXIT
./BrowserStackLocal --key $KEY &
TUNNEL_PID=$!
mvn test
# trap kills tunnel on script exit
This prevents orphan tunnels from consuming your monthly tunnel minutes.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.