Quickstart
Deploy and connect to your first Hyperstack GPU virtual machine using the API.
Before you begin
You'll need:
- A Hyperstack account with billing activated and credit added.
- An API key. Generate one in the Hyperstack console.
Set your API key in the shell so the snippets below work as-is. For how to send the key in requests, see Authentication. Replace your-api-key-here with the key you generated:
export HYPERSTACK_API_KEY="your-api-key-here"
Deploy and connect to a VM
- cURL
- Python
- Node.js
-
Create an environment
Create an environment to hold your VMs, SSH keypairs, volumes, and firewalls. All resources in one environment live in the same region. Use
CANADA-1for this Quickstart; it's where then3-L40x1flavor is available.curl https://infrahub-api.nexgencloud.com/v1/core/environments \
-H "api_key: $HYPERSTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "your-environment",
"region": "CANADA-1"
}'The response includes the environment's
idandname. Thenameis what you reference in subsequent calls. -
Set up an SSH key
Add an SSH keypair to the environment so you can connect to the VM after it deploys. Use an existing key or generate a new one:
- Use an existing key
- Generate a new key
If you have an SSH key (commonly at
~/.ssh/id_ed25519.pubor~/.ssh/id_rsa.pub), add its public half to the environment. Replaceyour-environmentwith the environment name from step 1:curl https://infrahub-api.nexgencloud.com/v1/core/keypairs \
-H "api_key: $HYPERSTACK_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<EOF
{
"name": "your-keypair",
"environment_name": "your-environment",
"public_key": "$(cat ~/.ssh/id_ed25519.pub)"
}
EOFIf your key lives elsewhere, substitute the path in the
catcommand.Generate a fresh keypair locally:
ssh-keygen -t ed25519 -f ~/.ssh/hyperstack_qs -C "hyperstack-quickstart"Press Enter when prompted for a passphrase to skip it, or set one for added security. This creates
~/.ssh/hyperstack_qs(private) and~/.ssh/hyperstack_qs.pub(public).Add the public half to the environment. Replace
your-environmentwith the environment name from step 1:curl https://infrahub-api.nexgencloud.com/v1/core/keypairs \
-H "api_key: $HYPERSTACK_API_KEY" \
-H "Content-Type: application/json" \
--data @- <<EOF
{
"name": "your-keypair",
"environment_name": "your-environment",
"public_key": "$(cat ~/.ssh/hyperstack_qs.pub)"
}
EOF -
Deploy the VM
Deploy a VM using the request body below. Replace
your-environmentandyour-keypairwith the names from steps 1 and 2.flavor_name: determines the hardware configuration. In this case, one NVIDIA L40 GPU, 28 CPU cores, 58 GB RAM (see all flavors)image_name: Ubuntu 22.04 with CUDA 12.2 pre-installed (see all images)assign_floating_ip: true: adds a public IP for SSH accesssecurity_rules: opens TCP port 22 for inbound SSH
curl https://infrahub-api.nexgencloud.com/v1/core/virtual-machines \
-H "api_key: $HYPERSTACK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "my-vm",
"environment_name": "your-environment",
"image_name": "Ubuntu Server 22.04 LTS R535 CUDA 12.2",
"flavor_name": "n3-L40x1",
"key_name": "your-keypair",
"count": 1,
"assign_floating_ip": true,
"security_rules": [
{
"direction": "ingress",
"protocol": "tcp",
"port_range_min": 22,
"port_range_max": 22,
"ethertype": "IPv4",
"remote_ip_prefix": "0.0.0.0/0"
}
]
}'The response includes the new VM's
idunderinstances[0]. Key fields shown below; the full response also includescreated_at,fixed_ip,keypair,security_rules, and others:{
"status": true,
"message": "VM is scheduled for creation.",
"instances": [
{
"id": 123,
"name": "my-vm",
"status": "CREATING",
"flavor": { "name": "n3-L40x1", "gpu": "L40", "gpu_count": 1 },
"image": { "name": "Ubuntu Server 22.04 LTS R535 CUDA 12.2" },
"environment": { "name": "your-environment", "region": "CANADA-1" }
}
]
}Note the
id. Substitute it for<vm_id>in step 4. -
Wait for the VM to become
ACTIVEPoll the VM by ID. Replace
<vm_id>with the id from step 3:curl https://infrahub-api.nexgencloud.com/v1/core/virtual-machines/<vm_id> \
-H "api_key: $HYPERSTACK_API_KEY"Check two fields on the
instanceobject:statusmust beACTIVE(transitions throughCREATING,BUILD, thenACTIVE).floating_ipmust hold the assigned public IP (nullwhile attaching).
Re-run the request until both fields reach the values above. Larger GPU configurations take longer. The value in
floating_ipis your public IP for step 5.BillingBilling does not begin until the VM is
ACTIVE. See VM states and billing for details. -
Connect over SSH
Once the VM is
ACTIVE, connect from your local machine using the matching private key. Replace<private_key>with the path to your private key (e.g.~/.ssh/id_ed25519or~/.ssh/hyperstack_qs) and<public_ip>with the floating-IP value from step 4.ssh -i <private_key> ubuntu@<public_ip>For other OS images (AlmaLinux, Debian) and SSH key permission troubleshooting, see Connect to your VM.
-
Create an environment
Create an environment to hold your VMs, SSH keypairs, volumes, and firewalls. All resources in one environment live in the same region. Use
CANADA-1for this Quickstart; it's where then3-L40x1flavor is available.import os
import requests
base = "https://infrahub-api.nexgencloud.com/v1"
headers = {"api_key": os.environ["HYPERSTACK_API_KEY"]}
env = requests.post(
f"{base}/core/environments",
headers=headers,
json={"name": "your-environment", "region": "CANADA-1"},
).json()The response includes the environment's
idandname. Thenameis what you reference in subsequent calls. -
Set up an SSH key
Add an SSH keypair to the environment so you can connect to the VM after it deploys. Use an existing key or generate a new one:
- Use an existing key
- Generate a new key
If you have an SSH key (commonly at
~/.ssh/id_ed25519.pubor~/.ssh/id_rsa.pub), add its public half to the environment. Replaceyour-environmentwith the environment name from step 1:with open(os.path.expanduser("~/.ssh/id_ed25519.pub")) as f:
public_key = f.read().strip()
key = requests.post(
f"{base}/core/keypairs",
headers=headers,
json={
"name": "your-keypair",
"environment_name": "your-environment",
"public_key": public_key,
},
).json()If your key lives elsewhere, substitute the path in the
open()call.Generate a fresh keypair locally:
ssh-keygen -t ed25519 -f ~/.ssh/hyperstack_qs -C "hyperstack-quickstart"Press Enter when prompted for a passphrase to skip it, or set one for added security. This creates
~/.ssh/hyperstack_qs(private) and~/.ssh/hyperstack_qs.pub(public).Add the public half to the environment. Replace
your-environmentwith the environment name from step 1:with open(os.path.expanduser("~/.ssh/hyperstack_qs.pub")) as f:
public_key = f.read().strip()
key = requests.post(
f"{base}/core/keypairs",
headers=headers,
json={
"name": "your-keypair",
"environment_name": "your-environment",
"public_key": public_key,
},
).json() -
Deploy the VM
Deploy a VM using the request body below. Replace
your-environmentandyour-keypairwith the names from steps 1 and 2.flavor_name: determines the hardware configuration. In this case, one NVIDIA L40 GPU, 28 CPU cores, 58 GB RAM (see all flavors)image_name: Ubuntu 22.04 with CUDA 12.2 pre-installed (see all images)assign_floating_ip: true: adds a public IP for SSH accesssecurity_rules: opens TCP port 22 for inbound SSH
vm = requests.post(
f"{base}/core/virtual-machines",
headers=headers,
json={
"name": "my-vm",
"environment_name": "your-environment",
"image_name": "Ubuntu Server 22.04 LTS R535 CUDA 12.2",
"flavor_name": "n3-L40x1",
"key_name": "your-keypair",
"count": 1,
"assign_floating_ip": True,
"security_rules": [
{
"direction": "ingress",
"protocol": "tcp",
"port_range_min": 22,
"port_range_max": 22,
"ethertype": "IPv4",
"remote_ip_prefix": "0.0.0.0/0",
}
],
},
).json()
vm_id = vm["instances"][0]["id"]The response includes the new VM's
idunderinstances[0]. Key fields shown below; the full response also includescreated_at,fixed_ip,keypair,security_rules, and others:{
"status": true,
"message": "VM is scheduled for creation.",
"instances": [
{
"id": 123,
"name": "my-vm",
"status": "CREATING",
"flavor": { "name": "n3-L40x1", "gpu": "L40", "gpu_count": 1 },
"image": { "name": "Ubuntu Server 22.04 LTS R535 CUDA 12.2" },
"environment": { "name": "your-environment", "region": "CANADA-1" }
}
]
}The code stores the
idasvm_id; step 4 uses it automatically. -
Wait for the VM to become
ACTIVEPoll until
statusisACTIVEandfloating_ipholds the assigned public IP:import time
while True:
detail = requests.get(
f"{base}/core/virtual-machines/{vm_id}",
headers=headers,
).json()
instance = detail["instance"]
if instance["status"] == "ACTIVE" and instance.get("floating_ip"):
public_ip = instance["floating_ip"]
break
time.sleep(10)
print(f"VM is ACTIVE at {public_ip}")statustransitions throughCREATING,BUILD, thenACTIVE;floating_ipstaysnulluntil attachment completes. Larger GPU configurations take longer.BillingBilling does not begin until the VM is
ACTIVE. See VM states and billing for details. -
Connect over SSH
Once the VM is
ACTIVE, connect from your local machine using the matching private key. Replace<private_key>with the path to your private key (e.g.~/.ssh/id_ed25519or~/.ssh/hyperstack_qs) and<public_ip>with the value ofpublic_ipfrom step 4.ssh -i <private_key> ubuntu@<public_ip>For other OS images (AlmaLinux, Debian) and SSH key permission troubleshooting, see Connect to your VM.
-
Create an environment
Create an environment to hold your VMs, SSH keypairs, volumes, and firewalls. All resources in one environment live in the same region. Use
CANADA-1for this Quickstart; it's where then3-L40x1flavor is available.const base = "https://infrahub-api.nexgencloud.com/v1";
const headers = {
api_key: process.env.HYPERSTACK_API_KEY,
"Content-Type": "application/json",
};
const env = await fetch(`${base}/core/environments`, {
method: "POST",
headers,
body: JSON.stringify({ name: "your-environment", region: "CANADA-1" }),
}).then((r) => r.json());The response includes the environment's
idandname. Thenameis what you reference in subsequent calls. -
Set up an SSH key
Add an SSH keypair to the environment so you can connect to the VM after it deploys. Use an existing key or generate a new one:
- Use an existing key
- Generate a new key
If you have an SSH key (commonly at
~/.ssh/id_ed25519.pubor~/.ssh/id_rsa.pub), add its public half to the environment. Replaceyour-environmentwith the environment name from step 1:import { readFileSync } from "node:fs";
import { homedir } from "node:os";
const publicKey = readFileSync(`${homedir()}/.ssh/id_ed25519.pub`, "utf8").trim();
const key = await fetch(`${base}/core/keypairs`, {
method: "POST",
headers,
body: JSON.stringify({
name: "your-keypair",
environment_name: "your-environment",
public_key: publicKey,
}),
}).then((r) => r.json());If your key lives elsewhere, substitute the path in the
readFileSynccall.Generate a fresh keypair locally:
ssh-keygen -t ed25519 -f ~/.ssh/hyperstack_qs -C "hyperstack-quickstart"Press Enter when prompted for a passphrase to skip it, or set one for added security. This creates
~/.ssh/hyperstack_qs(private) and~/.ssh/hyperstack_qs.pub(public).Add the public half to the environment. Replace
your-environmentwith the environment name from step 1:import { readFileSync } from "node:fs";
import { homedir } from "node:os";
const publicKey = readFileSync(`${homedir()}/.ssh/hyperstack_qs.pub`, "utf8").trim();
const key = await fetch(`${base}/core/keypairs`, {
method: "POST",
headers,
body: JSON.stringify({
name: "your-keypair",
environment_name: "your-environment",
public_key: publicKey,
}),
}).then((r) => r.json()); -
Deploy the VM
Deploy a VM using the request body below. Replace
your-environmentandyour-keypairwith the names from steps 1 and 2.flavor_name: determines the hardware configuration. In this case, one NVIDIA L40 GPU, 28 CPU cores, 58 GB RAM (see all flavors)image_name: Ubuntu 22.04 with CUDA 12.2 pre-installed (see all images)assign_floating_ip: true: adds a public IP for SSH accesssecurity_rules: opens TCP port 22 for inbound SSH
const vm = await fetch(`${base}/core/virtual-machines`, {
method: "POST",
headers,
body: JSON.stringify({
name: "my-vm",
environment_name: "your-environment",
image_name: "Ubuntu Server 22.04 LTS R535 CUDA 12.2",
flavor_name: "n3-L40x1",
key_name: "your-keypair",
count: 1,
assign_floating_ip: true,
security_rules: [
{
direction: "ingress",
protocol: "tcp",
port_range_min: 22,
port_range_max: 22,
ethertype: "IPv4",
remote_ip_prefix: "0.0.0.0/0",
},
],
}),
}).then((r) => r.json());
const vmId = vm.instances[0].id;The response includes the new VM's
idunderinstances[0]. Key fields shown below; the full response also includescreated_at,fixed_ip,keypair,security_rules, and others:{
"status": true,
"message": "VM is scheduled for creation.",
"instances": [
{
"id": 123,
"name": "my-vm",
"status": "CREATING",
"flavor": { "name": "n3-L40x1", "gpu": "L40", "gpu_count": 1 },
"image": { "name": "Ubuntu Server 22.04 LTS R535 CUDA 12.2" },
"environment": { "name": "your-environment", "region": "CANADA-1" }
}
]
}The code stores the
idasvmId; step 4 uses it automatically. -
Wait for the VM to become
ACTIVEPoll until
statusisACTIVEandfloating_ipholds the assigned public IP:let publicIp;
while (true) {
const detail = await fetch(`${base}/core/virtual-machines/${vmId}`, { headers }).then((r) => r.json());
const instance = detail.instance;
if (instance.status === "ACTIVE" && instance.floating_ip) {
publicIp = instance.floating_ip;
break;
}
await new Promise((r) => setTimeout(r, 10000));
}
console.log(`VM is ACTIVE at ${publicIp}`);statustransitions throughCREATING,BUILD, thenACTIVE;floating_ipstaysnulluntil attachment completes. Larger GPU configurations take longer.BillingBilling does not begin until the VM is
ACTIVE. See VM states and billing for details. -
Connect over SSH
Once the VM is
ACTIVE, connect from your local machine using the matching private key. Replace<private_key>with the path to your private key (e.g.~/.ssh/id_ed25519or~/.ssh/hyperstack_qs) and<public_ip>with the value ofpublicIpfrom step 4.ssh -i <private_key> ubuntu@<public_ip>For other OS images (AlmaLinux, Debian) and SSH key permission troubleshooting, see Connect to your VM.
Start running your workload. Common uses include AI training and inference, 3D rendering, scientific and engineering simulation, and data analytics.
Next steps
Resources
Core
Virtual machines, volumes, snapshots, networking, firewalls, clusters, and templates.
Object Storage
S3-compatible storage buckets and access keys.
AI Studio
Base models, inference, fine-tuning, datasets, model evaluations, and synthetic data.
Organization & Access
Authentication, API keys, organization membership, RBAC roles, invites, and permissions.
Pricebook
Pricing data, cost calculation, and long-term GPU contracts.
Billing
Credit balances, payments, vouchers, and usage history.