Test apps on a private network with the TestOptim CLI
Run the TestOptim CLI on a machine inside your network so TestOptim can reach internal apps, staging hosts and single sign-on pages that are not on the public internet.
In this article
To test an app that only your network can reach, run the TestOptim CLI on a machine inside that network with testoptim tunnel. TestOptim then runs its browsers through that machine, so internal URLs such as https://app.corp work the same as public ones.
Before you start
- To turn on the private tunnel for a project, you need the Owner, Admin or QA Lead role. Other roles see the switch but can't change it.
- To create the API token the CLI uses, you need the Owner or Admin role.
- Your project needs a URL that the machine running the CLI can open in a browser.
- The machine needs outbound HTTPS (port 443) access to
api.testoptim.comandtunnel.testoptim.com. You don't need to open any inbound ports.
Install the CLI
On macOS or Linux, install the testoptim binary with Homebrew or the install script:
brew install testoptim-ai/tap/testoptim
# or
curl -fsSL https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.sh | sh
On Windows, run this in PowerShell:
irm https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.ps1 | iex
It installs testoptim.exe in %LOCALAPPDATA%\Programs\testoptim and adds that folder to your user PATH. You don't need administrator rights. Open a new terminal before you run testoptim from another window.
To run it in a container, use the ghcr.io/testoptim-ai/testoptim-cli image.
Turn on Private network for your project
For a new project, turn on Private network in the New project form, then select Create and connect CLI. The project's Knowledge page opens and shows Waiting for the CLI to connect, with the install, sign-in and tunnel commands for your project.
For an existing project:
- Open the project, then Settings in the project's sidebar.
- Turn on Private network, then select Save changes. The same connect steps appear under the switch.
While it is on, all of the project's test traffic goes through the tunnel. Start exploration on the Knowledge page stays disabled until the CLI connects. Test runs and issue re-verification fail straight away if the tunnel is offline.
Create a token for the tunnel
The quickest way is from the connect steps: under Sign in, select Create token. TestOptim creates a token named Private tunnel that can only connect a tunnel (tunnel:connect) for this project. Copy it straight away. It starts with topt_ and is shown only once. Owners and admins see the button; anyone else is asked to get the token from one of them.
To create the token from scratch instead, select your name at the top right, then Settings > API keys > New token. A new token starts with the permissions for running tests from CI ticked and Connect private tunnel unticked. Untick the others, tick Connect private tunnel, and under Project access choose the project you want to test. A token limited to one project can only open tunnels for that project.
Note
A token without Connect private tunnel can't open a tunnel. testoptim auth warns you if the token you paste doesn't have it.
Connect the CLI
Save the token on the machine:
testoptim authPaste the token when prompted. The CLI checks it with TestOptim and saves it in
~/.config/testoptim/config.jsonwith owner-only permissions. On Windows, the file is%USERPROFILE%\.config\testoptim\config.json.Start the tunnel for your project, using the project ID from the project's URL, or copy the command from the connect steps:
testoptim tunnel --project <project-id>If the token is limited to one project, you can leave out
--project.When the tunnel is up, the CLI prints which hosts it allows, then one line for each connection TestOptim makes through the tunnel:
Tunnel online for app.corp — allowing app.corp:80,443. Press Ctrl-C to stop. ✔ app.corp:443 ✘ blocked 10.1.2.3:22 (not in allowlist)Leave the command running while you test. Press Ctrl-C to close the tunnel.
Once the tunnel is online, the connect steps change to CLI connected, with the Computer (the machine's host name), Last check-in and Allowed hosts, and Start exploration unlocks. The page checks every few seconds, so you don't need to reload it. If the CLI stops checking in for 90 seconds, it shows The CLI disconnected and Start exploration is disabled again until the tunnel is back.
Warning
A project has one tunnel at a time. Starting testoptim tunnel for the same project on a second machine takes over from the first, and the two then keep taking the tunnel from each other. Run it on one machine per project.
Choose which hosts the tunnel can reach
By default the tunnel reaches only the host of your project URL, on ports 80 and 443, plus the port in the URL if it uses another one, such as :8443. Everything else is blocked. Add the other hosts your app needs:
--allow <host[:port]>adds a host name. Repeat it for each host. Wildcards such as*.corpare allowed. Without a port, it allows ports 80 and 443. It doesn't accept IP addresses.--allow-cidr <cidr>allows an IP range on every port, such as10.20.0.0/16. For a single address, add/32, as in10.1.2.3/32. A bare address such as10.1.2.3is rejected.
Host names that resolve to private addresses, such as 10.x.x.x, 172.16.x.x or 192.168.x.x, work with --allow alone. You only need --allow-cidr when:
- TestOptim reaches a host by IP address rather than by name. If your project URL is an IP address, the CLI won't start until you allow it, and tells you the
--allow-cidrto add. - A host name resolves to a loopback or link-local address. For example, to test an app running on the CLI machine itself at
http://localhost:3000, add--allow-cidr 127.0.0.1/32.
testoptim tunnel --project <project-id> \
--allow sso.corp \
--allow auth.example.com:443 \
--allow-cidr 10.20.0.0/16
In PowerShell, end each continued line with a backtick (`) instead of \, or put the whole command on one line.
Note
Single sign-on pages run on your identity provider's host. Add that host with --allow, or sign-in will fail when TestOptim reaches it.
Security model
- The CLI makes only outbound HTTPS connections: to
api.testoptim.com, to start the tunnel and check in every 30 seconds, and to the relay attunnel.testoptim.com. You don't open any inbound ports. - Only the hosts and ports you allow can be reached. Requests to other hosts are blocked and shown in the CLI output.
- Your machine resolves internal host names with your own DNS, so names that only exist inside your network keep working.
- Loopback addresses such as
127.0.0.1, link-local addresses and cloud metadata addresses such as169.254.169.254are blocked unless you allow them with--allow-cidr. - If your app uses HTTPS, TLS runs end to end between the TestOptim browser and your app, and TestOptim's relay sees only encrypted traffic. Plain HTTP is encrypted between your machine and the relay, but the relay can read it.
- To cut off a machine, revoke its token: on the API keys page, select the red bin icon next to the token, then Revoke in the Revoke token dialog. A running tunnel stops within about 30 seconds with API token no longer valid, and the token can't open new tunnels.
Run the tunnel in Docker or CI
For a container or a CI job, skip testoptim auth and set the token as an environment variable. TESTOPTIM_API_KEY overrides any saved token.
docker run --rm -e TESTOPTIM_API_KEY="$TESTOPTIM_API_KEY" \
ghcr.io/testoptim-ai/testoptim-cli tunnel --project <project-id> --allow sso.corp
Store the token in your CI secrets. Don't put it in the command line or in your repository.
Troubleshooting
"Private tunnel offline"
If a test run or issue re-verification fails with Private tunnel offline — run testoptim tunnel --project <project-id>, the project has Private network turned on, but no machine has checked in for it in the last 90 seconds. Either no CLI is running for the project, or it lost its connection. Start testoptim tunnel on a machine inside your network, wait until the project shows CLI connected, then start the run again. The failed run isn't retried.
A host shows as blocked
- not in allowlist: add the host with
--allow <host>, or with--allow-cidr <address>/32if it is an IP address, and start the tunnel again. - resolves to a blocked address: the host name points to a loopback or link-local address. If that is what you want, for example for an app on the CLI machine, allow the address with
--allow-cidr, such as127.0.0.1/32.
The Windows installer can't connect
On older Windows Server versions, PowerShell can fail with The underlying connection was closed before the install starts. Turn on TLS 1.2 for the session, then run the installer again:
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072
irm https://raw.githubusercontent.com/TestOptim-AI/testoptim-cli/main/install.ps1 | iex
If your organization blocks PowerShell scripts, download the windows_amd64 (or windows_arm64) .zip from the latest release, extract testoptim.exe and put it in a folder on your PATH.
The tunnel keeps reconnecting
If the CLI keeps printing Tunnel session was closed by the server (another client may have taken over); reconnecting, another machine is running a tunnel for the same project. Stop the tunnel on one of them.
If it prints Connection lost or Relay unreachable, check that the machine can open outbound HTTPS connections to api.testoptim.com and tunnel.testoptim.com. A proxy or firewall that drops long-lived connections can cause repeated reconnects.
The CLI exits with "API token no longer valid" or "API token rejected"
The token was revoked. Create a new one and run testoptim auth again.
Related
Keep reading
- Integrations & APIRun TestOptim tests from CI with an API keyCreate an API key, start a TestOptim test run from GitHub Actions, a script or an AI assistant, and fail the build on critical or high issues.
- Integrations & APIConnect Slack and use /testoptim commandsPost test results, new issues and run failures to a Slack channel, choose which events to send, and use /testoptim to list issues or start a run from Slack.
- Integrations & APIConnect Jira and sync issue statusFile the issues TestOptim finds into a Jira project automatically or by hand, and keep their status in sync both ways, with optional re-verification.
- Account & notificationsManage your profile, password and sessionsChange your display name, reset your password, and understand when TestOptim signs you out. Resetting your password signs you out on every device.