Importing a Hetzner VM into a new Terraform template

I’m creating a new VM on Hetzner that I want to manage with Terraform, but this is the first time I’ve used the Hetzner Provider. Rather than stumble through the required options for a new VM, I used the -generate-config-out option with terraform plan to generate the Terraform config for me based on the currrent config.

Here’s my starting point for my main.tf:

terraform {
  required_providers {
    hcloud = {
      source  = "hetznercloud/hcloud"
      version = "~> 1.45"
    }
  }
}


# Set the variable value in *.tfvars file
# or using the -var="hcloud_token=..." CLI option
variable "hcloud_token" {
  sensitive = true
}

# Configure the Hetzner Cloud Provider
provider "hcloud" {
  token = var.hcloud_token
}

import {
  id = "name-of-my-hertzner-vm"
  to = hcloud_server.name-of-my-new-terraform-resource
}

On running:

terraform plan -generate-config-out=generated.tf

I now have the equivalent Terraform config for my VM, in generated.tf, and now I can include this in my main.tf and manage it incrementally via Terraform from this point onwards.

ssh into Hetzner VMs with an ssh key

During VM creation, assuming you added an ssh public key value when prompted:

Add an entry like the following to your ~/.ssh/config:

Host ip-of-your-new-vm
PreferredAuthentications publickey
IdentityFile ~/.ssh/name-of-your-private-key

ssh into your VM with:

ssh root@ip-of-your-new-vm

GitLab CI – allowing later stages to run if manual job in previous stage is not run

By default, later stages will not run if a previous stage in your GitLab pipeline fails. If you have a manual job in a previous stage, not running that job will also block later stages from running automatically.

To allow a later stage to run, mark any optional/manual jobs with ‘allow_failure: true’

For example:

stages:
- build
- setup
- deploy

build:
stage: build
script:
- doTaskA

optional-setup:
stage: setup
script:
- doOptionalSetup
allow_failure: true
when: manual

deploy:
stage: deploy
script:
- doTaskC
when: manual

Configuring nginx virtual hosts with sites-available / sites-enabled

I recently ran into an issue with how /etc/nginx/sites-enabled is used (or not) depending what nginx version you’re running on, or more likely according to this post, whether you’re running nginx on Debian/Ubuntu or the official nginx package.

The difference (which is pretty significant if you’re not expecting it), is that:

  • Debian/Ubuntu versions for nginx have sites-enabled included in nginx.conf by default
  • The official upstream nginx package does not

What this means is on Debian/Ubuntu, in /etc/nginx/nginx.conf you’ll have this include:

include /etc/nginx/sites-enabled/*;

but it’s missing if you run the upstream nginx package, like what seems to be included in the Docker image nginx:latest.

In my case running the Docker image nginx:latest every GET request was getting a 404 and the only clue was in my error.log each request was attempting to serve files from a default /usr/share/nginx/html folder, which is definitely not what was configured as my root in the config in /etc/nginx/sites-enabled:

open() "/usr/share/nginx/html/[url-request-here] HTTP/1.1" failed (2: No such file or directory)

Once I worked out what the issue was I just added the include line for sites-enabled.