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

# Networking

> Publish stable subdomain URLs, protect access, forward private ports, and restrict egress

## Stable application URLs

Run a service on `0.0.0.0` and publish its port:

```bash theme={null}
beam vm exec --detach devbox -- python3 -m http.server 8000 --bind 0.0.0.0
beam vm expose devbox 8000 --public
beam vm ports devbox
```

Each published port has a stable subdomain URL. Your application's `/`, root-relative assets, redirects, and WebSockets use that origin without a VM path prefix. Always use the URL returned by Beam instead of constructing a hostname yourself.

```python theme={null}
from beam import VM

with VM.connect("devbox") as vm:
    print(vm.expose(8000, protected=False))
    print(vm.get_url(8000))
```

`get_url()` only retrieves an already published URL; it does not expose a private port. Removing a published route does not stop the service:

```bash theme={null}
beam vm unexpose devbox 8000
```

URLs stay the same after stop/start or pause/resume. A fork or restored VM gets its own URLs. A URL cannot serve traffic while the VM is asleep unless [automatic resume](/v2/vm/lifecycle#idle-ttl-and-automatic-resume) is enabled.

## Protect a published port

An ordinary published URL is accessible to anyone who has it. A random hostname is not a substitute for authentication. Protect sensitive services, especially the root browser terminal and desktop:

```bash theme={null}
beam vm new private-desktop --desktop --protected-port 7681 --protected-port 8080
beam vm expose devbox 8000 --protected
```

In Python, supply `ports` and `protected_ports` when creating application ports, or call `expose(port, protected=True)`:

```python theme={null}
from beam import VM

vm = VM(
    "private-desktop",
    desktop=True,
    protected_ports=[7681, 8080],
).create()
vm.close()
```

### Browser access

`beam vm desktop NAME` and `beam vm terminal NAME` generate an expiring entry URL automatically when their port is protected. Opening it exchanges the session credential for an HTTP-only cookie scoped to that port's host, then redirects to the stable URL.

For another protected application, generate an entry URL in Python:

```python theme={null}
from beam import VM

with VM.get("devbox") as vm:
    print(vm.access_url(8000, ttl=600))
```

Session TTLs are 1–3600 seconds; the default is 600. Treat entry URLs as credentials. When a session expires, request a fresh entry URL rather than making the port public.

### Programmatic access

For HTTP clients, use the VM traffic token in `X-Beam-VM-Token`. This token is distinct from your workspace API token:

```bash theme={null}
url=$(beam vm ports devbox --json | python3 -c \
  'import json, sys; print(json.load(sys.stdin)["8000"])')
token=$(beam vm access-token devbox)
curl -H "X-Beam-VM-Token: $token" "$url"
unset token
```

Rotate it to revoke the old token and browser sessions:

```bash theme={null}
beam vm access-token devbox --rotate
```

In Python, use `vm.traffic_access_token` and `vm.rotate_access_token()`. The token is consumed by the gateway and is not forwarded to the application.

## Private TCP forwarding

Keep a database or other TCP service private and connect through localhost:

```bash theme={null}
beam vm port-forward devbox 15432:5432
# In another terminal:
psql -h 127.0.0.1 -p 15432 -U postgres
```

The service must already be running in the VM. Configure its application credentials separately. The forwarding listener binds to `127.0.0.1`; the command keeps running until you stop it.

Equivalent syntax is `beam vm port-forward devbox 5432 --local-port 15432`. Port forwarding binds an unpublished port for authenticated tunnels without creating a public HTTP URL. SSH uses the same private transport.

In Python, `vm.bind(5432)` makes a port available to authenticated tunnels without publishing it. The low-level `beam vm tunnel NAME PORT` command bridges a tunnel through stdin/stdout, for tooling integrations; use `ssh` or `port-forward` for normal interactive use.

## Outbound network controls

Block all outbound traffic or allow only specific IP ranges:

```bash theme={null}
beam vm network devbox --block
beam vm network devbox --allow 203.0.113.0/24
beam vm network devbox --open
```

`203.0.113.0/24` is an example range; replace it with the real CIDRs your application needs. These controls persist across restarts. Do not combine blocking all traffic with an allow list.

```python theme={null}
from beam import VM

with VM.get("devbox") as vm:
    vm.update_network_permissions(block_network=True)
    vm.update_network_permissions(block_network=False, allow_list=["203.0.113.0/24"])
    vm.update_network_permissions(block_network=False, allow_list=[])
```

Use `--block-network` or repeat `--allow-network CIDR` at creation for the same policy. Image building happens separately from guest runtime egress controls. Blocking outbound traffic also prevents apt, pip, agent APIs, and other external downloads unless their destinations are allowed.

Egress restrictions do not protect inbound URLs. Configure published-port protection independently.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.