Automatic Nginx Installation

Technical Background

In modern cloud environments, infrastructure automation is essential to minimize manual work and to ensure consistent system configuration. Cloud-init is a widely used tool for initializing Linux cloud instances on first boot. It supports configuration through a user_data script passed during instance creation, which allows package installation, user creation, and service configuration automatically.

In this exercise, you use Terraform to provision a Hetzner Cloud server and configure it with a user_data script. This script installs the Nginx web server, ensures it is started, and configures it to start automatically on every reboot. Using Terraform’s user_data mechanism eliminates manual SSH setup and ensures your infrastructure is reproducible and reliable.

Info

The provided image (Debian 12) already has cloud-init support enabled, so the user_data script will be executed at boot time. Using apt or apt-get is generally recommended in cloud-init scripts instead of aptitude, as minimal cloud images often do not have aptitude installed by default.

Warning

The server needs access / privileges to reach external repositories for aptitude.

Solution

Prerequisits

Create a main.tf, outputs.tf, variables.tf, network.tf,providers.tf and secrets.auto.tfvars like in 1 Incrementally Creating A Base System.

Preparing the user_data script

  1. Create a file myinit.sh with the following content:
#!/bin/bash
set -e

Failure

  • Make sure to use the correct syntax and formatting
  1. Update package index and upgrade existing packages:
apt update && apt -y upgrade
  1. Install nginx:
apt -y install nginx
  1. Start nginx immediately:
systemctl start nginx
  1. Enable nginx to start on boot
systemctl enable nginx

Note

  • set -e ensures that the script stops if any command fails.
  • If you want to test this before running Terraform, you can manually copy the script to an existing VM and run sudo bash myinit.sh.

Allow HTTP traffic in the firewall

  1. Modify (or create) a firewall resource in your network.tf:
resource "hcloud_firewall" "ssh" {
  name = "allow-ssh"
  rule {
    direction   = "in"
    protocol    = "tcp"
    port        = "22"
    source_ips  = ["0.0.0.0/0"]
  }
  rule {
    direction = "in"
    protocol  = "tcp"
    port      = "80"
    source_ips = ["0.0.0.0/0"]
  }
}

Warning

Opening ports to 0.0.0.0/0 means anyone on the internet can access your server. In production, restrict the source IPs.

Configure Terraform to use the script

  1. Add the server resource in main.tf:
resource "hcloud_server" "web" {
  name         = "web"
  image        = "debian-12"
  server_type  = "cx22"
  firewall_ids = [hcloud_firewall.sshFw.id]
  ssh_keys     = [hcloud_ssh_key.loginUser.id]
  user_data    = file("myinit.sh")
}
  1. Apply the configuration:
terraform init
terraform apply

Verify Nginx installation

  1. After Terraform finishes, open a browser and go to:
http://<your-server-ip>

Success

You should see the default Nginx Welcome Page.

Failure

  • Check if port 80 is open: sudo ufw status or verify your firewall.
  • Check cloud-init logs on the VM: sudo cat /var/log/cloud-init-output.log.
  • Manually check service status: systemctl status nginx.

Cloud Stack Talk

cloud-init docs

Validation

Debugging

systemctl