> ## Documentation Index
> Fetch the complete documentation index at: https://novita.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Internet access

export const SandboxConfigHint = () => {
  if (typeof document === "undefined") {
    return null;
  } else {
    return <Note>Before running the example code in this document, please ensure you have properly configured environment variables. For details, please refer to <a href="/guides/sandbox-your-first-agent-sandbox#configure-environment-variables">Configure Environment Variables</a>.</Note>;
  }
};

Internet connectivity is available in every sandbox, and external access is provided through a public URL.

<SandboxConfigHint />

## Toggling internet access

When creating a sandbox, you can use the `allowInternetAccess` / `allow_internet_access` parameter to configure internet connectivity. Internet access is turned on by default, but it can be disabled for workloads with stricter security requirements.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Create sandbox with internet access enabled (default)
  const sandbox = await Sandbox.create({ allowInternetAccess: true })

  // Create sandbox without internet access
  const isolatedSandbox = await Sandbox.create({ allowInternetAccess: false })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Create sandbox with internet access enabled (default)
  sandbox = Sandbox.create(allow_internet_access=True)

  # Create sandbox without internet access
  isolated_sandbox = Sandbox.create(allow_internet_access=False)
  ```
</CodeGroup>

If internet access is disabled, the sandbox is prevented from initiating outbound network requests. This helps add an extra layer of protection when running sensitive code.

<Note>
  Passing a falsy value to `allowInternetAccess` / `allow_internet_access` has the same effect as adding `['0.0.0.0/0']` to `network.denyOut` / `network.deny_out`, which blocks every destination.
</Note>

## Fine-grained network control

Network configuration provides finer-grained control over outbound traffic by allowing you to define allowlists and denylists.

### Allow and deny lists

IP addresses, CIDR blocks, or domain names that the sandbox is allowed to access can be specified.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Deny all traffic except specific IPs
  const sandbox = await Sandbox.create({
    network: {
      denyOut: ['0.0.0.0/0'],
      allowOut: ['1.1.1.1', '8.8.8.0/24']
    }
  })

  // Deny specific IPs only
  const restrictedSandbox = await Sandbox.create({
    network: {
      denyOut: ['8.8.8.8']
    }
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Deny all traffic except specific IPs
  sandbox = Sandbox.create(
      network={
          "deny_out": ["0.0.0.0/0"],
          "allow_out": ["1.1.1.1", "8.8.8.0/24"]
      }
  )

  # Deny specific IPs only
  restricted_sandbox = Sandbox.create(
      network={
          "deny_out": ["8.8.8.8"]
      }
  )
  ```
</CodeGroup>

<Note>
  The CIDR `'0.0.0.0/0'` / `"0.0.0.0/0"` is shorthand for "every destination". An exported `ALL_TRAFFIC` constant resolves to the same `0.0.0.0/0` value if you prefer a named alternative to the literal.
</Note>

### Domain-based filtering

You can specify hostnames in `allowOut` / `allow_out` to permit outbound traffic to selected domains. When domain-based filtering is enabled, all remaining traffic must be blocked through `denyOut` / `deny_out`. Domain entries are only supported in allow lists and cannot be used in deny lists.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Allow only traffic to google.com
  const sandbox = await Sandbox.create({
    network: {
      allowOut: ['google.com'],
      denyOut: ['0.0.0.0/0']
    }
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Allow only traffic to google.com
  sandbox = Sandbox.create(
      network={
          "allow_out": ["google.com"],
          "deny_out": ["0.0.0.0/0"]
      }
  )
  ```
</CodeGroup>

<Note>
  Whenever a domain appears in the configuration, the default nameserver `8.8.8.8` is allowed automatically so that DNS resolution keeps working.
</Note>

You can also match every subdomain of a domain with a wildcard:

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Allow traffic to any subdomain of mydomain.com
  const sandbox = await Sandbox.create({
    network: {
      allowOut: ['*.mydomain.com'],
      denyOut: ['0.0.0.0/0']
    }
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Allow traffic to any subdomain of mydomain.com
  sandbox = Sandbox.create(
      network={
          "allow_out": ["*.mydomain.com"],
          "deny_out": ["0.0.0.0/0"]
      }
  )
  ```
</CodeGroup>

Domains, IP addresses, and CIDR ranges can all be mixed together in the same list:

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Allow traffic to specific domains and IPs
  const sandbox = await Sandbox.create({
    network: {
      allowOut: ['api.example.com', '*.github.com', '8.8.8.8'],
      denyOut: ['0.0.0.0/0']
    }
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Allow traffic to specific domains and IPs
  sandbox = Sandbox.create(
      network={
          "allow_out": ["api.example.com", "*.github.com", "8.8.8.8"],
          "deny_out": ["0.0.0.0/0"]
      }
  )
  ```
</CodeGroup>

<Note>
  Filtering by domain applies only to HTTP over port 80 (inspected via the Host header) and TLS over port 443 (inspected via SNI). Any other port falls back to CIDR-based matching, and UDP protocols such as QUIC/HTTP3 cannot be filtered by domain.
</Note>

### How blocked TCP connections behave

Because of the firewall architecture, a blocked outbound connection can still look successful from within the sandbox.

The firewall must first accept the TCP connection before it can evaluate whether the target destination is permitted. As a result, code running inside the sandbox may see the connection succeed and the socket open, even if the destination is blocked. In that case, no traffic is actually delivered to the remote endpoint.

To confirm that the destination is reachable, validate an application-level response instead of relying only on TCP connection success. For example, check for an HTTP status code, a completed TLS handshake, or the expected protocol response bytes.

This behavior is a current limitation of how sandbox outbound traffic is routed through our firewall and may be updated in the future.

### Priority rules

If both allow and deny rules are configured, **the allow rules take priority**. Therefore, any IP address that appears in both lists will still be permitted.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Even though all traffic is denied, 1.1.1.1 and 8.8.8.8 are explicitly allowed
  const sandbox = await Sandbox.create({
    network: {
      denyOut: ['0.0.0.0/0'],
      allowOut: ['1.1.1.1', '8.8.8.8']
    }
  })
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Even though all traffic is denied, 1.1.1.1 and 8.8.8.8 are explicitly allowed
  sandbox = Sandbox.create(
      network={
          "deny_out": ["0.0.0.0/0"],
          "allow_out": ["1.1.1.1", "8.8.8.8"]
      }
  )
  ```
</CodeGroup>

The `network` settings take effect only when the sandbox is created — supply them to `Sandbox.create`. Once the sandbox exists, they are fixed and cannot be modified.

## Sandbox public URL

Services in a sandbox can be accessed by using the sandbox’s public URL.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  // You need to always pass a port number to get the host
  const host = sandbox.getHost(3000)
  console.log(`https://${host}`)
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  sandbox = Sandbox.create()

  # You need to always pass a port number to get the host
  host = sandbox.get_host(3000)
  print(f'https://{host}')
  ```
</CodeGroup>

The output will be like this:

<CodeGroup>
  ```bash JavaScript & TypeScript icon="terminal" theme={"system"}
  https://3000-i62mff4ahtrdfdkyn2esc.sandbox.novita.ai
  ```

  ```bash Python icon="terminal" theme={"system"}
  https://3000-i62mff4ahtrdfdkyn2esc.sandbox.novita.ai
  ```
</CodeGroup>

The leftmost segment of the hostname is exactly the port number you handed to the method.

## Connecting to a server running inside the sandbox

You can connect to a server running inside the sandbox using the method described earlier; for example, start a lightweight HTTP server on port 3000 to serve files from its launch directory.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  const sandbox = await Sandbox.create()

  // Start a simple HTTP server inside the sandbox.
  const process = await sandbox.commands.run('python -m http.server 3000', { background: true })
  const host = sandbox.getHost(3000)
  const url = `https://${host}`
  console.log('Server started at:', url)

  // Fetch data from the server inside the sandbox.
  const response = await fetch(url);
  const data = await response.text();
  console.log('Response from server inside sandbox:', data);

  // Kill the server process inside the sandbox.
  await process.kill()
  ```

  ```python Python icon="python" theme={"system"}
  import requests
  from novita_sandbox.code_interpreter import Sandbox

  sandbox = Sandbox.create()

  # Start a simple HTTP server inside the sandbox.
  process = sandbox.commands.run("python -m http.server 3000", background=True)
  host = sandbox.get_host(3000)
  url = f"https://{host}"
  print('Server started at:', url)

  # Fetch data from the server inside the sandbox.
  response = requests.get(url)
  data = response.text
  print('Response from server inside sandbox:', data)

  # Kill the server process inside the sandbox.
  process.kill()
  ```
</CodeGroup>

This output will be as follows:

<CodeGroup>
  ```bash JavaScript & TypeScript icon="terminal" theme={"system"}
  Server started at: https://3000-ip3nfrvajtqu5ktoxugc7.sandbox.novita.ai
  Response from server inside sandbox: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Directory listing for /</title>
  </head>
  <body>
  <h1>Directory listing for /</h1>
  <hr>
  <ul>
  <li><a href=".bash_logout">.bash_logout</a></li>
  <li><a href=".bashrc">.bashrc</a></li>
  <li><a href=".profile">.profile</a></li>
  </ul>
  <hr>
  </body>
  </html>
  ```

  ```bash Python icon="terminal" theme={"system"}
  Server started at: https://3000-ip3nfrvajtqu5ktoxugc7.sandbox.novita.ai
  Response from server inside sandbox: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Directory listing for /</title>
  </head>
  <body>
  <h1>Directory listing for /</h1>
  <hr>
  <ul>
  <li><a href=".bash_logout">.bash_logout</a></li>
  <li><a href=".bashrc">.bashrc</a></li>
  <li><a href=".profile">.profile</a></li>
  </ul>
  <hr>
  </body>
  </html>
  ```
</CodeGroup>

## Masking request host headers

You can use the `maskRequestHost` / `mask_request_host` option to customize the Host header sent to services running inside the sandbox. This is useful when your application expects requests to follow a specific host format.

<CodeGroup>
  ```js JavaScript & TypeScript icon="js" theme={"system"}
  import { Sandbox } from 'novita-sandbox/code-interpreter'

  // Create sandbox with custom host masking
  const sandbox = await Sandbox.create({
    network: {
      maskRequestHost: 'localhost:${PORT}'
    }
  })

  // The ${PORT} variable will be replaced with the actual port number
  // Requests to the sandbox will have Host header set to for example: localhost:8080
  ```

  ```python Python icon="python" theme={"system"}
  from novita_sandbox.code_interpreter import Sandbox

  # Create sandbox with custom host masking
  sandbox = Sandbox.create(
      network={
          "mask_request_host": "localhost:${PORT}"
      }
  )

  # The ${PORT} variable will be replaced with the actual port number
  # Requests to the sandbox will have Host header set to for example: localhost:8080
  ```
</CodeGroup>

At request time, `${PORT}` in the mask is substituted with the real port number of the service being addressed.
