Skip to content

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_application_gateway (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.

Authoritative scope — who owns what on this resource, declared in internal/scopedecl and machine-checked against the schema.

Enacted and reconciled — every configurable attribute not listed below: the platform applies it, and a refresh reads the truth back.

Create-immutable — php_enabled, php_version, subnet_id, version, vpc_id: the managed offer has no in-place migration for it — a change re-creates the instance.

Observed, not enacted — private_ip: platform-assigned from the subnet at create. public_ip: platform-allocated and attached when public is true. security_group_id: the platform creates and owns the managed group; reads succeed but every write is refused (409 resource_in_use), permanently. tags_all: keys set outside Terraform — in the portal, by the fm CLI, or stamped by the platform — appear only here and are kept on every apply, never removed.

Platform-invented default — security group provisioned for the managed web server: keep-with-docs. Platform-provisioned and platform-owned; do not import it as a frostmoln_security_group — applies including destroy are refused.

Example Usage ​

terraform
resource "frostmoln_nginx_instance" "site" {
  name       = "site-1"
  version    = "1.30"
  flavor_id  = "web.co1.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

  # Resource tags: your own metadata for search and filtering. Merged with
  # the provider's default_tags; changing them updates in place.
  tags = {
    env = "prod"
  }
}

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.co1.small", "web.co1.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) Type-specific configuration applied to the webserver, as key/value pairs (sent as the typeConfig 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 server (up to the platform's two-hour apply deadline, reached only when the instance's agent is unreachable), and the apply fails if the server rejects it. Setting it to an empty map resets the instance 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 service 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.

  • tags (Map of String) Resource tags on the instance: your own key/value metadata for search and filtering (?tag=key=value in the API, --tag in the fm CLI), stored by the platform only and never applied to the web server. Changing them updates the instance in place and does not restart or reconfigure it. At most 32 keys including the tenant's default tags, which the platform merges in at create; a key is 1-64 bytes matching ^[a-zA-Z0-9]([a-zA-Z0-9._:/-]*[a-zA-Z0-9])?$, a value at most 256 bytes; keys beginning frostmoln_ or frostmoln- (any case) are reserved. Merged with the provider's default_tags on every write (a key set here wins). Holds only the keys this configuration sets; the full set is in tags_all.

  • timeouts (Block, Optional) (see below for nested schema)

  • 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).
  • security_group_id (String) The platform-managed security group attached to this instance. The platform creates and owns it: the group is not intended for customer modification, and changes to it are normally rejected. Do not import it as a frostmoln_security_group -- reads succeed, but applies including destroy are refused. It allows inbound tcp/80 and tcp/443 from any source (0.0.0.0/0), and outbound is unrestricted. Empty until the instance has finished provisioning.
  • status (String) The current status of the Nginx instance.
  • tags_all (Map of String) Every tag the platform holds on this resource: the provider's default_tags, this resource's own tags (which win on a shared key), and any key set outside Terraform — in the portal, by the fm CLI, or stamped by the platform. Keys set outside Terraform appear only here and are kept on every apply, never removed.
  • tenant_id (String) The tenant ID that owns this instance.
  • updated_at (String) The timestamp when the instance was last updated.

Nested Schema for timeouts ​

Optional:

  • create (String) How long the provider waits for the create operation to converge before giving up (e.g. "45m", "2h").
  • delete (String) How long the provider waits for the delete to complete before giving up (e.g. "30m").
  • update (String) How long the provider waits for an update (resize, in-place change) to converge before giving up (e.g. "30m").