Docs / Terraform
Quick start with Terraform
No fuss: a working main.tf, five commands, and a real allocated subnet by the end of it. The provider is published on the public Terraform Registry as uk-sw/nxip. Working in IPv6? There's a dedicated IPv6 quick start.
Quick start
1. Get an API key. Sign up. Free tier is enough to run this end to end.
2. Set it as an environment variable. The provider reads it automatically, so no credential goes in a .tf file.
export NXIP_API_KEY="<your key>"That only lasts for the current terminal session. To make it stick around:
- Recommended: direnv. Put the same
exportline in a.envrcfile in your project directory, add.envrcto.gitignore, then rundirenv allowonce. It loads automatically whenever youcdin, and the key stays scoped to this project rather than every shell you open. - Simpler: add the same line to your shell profile (
~/.zshrcor~/.bashrc). Works everywhere with no extra tool, at the cost of the key being available in every terminal, sitting in plaintext in a dotfile you might sync or share elsewhere.
Either way: never paste the key directly into a .tf file or commit it anywhere.
3. Save this as main.tf. One file, five resources: a pool, a subnet that finds its own home, that subnet split explicitly across two AZs, and one exact address reserved inside one of them.
terraform {
required_providers {
nxip = {
source = "uk-sw/nxip"
version = "~> 0.2" # optional, but recommended
}
}
}
provider "nxip" {
# api_key / url also read from NXIP_API_KEY / NXIP_URL env vars
}
resource "nxip_pool" "production_us_east" {
name = "Production US-East"
cidr = "10.100.0.0/16"
family = "IPV4"
environment = "production"
region = "us-east-1"
}
# Auto-resolves onto the pool above by matching environment/region/family.
resource "nxip_subnet" "payments" {
family = nxip_pool.production_us_east.family
environment = nxip_pool.production_us_east.environment
region = nxip_pool.production_us_east.region
prefix_length = 24
name = "Payments team"
}
# Explicit nesting via parent_subnet_id: splits the team's subnet across two AZs.
resource "nxip_subnet" "payments_az_a" {
parent_subnet_id = nxip_subnet.payments.id
family = "IPV4"
prefix_length = 27
kind = "az-subnet"
name = "Payments AZ-a"
}
resource "nxip_subnet" "payments_az_b" {
parent_subnet_id = nxip_subnet.payments.id
family = "IPV4"
prefix_length = 27
kind = "az-subnet"
name = "Payments AZ-b"
}
# One exact address inside that AZ subnet, e.g. a load balancer VIP.
resource "nxip_address" "payments_lb_vip" {
subnet_id = nxip_subnet.payments_az_a.id
address = cidrhost(nxip_subnet.payments_az_a.cidr, 1)
status = "RESERVED"
hostname = "payments-lb-01"
}
output "payments_subnet_cidr" {
value = nxip_subnet.payments.cidr
}
output "payments_az_a_cidr" {
value = nxip_subnet.payments_az_a.cidr
}
output "payments_az_b_cidr" {
value = nxip_subnet.payments_az_b.cidr
}
output "payments_lb_vip_address" {
value = nxip_address.payments_lb_vip.address
}production_us_eastis the pool: the parent range everything else carves from.paymentsfinds its own home automatically. It only declares environment/region/family, and nxip resolves it onto the pool above with no hardcoded parent.payments_az_aandpayments_az_bnest explicitly underpaymentsviaparent_subnet_id, the deliberate path for splitting a team's range across AZs.payments_lb_vipreserves one exact address insidepayments_az_a, usingcidrhost()to pick an address rather than hardcoding one.
4. Run it.
terraform init
terraform applyWhat you'll see, trimmed to the parts that matter:
Plan: 5 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Enter a value: yes
nxip_pool.production_us_east: Creating...
nxip_pool.production_us_east: Creation complete after 0s [id=cm...]
nxip_subnet.payments: Creating...
nxip_subnet.payments: Creation complete after 0s [id=cm...]
nxip_subnet.payments_az_a: Creating...
nxip_subnet.payments_az_a: Creation complete after 0s [id=cm...]
nxip_subnet.payments_az_b: Creating...
nxip_subnet.payments_az_b: Creation complete after 0s [id=cm...]
nxip_address.payments_lb_vip: Creating...
nxip_address.payments_lb_vip: Creation complete after 0s [id=cm...]
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Outputs:
payments_az_a_cidr = "10.100.0.0/27"
payments_az_b_cidr = "10.100.0.32/27"
payments_lb_vip_address = "10.100.0.1"
payments_subnet_cidr = "10.100.0.0/24"Clean up when you're done
Free tier caps out at 6 pools and 20 subnets, so destroying what you don't need frees that quota back up for the next thing you try.
terraform destroyPlan: 0 to add, 0 to change, 5 to destroy.
Do you really want to destroy all resources?
Enter a value: yes
nxip_address.payments_lb_vip: Destroying...
nxip_address.payments_lb_vip: Destruction complete after 0s
nxip_subnet.payments_az_b: Destroying...
nxip_subnet.payments_az_b: Destruction complete after 0s
nxip_subnet.payments_az_a: Destroying...
nxip_subnet.payments_az_a: Destruction complete after 0s
nxip_subnet.payments: Destroying...
nxip_subnet.payments: Destruction complete after 0s
nxip_pool.production_us_east: Destroying...
nxip_pool.production_us_east: Destruction complete after 0s
Destroy complete! Resources: 5 destroyed.Watch it happen
The whole loop above, played back start to finish.
Full resource docs (every attribute, import support) are on the Registry's docs tab. For the concepts behind auto-resolution and nesting, see Pools, subnets & hierarchy, or the IPv6 quick start for the same walkthrough in IPv6.
