−50% on all plans · starting at €2.48/mo · Blog·Docs·Sales

Terraform on FranceVPS: getting started

From zero to multi-region deployment with the FranceVPS Terraform provider.

If you're managing more than 3-4 servers, you should be using infrastructure as code. The benefits compound: reproducible deployments, version-controlled infrastructure, peer-reviewed changes, and the ability to spin up identical environments for staging or testing in minutes. This post walks through getting started with the FranceVPS Terraform provider, from zero to a multi-region deployment.

Install Terraform

On macOS:

brew install terraform

On 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

Verify with terraform -version. Terraform 1.6 or later is required for the FranceVPS provider's current features.

Get an API token

In the FranceVPS dashboard, go to Settings → API Tokens → Create new token. Give it a descriptive name ("terraform-prod" or similar) and minimum required scopes — typically compute:read, compute:write, networking:read, networking:write. Copy the token; it's shown only once.

Store it securely. Don't commit it to git. The cleanest pattern is environment variables:

export FRANCEVPS_TOKEN="fra_..."

Or, for production, use a secrets manager (Vault, AWS Secrets Manager, 1Password CLI).

Your first Terraform config

Create a directory for your project:

mkdir my-infra && cd my-infra

Create main.tf:

terraform {
  required_providers {
    francevps = {
      source  = "francevps/francevps"
      version = "~> 1.0"
    }
  }
}

provider "francevps" {
  # Token comes from FRANCEVPS_TOKEN env var
}

resource "francevps_ssh_key" "deploy" {
  name       = "deploy-key"
  public_key = file("~/.ssh/id_ed25519.pub")
}

resource "francevps_vps" "web" {
  name     = "web-01"
  plan     = "cloud-hp-2"  # 2 vCPU, 4 GB RAM, 60 GB NVMe
  image    = "ubuntu-24.04"
  region   = "fr-par-1"
  ssh_keys = [francevps_ssh_key.deploy.id]

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

output "web_ip" {
  value = francevps_vps.web.ipv4_address
}

Initialize and apply

terraform init
terraform plan
terraform apply

Terraform downloads the provider, plans the changes (showing you what it'll create), and applies on confirmation. About 60 seconds later, you have a running VPS with the IP printed as output.

Beyond a single server

The real power shows up with multiple resources. Let's add a load balancer in front of three web servers:

resource "francevps_vps" "web" {
  count    = 3
  name     = "web-${count.index + 1}"
  plan     = "cloud-hp-2"
  image    = "ubuntu-24.04"
  region   = "fr-par-1"
  ssh_keys = [francevps_ssh_key.deploy.id]

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

resource "francevps_load_balancer" "main" {
  name   = "web-lb"
  region = "fr-par-1"
  algorithm = "round_robin"

  forwarding_rule {
    entry_protocol  = "https"
    entry_port      = 443
    target_protocol = "http"
    target_port     = 8080
    certificate     = francevps_certificate.main.id
  }

  health_check {
    protocol = "http"
    port     = 8080
    path     = "/health"
    interval = 30
    timeout  = 5
  }

  targets = francevps_vps.web[*].id
}

resource "francevps_certificate" "main" {
  name    = "main-cert"
  type    = "lets_encrypt"
  domains = ["app.example.com"]
}

One terraform apply creates: 3 VPS instances, a load balancer with round-robin, an automatic Let's Encrypt certificate for HTTPS termination, and the load balancer health checks targeting all three VPS.

Multi-region deployment

Add a Marseille mirror:

resource "francevps_vps" "web_mrs" {
  count    = 2
  name     = "web-mrs-${count.index + 1}"
  plan     = "cloud-hp-2"
  image    = "ubuntu-24.04"
  region   = "fr-mrs-1"
  ssh_keys = [francevps_ssh_key.deploy.id]
}

Now you have 5 VPS across 2 regions. Pair this with cross-region database replication and DNS-based failover, and you have Tier 2 disaster recovery in code.

Modules for reusability

As your infrastructure grows, copy-paste becomes a liability. Modules let you define a "web tier" pattern once and instantiate it multiple times:

# modules/web-tier/main.tf
variable "name" {}
variable "region" {}
variable "count" { default = 2 }
variable "ssh_key_id" {}

resource "francevps_vps" "this" {
  count    = var.count
  name     = "${var.name}-${count.index + 1}"
  plan     = "cloud-hp-2"
  image    = "ubuntu-24.04"
  region   = var.region
  ssh_keys = [var.ssh_key_id]
}

output "ips" {
  value = francevps_vps.this[*].ipv4_address
}

Use it:

module "web_paris" {
  source     = "./modules/web-tier"
  name       = "web-par"
  region     = "fr-par-1"
  count      = 3
  ssh_key_id = francevps_ssh_key.deploy.id
}

module "web_marseille" {
  source     = "./modules/web-tier"
  name       = "web-mrs"
  region     = "fr-mrs-1"
  count      = 2
  ssh_key_id = francevps_ssh_key.deploy.id
}

State management

Terraform tracks the deployed state in a state file. By default it's local (terraform.tfstate), but for team use, store it remotely:

terraform {
  backend "s3" {
    endpoint = "https://s3.fr-par-1.fra-vps.com"
    bucket   = "my-infra-state"
    key      = "production.tfstate"
    region   = "fr-par-1"
  }
}

S3-compatible object storage (FranceVPS has its own, or use Scaleway / OVH) with versioning enabled gives you remote state, history, and collaborative locking.

What's next

Once you have a baseline working:

The goal is that "infrastructure changes" become git commits, reviewed via pull request, applied via CI. Same workflow as application code, with the same benefits.


Related articles

Try FranceVPS today

14-day money-back guarantee. No card required to explore. Sovereign French infrastructure.