Gateway
A Gateway is a VPC's connection to the internet. It is a resource of its own, not a setting on the VPC: a VPC has at most one, and a VPC without one has no way to the internet at all.
It carries both directions. Traffic from instances that have no public IP of their own leaves through the gateway's source address, and traffic addressed to an instance's own public IP arrives back over that same path — which is why associating a public IP in a VPC that has no gateway gives that VPC one.
What the gateway does not decide is who may reach in: that is the security group rules on the resource, and a public IP on the instance you want reached.
The three connectivity states
A VPC is always in exactly one of these. A VPC that has a gateway always leaves from one public address; what you choose is where that address comes from.
| Outbound internet | Source address the far side sees | Public IPs used | |
|---|---|---|---|
| No Gateway | No — isolated | — | 0 |
| Gateway, the default address | Yes | An address the platform picks. Shown nowhere, and redrawn if the gateway is rebuilt | 0 |
| Gateway, a public IP you name | Yes | The public IP you named — stable, and yours | 1, from your tenant quota |
"No Gateway" is the absence of the resource, not a mode and not a switch you turn off. There is no such thing as a gateway with no address: either the VPC has a gateway, or it has none.
Which one do you want
- The default address — the right choice whenever nothing on the far side cares which address you arrive from: package mirrors, public APIs, webhooks you send, software updates. You get it by asking for a gateway and naming no address. It costs you nothing: it uses none of your public IP quota, it appears in no list of yours, it has no id, and it never reaches an invoice. What it cannot do is stay the same — see the warning below.
- A public IP you name — choose it when a remote peer allow-lists your source address, or when the address goes into DNS: a partner API, a customer firewall, an SFTP endpoint that only accepts known addresses. The address is a public IP of your own that you select. It is listed among your public IPs, it counts against your tenant's public IP quota, it is billed as a public IP, and it is pinned — it keeps its address even if the gateway or the VPC is removed and rebuilt. See Choose the address the gateway uses.
- No gateway — the right answer for a VPC that must not talk to the internet at all: an isolated back-end tier, a data-processing network reached only from other resources in the same VPC. It spends nothing.
Only an address you named is safe to publish or have allow-listed
The default address is not yours and is not stable. It is drawn by the platform, it is not a resource you own, it appears in no public IP list, and it is redrawn whenever the gateway or the VPC is rebuilt. It also does not outlive the gateway.
So it must never be given to a partner for an allow-list, never be put in a customer's firewall, and never be published in a DNS record. When the address changes — and nothing warns you before it does — that traffic simply stops being accepted.
If anyone outside your VPC needs to know the address your traffic comes from, name a public IP of your own. That is the only address on this page with a promise attached to it.
Removing a Gateway costs more than internet access
The VPC's name resolution (DNS) and its connectivity to managed services travel the same path. Remove the Gateway and the VPC loses all three at once: no outbound internet, no DNS, and no managed-service connectivity. Resources inside the VPC keep running and keep talking to each other over private addresses — but anything that resolves a hostname or reaches a managed service stops working.
This is why every surface makes you state the intent explicitly: a confirmation in the portal, a flag on the CLI, an approved plan in Terraform.
Choose connectivity when you create a VPC
Creating a VPC takes an optional connectivity choice — none or public-ip. Omitting it means none: nothing is provisioned, so a VPC never acquires outbound connectivity because a field was left out.
In the portal, Network → VPCs → Create asks for the choice and pre-selects nothing.
fm network vpc create --name my-vpc --cidr 10.0.0.0/16 --gateway public-ip
fm network vpc create --name my-vpc --cidr 10.0.0.0/16 --gateway noneThe CLI spells the connected choice public-ip and accepts public_ip too. It gives the VPC a gateway on the default address; naming a public IP of your own is done on the gateway itself, below.
Verify the gateway after the VPC is created
The create-time choice is applied best-effort, and after the VPC itself exists. The VPC is created first; the gateway is provisioned in a follow-up step, and a failure there is deliberately not fatal to the VPC — a platform capacity limit, an error setting up the outbound path or a failure to record it leaves you with the VPC you asked for, without a gateway, and the create still reports success.
So confirm it afterwards rather than assuming:
fm network gateway get --vpc-id vpc-abc123or look at the VPC's connectivity panel in the portal — which checks for you and warns if the choice you made was not applied. If the VPC ended up without one, nothing was spent and nothing is broken: add one with fm network gateway create (below).
Terraform is deliberately different. frostmoln_vpc has no connectivity argument, because a VPC that created a gateway on the side would own an object Terraform does not manage. In Terraform the connectivity choice is the presence or absence of that resource.
That matters for a VPC that did not start in Terraform, and the failure mode is quieter than you would expect. If the VPC already has a gateway — chosen at create, or attached by the platform when a public IP was associated — then declaring frostmoln_gateway for it does not necessarily fail. A resource that names no public_ip_id adopts the gateway that is already there: Terraform reports a create it did not perform, and the VPC keeps going out through whatever address that gateway already had — the one the platform drew, or one chosen earlier from the portal or the CLI, but not one this configuration names. It is normally refused with GATEWAY_EXISTS only when the resource names a public_ip_id that the existing gateway does not have. To manage a gateway that already exists, import it instead of declaring a new one.
Whichever way the VPC starts, the gateway resource below is how you add, change or remove connectivity afterwards — the create-time choice cannot be re-stated on a VPC that already exists.
Add a Gateway to an existing VPC
Adding one is non-destructive: instances keep running and keep their addresses, they simply gain a way out.
In the portal
Open Network → VPCs, then the VPC. The Gateway panel shows whether the VPC has one and the address its outbound traffic appears to come from. Adding one asks where that address should come from: the platform's default address, or one of your own public IPs, which you then pick from a list. Once the gateway exists, the panel offers Remove Gateway, and — while the gateway is on the default address — Make this address mine, which is described under Make the gateway's address your own.
From the CLI
fm network gateway manages a VPC's gateway:
# Every gateway in the tenant. A VPC with none is simply absent from the list.
fm network gateway list
# One VPC's gateway
fm network gateway get --vpc-id vpc-abc123
# Give a VPC outbound access on the default address — --mode is required and
# never defaulted
fm network gateway create --vpc-id vpc-abc123 --mode public-ip
# ...or going out through a public IP you already hold
fm network gateway create --vpc-id vpc-abc123 --mode public-ip --public-ip-id pip-xyz789
# Point an existing gateway at a different public IP of yours — --yes confirms
# the interruption
fm network gateway set-mode --vpc-id vpc-abc123 \
--mode public-ip --public-ip-id pip-xyz789 --yes
# Remove it — --yes confirms the loss of internet, DNS and managed services
fm network gateway delete --vpc-id vpc-abc123 --yes--mode takes public-ip (public_ip is accepted too) and is never defaulted: connectivity is a stated choice, never one a VPC acquires because a flag was left out.
--public-ip-id names the public IP the VPC should go out through, and it is optional:
- Leave it out and the gateway takes the platform's default address. Nothing is allocated to you, nothing appears in
fm network public-ip list, and nothing is billed. The address is not stable. - Name one and that public IP becomes the VPC's source address — listed, counted against your quota, billed as a public IP, and pinned.
Omitting --public-ip-id does not allocate an address for you
It used to. It no longer does: an omitted --public-ip-id now means "use the platform's default address", which is hidden and unbilled — not "allocate a public IP on my behalf". Nothing appears in your public IP list as a result of creating a gateway without naming one, and nothing there is safe to allow-list.
Scripts written against the old behaviour keep working and keep the VPC connected; what changes is that they no longer produce an address you can look up, publish, or hand to a partner. If yours relied on that, allocate a public IP and name it explicitly.
Worth knowing when you script this:
get -o jsonalways emits a list of zero or one gateway — the same shapelistemits — so the samejqworks whatever the answer:bashfm network gateway get --vpc-id vpc-abc123 -o json | jq -r '.[0].mode // empty'createagainst a VPC that already has a gateway is an idempotent replay: it reports the existing gateway, and nothing is created or spent. Naming no address replays too — an omitted address means "keep whichever address the gateway has", so it never re-addresses anything. Only acreatethat names a different address is refused (GATEWAY_EXISTS); useset-modefor that. The same rule is what makes Terraform adopt a gateway it did not create.set-modethat asks for what the gateway already has is a no-op, and needs no--yes.set-modewith no--public-ip-idnever takes an address away. Omitting it means "keep whichever address the gateway has", not "go back to the default address" — otherwise every tool that has never heard of the flag would un-pin your chosen address behind your back. Giving a chosen address back is deliberate, and is described under Give a chosen address back.deleteexits non-zero for a--vpc-idit cannot confirm exists. An empty gateway lookup looks identical for "this VPC has none", "unknown id" and "another tenant's VPC" — so a decommission script pointed at a stale or mistyped id learns that it did nothing, instead of being told the gateway is gone while it is still attached.For the same reason,
geton a VPC with no gateway says so rather than failing. Pair it withfm network vpc get <vpc-id>, which does report a missing VPC.
With Terraform
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
}
# The address outbound traffic appears to come from. On a gateway with no
# public_ip_id this is the platform's address — read it for troubleshooting,
# never to publish it.
output "gateway_source_address" {
value = frostmoln_gateway.main.source_address
}public_ip_id names the address to go out through, and is what you declare when the address has to be stable:
resource "frostmoln_public_ip" "gateway" {}
resource "frostmoln_gateway" "main" {
vpc_id = frostmoln_vpc.main.id
mode = "public_ip"
public_ip_id = frostmoln_public_ip.gateway.id
}public_ip_idis optional. Omit it and the gateway uses the platform's default address: the VPC has outbound connectivity, nothing is allocated to your tenant, and nothing is billed. The attribute stays null — the platform reports no id back, because there is no resource of yours to report.Declaring it as its own
frostmoln_public_ipis the point. The address then outlives the gateway: destroy and recreatefrostmoln_gateway.main, or the whole VPC, and the samefrostmoln_public_ipis attached again with the same address.Removing the attribute again does not give the address back. Terraform keeps the recorded value and plans no change, because an omitted
public_ip_idmeans "keep what you have" rather than "revert to the platform address". To move the gateway onto a different address, name the different address; to go back to the platform's, see Give a chosen address back.Changing
public_ip_idis applied in place — never a destroy and recreate. It does re-address the VPC's traffic and drop existing connections, so it needsacknowledge_connectivity_loss = true.modetakespublic_ip. Anything else is refused while the plan is validated, so a configuration that still sets it fails before anything is applied. Note the spelling: the CLI also accepts the hyphenatedpublic-ip, so a value copied out of a CLI command has to be rewritten with the underscore here.acknowledge_connectivity_lossis an optional bool that arms the resource for a destroy or apublic_ip_idchange. The provider refuses both without it, before any request is sent. Set it totrue, apply, then destroy or make the change — and remove the line again afterwards. Left in place it disarms the control for the life of the resource: a laterterraform destroy -target, a module removal, or avpc_idchange would then disconnect the VPC with nothing in the plan beyond an ordinary "will be destroyed".vpc_idis what forces replacement — and that replacement destroys the existing gateway first, which is refused unless the acknowledgement is already applied.source_address,statusandoriginare read-only. After apublic_ip_idchange the platform re-records the address, so it plans as "(known after apply)".Import by the gateway's id or by the VPC's id (a gateway with no stored record is only addressable by VPC id). An imported gateway is never pre-acknowledged.
bashterraform import frostmoln_gateway.main vpc-abc123
Order attached addresses against the gateway
An address attached to something needs the VPC to have a gateway — but nothing that attaches one refers to frostmoln_gateway, so Terraform sees no relationship between them and runs the two concurrently. That covers frostmoln_public_ip (through its instance_id), frostmoln_public_ip_association, frostmoln_load_balancer, and frostmoln_kubernetes_cluster (public_ip_id). Either can win, and both wrong orders bite:
- On teardown the gateway can go first, and its delete is then refused with
GATEWAY_IN_USE— the destroy stops half way through, with part of the stack already gone. - On create the attachment can land first, and the platform attaches a gateway itself to carry it. Your
frostmoln_gatewaythen either collides with it (GATEWAY_EXISTS, if it names apublic_ip_id) or silently adopts it, as above.
This applies 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. If the gateway is not yours to manage, import it first.
Say the order yourself, on the resource that makes the attachment:
resource "frostmoln_public_ip_association" "web" {
public_ip_id = frostmoln_public_ip.web.id
instance_id = frostmoln_instance.web.id
depends_on = [frostmoln_gateway.main]
}The same line goes on any of the others: a frostmoln_public_ip whose own instance_id makes the attachment, a frostmoln_load_balancer with scheme = "public", a frostmoln_kubernetes_cluster that names a public_ip_id. Where the gateway lives in another module, point the dependency at the module: depends_on = [module.network].
Four things worth knowing before you copy it:
- It belongs on the attachment, not the allocation. An address that is only allocated depends on nothing — and an address looked up with the
frostmoln_public_ipdata source has no allocation resource to hang it on. - Never put it on the address your
frostmoln_gateway.public_ip_idnames. The gateway already depends on that address, so a dependency back the other way is aCycle:error at plan time. That address is already ordered correctly. - Never write it the other way about — on the gateway, listing the addresses. That is the tempting mistake, because the gateway is what has to exist first; but
depends_onorders the resource it is written on, so it 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 — and it does not arm the gateway's own destroy, which still needs
acknowledge_connectivity_lossfirst.
If a gateway was already adopted, the tell is origin: it reads implicit_public_ip or vpc_create rather than explicit, and source_address is an address you never chose. You do not need to import or rebuild anything — the resource is already in state. Add the ordering so it cannot recur, then give the gateway the address you meant by setting public_ip_id, which is applied in place and needs acknowledge_connectivity_loss = true.
To read a gateway you do not manage — one chosen at VPC create, or attached when a public IP was associated — use the data source:
data "frostmoln_gateway" "production" {
vpc_id = frostmoln_vpc.production.id
}
# Safe to hand to a partner ONLY if this gateway has a public_ip_id. Without one
# the value is the platform's address, which is redrawn on a rebuild.
output "gateway_source_address" {
value = data.frostmoln_gateway.production.source_address
}Choose the address the gateway uses
Every Gateway has one source address. It is either the platform's, or one of your public IPs — the same resource you allocate, list and release yourself. You decide which:
- Name an address you hold. Allocate a public IP (or reuse an
availableone) and name it when you create the gateway, or point an existing gateway at it. That address is listed among your public IPs, counts against your quota, is billed as a public IP, and is pinned onto the gateway. - Or name nothing. The gateway takes the platform's address. Nothing is allocated to you, nothing is listed, no quota is drawn and nothing is billed — and the address is not stable.
Why name the address yourself
Because the address is then a resource of yours, it outlives the gateway. Remove the Gateway, or delete the VPC and build it again from scratch: the public IP stays allocated to your tenant, keeps its id and keeps its address, and pointing the new gateway at it restores exactly the address you had before.
That is what makes the address safe to give out:
- to a partner or supplier who allow-lists the address your traffic arrives from,
- to a customer whose firewall only accepts known sources,
- in a DNS record you publish.
The platform's default address makes no such promise. It is not yours, it is in no list, it is redrawn if the gateway or the VPC is rebuilt, and it does not outlive the gateway. Never hand it to anyone who intends to allow-list it, and never publish it.
Give a chosen address back
Going the other way — from a public IP of yours back to the platform's address — is deliberate, because no client can do it by accident. Omitting the address is read as "keep what you have", so the way back is to remove the gateway and create it again without naming an address:
fm network gateway delete --vpc-id vpc-abc123 --yes
fm network gateway create --vpc-id vpc-abc123 --mode public-ipThe public IP returns to your list with its id and its address intact, as an available address you still hold — releasing it is a separate, permanent act. Between the two commands the VPC has no outbound internet, no DNS and no managed-service connectivity, so treat it as a short maintenance window.
While the address is attached to a gateway
A public IP in use by a Gateway is in use, so:
- it cannot be associated with an instance — give that instance a different address, and
- it cannot be released — releasing gives the address up for good, which is the one thing the gateway is there to prevent.
Detach it first and both become possible again. Detaching means: point the gateway at a different public IP, or remove the gateway. The address then goes back to being an ordinary available public IP of yours — still allocated to your tenant, and still counting against your quota, until you release it.
It does not override an instance's own public IP
An instance that has its own public IP still goes out through that address. The gateway's address is the source only for traffic from instances that have none. So choosing an address for the gateway changes nothing about how your public-facing instances appear to the outside world.
Make the gateway's address your own
A gateway on the platform's default address can have that exact address turned into a public IP you own, without the address changing. It is the one action on this page that changes nothing about your traffic:
- The address stays exactly the same. Nothing is moved and nothing is restarted; there is no interruption.
- Afterwards it appears in your public IP list and is pinned, so it survives the Gateway or the VPC being recreated — the same promise as naming an address yourself.
- From then on it counts against your public IP quota and is billed as a public IP. That is the whole reason this is your choice rather than something done for you.
fm network gateway adopt-public-ip --vpc-id vpc-abc123In the portal, the VPC's Gateway panel offers Make this address mine.
This is the right move when an address you were never meant to publish has already been published — it is the only path from the default address to a stable one that does not change the address, so allow-lists and DNS records that already carry it keep working.
Adopting twice is harmless — the second time changes nothing and reports the same address. It applies only to a gateway that is not already going out through a public IP you chose; one that is has nothing to adopt.
What a gateway tells you
| Field | Meaning |
|---|---|
| Source address | The public address outbound traffic appears to come from. Safe to allow-list only when a public IP is shown below; otherwise it is the platform's, and it changes. Empty while the address is not yet known. |
| Public IP | The public IP the gateway goes out through, when you named one. Its address is the source address, and it stays yours when the gateway goes away. Empty means the gateway is on the platform's default address — the one you must not publish. |
| Status | Observed from the platform, not from stored settings: active, or detached. |
| Origin | Who asked for the gateway (below). |
Origin values:
explicit— created directly, through the portal, the CLI, Terraform or the API, without naming an address.explicit_public_ip— created directly, likeexplicit, and the public IP it goes out through was named by you. Kept separate because that address is your own resource: it is handed back to you rather than to the platform when the gateway lets it go.implicit_public_ip— added by the platform because a public IP was associated in this VPC. Inbound and outbound share the same path, so associating a public IP in a VPC that had no gateway gives it one.vpc_create— it came with the VPC, from a connectivity choice made when the VPC was created. Only that choice records this origin.legacy— unknown. No record exists of who asked for this gateway. That is usually because the VPC predates the resource, but not always — read it as "unknown", never as "old".
Changing the source address
Pointing a gateway at a different public IP of yours is applied in place: the gateway keeps its identity and nothing is destroyed and recreated. It is, however, an interruption — not a silent hot-swap:
- The source address changes. Anything that allow-lists your old address stops accepting your traffic until the new one is added on their side. Because you name the new address, this is the one case where you know it in advance.
- In-flight connections drop. Sessions open across the change are broken and have to reconnect.
- It requires an explicit acknowledgement, and that is what it acknowledges: the changed source address and the dropped connections.
This is not a removal. Internet access itself continues, and DNS and managed-service connectivity are not part of what the change costs.
Naming an address spends one address from your tenant's quota and puts it on your invoice as a public IP. The address you point away from is detached: it stays allocated to your tenant, keeps its address, and becomes available again, so a later change back can use the very same address.
Portal — the VPC's Gateway panel, then confirm.
CLI:
bashfm network gateway set-mode --vpc-id vpc-abc123 \ --mode public-ip --public-ip-id pip-xyz789 --yesTerraform — apply
acknowledge_connectivity_loss = truefirst, then changepublic_ip_idand apply again, then remove the acknowledgement line.
Treat it as a short maintenance window. The platform reserves what the change needs before it takes the old address down, so if it cannot be carried out it is refused and the VPC is left exactly as it was.
Remove a Gateway
This removes DNS and managed-service connectivity too
The VPC loses outbound internet, name resolution and managed-service connectivity together. Resources inside keep running; anything that resolves a name or talks to a managed service stops working.
Portal — Remove Gateway on the VPC, then confirm.
CLI —
--yesis the confirmation, and the command refuses without it:bashfm network gateway delete --vpc-id vpc-abc123 --yesTerraform — set
acknowledge_connectivity_loss = trueand apply, then remove the resource (orterraform destroy). Without it applied first, the destroy fails rather than silently disconnecting the VPC.
Removal is refused while public IPs in the VPC still depend on the gateway. Disassociate them first — it is free, reversible, and enough to clear the check:
fm network public-ip disassociate <public-ip-id>Releasing them clears the check too, but releasing is permanent: the address goes back to the platform, is handed out again to whoever asks next, and you cannot get it back. Only release an address you are certain you will never want.
Deleting the VPC itself removes its gateway along with it.
The gateway's own address is not one of those blockers. If it is a public IP of yours, it is detached for you when the gateway goes and stays allocated to your tenant as an available public IP with the same address — removing the gateway does not give it away, only releasing the public IP does. If it is the platform's default address, it simply goes with the gateway; there was never anything of yours to keep.
One exception, on older VPCs. A gateway whose Origin is vpc_create may hold a public IP the platform allocated when the VPC was created — from before naming an address became the only way to get one of your own. You never asked for a standing address, so that one is released when the gateway is removed, rather than left allocated and billed. Releasing is permanent. If that address matters to anyone outside your VPC, note it before you remove the gateway.
If a request is refused
Every refusal carries a machine-readable code alongside the message. Match on the code, not on the message — the wording is free to improve, the code is not. All of these codes were renamed with the resource: what used to read EGRESS_* now reads GATEWAY_*, and nothing answers to the old spelling.
| What you see | Code | What it means |
|---|---|---|
| The VPC already has a Gateway | GATEWAY_EXISTS | A VPC has at most one. Change the address it uses instead of adding a second. In Terraform this fires only when the resource names a public_ip_id; one that names none adopts the existing gateway silently — see Order attached addresses against the gateway. |
| Public IPs still depend on the gateway | GATEWAY_IN_USE | Disassociate the VPC's public IPs — free and reversible — then remove the gateway. Releasing them works too, but is permanent. In Terraform this is usually an ordering problem — see Order attached addresses against the gateway — unless a managed resource in the VPC holds the address, which the message says. |
| No public addresses are available in this region | GATEWAY_POOL_EXHAUSTED | A platform capacity limit, not your quota — asking for more quota will not help. Retry later. |
| Your public IP quota is exhausted | a quota error, not a gateway one | Only naming an address — or adopting one — draws quota, so this never blocks a gateway on the default address. Release an address you are not using, or ask for more quota. |
| The public IP cannot be used as the source address | GATEWAY_PUBLIC_IP_UNAVAILABLE | The address you named is associated with an instance or load balancer, is already attached to another VPC's gateway, or is not an address that can carry a VPC's traffic. Free it, or pick another. The message names which of the three it is. |
| Removing the gateway was not acknowledged | GATEWAY_LOSS_NOT_ACKED | Removal takes internet, DNS and managed-service connectivity with it, so it has to be stated: --yes on the CLI, acknowledge_connectivity_loss = true in Terraform. |
| The mode switch was not acknowledged | GATEWAY_MODE_SWITCH_NOT_ACKED | A mode switch re-addresses the VPC and drops open connections. Distinct from removal, because you come back online rather than going dark. |
| The source-address change was not acknowledged | GATEWAY_SOURCE_ADDRESS_CHANGE_NOT_ACKED | Pointing the gateway at a different public IP changes the address the far side sees and drops in-flight connections; acknowledge it the same way. |
| The public IP is held by a gateway | PUBLIC_IP_IN_USE_BY_GATEWAY | Returned on the public IP, not the gateway: an address a gateway goes out through can neither be associated with an instance nor released. Detach it from the gateway first. |