frostmoln_nginx_instance (Resource)
Manages a managed Nginx webserver instance in the Frostmoln platform.
~> Terraform cannot see that an ATTACHED address depends on the VPC's gateway. This resource attaches one when public is true, and an address reaches the outside world only through a gateway — but nothing that attaches an address refers to frostmoln_gateway, so nothing orders the two. Terraform runs them concurrently and either can win.
On teardown the gateway can go first, and its delete is then refused ("Gateway is still in use", GATEWAY_IN_USE) because something in the VPC still depends on it — the failure that stops a terraform destroy half way through. On create the attachment can land first, and the platform then attaches a gateway ITSELF to carry it: a frostmoln_gateway that names a public_ip_id is refused after that ("VPC already has a gateway", GATEWAY_EXISTS), and one that names none is not refused at all — it quietly ADOPTS the gateway the platform made, leaving the VPC egressing from whatever address that gateway already had rather than one this configuration names, with origin reading implicit_public_ip.
Where the same configuration manages the gateway, state the ordering yourself: put depends_on = [frostmoln_gateway.<name>] on the resource that makes the ATTACHMENT — this one. Where the gateway is in another module, the dependency is on the module itself: depends_on = [module.<name>]. This resource is not the only one that needs it: frostmoln_apache_instance (public), frostmoln_kubernetes_cluster (public_ip_id), frostmoln_load_balancer (public_ip_id), frostmoln_public_ip_association and frostmoln_public_ip (instance_id) attach addresses too, and each takes the line on itself.
It works only where the gateway is a frostmoln_gateway RESOURCE in the same configuration. A data "frostmoln_gateway" cannot carry the order — a data source is read, never created or destroyed — so depending on one defers a read and sequences nothing.
Do not write it the other way about — on the gateway, listing what attaches. depends_on orders the resource it is written on, so that reverses both orders and turns a race that sometimes passed into a teardown that fails every time.
It changes ORDER only: nothing is created and nothing is released. It does not arm the gateway's own destroy either — without acknowledge_connectivity_loss the teardown stops at that refusal instead, and never reaches the ordering at all. And if a gateway was already adopted, nothing needs importing or rebuilding: it is in state already — add the ordering so it cannot recur, then give the gateway the address you meant with public_ip_id, which is applied in place.
Example Usage
resource "frostmoln_nginx_instance" "site" {
name = "site-1"
version = "1.30"
flavor_id = "web.gp1.small"
storage_gb = 20
vpc_id = frostmoln_vpc.main.id
subnet_id = frostmoln_subnet.public.id
php_enabled = true
php_version = "8.3"
# Curated allowlist keys — anything else is rejected by the API.
config = {
indexFiles = "index.html index.htm"
spaFallback = "true"
clientMaxBodySize = "25m"
gzip = "true"
securityHeaders = "true"
}
# Allocate and attach a public IP so the site is reachable from the internet.
# A public IP is billed for as long as it is held.
public = true
}
output "nginx_site_public_ip" {
value = frostmoln_nginx_instance.site.public_ip
}Schema
Required
flavor_id(String) The flavor ID/size for the webserver instance (e.g. "web.gp1.small", "web.gp1.medium").name(String) The name of the Nginx instance.storage_gb(Number) The storage size in gigabytes. Can be increased in place (online resize); decreasing it is not supported.subnet_id(String) The subnet ID where the webserver instance will be deployed.version(String) The Nginx version (e.g. "1.30", "1.31").vpc_id(String) The VPC ID where the webserver instance will be deployed.
Optional
config(Map of String) Engine-specific configuration applied to the webserver, as key/value pairs (sent as the engineConfig object). Keys must be from the platform's curated allowlist (e.g. gzip, securityHeaders, clientMaxBodySize, spaFallback); unknown keys are rejected. Changing this reconfigures the running instance: Terraform waits for the platform to validate the new configuration and load it into the engine (up to the platform's two-hour apply deadline, reached only when the instance's agent is unreachable), and the apply fails if the engine rejects it. Setting it to an empty map resets the engine to its boot defaults; removing the attribute leaves the current configuration in place.php_enabled(Boolean) Whether PHP-FPM support is enabled for the webserver. Fixed for the life of the instance — php-fpm is installed at boot, not by a live config apply, so changing this replaces the instance.php_version(String) The PHP version to run (e.g. "8.1", "8.2", "8.3"). Only applicable when php_enabled is true; the platform selects a supported default when omitted. Fixed for the life of the instance — changing it replaces the instance.public(Boolean) Whether the instance is publicly exposed: when true a Public IP is associated to the instance's engine port so the deployed site is reachable on the public internet, and public_ip is populated. Set at create to expose immediately; toggling it afterwards runs the platform's expose (true) or unexpose (false) action.
Setting it true makes this instance depend on the VPC having a gateway, which Terraform cannot see — see the ordering note on this resource above.
tls_enabled(Boolean) Whether TLS is enabled for the webserver.
Read-Only
created_at(String) The timestamp when the instance was created.id(String) The unique identifier of the Nginx instance.port(Number) The port number the Nginx instance is listening on.private_ip(String) The private IP address of the Nginx instance.public_ip(String) The public IP address associated with the instance while it is exposed (empty when not public).status(String) The current status of the Nginx instance.tenant_id(String) The tenant ID that owns this instance.updated_at(String) The timestamp when the instance was last updated.