> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ibee.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ibee.ai/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 the
platform auto-assigns when a node 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**
>
> 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

### Pick a subnet and a free host address

Choose the subnet and an unused host address inside its CIDR (for example
`10.144.4.17`).

### Choose the announcer nodes

Select the NAT-connected VMs that may announce the address. Provide their VM IDs
in `announcer_vm_ids`.

### Reserve the address

```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. The Reserved (public) address then forwards to the Virtual IP, while the
announcers continue to serve the traffic inside the VPC.

## Release a Virtual IP

Releasing a Virtual IP returns the private address to the subnet pool. Any
Reserved IP attached to it must be detached first.

```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)