wihan/dev

writing / post

Managing Dokploy with a Terraform provider

2026-08-30terraform · dokploy · infra1 minmarkdown

Everything behind this site is declared in one Terraform repo: the Dokploy project, a prod and a dev environment, the applications, their domains, and the Cloudflare DNS records that point at them. One terraform plan shows the whole estate. The goal state is an empty plan, and reaching it after every change is the entire workflow.

Two environments, one map

There will always be exactly two environments here, so they live in a map and a module handles the rest:

locals {
  environments = {
    prod = { branch = "master", hosts = ["wihan.dev", "www.wihan.dev"] }
    dev  = { branch = "dev",    hosts = ["dev.wihan.dev"] }
  }
}

module "app" {
  source   = "./modules/web-service"
  for_each = local.environments

  name     = "wihan-dev-app-${each.key}"
  branch   = each.value.branch
  hosts    = each.value.hosts
}

The module creates the Dokploy application, one domain per host, and one proxied CNAME per host. Adding an environment would be one map entry, which is exactly the amount of ceremony it deserves. Deploys themselves stay with Dokploy: push to a branch, the webhook fires, the right environment rebuilds.

Two lessons from running it

First: do not reach through a resource’s computed collections. The project resource returns its environments list, but the API recomputes it on every read, so every downstream reference goes unknown and the plan churns. Resolve the environment by name through a data source chain instead, and the plan settles.

Second: compose services get their reverse-proxy labels injected at deploy time. Add a domain to an already-running stack and Terraform applies cleanly while the router serves a 404, because the running containers never heard about it. The fix is one redeploy call after the domain lands. Terraform tells you what is declared; it cannot tell you what the containers were told.

The provider is vanillauys/dokploy on the registry. Building it is its own story.