# Private networks

Test private apps through Tailscale or AWS Client VPN, or allowlist dedicated static IPs in Cloudflare and Vercel firewalls.

For a short workflow, start with [testing a private preview or internal app](/docs/verify/guides/private-apps).

## Test private networks and local apps

Connect Verify browser agents to your private app through Tailscale or AWS Client VPN. Choose the provider your team uses, configure a restricted connection, then select it for the Verify environment. Network access is separate from signing in to your app; add a test account under the project's **Credentials** when needed.

Organization administrators configure connections under **Project → Environments → selected environment → Network Access → Private network**. For a standalone preview, open **Verify → Environments**, then its **Private network** card.

## Use static outbound IPs

Composal supports dedicated static outbound IPs for hosted Verify browsers. If
your application requires an IP allowlist, [contact us](/contact) or ask your
account manager to arrange an assignment for your organization. Static IPs are
optional and enabled manually; organizations without an assignment use shared
outbound IPs that can change.

An assigned static IP can be shared across selected organizations by arrangement.
Ask your account manager if you need an IP exclusive to your organization. An IP
allowlist permits traffic from every organization using that address; application
sign-in remains separate.

Once enabled, find your assigned addresses under **Organization settings →
Dedicated outbound IP** and allowlist every address on your application or
firewall. Your account manager manages setup and changes; this setting cannot be
enabled by organization members or administrators.

Allowlist the exact addresses shown in your settings. For a firewall that requires
CIDR notation, use `/32` for each IPv4 address or `/128` for each IPv6 address.
There is no single shared Composal IP to allowlist for every organization.

The assignment applies to newly created hosted Verify runs, discovery browsers,
and login or scenario-recording browsers. Reprepare work that was admitted before
the assignment. Existing runs keep their original network configuration.
The gateway and sandbox must use the same concrete region, so Automatic region
selection is unavailable while a gateway is assigned. A missing or mismatched
gateway stops execution rather than sending traffic through shared IPs.

Dedicated egress covers Blaxel-hosted browsers. Self-hosted runners and macOS
devices need their own network setup. Application login credentials remain
separate from the IP allowlist.

### Allowlist your IPs in Cloudflare WAF

After your static IP assignment is enabled, create a Cloudflare custom rule for
the application you test. Match its hostname and all of your assigned addresses:

```text
(http.host eq "app.example.com" and ip.src in {203.0.113.10 203.0.113.11})
```

Replace `app.example.com` with your application's hostname and the example IPs
with the addresses in your org settings. Include other protected hostnames, such
as a separate API hostname, only when your tests need them.

1. In the Cloudflare dashboard, select your domain and open **Security → Security
   rules**. Choose **Create rule → Custom rules**.
2. Name the rule **Composal Verify**, open the expression editor, and enter the
   expression above with your hostname and assigned IPs.
3. Choose **Skip** and select the security features causing the block or
   challenge. For example, **All Super Bot Fight Mode rules** skips that product
   for matching requests. **All managed rules** skips WAF managed rules; if only
   one managed rule causes a false positive, prefer a [managed-rule
   exception](https://developers.cloudflare.com/waf/managed-rules/waf-exceptions/)
   for that rule using the same IP-and-hostname condition. Keep the other
   protections enabled.
4. Keep **Log matching requests** enabled and choose **Deploy**, then start a
   new Verify run. In Cloudflare **Security Events**, filter by your assigned
   source IP and check that the expected rule matches.

If a custom rule blocks or challenges Verify, exclude your assigned IPs from
that rule. Alternatively, place the scoped Skip rule before it and select **All
remaining custom rules**; this skips every later rule in that ruleset for matching
requests. A Skip rule cannot undo a block that already happened. If you have an
existing rule that blocks all IPs outside an allowlist, add your assigned IPs to
that allowlist as well.

Cloudflare's **Bot Fight Mode** cannot be skipped by WAF custom rules; **Super Bot
Fight Mode** supports Skip rules. Check the product that issued the challenge if
Verify is still blocked. Cloudflare Access and your application's sign-in
requirements still need their own authentication setup. For an embedded Turnstile
widget, follow the [signed Verify request exemption guide](/docs/verify/cloudflare-turnstile);
a WAF Skip rule alone does not exempt your app's Turnstile check.

See Cloudflare's [Skip rule
guide](https://developers.cloudflare.com/waf/custom-rules/skip/) and [available
skip options](https://developers.cloudflare.com/waf/custom-rules/skip/options/)
for the current controls and behavior. [Contact us](/contact) if you need static
IPs or help configuring your allowlist.

### Allowlist your IPs in Vercel Firewall

After your static IP assignment is enabled, create a bypass rule in the Vercel
project serving your app. Use the addresses under **Organization settings →
Dedicated outbound IP**, and scope the rule to the hostnames your tests visit.

1. Open your Vercel project, select **Firewall**, then **⋯ → Configure** and
   **Add New… → Rule**.
2. Name the rule **Composal Verify**. Add **IP Address → Is any of** with all
   assigned addresses, and combine it with **AND → Hostname → Equals** your test
   hostname, such as `app.example.com`. For multiple hostnames, use **Hostname →
   Is any of**. Both the IP and hostname conditions must match.
3. Set **Then → Bypass**, select **Save Rule**, then **Review Changes → Publish**.
   Place this rule before custom deny, challenge, or rate-limit rules that would
   block Verify. A bypass cannot undo an earlier block.
4. Start a new Verify run. In the project's **Firewall** traffic view, filter
   by the assigned source IP and check that the bypass rule matches. Include a
   separate API hostname only if your tests use it, and configure its Vercel
   project separately if needed.

A custom bypass skips subsequent custom and managed WAF rules for matching
traffic. It does not bypass Vercel's system-level mitigations. If traffic is
still blocked, inspect the firewall event to identify the responsible layer.
Remove conflicting explicit IP-block entries for your assigned addresses;
IP-block rules run before custom rules.

For a system-level block, **Pro and Enterprise** projects can add a **System
Bypass**: from **Firewall → Add New → System Bypass**, enter one assigned IP or
its exact CIDR (`/32` for IPv4, `/128` for IPv6), the app's domain, and a note,
then select **Create System Bypass**. Repeat for each assigned address and
required domain. Prefer specific domains to `*`. This bypass covers system
mitigations; retain the custom bypass if your own WAF rules also block Verify.

Vercel **Deployment Protection** and application sign-in still need their own
access configuration. A firewall bypass does not grant access through Vercel
Authentication, password protection, or your app's login. If Cloudflare sits in
front of Vercel, configure each firewall that blocks the request and check the
source IP reported by each provider before adding rules.

See Vercel's [custom-rule
guide](https://vercel.com/docs/vercel-firewall/vercel-waf/custom-rules),
[rule configuration
reference](https://vercel.com/docs/vercel-firewall/vercel-waf/rule-configuration),
and [system bypass
guide](https://vercel.com/docs/vercel-firewall/vercel-waf/system-bypass-rules)
for the current controls. [Contact us](/contact) if you need static IPs or help
configuring your allowlist.

## Tailscale

Use Tailscale for internal previews, services behind a subnet router, or an app running on your computer. Each browser sandbox joins your tailnet as an ephemeral device with a dedicated tag and the access your policy grants it.

Follow the [Tailscale guide](/docs/verify/tailscale) to configure the policy and OAuth client, save the connection, and check access.

## Localhost

A remote browser's `localhost` refers to its own sandbox. Use [Tailscale Serve to reach your local app](/docs/verify/tailscale#localhost), then set the reachable tailnet address as your environment URL.

## AWS Client VPN

Use certificate-authenticated, split-tunnel AWS Client VPN for private apps and APIs inside an AWS VPC. Public services such as your frontend, hosted sign-in page, and S3 remain reachable alongside the private API.

Follow the [AWS Client VPN guide](/docs/verify/aws-client-vpn) to prepare the endpoint, restrict service access, save the client profile, test the connection, and revoke access.
