Terraform based server install at Upcloud using guide outlined at https://upcloud.com/resources/tutorials/get-started-terraform & https://www.terraform.io/downloads. If you like this guide and want to try out Upcloud, use my referral link here.
- Install Terraform
- Setup Upcloud API Credentials
- Initialize New Terraform Project
- Planning Infrastructure With Terraform
- Using upctl Command Line Tool
- Deleting Terraform Created Server
- Upcloud Region List
- Upcloud Plan List
- OS Template Storage UUID
yum install -y yum-utils
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
yum -y install terraform
terraform -v
Terraform v1.2.9
on linux_amd64
Download upctl command line tool from https://github.com/UpCloudLtd/upcloud-cli/releases
upctl_version=2.1.0
curl -L -o upcloud-cli.tar.gz https://github.com/UpCloudLtd/upcloud-cli/releases/download/v${upctl_version}/upcloud-cli_${upctl_version}_linux_x86_64.tar.gz
tar -C /usr/local/bin -xf upcloud-cli.tar.gz
wget https://github.com/centminmod/upcloud-terraform/raw/master/upctl/bash_completion.d/upctl -O /etc/bash_completion.d/upctl
source /etc/bash_completion.d/upctl
Create a new API Access key as outlined at https://upcloud.com/community/tutorials/%20/getting-started-upcloud-api/ and replace the UPCLOUD_USERNAME
and UPCLOUD_PASSWORD
variable values username
and password
with your Upcloud API credentials and run the below commands to populate ~/.bashrc
. Then apply the new additions.
echo 'export UPCLOUD_USERNAME=username' | tee -a ~/.bashrc
echo 'export UPCLOUD_PASSWORD=password' | tee -a ~/.bashrc
source ~/.bashrc
This will work for both Terraform and upctl command line tool.
Create a new directory for your Terraform project and change into it.
mkdir -p /home/terraform/base
cd /home/terraform/base
Deploying Cloud Servers on UpCloud using Terraform works using the verified provider module.
Create /home/terraform/base/version.tf
touch version.tf
Place in /home/terraform/base/version.tf
terraform {
required_providers {
upcloud = {
source = "UpCloudLtd/upcloud"
}
}
}
provider "upcloud" {
# Your UpCloud credentials are read from the environment variables
# export UPCLOUD_USERNAME="Username for Upcloud API user"
# export UPCLOUD_PASSWORD="Password for Upcloud API user"
# Optional configuration settings can be depclared here
}
terraform init
The initialisation process creates a directory for the plugins in your Terraform folder under .terraform/providers
and installs the UpCloud provider module. The Terraform installation for UpCloud is then all set.
ls -lah .terraform/providers/registry.terraform.io/upcloudltd/upcloud/2.5.0/linux_amd64/
total 17M
drwxr-xr-x 2 root root 4.0K Sep 14 09:07 .
drwxr-xr-x 3 root root 4.0K Sep 14 09:07 ..
-rw-rw-rw- 1 root root 9.0K Sep 14 09:07 CHANGELOG.md
-rw-rw-rw- 1 root root 1.1K Sep 14 09:07 LICENSE
-rw-rw-rw- 1 root root 607 Sep 14 09:07 README.md
-rwxr-xr-x 1 root root 17M Sep 14 09:07 terraform-provider-upcloud_v2.5.0
Using values from https://developers.upcloud.com/1.3/ and https://upcloud.com/resources/tutorials/reduce-downtime-terraform-redeployments. Later you can create variables outlined at https://upcloud.com/resources/tutorials/terraform-variables.
Create server1.tf
touch server1.tf
Using:
-
zone =
us-nyc1
list of regions -
plan =
4xCPU-8GB
list of plans -
storage template list of OS storage templete UUIDs
- for CentOS 7 UUID =
01000000-0000-4000-8000-000050010300
with size =160GB
- for AlmaLinux 8 UUID =
01000000-0000-4000-8000-000140010100
with size =160GB
- for Rocky Linux 8 UUID =
01000000-0000-4000-8000-000150010100
with size =160GB
- for AlmaLinux 9 UUID =
01000000-0000-4000-8000-000140020100
with size =160GB
- for Rocky Linux 9 UUID =
01000000-0000-4000-8000-000150020100
with size =160GB
- for CentOS 7 UUID =
-
save your desired SSH public key into
~/.ssh/rsa_public_key
and corresponding SSH private key into~/.ssh/rsa_private_key
-
The user data scripted section is configured the way it is as in that environment the
$HOME
variable for root user ends up as/
while in a normal SSH terminal session$HOME
is/root
. This difference seems to break any scripting which relies of$HOME
variables. TheRANDFILE
is foropenssl
binary operations to work properly if you use scripts which runopenssl
binary. -
Change the default
remote-exec
script path from running at/tmp
in case server has noexec set on/tmp
. So set inconnection
blockscript_path = "/home/tftmp/terraform_%RAND%.sh"
(https://www.terraform.io/language/resources/provisioners/connection)
Notes:
- looks like for AlmaLinux 9 and Rocky Linux 9, they are using
cloud-init
templates and need to have Upcloud's Metadata enabled otherwise, you'd get an error like:
╷
│ Error: Metadata must be enabled when cloning a cloud-init template (METADATA_DISABLED_ON_CLOUD-INIT)
│
│ with upcloud_server.server1,
│ on server1.tf line 1, in resource "upcloud_server" "server1":
│ 1: resource "upcloud_server" "server1" {
│
╵
- EL9 OSes have SELinux enabled by default and you'd want to disable that before installing Centmin Mod. Centmin Mod can't automatically disable SELinux in EL9 like it can in EL7/EL8 OSes.
grep '^SELINUX=' /etc/selinux/config
SELINUX=enforcing
Contents of server1.tf
resource "upcloud_server" "server1" {
# System hostname
hostname = "terraform.example.com"
# Availability zone
zone = "us-nyc1"
# Number of CPUs and memory in GB
plan = "4xCPU-8GB"
metadata = true
template {
# System storage device size
size = 160
# Template UUID for CentOS 7
storage = "01000000-0000-4000-8000-000050010300"
}
# Network interfaces
network_interface {
type = "public"
}
network_interface {
type = "utility"
}
# Include at least one public SSH key
login {
user = "root"
keys = [
file("~/.ssh/rsa_public_key")
]
create_password = false
password_delivery = "email"
}
# Configuring connection details
connection {
# The server public IP address
host = self.network_interface[0].ip_address
type = "ssh"
user = "root"
private_key = file("~/.ssh/rsa_private_key")
script_path = "/home/terraform_%RAND%.sh"
}
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo 'Hello world!'"
]
}
user_data = <<-EOF
export TERM=xterm-256color
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOF
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo",
"lscpu",
"echo",
"free -mlt",
"echo",
"df -hT",
"echo",
"cat /etc/redhat-release"
]
}
}
You can optionally enable backups by adding to template{}
block
backup_rule {
interval = "daily"
time = "0100"
retention = 8
}
terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# upcloud_server.server1 will be created
+ resource "upcloud_server" "server1" {
+ cpu = (known after apply)
+ hostname = "terraform.example.com"
+ id = (known after apply)
+ mem = (known after apply)
+ plan = "4xCPU-8GB"
+ user_data = <<-EOT
export TERM=xterm-256color
mkdir -p /home/tftmp
sleep 5
chmod 1777 /home/tftmp
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOT
+ zone = "us-nyc1"
+ login {
+ create_password = false
+ keys = [
+ "ssh-rsa XYZABC",
]
+ password_delivery = "email"
+ user = "root"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "public"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "utility"
}
+ template {
+ address = (known after apply)
+ delete_autoresize_backup = false
+ filesystem_autoresize = false
+ id = (known after apply)
+ size = 160
+ storage = "01000000-0000-4000-8000-000050010300"
+ tier = (known after apply)
+ title = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
upcloud_server.server1: Creating...
upcloud_server.server1: Still creating... [10s elapsed]
upcloud_server.server1: Still creating... [20s elapsed]
upcloud_server.server1: Still creating... [30s elapsed]
upcloud_server.server1: Provisioning with 'remote-exec'...
upcloud_server.server1 (remote-exec): Connecting to remote host via SSH...
upcloud_server.server1 (remote-exec): Host: 209.xxx.xxx.xxx
upcloud_server.server1 (remote-exec): User: root
upcloud_server.server1 (remote-exec): Password: false
upcloud_server.server1 (remote-exec): Private key: true
upcloud_server.server1 (remote-exec): Certificate: false
upcloud_server.server1 (remote-exec): SSH Agent: true
upcloud_server.server1 (remote-exec): Checking Host Key: false
upcloud_server.server1 (remote-exec): Target Platform: unix
upcloud_server.server1: Still creating... [40s elapsed]
upcloud_server.server1: Still creating... [50s elapsed]
upcloud_server.server1 (remote-exec): Connecting to remote host via SSH...
upcloud_server.server1 (remote-exec): Host: 209.xxx.xxx.xxx
upcloud_server.server1 (remote-exec): User: root
upcloud_server.server1 (remote-exec): Password: false
upcloud_server.server1 (remote-exec): Private key: true
upcloud_server.server1 (remote-exec): Certificate: false
upcloud_server.server1 (remote-exec): SSH Agent: true
upcloud_server.server1 (remote-exec): Checking Host Key: false
upcloud_server.server1 (remote-exec): Target Platform: unix
upcloud_server.server1 (remote-exec): Connected!
upcloud_server.server1 (remote-exec): Architecture: x86_64
upcloud_server.server1 (remote-exec): CPU op-mode(s): 32-bit, 64-bit
upcloud_server.server1 (remote-exec): Byte Order: Little Endian
upcloud_server.server1 (remote-exec): CPU(s): 4
upcloud_server.server1 (remote-exec): On-line CPU(s) list: 0-3
upcloud_server.server1 (remote-exec): Thread(s) per core: 1
upcloud_server.server1 (remote-exec): Core(s) per socket: 1
upcloud_server.server1 (remote-exec): Socket(s): 4
upcloud_server.server1 (remote-exec): NUMA node(s): 1
upcloud_server.server1 (remote-exec): Vendor ID: AuthenticAMD
upcloud_server.server1 (remote-exec): CPU family: 23
upcloud_server.server1 (remote-exec): Model: 49
upcloud_server.server1 (remote-exec): Model name: AMD EPYC 7542 32-Core Processor
upcloud_server.server1 (remote-exec): Stepping: 0
upcloud_server.server1 (remote-exec): CPU MHz: 2894.558
upcloud_server.server1 (remote-exec): BogoMIPS: 5789.11
upcloud_server.server1 (remote-exec): Hypervisor vendor: KVM
upcloud_server.server1 (remote-exec): Virtualization type: full
upcloud_server.server1 (remote-exec): L1d cache: 64K
upcloud_server.server1 (remote-exec): L1i cache: 64K
upcloud_server.server1 (remote-exec): L2 cache: 512K
upcloud_server.server1 (remote-exec): L3 cache: 16384K
upcloud_server.server1 (remote-exec): NUMA node0 CPU(s): 0-3
upcloud_server.server1 (remote-exec): Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm art rep_good nopl extd_apicid eagerfpu pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw perfctr_core retpoline_amd ssbd ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr arat umip spec_ctrl intel_stibp arch_capabilities
upcloud_server.server1 (remote-exec): total used free shared buff/cache available
upcloud_server.server1 (remote-exec): Mem: 7802 339 7030 17 432 7215
upcloud_server.server1 (remote-exec): Low: 7802 772 7030
upcloud_server.server1 (remote-exec): High: 0 0 0
upcloud_server.server1 (remote-exec): Swap: 0 0 0
upcloud_server.server1 (remote-exec): Total: 7802 339 7030
upcloud_server.server1 (remote-exec): Filesystem Type Size Used Avail Use% Mounted on
upcloud_server.server1 (remote-exec): devtmpfs devtmpfs 3.8G 0 3.8G 0% /dev
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 18M 3.8G 1% /run
upcloud_server.server1 (remote-exec): tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
upcloud_server.server1 (remote-exec): /dev/vda1 xfs 160G 1.6G 159G 1% /
upcloud_server.server1 (remote-exec): tmpfs tmpfs 781M 0 781M 0% /run/user/0
upcloud_server.server1 (remote-exec): CentOS Linux release 7.9.2009 (Core)
upcloud_server.server1: Creation complete after 52s [id=0006f04a-15e3-4f4d-83xxx-7cc592935xxx]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Instead of hardcoding server1.tf
settings, you can use variables outlined at https://upcloud.com/resources/tutorials/terraform-variables via a dedicated variables.tf
file. Updated with new Upcloud High CPU and High MEM plans.
The variables.tf
file
variable "hostname" {
description = "Server hostname"
default = "terraform.example.com"
type = string
}
variable "private_key_path" {
type = string
default = "~/.ssh/rsa_private_key"
}
variable "public_key_path" {
type = string
default = "~/.ssh/rsa_public_key"
sensitive = true
}
variable "zones" {
type = map
default = {
"amsterdam" = "nl-ams1"
"london" = "uk-lon1"
"frankfurt" = "de-fra1"
"helsinki1" = "fi-hel1"
"helsinki2" = "fi-hel2"
"chicago" = "us-chi1"
"sanjose" = "us-sjo1"
"singapore" = "sg-sin1"
"sydney" = "au-syd1"
"warsaw" = "pl-waw1"
"madrid" = "es-mad1"
"newyork" = "us-nyc1"
}
}
variable "plans" {
type = map
default = {
"5USD" = "1xCPU-1GB"
"10USD" = "1xCPU-2GB"
"20USD" = "2xCPU-4GB"
"40USD" = "4xCPU-8GB"
"80USD" = "6xCPU-16GB"
"160USD" = "8xCPU-32GB"
"240USD" = "12xCPU-48GB"
"320USD" = "16xCPU-64GB"
"490USD" = "20xCPU-96GB"
"640USD" = "20xCPU-128GB"
"40USDM" = "HIMEM-2xCPU-8GB"
"65USDM" = "HIMEM-2xCPU-16GB"
"132USDM" = "HIMEM-4xCPU-32GB"
"240USDM" = "HIMEM-4xCPU-64GB"
"480USDM" = "HIMEM-6xCPU-128GB"
"840USDM" = "HIMEM-8xCPU-192GB"
"1080USDM" = "HIMEM-12xCPU-256GB"
"1680USDM" = "HIMEM-16xCPU-384GB"
"130USDC" = "HICPU-8xCPU-12GB"
"160USDC" = "HICPU-8xCPU-16GB"
"260USDC" = "HICPU-16xCPU-24GB"
"310USDC" = "HICPU-16xCPU-32GB"
"530USDC" = "HICPU-32xCPU-48GB"
"620USDC" = "HICPU-32xCPU-64GB"
"1056USDC" = "HICPU-64xCPU-96GB"
"1248USDC" = "HICPU-64xCPU-128GB"
}
}
variable "storage_sizes" {
type = map
default = {
"1xCPU-1GB" = "25"
"1xCPU-2GB" = "50"
"2xCPU-4GB" = "80"
"4xCPU-8GB" = "160"
"6xCPU-16GB" = "320"
"8xCPU-32GB" = "640"
"12xCPU-48GB" = "960"
"16xCPU-64GB" = "1280"
"20xCPU-96GB" = "1920"
"20xCPU-128GB" = "2048"
"HIMEM-2xCPU-8GB" = "100"
"HIMEM-2xCPU-16GB" = "100"
"HIMEM-4xCPU-32GB" = "100"
"HIMEM-4xCPU-64GB" = "200"
"HIMEM-6xCPU-128GB" = "300"
"HIMEM-8xCPU-192GB" = "400"
"HIMEM-12xCPU-256GB" = "500"
"HIMEM-16xCPU-384GB" = "600"
"HICPU-8xCPU-12GB" = "100"
"HICPU-8xCPU-16GB" = "200"
"HICPU-16xCPU-24GB" = "100"
"HICPU-16xCPU-32GB" = "200"
"HICPU-32xCPU-48GB" = "200"
"HICPU-32xCPU-64GB" = "300"
"HICPU-64xCPU-96GB" = "200"
"HICPU-64xCPU-128GB" = "300"
}
}
variable "templates" {
type = map
default = {
"centos7" = "01000000-0000-4000-8000-000050010300"
"almalinux8" = "01000000-0000-4000-8000-000140010100"
"rockylinux8" = "01000000-0000-4000-8000-000150010100"
"almalinux9" = "01000000-0000-4000-8000-000140020100"
"rockylinux9" = "01000000-0000-4000-8000-000150020100"
}
}
variable "set_password" {
type = bool
default = false
}
variable "users" {
type = list
default = ["root", "user1", "user2"]
}
variable "plan" {
type = string
default = "40USD"
}
variable "template" {
type = string
default = "centos7"
}
Which allows you to specify a plan by the pre-defined plan name which in this case is as follows:
"5USD" = "1xCPU-1GB"
"10USD" = "1xCPU-2GB"
"20USD" = "2xCPU-4GB"
"40USD" = "4xCPU-8GB"
"80USD" = "6xCPU-16GB"
"160USD" = "8xCPU-32GB"
"240USD" = "12xCPU-48GB"
"320USD" = "16xCPU-64GB"
"490USD" = "20xCPU-96GB"
"640USD" = "20xCPU-128GB"
"40USDM" = "HIMEM-2xCPU-8GB"
"65USDM" = "HIMEM-2xCPU-16GB"
"132USDM" = "HIMEM-4xCPU-32GB"
"240USDM" = "HIMEM-4xCPU-64GB"
"480USDM" = "HIMEM-6xCPU-128GB"
"840USDM" = "HIMEM-8xCPU-192GB"
"1080USDM" = "HIMEM-12xCPU-256GB"
"1680USDM" = "HIMEM-16xCPU-384GB"
"130USDC" = "HICPU-8xCPU-12GB"
"160USDC" = "HICPU-8xCPU-16GB"
"260USDC" = "HICPU-16xCPU-24GB"
"310USDC" = "HICPU-16xCPU-32GB"
"530USDC" = "HICPU-32xCPU-48GB"
"620USDC" = "HICPU-32xCPU-64GB"
"1056USDC" = "HICPU-64xCPU-96GB"
"1248USDC" = "HICPU-64xCPU-128GB"
For CentOS 7 centos.tfvars
template = "centos7"
For AlmaLinux 8 almalinux8.tfvars
template = "almalinux8"
For Rocky Linux 8 rockylinux8.tfvars
template = "rockylinux8"
For AlmaLinux 9 almalinux9.tfvars
template = "almalinux9"
For Rocky Linux 9 rockylinux9.tfvars
template = "rockylinux9"
You can then utilise these definition files on the command line and set the pre-defined plan name from above and desired hostname and --var-file
for the OS template name i.e.
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars
To apply without prompt at -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars -auto-approve
terraform apply -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars -auto-approve
Or save to plan files
# save plan files
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file centos.tfvars -out plan20usd-c7
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux8.tfvars -out plan20usd-al8
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux8.tfvars -out plan20usd-rl8
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file almalinux9.tfvars -out plan20usd-al9
terraform plan -var plan="20USD" -var hostname="host.domain.com" --var-file rockylinux9.tfvars -out plan20usd-rl9
# inspect plan files
terraform show "plan20usd-c7"
terraform show "plan20usd-al8"
terraform show "plan20usd-rl8"
terraform show "plan20usd-al9"
terraform show "plan20usd-rl9"
# inspect plan files with debug output prefix with TF_LOG=debug
TF_LOG=debug terraform show "plan20usd-c7"
TF_LOG=debug terraform show "plan20usd-al8"
TF_LOG=debug terraform show "plan20usd-rl8"
TF_LOG=debug terraform show "plan20usd-al9"
TF_LOG=debug terraform show "plan20usd-rl9"
# inspect plan files in json output
terraform show -json "plan20usd-c7"
terraform show -json "plan20usd-al8"
terraform show -json "plan20usd-rl8"
terraform show -json "plan20usd-al9"
terraform show -json "plan20usd-rl9"
# apply plan files
terraform apply "plan20usd-c7"
terraform apply "plan20usd-al8"
terraform apply "plan20usd-rl8"
terraform apply "plan20usd-al9"
terraform apply "plan20usd-rl9"
# apply plan files with debug output prefix with TF_LOG=debug
TF_LOG=debug terraform apply "plan20usd-c7"
TF_LOG=debug terraform apply "plan20usd-al8"
TF_LOG=debug terraform apply "plan20usd-rl8"
TF_LOG=debug terraform apply "plan20usd-al9"
TF_LOG=debug terraform apply "plan20usd-rl9"
The server.tf
file
resource "upcloud_server" "server1" {
# System hostname
hostname = var.hostname
# Availability zone
zone = var.zones["newyork"]
# Number of CPUs and memory in GB
plan = var.plans[var.plan]
metadata = true
template {
# System storage device size
size = lookup(var.storage_sizes, var.plans[var.plan])
# Template UUID for CentOS 7
storage = var.templates[var.template]
}
# Network interfaces
network_interface {
type = "public"
}
network_interface {
type = "utility"
}
# Include at least one public SSH key
login {
user = var.users[0]
keys = [
chomp(file(var.public_key_path))
]
create_password = var.set_password
password_delivery = "email"
}
# Configuring connection details
connection {
# The server public IP address
host = self.network_interface[0].ip_address
type = "ssh"
user = var.users[0]
private_key = file(var.private_key_path)
script_path = "/home/terraform_%RAND%.sh"
}
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo 'Hello world!'"
]
}
user_data = <<-EOF
export TERM=xterm-256color
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOF
# Remotely executing a command on the server
provisioner "remote-exec" {
inline = [
"echo",
"lscpu",
"echo",
"free -mlt",
"echo",
"df -hT",
"echo",
"cat /etc/redhat-release"
]
}
}
You can optionally enable backups by adding to template{}
block
backup_rule {
interval = "daily"
time = "0100"
retention = 8
}
Create an output.tf
file with your server name defined in server1.tf
= server1
as defined by resource "upcloud_server" "server1" {
output "public_ip" {
value = upcloud_server.server1.network_interface[0].ip_address
}
output "utility_ip" {
value = upcloud_server.server1.network_interface[1].ip_address
}
output "hostname" {
value = upcloud_server.server1.hostname
}
output "plan" {
value = upcloud_server.server1.plan
}
output "zone" {
value = upcloud_server.server1.zone
}
output "size" {
value = upcloud_server.server1.template[0].size
}
Then creating a 20USD
plan Upcloud server. You can also add -var hostname="host.domain.com"
to change the desired hostname.
terraform plan -var plan="20USD"
terraform apply -var plan="20USD"
To apply without prompt at -auto-approve
terraform apply -var plan="20USD" -auto-approve
terraform plan -var plan="20USD"
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# upcloud_server.server1 will be created
+ resource "upcloud_server" "server1" {
+ cpu = (known after apply)
+ hostname = "terraform.example.com"
+ id = (known after apply)
+ mem = (known after apply)
+ plan = "2xCPU-4GB"
+ user_data = <<-EOT
export TERM=xterm-256color
mkdir -p /home/tftmp
sleep 5
chmod 1777 /home/tftmp
mkdir -p /root
export HOME=/root
echo $HOME
touch $HOME/.rnd
export RANDFILE=$HOME/.rnd
chmod 600 $HOME/.rnd
env
yum -y update
EOT
+ zone = "us-nyc1"
+ login {
+ create_password = false
+ keys = [
+ "ssh-rsa XYZABC",
]
+ password_delivery = "email"
+ user = "root"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "public"
}
+ network_interface {
+ bootable = false
+ ip_address = (known after apply)
+ ip_address_family = "IPv4"
+ ip_address_floating = (known after apply)
+ mac_address = (known after apply)
+ network = (known after apply)
+ source_ip_filtering = true
+ type = "utility"
}
+ template {
+ address = (known after apply)
+ delete_autoresize_backup = false
+ filesystem_autoresize = false
+ id = (known after apply)
+ size = 80
+ storage = "01000000-0000-4000-8000-000050010300"
+ tier = (known after apply)
+ title = (known after apply)
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ hostname = "terraform.example.com"
+ plan = "2xCPU-4GB"
+ public_ip = (known after apply)
+ size = 80
+ utility_ip = (known after apply)
+ zone = "us-nyc1"
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
You can check the user data log at /var/log/upcloud_userdata.log
on the created Upcloud server
tail -f /var/log/upcloud_userdata.log
Or SSH into the created Upcloud server
ssh [email protected] tail -f /var/log/upcloud_userdata.log
Use upctl command line tool https://upcloud.com/resources/tutorials/get-started-upcloud-command-line-interface
List servers
upctl server list
UUID Hostname Plan Zone State
────────────────────────────────────── ─────────────────────── ─────────── ───────── ─────────
0006f04a-15e3-4f4d-83xxx-7cc592935xxx terraform.example.com 4xCPU-8GB us-nyc1 started
Stop server
upctl server stop terraform.example.com
Start server
upctl server start terraform.example.com
Show server info
upctl server show terraform.example.com
upctl server show terraform.example.com
Common
UUID: 0006f04a-15e3-4f4d-83xxx-7cc592935xxx
Hostname: terraform.example.com
Title: terraform.example.com (managed by terraform)
Plan: 4xCPU-8GB
Zone: us-nyc1
State: started
Simple Backup: no
Licence: 0
Metadata: False
Timezone: UTC
Host ID: 746718xxxxx
Tags:
Storage: (Flags: B = bootdisk, P = part of plan)
UUID Title Type Address Size (GiB) Flags
────────────────────────────────────── ────────────────────────────────────── ────── ────────── ──────────── ───────
01a400de-930e-4cac-8114-62408b5xxxxx terraform-terraform.example.com-disk disk virtio:0 160 P
NICs: (Flags: S = source IP filtering, B = bootable)
# Type IP Address MAC Address Network Flags
─── ───────── ────────────────────── ─────────────────── ────────────────────────────────────── ───────
1 public IPv4: 209.xxx.xxx.xxx 52:xx:xx:xx:61:5c 034a97cd-e05c-4785-bf33-7648b64xxxxx S
2 utility IPv4: 10.x.x.xxx 52:xx:xx:xx:be:aa 03243004-e399-49cc-9697-4f5e9fcxxxxx S
terraform destroy
{
"zones": {
"zone": [
{
"description": "Sydney #1",
"id": "au-syd1",
"public": "yes"
},
{
"description": "Frankfurt #1",
"id": "de-fra1",
"public": "yes"
},
{
"description": "Madrid #1",
"id": "es-mad1",
"public": "yes"
},
{
"description": "Helsinki #1",
"id": "fi-hel1",
"public": "yes"
},
{
"description": "Helsinki #2",
"id": "fi-hel2",
"public": "yes"
},
{
"description": "Amsterdam #1",
"id": "nl-ams1",
"public": "yes"
},
{
"description": "Warsaw #1",
"id": "pl-waw1",
"public": "yes"
},
{
"description": "Singapore #1",
"id": "sg-sin1",
"public": "yes"
},
{
"description": "London #1",
"id": "uk-lon1",
"public": "yes"
},
{
"description": "Chicago #1",
"id": "us-chi1",
"public": "yes"
},
{
"description": "New York #1",
"id": "us-nyc1",
"public": "yes"
},
{
"description": "San Jose #1",
"id": "us-sjo1",
"public": "yes"
}
]
}
}
{
"plans": {
"plan": [
{
"core_number": 1,
"memory_amount": 2048,
"name": "1xCPU-2GB",
"public_traffic_out": 2048,
"storage_size": 50,
"storage_tier": "maxiops"
},
{
"core_number": 1,
"memory_amount": 1024,
"name": "1xCPU-1GB",
"public_traffic_out": 1024,
"storage_size": 25,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 4096,
"name": "2xCPU-4GB",
"public_traffic_out": 4096,
"storage_size": 80,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 8192,
"name": "HIMEM-2xCPU-8GB",
"public_traffic_out": 2048,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 2,
"memory_amount": 16384,
"name": "HIMEM-2xCPU-16GB",
"public_traffic_out": 2048,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 65536,
"name": "HIMEM-4xCPU-64GB",
"public_traffic_out": 4096,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 32768,
"name": "HIMEM-4xCPU-32GB",
"public_traffic_out": 4096,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 4,
"memory_amount": 8192,
"name": "4xCPU-8GB",
"public_traffic_out": 5120,
"storage_size": 160,
"storage_tier": "maxiops"
},
{
"core_number": 6,
"memory_amount": 16384,
"name": "6xCPU-16GB",
"public_traffic_out": 6144,
"storage_size": 320,
"storage_tier": "maxiops"
},
{
"core_number": 6,
"memory_amount": 131072,
"name": "HIMEM-6xCPU-128GB",
"public_traffic_out": 6144,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 12288,
"name": "HICPU-8xCPU-12GB",
"public_traffic_out": 4096,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 16384,
"name": "HICPU-8xCPU-16GB",
"public_traffic_out": 4096,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 196608,
"name": "HIMEM-8xCPU-192GB",
"public_traffic_out": 8192,
"storage_size": 400,
"storage_tier": "maxiops"
},
{
"core_number": 8,
"memory_amount": 32768,
"name": "8xCPU-32GB",
"public_traffic_out": 7168,
"storage_size": 640,
"storage_tier": "maxiops"
},
{
"core_number": 12,
"memory_amount": 262144,
"name": "HIMEM-12xCPU-256GB",
"public_traffic_out": 10240,
"storage_size": 500,
"storage_tier": "maxiops"
},
{
"core_number": 12,
"memory_amount": 49152,
"name": "12xCPU-48GB",
"public_traffic_out": 9216,
"storage_size": 960,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 24576,
"name": "HICPU-16xCPU-24GB",
"public_traffic_out": 5120,
"storage_size": 100,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 393216,
"name": "HIMEM-16xCPU-384GB",
"public_traffic_out": 12288,
"storage_size": 600,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 32768,
"name": "HICPU-16xCPU-32GB",
"public_traffic_out": 5120,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 16,
"memory_amount": 65536,
"name": "16xCPU-64GB",
"public_traffic_out": 10240,
"storage_size": 1280,
"storage_tier": "maxiops"
},
{
"core_number": 20,
"memory_amount": 131072,
"name": "20xCPU-128GB",
"public_traffic_out": 24576,
"storage_size": 2048,
"storage_tier": "maxiops"
},
{
"core_number": 20,
"memory_amount": 98304,
"name": "20xCPU-96GB",
"public_traffic_out": 12288,
"storage_size": 1920,
"storage_tier": "maxiops"
},
{
"core_number": 32,
"memory_amount": 49152,
"name": "HICPU-32xCPU-48GB",
"public_traffic_out": 6144,
"storage_size": 200,
"storage_tier": "maxiops"
},
{
"core_number": 32,
"memory_amount": 65536,
"name": "HICPU-32xCPU-64GB",
"public_traffic_out": 6144,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 64,
"memory_amount": 131072,
"name": "HICPU-64xCPU-128GB",
"public_traffic_out": 7168,
"storage_size": 300,
"storage_tier": "maxiops"
},
{
"core_number": 64,
"memory_amount": 98304,
"name": "HICPU-64xCPU-96GB",
"public_traffic_out": 7168,
"storage_size": 200,
"storage_tier": "maxiops"
}
]
}
}
{
"storages": {
"storage": [
{
"access": "public",
"license": 3.36,
"size": 28,
"state": "online",
"template_type": "native",
"title": "Windows Server 2016 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010060200"
},
{
"access": "public",
"license": 0.694,
"size": 29,
"state": "online",
"template_type": "native",
"title": "Windows Server 2016 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010060300"
},
{
"access": "public",
"license": 3.36,
"size": 25,
"state": "online",
"template_type": "native",
"title": "Windows Server 2019 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010070200"
},
{
"access": "public",
"license": 0.694,
"size": 25,
"state": "online",
"template_type": "native",
"title": "Windows Server 2019 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010070300"
},
{
"access": "public",
"license": 3.36,
"size": 18,
"state": "online",
"template_type": "native",
"title": "Windows Server 2022 Datacenter",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010080200"
},
{
"access": "public",
"license": 0.694,
"size": 18,
"state": "online",
"template_type": "native",
"title": "Windows Server 2022 Standard",
"type": "template",
"uuid": "01000000-0000-4000-8000-000010080300"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 9 (Stretch)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020040100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 10 (Buster)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020050100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Debian GNU/Linux 11 (Bullseye)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000020060100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "native",
"title": "Ubuntu Server 18.04 LTS (Bionic Beaver)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030080200"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "native",
"title": "Ubuntu Server 20.04 LTS (Focal Fossa)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030200200"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "Ubuntu Server 22.04 LTS (Jammy Jellyfish)",
"type": "template",
"uuid": "01000000-0000-4000-8000-000030220200"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS 7",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010300"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010400"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "CentOS Stream 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010500"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "native",
"title": "CentOS Stream 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000050010600"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "native",
"title": "Plesk Obsidian",
"type": "template",
"uuid": "01000000-0000-4000-8000-000130010100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "AlmaLinux 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000140010100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "AlmaLinux 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000140020100"
},
{
"access": "public",
"license": 0,
"size": 3,
"state": "online",
"template_type": "native",
"title": "Rocky Linux 8",
"type": "template",
"uuid": "01000000-0000-4000-8000-000150010100"
},
{
"access": "public",
"license": 0,
"size": 4,
"state": "online",
"template_type": "cloud-init",
"title": "Rocky Linux 9",
"type": "template",
"uuid": "01000000-0000-4000-8000-000150020100"
},
{
"access": "public",
"license": 0,
"size": 5,
"state": "online",
"template_type": "cloud-init",
"title": "UpCloud K8s",
"type": "template",
"uuid": "01000000-0000-4000-8000-000160010100"
}
]
}
}