# How to Create a VM on a Private Network

Source: https://docs.quake.ai/docs/compute/how-to/create-vm-private-network
Markdown: https://docs.quake.ai/docs/compute/how-to/create-vm-private-network.md

---

# How to create a VM on a private network

Create a virtual machine on an isolated private network with internet access via a router and floating IP. This is the recommended approach for production workloads.

In this guide you will:

1. Create a network and subnet
2. Create a router connected to the public network
3. Create a security group with SSH access
4. Launch an instance on the private network
5. Allocate and associate a floating IP
6. SSH into the instance

<PrerequisiteBlock methods={["console", "cli", "api"]}>

- An [SSH key pair](/docs/tools/add-ssh-key) uploaded to your account

</PrerequisiteBlock>

## Step 1. Create a network and subnet

<MethodTabs>
<Method label="Console">

1. Go to **Network** > **Networks** > **Create Network**.
2. Name the network (e.g., `my-private-net`).
3. Create a subnet named `my-private-subnet` with IPv4 CIDR `192.168.200.0/24` and DNS `1.1.1.1`.
4. Select **OK**.

</Method>
<Method label="CLI">

```bash
openstack network create my-private-net

openstack subnet create \
  --network my-private-net \
  --subnet-range 192.168.200.0/24 \
  --dns-nameserver 1.1.1.1 \
  my-private-subnet
```

</Method>
<Method label="API">

See [How to create a network](/docs/network/how-to/create-network) for the full API calls to create a network and subnet.

</Method>
</MethodTabs>

## Step 2. Create a router

<MethodTabs>
<Method label="Console">

<NoMoreButton />

The Routers list adds a third per-row icon to the affordances above: a **Networking** icon (chain glyph, tooltip `Networking`) that hosts `Connect Private Network`, `Disconnect Private Network`, and `Detach Public Network`. The **Settings** gear holds `Edit` only.

1. Go to **Network** > **Routers** > **Create Router**.
2. Name it (e.g., `my-router`). In the **Options** section, enable **Attach to Public Network** and select `PublicStatic` from the dropdown.
3. After creation, on the router's row open the **Networking** icon menu, select **Connect Private Network**, and pick the `my-private-subnet` row.

</Method>
<Method label="CLI">

```bash
openstack router create --external-gateway PublicStatic my-router
openstack router add subnet my-router my-private-subnet
```

</Method>
<Method label="API">

See [How to create a router](/docs/network/how-to/create-router) for the full API calls.

</Method>
</MethodTabs>

## Step 3. Create a security group

<MethodTabs>
<Method label="Console">

1. Go to **Network** > **Security Groups** > **Create Security Group**.
2. Name it (e.g., `ssh-access`). On the new group's row, open the **Settings** gear icon dropdown and select **Create Rule**.
3. Select **SSH** (TCP port 22, all traffic).

</Method>
<Method label="CLI">

```bash
openstack security group create ssh-access
openstack security group rule create \
  --protocol tcp --dst-port 22 --remote-ip 0.0.0.0/0 \
  ssh-access
```

</Method>
<Method label="API">

See [How to create a security group](/docs/network/how-to/create-security-group) and [create rules](/docs/network/how-to/create-security-group-rules) for the full API calls.

</Method>
</MethodTabs>

## Step 4. Create the instance

<MethodTabs>
<Method label="Console">

the Console flavor picker on the Create Instance wizard groups flavors into four category tabs:

| Tab | Family | Sample flavors |
|---|---|---|
| General Purpose | `m2a` | `m2a.large`, `m2a.xlarge`, `m2a.2xlarge`, `m2a.4xlarge` |
| Compute Optimized | `c2a` | `c2a.large`, `c2a.xlarge`, `c2a.2xlarge`, `c2a.4xlarge` |
| Memory Optimized | `r2a` | `r2a.large`, `r2a.xlarge`, `r2a.2xlarge`, `r2a.4xlarge` |
| Shared Resources | `s1a` | `s1a.micro`, `s1a.small`, `s1a.medium`, `s1a.large`, `s1a.xlarge` |

The picker opens on the **General Purpose** tab; switch tabs to find the family you want.

1. Go to **Compute** > **Instances** > **Create Instance**.
2. Name the instance, select `us-east-1a`, and choose a flavor. The example below uses `c2a.large`, which lives under the **Compute Optimized** tab.
3. Select **Ubuntu-22.04** as the image (under the **Ubuntu** tab in the OS picker), set disk to **10 GiB**, check **Deleted with the instance**.
4. Select **Next: Network Config** and choose `my-private-net` from **Current Project Networks**.
5. For subnets, select **Automatically Assigned Address**.
6. Select the `default` and `ssh-access` security groups.
7. Select **Next: System Config**, choose **Keypair**, and select your key.
8. Select **Next: Confirm Config** and confirm.

</Method>
<Method label="CLI">

```bash
openstack server create \
  --flavor c2a.large \
  --image Ubuntu-22.04 \
  --boot-from-volume 10 \
  --network my-private-net \
  --key-name my-keypair \
  --security-group default \
  --security-group ssh-access \
  my-private-vm
```

Wait for it to become active:

```bash
openstack server show my-private-vm -c status -c addresses
```

</Method>
<Method label="API">

```bash
curl -X POST "$OS_COMPUTE_URL/servers" \
  -H "X-Auth-Token: $OS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "server": {
      "name": "my-private-vm",
      "flavorRef": "FLAVOR_ID",
      "imageRef": "IMAGE_ID",
      "networks": [{"uuid": "PRIVATE_NETWORK_ID"}],
      "key_name": "my-keypair",
      "security_groups": [
        {"name": "default"},
        {"name": "ssh-access"}
      ]
    }
  }'
```

</Method>
</MethodTabs>

## Step 5. Add a floating IP

<MethodTabs>
<Method label="Console">

The Instances list exposes five per-row icons: **Console**, **Instance Status**, **Volumes**, **Networking** (chain glyph), and **Settings** (gear glyph). Floating-IP actions live behind the **Networking** icon. There is no `More` button and no `Related Resources` submenu.

1. On the **Instances** list, find your instance row, open its **Networking** icon menu, and select **Associate Floating IP**.
2. Select the private IP address from the instance.
3. Allocate a new floating IP (or select an existing one) from `PublicStatic`.
4. Select **OK**.

</Method>
<Method label="CLI">

```bash
openstack floating ip create PublicStatic
openstack server add floating ip my-private-vm FLOATING_IP_ADDRESS
```

</Method>
<Method label="API">

See [How to allocate floating IPs](/docs/network/how-to/allocate-floating-ips) for the full API calls to allocate and associate a floating IP.

</Method>
</MethodTabs>

## Step 6. Connect to the instance

```bash
ssh ubuntu@FLOATING_IP_ADDRESS
```

Type `yes` to accept the host key. Your prompt changes to `ubuntu@my-private-vm`.

Type `logout` to end the session.

## Tear down

To remove all resources, reverse the creation order:

<MethodTabs>
<Method label="Console">

1. Delete the instance. Because Step 4 checked **Deleted with the instance**, deleting the instance also removes the boot volume.
2. If you cleared **Deleted with the instance** at create time, the boot volume remains. Delete it under **Storage** > **Volumes**.
3. Release the floating IP (**Network** > **Floating IPs** > **Release**).
4. On the **Network** > **Routers** list, open the router row's **Networking** icon menu and select **Disconnect Private Network**.
5. From the same row's **Networking** icon menu, select **Detach Public Network**.
6. Delete the router.
7. Delete the network.



The Console delete-instance dialog has no option to delete attached volumes. The **Deleted with the instance** checkbox you set when creating the instance controls whether the platform removes the boot volume; the delete dialog does not. Boot volumes created by the instance wizard show no name in **Storage** > **Volumes** (the Name column renders `-`), so the Console cannot match a leftover boot volume by name. Identify it by its **Available** status and creation time, or read the volume ID from the CLI or API.



</Method>
<Method label="CLI">

```bash
openstack server delete --wait my-private-vm

# Delete the boot volume that --boot-from-volume auto-created. The
# server delete does not cascade to the volume because
# `--boot-from-volume` defaults to `delete_on_termination=false`.
# Find the orphan by listing volumes created at instance create time:
openstack volume list -c ID -c Status -c Name --status available
openstack volume delete BOOT_VOLUME_ID

openstack floating ip delete FLOATING_IP_ADDRESS
openstack router remove subnet my-router my-private-subnet
openstack router unset --external-gateway my-router
openstack router delete my-router
openstack network delete my-private-net
```

</Method>
<Method label="API">

Delete resources in reverse order using the corresponding DELETE endpoints. See each resource's API reference for the exact calls.

</Method>
</MethodTabs>

## See also

- [How to create a VM on a public network](/docs/compute/how-to/create-vm-public-network) (for quick testing)
- [How to create an instance](/docs/compute/how-to/create-instance) (full reference)
- [Instances CLI reference](/reference/compute/instances-cli)
- [Instances API reference](/reference/compute/instances-api)
- [Compute console](/reference/compute/console/index)
