Skip to main content

Create servers with Terraform and the Arianet CLI

Creating a server in the panel is fine once, but when you have several environments (staging and production) or several identical servers, it is better to define the infrastructure as code: you get exactly the same result every time, keep changes in git, and see what will change before applying it.

In this tutorial you first use the Arianet CLI (arianet) to browse the catalog and create and delete a test server, then define the same server with a firewall and a volume as code with the Terraform provider (ariaservice/arianet).

Prerequisites​

  • An Arianet account with wallet balance (creating servers costs money; reading lists and the price list is free)
  • An SSH key in ~/.ssh/id_ed25519.pub (creating an SSH key)
  • Terraform 1.0 or newer on your computer

1. Create an API token​

In the panel, on the API tokens page, create a token with cloud:servers:read and cloud:servers:write. The token is shown only once. Put it in an environment variable; both the CLI and Terraform read it:

export ARIANET_TOKEN="paste-your-token-here"
tip

For CI, create a separate token with an expiry date and an allowed IP (API tokens). Never write the token into .tf files or a git repository.

2. Install the CLI and browse the catalog​

Install the CLI as described in the CLI guide and check:

arianet version
arianet cloud datacenters # datacenter codes, e.g. ovh
arianet cloud plans --datacenter ovh # plan ids, cpu, ram, disk, price
arianet cloud images list --type system # image names, e.g. ubuntu-24.04
arianet cloud pricing --datacenter ovh # public price list, no token needed

Note the data center code, plan id and image name for the next steps. The examples use ovh, plan 3 and ubuntu-24.04.

3. Create a test server with the CLI​

arianet cloud servers create --name cli-test --datacenter ovh --plan 3 --image ubuntu-24.04 \
--ssh-key "$(cat ~/.ssh/id_ed25519.pub)" --labels env=test --wait
arianet cloud servers list --label-selector env=test

Take the server's IPv4 from the output and log in:

ssh root@SERVER_IP

The server's hourly and monthly cost:

arianet cloud servers costs <server-id>

Delete the server to stop its cost:

arianet cloud servers delete <server-id> --yes --wait
caution

Each plan has a minimum number of billed hours (minimum_usage_hours in the price list). If you delete the server sooner, that minimum is charged. For back-to-back experiments, keep the server and reinstall it with arianet cloud servers rebuild.

4. The Terraform project​

Create a folder:

mkdir arianet-tf && cd arianet-tf

main.tf:

terraform {
required_providers {
arianet = {
source = "ariaservice/arianet"
version = "~> 0.1"
}
}
}

provider "arianet" {} # token from ARIANET_TOKEN

variable "datacenter" {
type = string
default = "ovh"
}

variable "plan_id" {
type = number
description = "Plan id from: arianet cloud plans --datacenter <code>"
}

variable "admin_ip" {
type = string
description = "Your public IP in CIDR form, e.g. 203.0.113.4/32"
}

resource "arianet_firewall" "web" {
name = "web"

rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = [var.admin_ip]
}

rule {
direction = "in"
protocol = "tcp"
port = "80"
source_ips = ["0.0.0.0/0", "::/0"]
}

rule {
direction = "in"
protocol = "tcp"
port = "443"
source_ips = ["0.0.0.0/0", "::/0"]
}
}

resource "arianet_server" "web" {
name = "web-1"
datacenter = var.datacenter
plan_id = var.plan_id
image = "ubuntu-24.04"
ssh_keys = [trimspace(file("~/.ssh/id_ed25519.pub"))]
firewall_ids = [arianet_firewall.web.id]
labels = { role = "web", env = "prod" }

user_data = <<-EOT
#cloud-config
package_update: true
packages: [nginx]
EOT
}

resource "arianet_volume" "data" {
name = "web-1-data"
datacenter = var.datacenter
size = 20
}

resource "arianet_volume_attachment" "data" {
volume_id = arianet_volume.data.id
server_id = arianet_server.web.id
}

output "ipv4" {
value = arianet_server.web.ipv4_address
}

output "ipv6" {
value = arianet_server.web.ipv6_address
}

terraform.tfvars (replace the values with the output of step 2 and your own IP):

plan_id  = 3
admin_ip = "203.0.113.4/32"

.gitignore, because the state holds sensitive data (including root_password at creation):

.terraform/
*.tfstate
*.tfstate.*

5. Apply​

terraform init
terraform plan
terraform apply

plan shows which resources will be created; apply, confirmed with yes, creates them. Terraform waits for each resource's asynchronous action to finish. Then:

terraform output ipv4
ssh root@$(terraform output -raw ipv4)

The web-1-data volume is attached to the server but not formatted or mounted yet; follow Attach and mount a volume.

6. Change the infrastructure​

Edit the code and run plan and apply again. A few examples:

  • Bigger server: change plan_id; the server is resized in place.
  • Bigger volume: raise size; it grows in place (grow only). Then grow the filesystem.
  • Daily backups: add backups = true to arianet_server.
  • Delete protection: protection_delete = true.
caution

Changing a server's datacenter or image replaces it (the old server and its main disk are deleted). Always read the terraform plan output; must be replaced means delete and recreate.

7. Import existing resources​

You can bring a server or resource you created in the panel under Terraform:

terraform import arianet_server.web 123

After the import, terraform plan shows the differences between your code and reality; adjust the code until the plan shows no changes.

8. Tear everything down​

terraform destroy

If you set protection_delete = true, set it to false and apply first. What happens to snapshots and backups on delete is set with keep_backups and delete_snapshots, which must be applied before destroy (Terraform provider).

Verify​

terraform state list
arianet cloud servers list --label-selector role=web
arianet cloud firewalls list

Every resource Terraform created should appear in both lists.

Common errors​

ErrorFix
401 or unauthorizedARIANET_TOKEN is not set in this terminal or the token was revoked.
403 or forbiddenThe token lacks cloud:servers:write or is restricted to another IP.
402Not enough wallet balance for the order.
identity_neededBefore identity verification you can create only one server.
quota_exceededYou reached your account's resource limit: arianet cloud limits.
plan_sold_out or datacenter_closedThis plan or data center is not taking orders right now; pick another plan or data center.
rate_limit_exceeded (429)Limit of 60 requests a minute. The provider retries by itself, honoring Retry-After.
terraform init cannot reach the registryCheck that your network can reach registry.terraform.io.

Next steps​

Build your infrastructure as code​

In the Arianet panel, create an API token and bring up your first cloud server with terraform apply. Every Arianet Cloud resource is billed hourly, and terraform destroy stops the cost.