Manage Your openstatus Stack with Terraform and the CLI
What you’ll learn
Section titled “What you’ll learn”| Time | ~20 minutes |
| Level | Intermediate |
| Prerequisites | openstatus account, Terraform installed, CLI installed |
In this tutorial, you’ll set up a complete monitoring stack using two tools:
- Terraform to manage your infrastructure — monitors, status pages, notifications. These are long-lived resources that change infrequently and benefit from code review, version control, and
terraform plan. - The openstatus CLI to handle operational tasks — creating and updating status reports during incidents. These are time-sensitive actions that need to happen fast, often from a terminal or a CI script.
Prerequisites
Section titled “Prerequisites”- An openstatus account (sign up free)
- Terraform installed
- The openstatus CLI installed (installation guide)
- Your API token from workspace settings (Settings > API)
What you’ll build
Section titled “What you’ll build”By the end of this tutorial, you’ll have:
- HTTP, TCP, and DNS monitors deployed via Terraform
- A public status page with grouped components
- Slack notifications wired to your monitors
- A status report workflow using the CLI for incident communication
Part 1 — Infrastructure with Terraform
Section titled “Part 1 — Infrastructure with Terraform”Step 1 — Set up the provider
Section titled “Step 1 — Set up the provider”Create a new directory for your Terraform configuration and add a main.tf file:
terraform { required_providers { openstatus = { source = "openstatusHQ/openstatus" version = "~> 0.1" } }}
provider "openstatus" { api_token = var.openstatus_api_token}
variable "openstatus_api_token" { type = string sensitive = true}Initialize the provider:
terraform initStep 2 — Define your monitors
Section titled “Step 2 — Define your monitors”Add monitors to your main.tf. We’ll create three types — HTTP, TCP, and DNS.
HTTP monitor with assertions:
resource "openstatus_http_monitor" "api" { name = "API Health Check" description = "Monitors the main API health endpoint." url = "https://api.example.com/health" periodicity = "5m" method = "GET" timeout = 30000 active = true public = true regions = ["fly-iad", "fly-ams", "fly-syd"]
headers { key = "Accept" value = "application/json" }
status_code_assertions { target = 200 comparator = "eq" }
body_assertions { target = "ok" comparator = "contains" }}TCP monitor for database connectivity:
resource "openstatus_tcp_monitor" "database" { name = "PostgreSQL" description = "Checks that the database port is reachable." uri = "db.example.com:5432" periodicity = "1m" timeout = 10000 active = true regions = ["fly-iad", "fly-fra"]}DNS monitor with record assertion:
resource "openstatus_dns_monitor" "domain" { name = "DNS Resolution" description = "Validates the A record for example.com." uri = "example.com" periodicity = "10m" active = true regions = ["fly-iad", "fly-ams"]
record_assertions { record = "A" comparator = "eq" target = "93.184.216.34" }}Step 3 — Add notifications
Section titled “Step 3 — Add notifications”Wire up a Slack notification so you get alerted when monitors fail:
variable "slack_webhook_url" { type = string sensitive = true}
resource "openstatus_notification" "slack" { name = "Slack Alerts" provider_type = "slack" monitor_ids = [ openstatus_http_monitor.api.id, openstatus_tcp_monitor.database.id, ]
slack { webhook_url = var.slack_webhook_url }}Step 4 — Create a status page with components
Section titled “Step 4 — Create a status page with components”Define a public status page and organize monitors into component groups:
resource "openstatus_status_page" "main" { title = "Example Inc. Status" slug = "example-status" description = "Real-time status for all Example Inc. services." homepage_url = "https://example.com" contact_url = "https://example.com/support"}
resource "openstatus_status_page_component_group" "services" { page_id = openstatus_status_page.main.id name = "Services"}
resource "openstatus_status_page_component_group" "infrastructure" { page_id = openstatus_status_page.main.id name = "Infrastructure"}
resource "openstatus_status_page_component" "api_component" { page_id = openstatus_status_page.main.id type = "monitor" monitor_id = openstatus_http_monitor.api.id name = "API" group_id = openstatus_status_page_component_group.services.id order = 1 group_order = 1}
resource "openstatus_status_page_component" "db_component" { page_id = openstatus_status_page.main.id type = "monitor" monitor_id = openstatus_tcp_monitor.database.id name = "Database" group_id = openstatus_status_page_component_group.infrastructure.id order = 2 group_order = 1}Step 5 — Plan and apply
Section titled “Step 5 — Plan and apply”Preview the changes Terraform will make:
terraform planYou should see all resources listed as “will be created”. Apply them:
terraform applyCheckpoint: After applying, verify everything is live:
- Open your openstatus dashboard — your monitors should appear in the Monitors tab
- Visit your status page at
https://<your-slug>.openstatus.dev— you should see your component groups and monitors
Step 6 — Update your infrastructure
Section titled “Step 6 — Update your infrastructure”To make changes, edit your .tf files and re-apply. For example, add a new region to the API monitor:
regions = ["fly-iad", "fly-ams", "fly-syd", "fly-nrt", "fly-gru"]Then:
terraform plan # Review the diffterraform apply # Apply the updateTerraform only modifies what changed — the monitor gets updated in place, no downtime.
Step 7 — Import existing resources
Section titled “Step 7 — Import existing resources”If you already have monitors or status pages created in the dashboard, import them into Terraform state:
terraform import openstatus_http_monitor.api <monitor-id>terraform import openstatus_status_page.main <page-id>terraform import openstatus_notification.slack <notification-id>After importing, run terraform plan to ensure your .tf files match the imported state. Adjust any drift until the plan shows no changes.
Part 2 — Status reports with the CLI
Section titled “Part 2 — Status reports with the CLI”Terraform is great for infrastructure, but status reports are operational — you create them when an incident is happening and update them as you investigate and resolve. The CLI is the right tool here.
Step 8 — Configure the CLI
Section titled “Step 8 — Configure the CLI”Make sure your API token is set:
export OPENSTATUS_API_TOKEN="your-api-token"Verify your setup:
openstatus whoamiStep 9 — Create a status report
Section titled “Step 9 — Create a status report”When an incident starts, create a status report and link it to your status page and affected components:
openstatus status-report create \ --title "API Elevated Latency" \ --status investigating \ --message "We are investigating increased response times on the API." \ --page-id <page-id> \ --component-ids <api-component-id> \ --notifyKey flags:
--status: The initial incident state —investigating,identified,monitoring, orresolved.--page-id: Links the report to your status page so visitors can see it.--component-ids: Marks specific components as affected (comma-separated for multiple).--notify: Sends a notification to all status page subscribers.
Step 10 — Post updates as you investigate
Section titled “Step 10 — Post updates as you investigate”As the incident progresses, add updates to the report. Each update changes the status and adds a timestamped message:
# Root cause identifiedopenstatus status-report add-update <report-id> \ --status identified \ --message "Root cause identified: a misconfigured cache TTL is causing stale responses." \ --notify
# Fix deployed, monitoringopenstatus status-report add-update <report-id> \ --status monitoring \ --message "Fix deployed to production. Monitoring response times for recovery."
# Incident resolvedopenstatus status-report add-update <report-id> \ --status resolved \ --message "Response times have returned to normal. Incident resolved." \ --notifyEach update appears on your public status page as a timeline entry, giving your users clear visibility into what happened and when.
Step 11 — Review and manage reports
Section titled “Step 11 — Review and manage reports”List recent incidents:
# All reportsopenstatus status-report list
# Only active incidentsopenstatus status-report list --status investigating
# Detailed view of a specific reportopenstatus status-report info <report-id>Update report metadata (title, affected components):
openstatus status-report update <report-id> \ --title "API Elevated Latency — Cache Misconfiguration" \ --component-ids <api-component-id>,<db-component-id>Delete a report (e.g., created by mistake):
openstatus status-report delete <report-id>Putting it all together
Section titled “Putting it all together”Here’s how the two tools fit into your workflow:
| Task | Tool | Why |
|---|---|---|
| Create/update monitors | Terraform | Version controlled, peer reviewed, reproducible |
| Create/update status pages | Terraform | Long-lived infrastructure, managed as code |
| Configure notifications | Terraform | Declarative, easy to audit |
| Report an incident | CLI | Fast, imperative, time-sensitive |
| Post incident updates | CLI | Happens in real-time during an outage |
| Trigger a monitor check | CLI | On-demand operational task |
CLI commands cheat sheet
Section titled “CLI commands cheat sheet”| Command | Description |
|---|---|
openstatus whoami | Verify your API token and workspace |
openstatus status-report create | Create a new incident report |
openstatus status-report add-update <id> | Add a status update to an incident |
openstatus status-report update <id> | Update report metadata (title, components) |
openstatus status-report list | List all status reports |
openstatus status-report list --status investigating | Filter by incident status |
openstatus status-report info <id> | View a report’s full timeline |
openstatus status-report delete <id> | Delete a status report |
openstatus monitors list | List all monitors |
openstatus monitors info <id> | View monitor details and metrics |
openstatus monitors trigger <id> | Trigger an immediate check |
openstatus status-page list | List all status pages |
openstatus status-page info <id> | View status page details and component IDs |
What you’ve accomplished
Section titled “What you’ve accomplished”You’ve successfully:
- ✅ Deployed HTTP, TCP, and DNS monitors with Terraform
- ✅ Created a status page with component groups and monitor-linked components
- ✅ Configured Slack notifications for monitor failures
- ✅ Used the CLI to manage the full lifecycle of an incident status report
- ✅ Learned when to use Terraform vs. the CLI for different tasks
What’s next?
Section titled “What’s next?”- Terraform Provider Reference — Full specification for all resources and data sources
- Run Synthetic Tests in GitHub Actions — Automate monitoring in your CI/CD pipeline
- Export Metrics to an OTLP Endpoint — Send monitor data to your observability stack
Learn more
Section titled “Learn more”- Understanding Monitoring as Code — Why manage monitors as code
- CLI Reference — Complete command documentation
- Status Report Reference — Status report properties and lifecycle
- HTTP Monitor Reference — Full HTTP monitor specification
- TCP Monitor Reference — Full TCP monitor specification
- DNS Monitor Reference — Full DNS monitor specification