Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

Terraform — zarządzanie infrastrukturą VPS jako kod

Opublikowano: 9 kwietnia 2026 · Kategoria: VPS / DevOps

Klikanie w panelu dostawcy działa dla jednego serwera. Przy dwóch serwerach, firewallach, rekordach DNS i backupach zaczyna się chaos. Terraform rozwiązuje ten problem: opisujesz całą infrastrukturę w plikach tekstowych, wersjonujesz w git i odtwarzasz jedną komendą. Infrastructure as Code (IaC) to standard w każdym profesjonalnym projekcie VPS.

Instalacja Terraform

Terraform to pojedynczy binarny plik. Instalacja na Ubuntu/Debian:

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install terraform

terraform version
# Terraform v1.7.x

Struktura projektu Terraform

Typowy projekt Terraform dla VPS wygląda tak:

infra/
├── main.tf          # Główne zasoby (serwery, sieci)
├── variables.tf     # Deklaracje zmiennych
├── outputs.tf       # Wartości wyjściowe (IP, ID)
├── versions.tf      # Wymagane wersje providerów
├── terraform.tfvars # Wartości zmiennych (NIE commituj jeśli zawiera tokeny!)
└── .terraform.lock.hcl  # Lock file providerów (commituj)

Provider Hetzner Cloud

Hetzner to popularny wybór dla polskich projektów — serwery w Niemczech (Frankfurt, Nuremberg), niskie ceny i oficjalny provider Terraform. Konfiguracja:

# versions.tf
terraform {
  required_version = ">= 1.5"
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.47"
    }
  }
}

provider "hcloud" {
  token = var.hcloud_token
}
# variables.tf
variable "hcloud_token" {
  description = "Hetzner Cloud API Token"
  type        = string
  sensitive   = true  # Nie pojawi się w logach
}

variable "server_type" {
  description = "Typ serwera Hetzner (cx11, cx21, cx31...)"
  type        = string
  default     = "cx22"
}

variable "location" {
  description = "Lokalizacja serwera"
  type        = string
  default     = "nbg1"  # Nuremberg
}
# main.tf — VPS na Hetzner
resource "hcloud_ssh_key" "default" {
  name       = "my-ssh-key"
  public_key = file("~/.ssh/id_rsa.pub")
}

resource "hcloud_server" "web" {
  name        = "web-01"
  image       = "ubuntu-22.04"
  server_type = var.server_type
  location    = var.location
  ssh_keys    = [hcloud_ssh_key.default.id]

  labels = {
    environment = "production"
    role        = "web"
  }

  # Cloud-init: podstawowa konfiguracja przy starcie
  user_data = <<-EOT
    #cloud-config
    package_update: true
    packages:
      - nginx
      - ufw
    runcmd:
      - ufw allow 22
      - ufw allow 80
      - ufw allow 443
      - ufw --force enable
  EOT
}

# Firewall
resource "hcloud_firewall" "web" {
  name = "web-firewall"

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

  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 "hcloud_firewall_attachment" "web" {
  firewall_id = hcloud_firewall.web.id
  server_ids  = [hcloud_server.web.id]
}
# outputs.tf
output "server_ip" {
  description = "Publiczne IP serwera"
  value       = hcloud_server.web.ipv4_address
}

output "server_id" {
  description = "ID serwera Hetzner"
  value       = hcloud_server.web.id
}

Provider DigitalOcean

DigitalOcean (Droplets) ma dojrzały provider z szerokim wsparciem dla Load Balancerów, Spaces (S3-compatible), Managed Databases i Kubernetes. Konfiguracja analogiczna do Hetzner:

# versions.tf — DigitalOcean
terraform {
  required_providers {
    digitalocean = {
      source  = "digitalocean/digitalocean"
      version = "~> 2.36"
    }
  }
}

provider "digitalocean" {
  token = var.do_token
}

resource "digitalocean_droplet" "web" {
  image    = "ubuntu-22-04-x64"
  name     = "web-01"
  region   = "fra1"  # Frankfurt
  size     = "s-1vcpu-1gb"
  ssh_keys = [digitalocean_ssh_key.default.fingerprint]
}

resource "digitalocean_ssh_key" "default" {
  name       = "my-key"
  public_key = file("~/.ssh/id_rsa.pub")
}

Cykl życia — plan, apply, destroy

# 1. Inicjalizacja (jednorazowo lub po zmianie providera)
terraform init

# 2. Walidacja składni
terraform validate

# 3. Plan — co zostanie zrobione (NIE wykonuje zmian)
terraform plan

# 4. Apply — wykonaj zmiany (pyta o potwierdzenie)
terraform apply

# Lub bez pytania (CI/CD):
terraform apply -auto-approve

# 5. Sprawdź outputy
terraform output server_ip

# 6. Zniszcz wszystko (OSTROŻNIE!)
terraform destroy

Zarządzanie state — remote backend

Domyślnie state zapisywany jest lokalnie w terraform.tfstate. W teamie lub CI/CD użyj remote backend — np. S3 (AWS) lub Terraform Cloud:

# backend.tf — S3 remote state
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/vps/terraform.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"  # State locking
  }
}
Backend Zalety Kiedy używać
local Zero konfiguracji Projekty osobiste, nauka
S3 + DynamoDB Locking, szyfrowanie, tanie Projekty AWS, CI/CD
GCS Wbudowany locking Projekty GCP
Terraform Cloud UI, runs, sentinel policies Teamy, enterprise

Zmienne i .tfvars

# terraform.tfvars (NIE commituj do gita jeśli zawiera tokeny!)
hcloud_token = "your-hetzner-api-token"
server_type  = "cx22"
location     = "nbg1"

# Lub przez zmienne środowiskowe (bezpieczniejsze dla tokenów):
export TF_VAR_hcloud_token="your-hetzner-api-token"
terraform apply

Best practices

  • Zawsze sprawdzaj plan przed apply — szczególnie gdy widzisz -/+ (replace): Terraform zniszczy i odtworzy zasób, co może oznaczać utratę danych.
  • Trzymaj state w remote backend — lokalny state + kilka osób w teamie = konflikty i korupcja state.
  • Używaj sensitive = true dla tokenów i haseł — nie pojawią się w logach plan/apply.
  • Moduły Terraform — dla powtarzalnych zasobów (np. "serwer z firewallem i DNS") twórz moduły w katalogu modules/. Reużywalność i DRY.
  • Lifecycle — prevent_destroy — chroni krytyczne zasoby (bazy danych) przed przypadkowym terraform destroy: dodaj blok lifecycle { prevent_destroy = true }.

Najczęstsze pytania

Czym jest Terraform i do czego służy w kontekście VPS? +
Terraform to narzędzie Infrastructure as Code (IaC) od HashiCorp. Zamiast klikać w panelu dostawcy, opisujesz infrastrukturę w plikach .tf (język HCL), a Terraform tworzy, modyfikuje i usuwa zasoby. Dla VPS oznacza to: tworzenie serwerów, przypisywanie IP, konfiguracja firewalli, DNS — wszystko w wersjonowanym kodzie. Przy awarii serwera odtworzysz całą infrastrukturę jedną komendą.
Jakie są dostępne providery Terraform dla hostingu VPS? +
Najpopularniejsze providery: Hetzner Cloud (hetznercloud/hetzner), DigitalOcean (digitalocean/digitalocean), Vultr (vultr/vultr), Linode/Akamai (linode/linode), OVHcloud (ovh/ovh). W Polsce Hetzner jest najchętniej wybierany ze względu na serwery w Niemczech, niskie ceny i dobry provider Terraform. Każdy provider wymaga tokenu API, który podajesz przez zmienną środowiskową.
Co to jest Terraform state i dlaczego jest ważny? +
State (terraform.tfstate) to plik JSON przechowujący aktualny stan infrastruktury — mapowanie między zasobami Terraform a rzeczywistymi obiektami u dostawcy (np. ID serwera). Bez state Terraform nie wiedziałby co już istnieje. Nigdy nie commituj state do gita — może zawierać sekrety. W produkcji trzymaj state w S3, GCS lub Terraform Cloud (remote backend). Utrata state nie niszczy infrastruktury, ale Terraform traci kontrolę nad zasobami.
Jaka jest kolejność komend w typowym workflow Terraform? +
Standardowy workflow: (1) terraform init — pobiera provider plugins, inicjalizuje backend. (2) terraform validate — sprawdza składnię HCL. (3) terraform plan — pokazuje co zostanie zmienione (diff infrastruktury). (4) terraform apply — wykonuje zmiany po potwierdzeniu. (5) terraform destroy — usuwa wszystko. Zasada: zawsze sprawdzaj plan przed apply, szczególnie gdy widzisz "will be destroyed" — Terraform może chcieć odtworzyć zasób zamiast go zmodyfikować.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.