Terraform Provider

The GPCN™ (Global Private Cloud Network™) Terraform provider lets you describe your infrastructure in code and build it with terraform apply. This guide takes you from an empty folder to a running virtual machine (VM) you can sign in to over SSH, then shows how to organize what you build and tear it down.

By the end you'll have a VPC in one data center, a security group that lets SSH in from your own address, a subnet, an SSH key, and a VM with an elastic IP. Everything is defined in one file you can version, review, and rebuild.

Prerequisites

  • Terraform 1.5 or later. Check with terraform version.
  • An API key. Create one in the portal under Identity & Access → Credentials → API Keys — see API Keys. The key acts with your roles, so it can only create what you could create in the portal.
  • A role that can create resources. Tenant Operator, Tenant Manager, or Tenant Administrator. An organization-wide role creates in your Default resource group; to create in another group, you need a role scoped to that group — see Roles & Permissions.
  • An SSH key pair on your machine. This guide uses ~/.ssh/id_ed25519.pub.
  • Your public IP address, so the security group can allow SSH from it and nothing else.

Install and authenticate

Create a new folder and a file named main.tf. Start it with the provider requirement:

terraform {
  required_providers {
    gpcn = {
      source  = "Global-Private-Cloud-Network/gpcn"
      version = "~> 1.5"
    }
  }
}

provider "gpcn" {}

The provider block can stay empty. The provider reads its connection from two environment variables:

export GPCN_HOST="https://api.gpcn.com"
export GPCN_API_KEY="<your API key>"

Then install the provider:

terraform init

terraform init downloads the provider from the Terraform Registry. You can also set host and api_key inside the provider block, but keep the key out of anything you commit.

The provider checks your API key when it starts. A revoked or expired key stops the plan with a clear message, and a key that expires within seven days shows a warning — rotate it before it lapses.

Build the infrastructure

Add each block below to main.tf, in order. Together they make one working configuration.

1. Pick a data center, an image, and a size

Data sources look up IDs so you don't have to copy them from the portal. This example uses the Chicago 1 data center, the Alma Linux 8.x image, and a general-purpose size with at least two CPUs:

data "gpcn_datacenters" "chicago" {
  name        = "Chicago 1"
  vpc_capable = true
}

locals {
  datacenter_id = data.gpcn_datacenters.chicago.datacenters[0].id
}

data "gpcn_virtualmachine_images" "alma" {
  datacenter_id = local.datacenter_id
  image_name    = "Alma Linux 8.x"
}

data "gpcn_virtualmachine_sizes" "small" {
  datacenter_id = local.datacenter_id
  category      = "general-purpose"
  min_cpu       = 2
}

To build somewhere else, swap in a data center and image your organization uses. Use the names the portal shows when you create a VM:

  • name matches any part of a data center's name or its code, without regard to case. "Chicago 1" and "CHI-1" find the same data center. Keep the value specific enough to match only the one you want, because the example takes the first match.
  • vpc_capable = true keeps only data centers that offer VPCs. If the plan reports no matching data center, check the name, then check that the data center offers VPCs.
  • image_name matches any part of an image's name, without regard to case. The image must be offered in the data center you picked.

gpcn_datacenters also filters by country_name, region_name, and gpu_enabled. Sizes come in two categories, general-purpose and memory-optimized.

2. Create a VPC

A VPC is your private network in one data center. Its range must be a private (RFC 1918) block between /16 and /24:

resource "gpcn_vpc" "main" {
  name          = "getting-started"
  datacenter_id = local.datacenter_id
  cidr          = "10.20.0.0/16"
}

3. Add a security group

The security group is the VPC's packet filter. The rule blocks you declare are the group's complete rule set: they replace its rules, they don't add to them. So list everything the group should allow.

This group allows three things:

  • SSH from your address. Replace 203.0.113.10/32 with your own public address.
  • All traffic from the subnet you'll create in the next step (10.20.1.0/24). Without this rule, the VM can't answer your connection.
  • All outbound traffic.
resource "gpcn_vpc_nsg" "ssh" {
  vpc_id = gpcn_vpc.main.id
  name   = "ssh"

  rule {
    direction      = "ingress"
    protocol       = "tcp"
    port_range_min = 22
    port_range_max = 22
    remote_cidr    = "203.0.113.10/32"
    description    = "SSH from my address"
  }

  rule {
    direction   = "ingress"
    protocol    = "all"
    remote_cidr = "10.20.1.0/24"
    description = "All traffic from the app subnet"
  }

  rule {
    direction   = "egress"
    protocol    = "all"
    remote_cidr = "0.0.0.0/0"
    description = "All outbound traffic"
  }
}

If you change the subnet's range in step 4, change this rule to match.

4. Add a subnet

A subnet is an address range inside the VPC. Binding the security group here applies it to every machine on the subnet:

resource "gpcn_vpc_subnet" "app" {
  vpc_id = gpcn_vpc.main.id
  name   = "app"
  cidr   = "10.20.1.0/24"
  nsg_id = gpcn_vpc_nsg.ssh.id
}

5. Register your SSH key

resource "gpcn_ssh_key" "me" {
  name       = "getting-started"
  public_key = file("~/.ssh/id_ed25519.pub")
}

6. Create the VM

resource "gpcn_virtualmachine" "web" {
  name          = "web-1"
  datacenter_id = local.datacenter_id
  size_id       = data.gpcn_virtualmachine_sizes.small.sizes[0].id
  image_id      = data.gpcn_virtualmachine_images.alma.images[0].id
  subnet_id     = gpcn_vpc_subnet.app.id

  allocate_public_ip = true

  initial_auth = {
    ssh_key_id = gpcn_ssh_key.me.id
    username   = "almalinux"
  }
}

output "web_public_ip" {
  value = gpcn_virtualmachine.web.public_ip
}

allocate_public_ip = true acquires an elastic IP for the VM so you can reach it over SSH. initial_auth takes an SSH key or a password, plus a username, and only applies when the VM is created.

Plan and apply

Preview what Terraform will create:

terraform plan

The plan lists five resources to add: the VPC, the security group, the subnet, the SSH key, and the VM. Apply it:

terraform apply

Creating a VM, GPU VM, volume, VPC, or L2 segment runs as a job on the platform, and the provider waits for each one to finish. When the apply completes, Terraform prints web_public_ip. Sign in with:

ssh almalinux@<web_public_ip>

Organize with resource groups

Every resource belongs to a resource group. gpcn_virtualmachine, gpcn_gpu, gpcn_volume, gpcn_vpc, and gpcn_l2_segment each take a resource_group_id:

  • Leave it out and the resource joins your organization's Default group. The attribute then reports the Default group's ID.
  • Set it to place the resource in another group. Your role must reach that group.
  • Change it to move the resource in place, without replacing it. Moving a VPC takes its subnets, security groups, and elastic IPs along.
  • Remove it from the configuration and nothing moves; the resource stays where it is.

If your API key's roles don't reach the Default group, set resource_group_id on every resource you create. Otherwise the platform refuses the create.

The gpcn_resource_groups data source finds a group by its exact name and gives you default_resource_group_id. Use gpcn_resource_group to create a group in code.

Terraform can't delete the Default group or a group that still holds resources. If one apply moves resources out of a group and also deletes it, Terraform tries the delete first and it fails. Apply the moves on their own (for example with -target), then apply again to delete the group. For how groups and roles work, see Resource Groups.

What changes in place and what replaces

Read the plan before you apply. Where a change can't be made to the existing resource, the plan says must be replaced, and Terraform destroys the resource and creates a new one.

  • VM size (size_id): changes in place when the new size is an upgrade the platform offers for that VM; otherwise the VM is replaced.
  • VM image or subnet (image_id, subnet_id): always replaces the VM.
  • initial_auth: only used at creation. Changing it later updates Terraform's state, not the VM.
  • Resource group (resource_group_id): changes in place.

Elastic IPs and other building blocks

There are two ways to give a VM a public address, and you can't combine them:

  • allocate_public_ip = true acquires an elastic IP for the VM. Destroying the VM releases it.
  • public_ip_id attaches an elastic IP your organization already holds (gpcn_vpc_public_ip). That address outlives the VM, and it keeps billing until you release it.

Other resources you'll use as you grow:

  • gpcn_gpu for GPU VMs, with the gpcn_gpu_inventory data source to see what's available.
  • gpcn_volume and gpcn_volume_attachment for storage. Attaching or detaching a volume doesn't stop the VM.
  • gpcn_l2_segment for a flat layer-2 network. A VM takes up to four segments through l2_segment_ids; changing them stops the VM unless its image supports network hotplug.
  • gpcn_vpc_public_ip_attachment to attach a held elastic IP separately from the VM.

gpcn_network, the legacy L3 network resource, is deprecated, and creating one is refused. Build new networking with VPCs.

Provider settings

Three optional settings tune how the provider talks to the platform:

Setting Default What it controls
polling_timeout 600 seconds How long the provider waits for a job to finish
request_timeout 60 seconds How long a single request can take
max_retries 3 How many times a request that fails for a temporary reason is retried

State and teams

The provider has no state backend of its own; any standard Terraform backend works. When several people manage the same infrastructure, use a remote backend with state locking so two applies can't run at once.

Clean up

When you're done, destroy what you built so it stops billing:

terraform destroy

Destroying the VM releases the elastic IP it acquired with allocate_public_ip. An elastic IP you hold separately stays, and keeps billing, until you release it.

Next Steps