> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ibee.co.in/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ibee.co.in/docs/_mcp/server.

# Virtual IPs

> Reserve a specific private IP inside a VPC subnet for MetalLB and Kubernetes LoadBalancer services, announced by nodes you authorize.

A Virtual IP (VIP) is a private address that **you choose** from a VPC subnet and
reserve as a floating endpoint. Unlike a VM's private address — which belongs
to one VM's interface once the VM attaches to a subnet — a Virtual IP is not
bound to any single VM's interface. Instead, you authorize one or more
NAT-connected nodes to *announce* it, so traffic for that address is served by
whichever announcer is healthy.

This is the mechanism behind bare-metal **MetalLB** and **Kubernetes
`LoadBalancer`** services: MetalLB advertises the reserved private address from
the announcer nodes, giving your service a stable in-VPC IP.

> **Info**
>
> A Virtual IP claims an address for MetalLB and authorizes the nodes that may
> announce it. IPAM will not assign the address to a VM, so the same address is
> never handed out as a node's interface IP.

## Prerequisites

* A VPC with at least one **NAT-connected node** to act as an announcer. Announcers
  are the VMs that advertise the Virtual IP.
* The subnet you want the address to live in (any subnet of the VPC).

## Choose the private IP

You pick the exact address. It must be a host address **inside the selected
subnet's CIDR** that is currently free. The backend validates the address and
rejects it when it is:

| Rejected                         | Reason                                                   |
| -------------------------------- | -------------------------------------------------------- |
| Outside the subnet CIDR          | The address must be a host in the chosen subnet's range. |
| The subnet gateway               | The gateway address is reserved for routing.             |
| The network or broadcast address | Neither is a usable host address.                        |
| Already allocated                | Another node or Virtual IP already holds it.             |

> **Tip**
>
> Check the **Private IP ledger** on the VPC's **Subnets** tab, or list the
> subnet's existing allocations with
> `GET /networking/vpcs/{vpc_id}/network-allocations?workspace_id=607005`, to see
> which host addresses are already taken before choosing one.

## Reserve a Virtual IP

### Open Reserved VIPs

Open the VPC's detail page and select the **Reserved VIPs** tab, then click
**Reserve Virtual IP**. The button is available once the VPC has a subnet.

### Pick a subnet and a free host address

Select a **Subnet** and enter the **Private IP** — an unused host address inside
its CIDR (for example `10.144.4.17`).

### Choose the announcer nodes

Under **MetalLB announcer nodes**, tick the NAT-connected VMs that may announce
the address.

### Reserve the address

Click **Reserve Virtual IP**.

The **Reserved VIPs** tab lists each reservation with its private IP, purpose,
announcers, attached public IP, and status.

### Reserve with the API

Provide the announcer VM IDs in `announcer_vm_ids`:

```bash
curl -X POST \
  "https://api.ibee.ai/v1/networking/vpcs/vpc-example/virtual-ips?workspace_id=607005" \
  -H "Authorization: Bearer $IBEE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subnet_id": "subnet-example",
    "private_ip": "10.144.4.17",
    "purpose": "metallb",
    "announcer_vm_ids": ["vm-example-a", "vm-example-b"]
  }'
```

#### Request fields

| Field              | Required | Description                                                                   |
| ------------------ | -------- | ----------------------------------------------------------------------------- |
| `subnet_id`        | Yes      | Subnet of the VPC that the address belongs to.                                |
| `private_ip`       | Yes      | The specific, unused host address to reserve, inside the subnet CIDR.         |
| `purpose`          | Yes      | `metallb` for a MetalLB / Kubernetes `LoadBalancer` Virtual IP.               |
| `announcer_vm_ids` | Yes      | One or more VM IDs of NAT-connected nodes authorized to announce the address. |

## List and inspect

```bash
# List every Virtual IP in the VPC
curl "https://api.ibee.ai/v1/networking/vpcs/vpc-example/virtual-ips?workspace_id=607005" \
  -H "Authorization: Bearer $IBEE_TOKEN"

# Inspect a single Virtual IP
curl "https://api.ibee.ai/v1/networking/vpcs/vpc-example/virtual-ips/vip-example?workspace_id=607005" \
  -H "Authorization: Bearer $IBEE_TOKEN"
```

Each Virtual IP reports its `private_ip`, `subnet_id`, `purpose`, and the
`announcer_vm_ids` currently authorized to advertise it.

## Expose a Virtual IP publicly

A Virtual IP is private by design. To make the service it fronts reachable from
the internet, attach a [Reserved IP](/docs/network-security/vpc-and-ip-management/reserved-ips)
to it:

1. On the **Reserved VIPs** tab, click **Attach** on the Virtual IP's row.
2. Select an unattached Reserved IP in the VPC's location.
3. Click **Attach Reserved IP**.

This creates a one-to-one public mapping: inbound and return traffic use the
Reserved IP, while the announcers continue to serve the traffic inside the VPC.

To remove public access, click **Detach** on the row and confirm **Detach
Reserved IP**. The Virtual IP stays reserved, and the Reserved IP returns to
your workspace pool for reuse.

On a NAT VPC you can instead forward a single NAT gateway port to the Virtual IP
with a [port forwarding rule](/docs/network-security/vpc-and-ip-management#nat-port-forwarding)
(destination type **MetalLB VIP**).

## Release a Virtual IP

Releasing a Virtual IP returns the private address to the subnet pool. Remove
the address from your MetalLB configuration first. Any Reserved IP attached to
it must be detached first — deletion is blocked while one is attached.

In the portal, click the delete icon on the Virtual IP's row on the **Reserved
VIPs** tab, then click **Delete Reservation**. With the API:

```bash
curl -X DELETE \
  "https://api.ibee.ai/v1/networking/vpcs/vpc-example/virtual-ips/vip-example?workspace_id=607005" \
  -H "Authorization: Bearer $IBEE_TOKEN"
```

## Errors

| Status            | When                                                                                      |
| ----------------- | ----------------------------------------------------------------------------------------- |
| `400 Bad Request` | The address is outside the subnet CIDR, or is the gateway, network, or broadcast address. |
| `404 Not Found`   | The VPC, subnet, or Virtual IP ID does not exist in this workspace.                       |
| `409 Conflict`    | The address is already allocated to another node or Virtual IP.                           |

## Related pages

* [VPC](/docs/network-security/vpc-and-ip-management)
* [Reserved IPs](/docs/network-security/vpc-and-ip-management/reserved-ips)
* [Networking for VMs](/docs/infrastructure/cloud-vms/networking-for-vms)
* [API reference](/docs/api-reference)