Overview

Date: 2026-05-11

Time: 15:51

Overview

This is a comprehensive example script demonstrating how to use FTL2 to provision and configure a complete web application stack on Hetzner Cloud. It orchestrates cloud infrastructure (SSH keys, networks, firewalls, servers) using the hetzner.hcloud Ansible collection through FTL2's Python API, then configures the provisioned server with nginx via SSH — all in a single async script. It serves as a reference for the "dynamic provisioning workflow" pattern where FTL2 creates cloud resources and immediately configures them.

Usage Patterns

The script is invoked directly with optional flags:


uv run python example_hetzner_web_stack.py            # Full provision + configure
uv run python example_hetzner_web_stack.py --check     # Dry run (no changes)
uv run python example_hetzner_web_stack.py --teardown   # Delete all resources

The core pattern is async with automation(...) as ftl: to get an FTL2 session, then chaining module calls via attribute access on ftl:


# Cloud resource modules via collection namespace
await ftl.hetzner.hcloud.server(name="...", state="present", ...)

# Host-targeted commands after add_host()
await ftl[SERVER_NAME].command(cmd="apt-get install -y nginx")
await ftl[SERVER_NAME].ansible.builtin.service(name="nginx", state="started")

The provision-then-configure pattern is key: after creating a server, the script reads back its IP, registers it as a host with ftl.addhost(), waits for SSH with ftl.waitfor_ssh(), then runs configuration modules against it — all within the same session.

API and Configuration

automation() context manager parameters used:

Environment variables:

Hardcoded config constants: SERVERNAME, SERVERTYPE (cx22), IMAGE (ubuntu-24.04), LOCATION (nbg1), network/subnet CIDRs, firewall and SSH key names.

Key Behaviors

Relationships