Skip to content

Terraform + UpCloud — UpCloud Resources

OWNER: arjan
ALSO_USED_BY: gerco, thijmen, rutger
LAST_VERIFIED: 2026-03-26
GE_STACK_VERSION: terraform ~> 1.14.x, upcloud provider ~> 5.0


Overview

UpCloud resource types used in GE, managed via the Terraform provider.
Covers server types, managed Kubernetes, storage, networking, firewalls,
and load balancers. All resources are EU-hosted (ISO 27001 A.8.31).


Cloud Server Types

UpCloud offers four server plan families:

Plan Family Use Case in GE vCPU Memory Storage
General Purpose Admin UI, wiki, monitoring 1-20 1-128 GB MaxIOPS SSD
High CPU Agent executors, orchestrator 2-20 4-64 GB MaxIOPS SSD
High Memory PostgreSQL, Redis 2-20 8-256 GB MaxIOPS SSD
Cloud Native K8s worker nodes (cost-optimised) 2-16 4-32 GB MaxIOPS SSD
resource "upcloud_server" "executor" {  
  hostname = "ge-${terraform.workspace}-executor"  
  zone     = "nl-ams1"  
  plan     = "HICPU-2xCPU-4GB"  

  template {  
    storage = "Ubuntu Server 24.04 LTS"  
    size    = 50  
  }  

  network_interface {  
    type = "private"  
  }  

  labels = {  
    "ge.zone"       = terraform.workspace  
    "ge.managed-by" = "terraform"  
    "ge.component"  = "compute"  
  }  

  lifecycle {  
    ignore_changes = [template[0].storage]  
  }  
}  

IF: selecting a server plan
THEN: match the workload profile to the plan family
THEN: start small, monitor, scale up — UpCloud supports hot resize


Managed Kubernetes (UKS)

Used for Zones 2 (staging) and 3 (production).
Control plane is free. Worker nodes billed as Cloud Servers.

resource "upcloud_kubernetes_cluster" "main" {  
  name                = "ge-${terraform.workspace}-cluster"  
  network             = upcloud_network.private.id  
  network_cidr        = "172.16.0.0/24"  
  zone                = "nl-ams1"  
  plan                = "production"  
  version             = "1.34"  
  private_node_groups = true  

  labels = {  
    "ge.zone"       = terraform.workspace  
    "ge.managed-by" = "terraform"  
  }  
}  

resource "upcloud_kubernetes_node_group" "workers" {  
  cluster    = upcloud_kubernetes_cluster.main.id  
  name       = "ge-${terraform.workspace}-workers"  
  node_count = local.config.node_count  
  plan       = local.config.server_plan  

  labels = {  
    "ge.zone"       = terraform.workspace  
    "ge.managed-by" = "terraform"  
    "ge.component"  = "kubernetes"  
  }  
}  

CHECK: private_node_groups = true — worker nodes not publicly accessible
CHECK: version matches GE pinned Kubernetes version
CHECK: lifecycle.prevent_destroy = true on production clusters

Key UKS features:
- CNCF conformance certified
- Up to 30 data plane nodes per cluster
- Integrated with UpCloud Block Storage CSI
- UpCloud Managed Load Balancer integration
- Private networking between nodes


Storage

Block Storage (MaxIOPS SSD)

resource "upcloud_storage" "data" {  
  title = "ge-${terraform.workspace}-data"  
  zone  = "nl-ams1"  
  size  = 100  
  tier  = "maxiops"  

  lifecycle {  
    prevent_destroy = true  
  }  
}  

CHECK: tier = "maxiops" for all production storage
CHECK: prevent_destroy = true on all data volumes

Object Storage

UpCloud offers managed object storage for static assets.
GE uses bunny.net Edge Storage instead for CDN-integrated storage.
READ_ALSO: wiki/docs/stack/bunnynet/edge.md


Networking

Private Network

All GE services communicate over private networking.
Public interfaces only on load balancers and bastion hosts.

resource "upcloud_network" "private" {  
  name = "ge-${terraform.workspace}-private"  
  zone = "nl-ams1"  

  ip_network {  
    address            = "10.0.0.0/24"  
    dhcp               = true  
    dhcp_default_route = false  
    family             = "IPv4"  
  }  
}  

CHECK: database and executor servers have ONLY private network interfaces
CHECK: public access goes through load balancer, never directly to servers

Router

resource "upcloud_router" "main" {  
  name = "ge-${terraform.workspace}-router"  

  static_route {  
    name    = "to-kubernetes"  
    nexthop = "10.0.0.1"  
    route   = "172.16.0.0/24"  
  }  
}  

Firewalls

UpCloud firewall rules attached to servers:

resource "upcloud_firewall_rules" "executor" {  
  server_id = upcloud_server.executor.id  

  firewall_rule {  
    action                 = "accept"  
    direction              = "in"  
    family                 = "IPv4"  
    protocol               = "tcp"  
    destination_port_start = 6381  
    destination_port_end   = 6381  
    source_address_start   = "10.0.0.0"  
    source_address_end     = "10.0.0.255"  
    comment                = "Redis from private network"  
  }  

  firewall_rule {  
    action    = "drop"  
    direction = "in"  
    family    = "IPv4"  
    comment   = "Default deny"  
  }  
}  

CHECK: default deny rule is LAST in the list
CHECK: only necessary ports are open
CHECK: source addresses restricted to private network where possible


Load Balancers

UpCloud Managed Load Balancer for Zones 2+3:

resource "upcloud_loadbalancer" "frontend" {  
  configured_status = "started"  
  name              = "ge-${terraform.workspace}-lb"  
  plan              = "production-small"  
  zone              = "nl-ams1"  

  networks {  
    name    = "private"  
    type    = "private"  
    family  = "IPv4"  
    network = upcloud_network.private.id  
  }  

  networks {  
    name   = "public"  
    type   = "public"  
    family = "IPv4"  
  }  

  labels = {  
    "ge.zone"       = terraform.workspace  
    "ge.managed-by" = "terraform"  
  }  
}  

UpCloud Essentials includes 1 free load balancer node with 1,000 concurrent sessions.
Production may need larger plans based on traffic.


Pricing Reference

All EU-hosted. Prices approximate (check upcloud.com/pricing for current):

Resource Starting Price Notes
Cloud Server (1 vCPU, 1 GB) ~$5/month Hourly billing
Managed K8s control plane Free Up to 30 nodes
K8s worker node Same as Cloud Server Per node plan
Block Storage (MaxIOPS) ~$0.11/GB/month
Managed Load Balancer Free (1 node) Essentials tier
Managed Database (PostgreSQL) ~$15/month Smallest plan
Data transfer (egress) Free Zero egress fees

UpCloud Regions

GE uses EU data centres only:

Region Code Use
Amsterdam, NL nl-ams1 Primary (all zones)
Frankfurt, DE de-fra1 Failover candidate
Helsinki, FI fi-hel1 UpCloud HQ region

CHECK: all resources deployed to nl-ams1 unless failover
CHECK: never deploy to non-EU regions


Cross-References

READ_ALSO: wiki/docs/stack/terraform-upcloud/index.md
READ_ALSO: wiki/docs/stack/terraform-upcloud/patterns.md
READ_ALSO: wiki/docs/stack/terraform-upcloud/pitfalls.md
READ_ALSO: wiki/docs/stack/terraform-upcloud/checklist.md
READ_ALSO: wiki/docs/stack/kubernetes/index.md