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

# Create and configure a virtual IP address

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    ## Virtual IP address overview

    <p>A virtual IP address (VIP) is an IP address that can be assigned to multiple Virtual Machines or serve as a secondary IP address for a network interface.</p>

    ## VIP use cases

    <p>To use a VIP for fault tolerance, install and configure Keepalived, a Linux daemon that uses the Virtual Router Redundancy Protocol (VRRP) to manage the address. VRRP allows multiple machines to share a common IP address. Keepalived passes the VIP between a primary machine and backup machines. When the primary fails, the VRRP detects the failure and assigns the VIP to the highest-priority backup, keeping the service available.</p>

    <p>To use a VIP as a secondary address for a network interface, reserve a VIP and assign it to a Virtual Machine — first in the Gcore Cloud settings, then in the machine's network configuration. The VIP then works alongside the machine's regular IP address, and the machine can receive and send traffic on both addresses.</p>

    ## Billing

    <p>A VIP is billed from the moment it is reserved until the moment it is deleted. For example, if a VIP is reserved and then deleted after an hour, charges apply only for that hour of use, regardless of whether the address was assigned to the Virtual Machine or not.</p>

    <p>The monthly price is displayed in the order window.</p>

    ## Public IP limits

    <p>A Virtual Machine has only one public interface, meaning it receives a Public IP from the public network. It also supports multiple Floating IPs from private networks, but quotas limit the number. In a multi-network setup, each subnet can have one Floating IP. Within a single network, multiple subnets can exist, and each subnet of a single machine (VM/BM) is allowed one Floating IP.</p>

    <p>By default, Bare Metal servers support up to six attached IPs. A dedicated Bare Metal network removes this limit, allowing unlimited IPs per machine. Unlike standard networks, this type of network lacks port security and can be allocated by request.</p>

    ## Create a virtual IP address

    1. In the Cloud menu, go to **Networking** → **Reserved IPs** and click **Reserve new IP**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-reserved-ips-list.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=0c0c20b09100357dfd76f18d570d60bf" alt="Reserved IPs page with Reserve new IP button" width="1102" height="403" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-reserved-ips-list.png" />
    </Frame>

    2. In the dialog, set **Network type** to **Public**, **Private**, or **Dedicated public**. For a private IP, also select the network and subnet. In the **IP address to reserve** section, leave **Any available IP** selected or choose **Custom** to specify an address from the subnet CIDR. Select an **IP Family** and click **Reserve IP**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-create-dialog.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=159920f95a5906d5168f51a7d0ee6469" alt="Reserve IP dialog showing Network type and IP Family options" width="475" height="484" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-create-dialog.png" />
    </Frame>

    3. In the list of reserved IPs, find the new address, click **⋯** next to it, and select **Set as VIP**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-set-as-vip-menu.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=c799cf456c218918b7d4fbd0a7ebd232" alt="Reserved IPs row context menu with Set as VIP option" width="1103" height="406" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-set-as-vip-menu.png" />
    </Frame>

    4. In the confirmation dialog, click **Set as VIP**.

    <p>The IP status changes to **VIP** and the **VIP settings** dialog opens. Instance interfaces can be added immediately or at any time later.</p>

    ## Assign a virtual IP address to multiple VMs

    1. In the Cloud menu, go to **Networking** → **Reserved IPs**, find the required virtual IP address, click **⋯** next to it, and select **VIP settings**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-manage-menu.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=42fea79eee8edecf77eb12ae210272ef" alt="Reserved IPs row context menu showing VIP settings option" width="1099" height="389" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-manage-menu.png" />
    </Frame>

    2. In the **VIP settings** dialog, click **+ Add Instance Interface**. Select the VM from the **Select VM** dropdown and choose its network port from **Select Port**. Add more VMs using **+ Add Instance Interface** again, then click **Save**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-settings-add-instance.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=af06b447a97454d8ab085cf5dd874916" alt="VIP settings dialog with Select VM and Select Port dropdowns" width="791" height="697" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-settings-add-instance.png" />
    </Frame>

    3. Install and configure Keepalived on the Virtual Machines using the [Keepalived documentation](https://keepalived.readthedocs.io/en/latest/installing_keepalived.html).

    4. Change the Keepalived configuration file to set the "MASTER" machine and "BACKUP" machines. Additionally, set the priority to determine the order in which the VIP will be transferred between devices. If the master server fails, the IP address will be transferred to the backup machine with the highest priority. If the second machine fails, the VIP will be transferred to the backup machine with the second-highest priority.

    5. Run Keepalived on the Virtual Machine and add it to the autostart list.

    <p>The VIP is now configured and the fault-tolerant system is operational.</p>

    ## Assign a virtual IP address as a secondary address

    1. In the Cloud menu, go to **Networking** → **Reserved IPs**, find the required virtual IP address, click **⋯** next to it, and select **VIP settings**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-manage-menu.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=42fea79eee8edecf77eb12ae210272ef" alt="Reserved IPs row context menu showing VIP settings option" width="1099" height="389" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-manage-menu.png" />
    </Frame>

    2. In the **VIP settings** dialog, click **+ Add Instance Interface**. Select the VM and its port, then click **Save**.

    <Frame>
      <img src="https://mintcdn.com/gcore/yrEa6OGy4Q_zWlXb/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-settings-add-instance.png?fit=max&auto=format&n=yrEa6OGy4Q_zWlXb&q=85&s=af06b447a97454d8ab085cf5dd874916" alt="VIP settings dialog with Select VM and Select Port dropdowns" width="791" height="697" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/vip-settings-add-instance.png" />
    </Frame>

    <p>Next, configure the VIP in the Virtual Machine settings. The sections below cover non-Windows and Windows VMs.</p>

    ## Configure a virtual IP address for non-Windows Virtual Machines

    1. Connect to the Virtual Machine.

    2. Run the following command as an administrator:

    ```sh theme={null}
    ip addr add [VIP]/[mask] dev [interface name]
    ```

    <p>where:
    <p>- **\[VIP]** is the virtual IP address to add to the interface.
    \- **\[mask]** is the subnet mask associated with the virtual IP address. It can be found in the **Networking** tab of the Virtual Machine.
    \- **\[interface name]** is the name of the network interface where the IP address will be added. To find the name, run the command:</p></p>

    ```sh theme={null}
    ip addr 
    ```

    <p>The interface name will appear on the left below the loopback interface.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946900210833.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=8a1bf5c4bab34118ba2f73fdf10325fd" alt="Terminal output of ip addr showing interface names" width="968" height="232" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946900210833.png" />
    </Frame>

    <p>For example, to add the virtual IP address *192.168.1.200* with a subnet mask of *24* to the *eth0* interface, use the following command:</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946938150161.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=b37a63ad12ec65e761ac881d36271604" alt="Terminal showing ip addr add command example" width="389" height="29" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946938150161.png" />
    </Frame>

    <p>The assignment lasts until the machine restarts. To make it permanent, add the IP address to the OS network configuration files.</p>

    <p>The VIP is now configured. To verify it, connect to the Virtual Machine [via SSH](/cloud/virtual-instances/connect/connect-to-your-instance-via-ssh) using the VIP. If the connection fails, there may be an error in the IP assignment command or the IP address may not have been added to the network configuration. Repeat the steps.</p>

    ### Configure a virtual IP address for Windows Virtual Machines

    1. Open the **Control Panel**.
    2. Go to the **Network and Sharing Center**.
    3. Right-click the network connection to which the virtual IP address will be added and select **Properties**.
    4. Select **Internet Protocol Version 4 (TCP/IPv4)** and click **Properties**.

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946990237457.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=f339c94305a30cc1576ec5e4609ce4b9" alt="Windows TCP/IPv4 Properties dialog" width="376" height="489" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12946990237457.png" />
    </Frame>

    5. Click **Use the following IP address** option and enter the virtual IP address, subnet mask, and default gateway in the appropriate fields. To find these parameters, run the following command:

    ```sh theme={null}
    ipconfig 
    ```

    <p>The output will be similar to:</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12947005842961.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=34ae4a231a2b48536253f700efd830ac" alt="Windows ipconfig output showing IP details" width="1074" height="494" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12947005842961.png" />
    </Frame>

    <p>Go back to the **Control Panel**, verify the values are correct, and click **Advanced ....**</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12947053843345.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=65ec62dbac116687378a7b3b5dccfefb" alt="Windows Advanced TCP/IP settings button" width="417" height="474" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/12947053843345.png" />
    </Frame>

    6. In the **IP Settings** tab, find the **IP addresses** section and click **Add ....**

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/20.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=bbdd688d60ee9b8effbfe445162b1bc4" alt="Windows IP Settings tab with Add button" width="496" height="606" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/20.png" />
    </Frame>

    7. In the next window, enter the VIP and the subnet mask from the command line. Then click **Add**.

    <Frame>
      <img src="https://mintcdn.com/gcore/c-GSw73gRYekqiTo/images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/21.png?fit=max&auto=format&n=c-GSw73gRYekqiTo&q=85&s=8014c6ada39cfe40d936af8db7583ed8" alt="Windows Add IP address dialog" width="498" height="608" data-path="images/docs/cloud/networking/ip-address/create-and-configure-a-virtual-ip-vip-address/21.png" />
    </Frame>

    8. Click **OK**.

    <p>The VIP is now configured. To verify it, connect to the Virtual Machine [via SSH](/cloud/virtual-instances/connect/connect-to-your-instance-via-ssh) using the VIP. If the connection fails, there may be an error in the IP assignment command or the IP address may not have been added to the network configuration. Repeat the steps.</p>
  </MethodSection>

  <MethodSection id="api" label="REST API">
    <p>Reserve a shared IP address and attach it to multiple Virtual Machines to enable high-availability failover configurations.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a [project ID](/api-reference/cloud/projects/list-projects) and a [region ID](/api-reference/cloud/regions/list-regions).
    </Info>

    <p>Set these environment variables before running the examples:</p>

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
    export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
    ```

    ## Quickstart

    <p>The scripts below reserve a public virtual IP address, connect one VM's network port to it, then remove the connection and delete the VIP.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        from gcore import Gcore

        client = Gcore()

        port_id = os.environ["PORT_ID"]  # Port ID of an existing VM's network interface; see Step 2

        # Step 1. Reserve a public virtual IP address
        vip = client.cloud.reserved_fixed_ips.create_and_poll(
            type="external",
            ip_family="ipv4",
            is_vip=True,
        )
        print(f"VIP: port_id={vip.port_id}  address={vip.fixed_ip_address}")

        # Step 2. List VM ports eligible to share this VIP
        candidates = client.cloud.reserved_fixed_ips.vip.candidate_ports.list(vip.port_id)
        print(f"Candidate VM ports: {candidates.count}")

        # Step 3. Connect a VM port to the VIP
        result = client.cloud.reserved_fixed_ips.vip.connected_ports.add(
            vip.port_id,
            port_ids=[port_id],
        )
        print(f"Connected VMs: {result.count}")

        # Step 4. List VMs connected to the VIP
        connected = client.cloud.reserved_fixed_ips.vip.connected_ports.list(vip.port_id)
        for vm in connected.results:
            print(f"  VM: {vm.instance_name}  port_id: {vm.port_id}")

        # Step 5. Disconnect all VMs from the VIP
        client.cloud.reserved_fixed_ips.vip.connected_ports.replace(
            vip.port_id,
            port_ids=[],
        )

        # Step 6. Disable VIP mode (required before deletion)
        client.cloud.reserved_fixed_ips.vip.toggle(vip.port_id, is_vip=False)

        # Step 7. Delete the reserved IP
        client.cloud.reserved_fixed_ips.delete_and_poll(vip.port_id)
        print("VIP deleted.")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
            "context"
            "fmt"
            "log"
            "os"

            gcore "github.com/G-Core/gcore-go"
            "github.com/G-Core/gcore-go/cloud"
            "github.com/G-Core/gcore-go/packages/param"
            "github.com/G-Core/gcore-go/shared/constant"
        )

        func main() {
            portID := os.Getenv("PORT_ID") // Port ID of an existing VM's network interface; see Step 2

            client := gcore.NewClient()
            ctx := context.Background()

            // Step 1. Reserve a public virtual IP address
            vip, err := client.Cloud.ReservedFixedIPs.NewAndPoll(ctx, cloud.ReservedFixedIPNewParams{
                OfExternal: &cloud.ReservedFixedIPNewParamsBodyExternal{
                    IsVip:    param.NewOpt(true),
                    IPFamily: cloud.InterfaceIPFamilyIpv4,
                    Type:     constant.ValueOf[constant.External](),
                },
            })
            if err != nil {
                log.Fatalf("create VIP: %v", err)
            }
            fmt.Printf("VIP: port_id=%s  address=%s\n", vip.PortID, vip.FixedIPAddress)

            // Step 2. List VM ports eligible to share this VIP
            candidates, err := client.Cloud.ReservedFixedIPs.Vip.CandidatePorts.List(ctx,
                vip.PortID,
                cloud.ReservedFixedIPVipCandidatePortListParams{},
            )
            if err != nil {
                log.Fatalf("list candidates: %v", err)
            }
            fmt.Printf("Candidate VM ports: %d\n", candidates.Count)

            // Step 3. Connect a VM port to the VIP
            result, err := client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.Add(ctx,
                vip.PortID,
                cloud.ReservedFixedIPVipConnectedPortAddParams{PortIDs: []string{portID}},
            )
            if err != nil {
                log.Fatalf("add connected port: %v", err)
            }
            fmt.Printf("Connected VMs: %d\n", result.Count)

            // Step 4. List VMs connected to the VIP
            connected, err := client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.List(ctx,
                vip.PortID,
                cloud.ReservedFixedIPVipConnectedPortListParams{},
            )
            if err != nil {
                log.Fatalf("list connected: %v", err)
            }
            for _, vm := range connected.Results {
                fmt.Printf("  VM: %s  port_id: %s\n", vm.InstanceName, vm.PortID)
            }

            // Step 5. Disconnect all VMs from the VIP
            if _, err = client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.Replace(ctx,
                vip.PortID,
                cloud.ReservedFixedIPVipConnectedPortReplaceParams{PortIDs: []string{}},
            ); err != nil {
                log.Fatalf("disconnect VMs: %v", err)
            }

            // Step 6. Disable VIP mode (required before deletion)
            if _, err = client.Cloud.ReservedFixedIPs.Vip.Toggle(ctx,
                vip.PortID,
                cloud.ReservedFixedIPVipToggleParams{IsVip: false},
            ); err != nil {
                log.Fatalf("toggle VIP off: %v", err)
            }

            // Step 7. Delete the reserved IP
            if err = client.Cloud.ReservedFixedIPs.DeleteAndPoll(ctx,
                vip.PortID, cloud.ReservedFixedIPDeleteParams{},
            ); err != nil {
                log.Fatalf("delete VIP: %v", err)
            }
            fmt.Println("VIP deleted.")
        }
        ```
      </Tab>
    </Tabs>

    ## Step-by-step

    <p>Each step below explains what the call does, which parameters matter, and what the response looks like. Use this section to understand the flow or to debug a specific step.</p>

    <Accordion title="Show all steps">
      ### Step 1. Reserve a virtual IP address

      Reserving a public IP with `is_vip: true` creates a port that can be shared across multiple VM interfaces — the VIP flag enables connecting more than one port to the same address.

      | Parameter   | Required | Description                                                  |
      | ----------- | -------- | ------------------------------------------------------------ |
      | `type`      | Yes      | `"external"` for a public IP, `"subnet"` for a private IP    |
      | `ip_family` | No       | `"ipv4"` (default), `"ipv6"`, or `"dual"`                    |
      | `is_vip`    | No       | Set to `true` to create the reserved IP as a VIP immediately |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          import os
          from gcore import Gcore

          client = Gcore()

          vip = client.cloud.reserved_fixed_ips.create_and_poll(
              type="external",
              ip_family="ipv4",
              is_vip=True,
          )
          print(f"port_id={vip.port_id}  address={vip.fixed_ip_address}  is_vip={vip.is_vip}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          vip, err := client.Cloud.ReservedFixedIPs.NewAndPoll(ctx, cloud.ReservedFixedIPNewParams{
              OfExternal: &cloud.ReservedFixedIPNewParamsBodyExternal{
                  IsVip:    param.NewOpt(true),
                  IPFamily: cloud.InterfaceIPFamilyIpv4,
                  Type:     constant.ValueOf[constant.External](),
              },
          })
          if err != nil {
              log.Fatalf("create VIP: %v", err)
          }
          fmt.Printf("port_id=%s  address=%s  is_vip=%t\n", vip.PortID, vip.FixedIPAddress, vip.IsVip)
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl -X POST "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID" \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"type": "external", "ip_family": "ipv4", "is_vip": true}'
          ```

          Response:

          ```json theme={null}
          {
            "tasks": ["28cfde66-33c5-4ace-b97a-d7869df10154"]
          }
          ```

          Poll `GET https://api.gcore.com/cloud/v1/tasks/{task_id}` every 5 seconds until `state` is `FINISHED`. Save `created_resources.ports[0]` as `VIP_PORT_ID`.

          ```json theme={null}
          {
            "state": "FINISHED",
            "created_resources": {
              "ports": ["6a6eb2dc-8647-4fb4-8497-9b8ba301b9ec"]
            }
          }
          ```

          Then retrieve the VIP details:

          ```bash theme={null}
          curl "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID" \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          Response:

          ```json theme={null}
          {
            "port_id": "6a6eb2dc-8647-4fb4-8497-9b8ba301b9ec",
            "fixed_ip_address": "85.234.84.202",
            "is_vip": true,
            "status": "DOWN",
            "reservation": {
              "status": "attached"
            }
          }
          ```
        </Tab>
      </Tabs>

      The `reservation.status` of `"attached"` confirms VIP mode is active. Additional creation options such as specifying a private network or a fixed IP address are described in the [reserved IPs API](/api-reference/cloud#tag/Reserved-Fixed-IPs/operation/ReservedFixedIPCreateV1.post).

      ### Step 2. Get a VM port ID

      Each VM network interface has a `port_id`. Supply this ID when connecting the VM to the VIP.

      <Tabs>
        <Tab title="curl">
          ```bash theme={null}
          curl "https://api.gcore.com/cloud/v1/instances/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID" \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          Response (excerpt):

          ```json theme={null}
          {
            "results": [
              {
                "id": "a1b2c3d4-...",
                "name": "my-vm",
                "addresses": {
                  "pub_net": [
                    {
                      "addr": "95.85.95.10",
                      "type": "fixed",
                      "port_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890"
                    }
                  ]
                }
              }
            ]
          }
          ```
        </Tab>
      </Tabs>

      Save the `port_id` from the relevant network interface. Use the port on the same network as the VIP:

      ```bash theme={null}
      export PORT_ID="{port_id}"
      ```

      <Info>
        `PORT_ID` is the UUID of the VM's network interface port on the same network as the VIP. The value appears in the response from Step 2 above, or by listing instances via `GET /cloud/v2/instances/{project_id}/{region_id}` and reading the `addresses` field.
      </Info>

      ### Step 3. Connect a VM to the VIP

      Adding a VM's port to the VIP makes both the VM's own IP and the VIP reachable on that interface. Multiple VM ports can share one VIP.

      | Parameter  | Required | Description                            |
      | ---------- | -------- | -------------------------------------- |
      | `port_ids` | Yes      | Array of VM port IDs to add to the VIP |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          result = client.cloud.reserved_fixed_ips.vip.connected_ports.add(
              vip.port_id,
              port_ids=[os.environ["PORT_ID"]],
          )
          print(f"Connected VMs: {result.count}")
          for vm in result.results:
              print(f"  VM: {vm.instance_name}  port_id: {vm.port_id}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          result, err := client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.Add(ctx,
              vip.PortID,
              cloud.ReservedFixedIPVipConnectedPortAddParams{
                  PortIDs: []string{os.Getenv("PORT_ID")},
              },
          )
          if err != nil {
              log.Fatalf("add connected port: %v", err)
          }
          fmt.Printf("Connected VMs: %d\n", result.Count)
          for _, vm := range result.Results {
              fmt.Printf("  VM: %s  port_id: %s\n", vm.InstanceName, vm.PortID)
          }
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl -X PATCH "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID/connected_devices" \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"port_ids": ["f1e2d3c4-b5a6-7890-abcd-ef1234567890"]}'
          ```

          Response:

          ```json theme={null}
          {
            "count": 1,
            "results": [
              {
                "instance_id": "a1b2c3d4-...",
                "instance_name": "my-vm",
                "port_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890",
                "ip_assignments": [
                  { "ip_address": "10.0.0.5" }
                ]
              }
            ]
          }
          ```
        </Tab>
      </Tabs>

      To replace all connected VMs at once, use `PUT /connected_devices` (curl) or `connected_ports.replace()` (SDK) with the full `port_ids` list.

      ### Configure the VIP inside the guest OS

      Connecting a VM's port to the VIP through the API is not enough for the VIP to carry traffic. The address must also be added to the network interface inside the VM's operating system.

      For Linux, run as root:

      ```bash theme={null}
      ip addr add {VIP_ADDRESS}/{MASK} dev {INTERFACE}
      ```

      where `{MASK}` is the subnet prefix length (find it in the VM's **Networking** tab) and `{INTERFACE}` is the network interface name (`ip addr` lists them).

      This assignment is non-persistent — it is lost on reboot. To make it permanent, add the address to the OS network configuration files.

      For Windows, use **Control Panel** → **Network and Sharing Center** → interface **Properties** → **TCP/IPv4 Properties** → **Advanced** → **Add IP address**. Full step-by-step instructions are in the [Customer Portal tab](#portal) under **Configure a virtual IP address for Windows Virtual Machines**.

      ### Step 4. List connected VMs

      Listing connected VMs confirms which ports share the VIP and returns the instance name alongside each port ID.

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          connected = client.cloud.reserved_fixed_ips.vip.connected_ports.list(vip.port_id)
          print(f"Total connected: {connected.count}")
          for vm in connected.results:
              print(f"  VM: {vm.instance_name}  port_id: {vm.port_id}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          connected, err := client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.List(ctx,
              vip.PortID,
              cloud.ReservedFixedIPVipConnectedPortListParams{},
          )
          if err != nil {
              log.Fatalf("list connected: %v", err)
          }
          fmt.Printf("Total connected: %d\n", connected.Count)
          for _, vm := range connected.Results {
              fmt.Printf("  VM: %s  port_id: %s\n", vm.InstanceName, vm.PortID)
          }
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID/connected_devices" \
            -H "Authorization: APIKey $GCORE_API_KEY"
          ```

          Response:

          ```json theme={null}
          {
            "count": 1,
            "results": [
              {
                "instance_id": "a1b2c3d4-...",
                "instance_name": "my-vm",
                "port_id": "f1e2d3c4-b5a6-7890-abcd-ef1234567890"
              }
            ]
          }
          ```
        </Tab>
      </Tabs>
    </Accordion>

    ## Enable or disable VIP mode

    <p>An existing [reserved IP](/cloud/networking/ip-address/create-and-configure-a-reserved-ip-address) can be promoted to a VIP at any time by setting `is_vip: true`. Setting it back to `false` removes VIP mode and disconnects any ports connected to the VIP.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        from gcore import Gcore

        client = Gcore()

        vip_port_id = "..."  # port_id from Step 1 or from listing reserved IPs

        # Enable VIP mode
        updated = client.cloud.reserved_fixed_ips.vip.toggle(vip_port_id, is_vip=True)
        print(f"is_vip={updated.is_vip}  reservation_status={updated.reservation.status}")

        # Disable VIP mode
        updated = client.cloud.reserved_fixed_ips.vip.toggle(vip_port_id, is_vip=False)
        print(f"is_vip={updated.is_vip}  reservation_status={updated.reservation.status}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        vipPortID := "..."  // port_id from Step 1 or from listing reserved IPs

        // Enable VIP mode
        updated, err := client.Cloud.ReservedFixedIPs.Vip.Toggle(ctx,
            vipPortID,
            cloud.ReservedFixedIPVipToggleParams{IsVip: true},
        )
        if err != nil {
            log.Fatalf("toggle on: %v", err)
        }
        fmt.Printf("is_vip=%t  reservation_status=%s\n", updated.IsVip, updated.Reservation.Status)

        // Disable VIP mode
        updated, err = client.Cloud.ReservedFixedIPs.Vip.Toggle(ctx,
            vipPortID,
            cloud.ReservedFixedIPVipToggleParams{IsVip: false},
        )
        if err != nil {
            log.Fatalf("toggle off: %v", err)
        }
        fmt.Printf("is_vip=%t  reservation_status=%s\n", updated.IsVip, updated.Reservation.Status)
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        # Enable VIP mode
        curl -X PATCH "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"is_vip": true}'
        ```

        Response:

        ```json theme={null}
        {
          "port_id": "6a6eb2dc-8647-4fb4-8497-9b8ba301b9ec",
          "fixed_ip_address": "85.234.84.202",
          "is_vip": true,
          "reservation": {
            "status": "attached"
          }
        }
        ```
      </Tab>
    </Tabs>

    <p>When `is_vip` is `true`, `reservation.status` becomes `"attached"`. When `false`, it reverts to `"available"`. The toggle is synchronous — no polling needed.</p>

    ## Clean up

    <p>Deleting a VIP requires disabling VIP mode first. The API rejects the delete request if `is_vip` is still `true`.</p>

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        # Disconnect all VMs first
        client.cloud.reserved_fixed_ips.vip.connected_ports.replace(
            vip.port_id,
            port_ids=[],
        )

        # Disable VIP mode
        client.cloud.reserved_fixed_ips.vip.toggle(vip.port_id, is_vip=False)

        # Delete the reserved IP
        client.cloud.reserved_fixed_ips.delete_and_poll(vip.port_id)
        print("VIP deleted.")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        // Disconnect all VMs first
        if _, err = client.Cloud.ReservedFixedIPs.Vip.ConnectedPorts.Replace(ctx,
            vip.PortID,
            cloud.ReservedFixedIPVipConnectedPortReplaceParams{PortIDs: []string{}},
        ); err != nil {
            log.Fatalf("disconnect: %v", err)
        }

        // Disable VIP mode
        if _, err = client.Cloud.ReservedFixedIPs.Vip.Toggle(ctx,
            vip.PortID,
            cloud.ReservedFixedIPVipToggleParams{IsVip: false},
        ); err != nil {
            log.Fatalf("toggle off: %v", err)
        }

        // Delete the reserved IP
        if err = client.Cloud.ReservedFixedIPs.DeleteAndPoll(ctx,
            vip.PortID, cloud.ReservedFixedIPDeleteParams{},
        ); err != nil {
            log.Fatalf("delete: %v", err)
        }
        fmt.Println("VIP deleted.")
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        # Disconnect all VMs
        curl -X PUT "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID/connected_devices" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"port_ids": []}'

        # Disable VIP mode
        curl -X PATCH "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"is_vip": false}'

        # Delete the reserved IP
        curl -X DELETE "https://api.gcore.com/cloud/v1/reserved_fixed_ips/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$VIP_PORT_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```

        Response:

        ```json theme={null}
        {
          "tasks": ["a4e8004b-cc6b-4861-9e45-d86c77ff031a"]
        }
        ```

        Poll `GET https://api.gcore.com/cloud/v1/tasks/{task_id}` until `state` is `FINISHED`.
      </Tab>
    </Tabs>
  </MethodSection>

  <MethodSection id="terraform" label="Terraform">
    <p>Reserve a Virtual IP that can be shared across multiple VM ports for failover scenarios. Set `is_vip = true` on [`gcore_cloud_reserved_fixed_ip`](https://registry.terraform.io/providers/G-Core/gcore/latest/docs/resources/cloud_reserved_fixed_ip) — port attachments are handled separately through the Portal or API.</p>

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a [project ID](/api-reference/cloud/projects/list-projects) and a [region ID](/api-reference/cloud/regions/list-regions). Set them in `terraform.tfvars`:

      ```hcl theme={null}
      api_key    = "{YOUR_API_KEY}"
      project_id = {YOUR_PROJECT_ID}
      region_id  = {YOUR_REGION_ID}
      ```
    </Info>

    ## Reserve a virtual IP address

    <p>Setting `is_vip = true` reserves the IP with VIP mode already active.</p>

    ```hcl theme={null}
    resource "gcore_cloud_reserved_fixed_ip" "vip" {
      project_id = var.project_id
      region_id  = var.region_id
      type       = "external"
      ip_family  = "ipv4"
      is_vip     = true
    }

    output "vip_port_id" {
      value = gcore_cloud_reserved_fixed_ip.vip.port_id
    }

    output "vip_address" {
      value = gcore_cloud_reserved_fixed_ip.vip.fixed_ip_address
    }
    ```

    <p>`port_id` is the identifier used in all subsequent operations — keep it in the Terraform output or pass it to the API.</p>

    ## Enable or disable VIP mode

    <p>Changing `is_vip` is an in-place update — the resource is not recreated:</p>

    ```hcl theme={null}
    resource "gcore_cloud_reserved_fixed_ip" "vip" {
      project_id = var.project_id
      region_id  = var.region_id
      type       = "external"
      ip_family  = "ipv4"
      is_vip     = false  # Set to true to re-enable
    }
    ```

    <p>Run `terraform apply` after the change.</p>

    ## Delete a virtual IP address

    <Warning>
      The API rejects delete requests while `is_vip = true`. Before removing the resource block, set `is_vip = false` and run `terraform apply`. Then remove the block and apply again.
    </Warning>

    ```hcl theme={null}
    # Step 1 — disable VIP mode
    resource "gcore_cloud_reserved_fixed_ip" "vip" {
      ...
      is_vip = false
    }
    # terraform apply

    # Step 2 — remove the block entirely and apply to delete
    # terraform apply
    ```

    ## Import

    <p>To bring an existing VIP under Terraform management:</p>

    ```bash theme={null}
    terraform import gcore_cloud_reserved_fixed_ip.vip '{PROJECT_ID}/{REGION_ID}/{PORT_ID}'
    ```

    <p>Replace `{PROJECT_ID}`, `{REGION_ID}`, and `{PORT_ID}` with the values from the Customer Portal or from the reserved IPs API response.</p>
  </MethodSection>
</MethodSwitch>
