---
title: 'TestingBot Tunnel Traffic Rules: Allow Hosts, Fast-Fail, Localhost Policy'
description: 'Control what TestingBot Tunnel may reach: allow-list hosts with --allow-hosts,
  block domains with --fast-fail-regexps, deny loopback with --localhost-policy, and
  remap destinations with --connect-to and --dns.'
source_url:
  html: https://testingbot.com/support/tunnel/traffic-rules
  md: https://testingbot.com/support/tunnel/traffic-rules.md
---

# Decide what the tunnel may reach

A tunnel can reach whatever the machine running it can reach. These options narrow that down to what your tests actually need, and steer requests to a different destination without touching your tests.

- Since v5.0 
- HTTP, CONNECT and WebSocket 

 Enforced on every way out 

`--allow-hosts`, `--fast-fail-regexps` and `--localhost-policy` apply to plain HTTP requests, HTTPS `CONNECT` tunnels and WebSocket upgrades alike. A refused request gets a `403` that says which rule refused it.

## Allow only named hosts

`--allow-hosts` names what the tunnel is _for_. Everything else is refused.

```bash
java -jar testingbot-tunnel.jar --allow-hosts 'staging.example.com,*.internal.example'
```

- An entry is an exact host or `*.suffix` for its subdomains.
- `*.internal.example` covers `app.internal.example` but not `internal.example` itself. List the apex separately if you need it.
- Omit the option and any host is reachable, as in 4.x.

This is the safer of the two approaches. A deny list only stops destinations somebody thought of in advance. An allow list keeps a tunnel on a CI runner from becoming a route into everything else on that network.

## Fast-fail domains

`--fast-fail-regexps` refuses requests to hosts matching any of a comma-separated list of regular expressions. The browser gets an immediate answer instead of waiting on a request that would go through the tunnel.

```bash
# skip analytics and ad networks to speed up page loads
java -jar testingbot-tunnel.jar -F '.*google-analytics\.com,.*doubleclick\.net'
```

**New in 5.0:** prefix an entry with `!` to make an exception. This blocks everything except `ok.com` and its subdomains:

```bash
java -jar testingbot-tunnel.jar -F '.*,!ok\.com'
```

An exception has to cover a whole host or subdomain, so it cannot be satisfied by a name that merely ends with it: `ok.com.attacker.net` is _not_ excepted by `!ok\.com`.

 Which one to use 

To speed tests up by skipping third-party noise, use `--fast-fail-regexps`. To limit what the tunnel may reach, use `--allow-hosts`. You can combine them: a host has to pass both.

## Localhost policy

`--localhost-policy deny` refuses tunnel traffic that would reach this machine's own loopback interface.

```bash
java -jar testingbot-tunnel.jar --localhost-policy deny
```

Use it for a tunnel that is meant to reach a staging network, and nothing running on the machine itself, such as a shared CI runner or a jump host. The check is applied to the address actually dialled, not only to the name in the URL, so a DNS answer that points a public-looking name at `127.0.0.1` cannot walk past it.

The default is `allow`, which is what you want when testing a development server on your laptop. The Selenium relay is not affected. For how cloud browsers reach your local server, see [Can I use localhost?](https://testingbot.com/support/tunnel/faq#localhost)

## Remap destinations with --connect-to

Dial a different host or port than the request asks for, while leaving the URL, the `Host` header and the TLS SNI name untouched. The format matches curl's `--connect-to`: `HOST1:PORT1:HOST2:PORT2`.

```bash
# test https://www.example.com against the staging instance
java -jar testingbot-tunnel.jar --connect-to 'www.example.com:443:staging-lb.internal:443'

# send every request on port 80 to a local dev server on 3000
java -jar testingbot-tunnel.jar --connect-to ':80:127.0.0.1:3000'
```

- An empty `HOST1` or `PORT1` matches anything. An empty `HOST2` or `PORT2` leaves that half of the destination unchanged.
- Comma-separate several rules. The first rule that matches wins.
- Bracket IPv6 literals: `example.com:443:[::1]:8443`.

This lets a test drive the production hostname against another instance, with the same virtual host and certificate name the real site uses. Editing `/etc/hosts` is the usual alternative, but it needs root, affects every process on the machine and cannot change a port.

## Custom DNS

`--dns` resolves hostnames through servers you name instead of the system resolver. Useful for split-horizon setups where the machine's default resolver does not know internal names.

```bash
java -jar testingbot-tunnel.jar --dns 10.0.0.53,10.0.0.54:5353
```

| Option | Effect |
| --- | --- |
| --dns \<server[,server]\> | Host or `host:port`, comma separated. The first is primary and the rest are tried in order when it does not answer. Falls back to the system resolver if none can. |
| --dns-round-robin | Spread queries across the servers instead of treating the first as primary, for a pool whose members are equal. |
| --dns-timeout \<seconds\> | How long to wait for each server. Default `5`. |

## Connection timeouts

| Option | Default | Effect |
| --- | --- | --- |
| --http-dial-timeout \<seconds\> | 5 for the API, 15 for tunnelled connections | How long to wait for a TCP connection to a target or upstream proxy. Lower it where unreachable hosts should fail fast. Also bounds the SSH control connection. |
| --http-idle-timeout \<seconds\> | 120 for HTTP, 300 for CONNECT | How long a connection may sit with no traffic before it is closed. Raise it for long-lived idle connections such as long polling. |

## Reading refusals and errors

When the tunnel cannot or will not complete a request, it says why three ways: the HTTP status, an `X-TestingBot-Error` header, and a one-line explanation in the body that shows up in the cloud browser's window.

| X-TestingBot-Error | Status | Meaning |
| --- | --- | --- |
| not-allowed | 403 | The host is not in `--allow-hosts`. |
| denied-by-fast-fail | 403 | Blocked by `--fast-fail-regexps`. |
| denied-localhost | 403 | Blocked by `--localhost-policy deny`. |
| dns-error | 502 | The hostname could not be resolved from the tunnel machine. |
| connection-refused | 502 | Nothing is listening on that port. |
| connection-timeout | 504 | Timed out connecting to the target. |
| host-unreachable | 502 | No network route to the target from the tunnel machine. |
| tls-error | 502 | The TLS handshake with the target failed. |
| upstream-proxy-\* | 502 | The [upstream proxy](https://testingbot.com/support/tunnel/upstream-proxy) was unreachable, rejected the credentials, or refused the destination. |
| loop-detected | 508 | The request targets the tunnel's own proxy port. |

The same reason string is the `reason` label on the proxy error counter in [Prometheus metrics](https://testingbot.com/support/tunnel/monitoring), so a spike on a dashboard and a header in a bug report name the same thing.

## Looking for more help?

Have questions or need more information? Reach out via email or Slack.

[Email us](https://testingbot.com/contact/new) [Join our Slack](https://join.slack.com/t/testingb0t/shared_invite/zt-3bcw9xch-jk19~6XPs_xBrsAgAedkCw)
