Skip to content

VPC routes ​

A route sends traffic for a destination to a next hop inside your VPC. Every VPC has a route table of its own; adding a route is how you send traffic through something you run — a VPN appliance, a firewall, a proxy — instead of the path the platform gives you by default.

Routes are managed on the VPC, in Network → VPCs → your VPC → Routes, with fm network vpc route, or with the frostmoln_vpc_route Terraform resource.

List routes ​

bash
fm network vpc route list <vpc-id>

This lists the routes you own. Routes the platform provides are not shown — see Routes you cannot see or change below.

Add a route ​

A route has two parts:

  • Destination — a CIDR block, e.g. 203.0.113.0/24. An IPv4 default route (0.0.0.0/0) is allowed; an IPv6 one (::/0) is not offered yet and is refused — write the IPv6 ranges you need as more specific destinations. Write the destination in canonical form: 203.0.113.0/24, not 203.0.113.5/24, which is refused.
  • Next hop — an address on a subnet attached to this VPC, of the same address family as the destination, or the reserved word internet.
bash
fm network vpc route add <vpc-id> --destination 203.0.113.0/24 --next-hop 10.0.1.10
hcl
resource "frostmoln_subnet" "app" {
  name   = "app"
  cidr   = "10.0.1.0/24"
  vpc_id = frostmoln_vpc.main.id
  zone   = "falkenberg"
}

resource "frostmoln_vpc_route" "partner" {
  vpc_id      = frostmoln_vpc.main.id
  destination = "203.0.113.0/24"
  next_hop    = "10.0.1.10"

  # The next hop must be on a subnet the VPC has already attached. Without this,
  # a single apply can create the route first and the write is refused.
  depends_on = [frostmoln_subnet.app]
}

The next hop has to be reachable inside the VPC — an address on a subnet the VPC has attached, usually an instance of yours. It is not somewhere on the internet, and it is not an address in another VPC.

A route applies to the whole VPC

A route is matched on its destination only. There is no per-source routing on a VPC, so a route you add for one instance takes every instance in the VPC down that path for that destination. Plan routes for the VPC as a whole; if two groups of instances need different paths, put them in different VPCs.

Change a route ​

A destination can have only one next hop, so there is no edit. Adding a second route for a destination you already route is refused. To repoint one, remove it and add it again:

bash
fm network vpc route remove <vpc-id> 203.0.113.0/24
fm network vpc route add <vpc-id> --destination 203.0.113.0/24 --next-hop 10.0.1.20

Terraform does the same thing for you: every argument of frostmoln_vpc_route forces replacement, so editing next_hop destroys the route and re-creates it.

Either way there is a gap between the two steps in which that destination has no route of yours, and traffic for it follows whatever less specific route remains.

The internet next hop ​

internet is a reserved word, not an address. It means "out this VPC's own Gateway", and it exists because the platform's own default route has no address you could name. It is matched exactly and is case-sensitive — Internet is refused.

bash
fm network vpc route add <vpc-id> --destination 198.51.100.7/32 --next-hop internet
hcl
resource "frostmoln_gateway" "main" {
  vpc_id = frostmoln_vpc.main.id
  mode   = "public_ip"
}

resource "frostmoln_vpc_route" "peer_exception" {
  vpc_id      = frostmoln_vpc.main.id
  destination = "198.51.100.7/32"
  next_hop    = "internet"

  # `internet` needs the VPC to have a Gateway, so the route must be created
  # after it.
  depends_on = [frostmoln_gateway.main]
}

It needs the VPC to have an internet-facing Gateway. If the VPC has no Gateway, add one and then create the route. If it already has one but that Gateway is an internal-connectivity path rather than an internet one, adding another will not help — use an address inside the VPC as the next hop instead.

On a site whose Gateway is IPv4, internet resolves to an IPv4 address, so an IPv6 destination cannot use it there — give such a route an address inside the VPC instead.

Traffic sent this way leaves through the platform's own gateway address, which is not one you can see or keep. If the far end pins or allow-lists your source address — or initiates the connection to you — give the instance its own public IP instead, and see Gateway.

Sending a VPC through your own appliance ​

The common reason to write routes is to put a VPN or firewall appliance in the path. It takes two routes, and the second is the one people miss:

bash
# Send traffic through the appliance...
fm network vpc route add <vpc-id> --destination 0.0.0.0/0 --next-hop 10.0.1.10

# ...except the appliance's own tunnel to its remote peer.
fm network vpc route add <vpc-id> --destination 198.51.100.7/32 --next-hop internet

Without the second route the appliance breaks itself: its own encrypted packets to the remote peer match the default route and are sent back to the appliance, which loops. That exception is a /32, so it reliably wins over any less specific route.

The same goes for everything else the appliance itself needs to reach. Routes are matched on the destination only, and the appliance is an instance in the VPC like any other, so its own traffic to the internet follows the default route straight back to it. It keeps whatever it reaches through its own tunnel and loses the rest — package mirrors, NTP, an API it calls. Give each such destination its own route via internet, or send that traffic through the tunnel too.

The exception cannot name a Frostmoln address

A route's destination may not fall inside Frostmoln's own public address range, whatever next hop you give it — internet included. So if the tunnel's remote peer is itself a Frostmoln public IP, another VPC of your own included, the exception route is refused, and a default route through the appliance loops its tunnel traffic back to it. Route the specific destinations you need through the appliance instead of writing a default route: the appliance's own traffic then never matches, and no exception is needed.

The appliance may source any address — with a default route, any address at all

An instance can only forward for others if the platform stops dropping the packets it sends with somebody else's source address. The platform does that by itself for every address a route names as its next hop: you configure nothing, there is nothing to request, and the permission is written before the route is — a route whose permission cannot be written is not written either.

What it covers. Every subnet attached to this VPC, plus the destination of every route pointing at that instance. A default route's destination is the whole address space, so an appliance holding this VPC's default route may source any address at all, not only addresses in your VPC.

What that costs. Security group rules that match on a source address or on a source group no longer constrain that instance — rules that allow-list a public address included, such as your office or a partner's range. It can also claim another instance's address on the subnet, so traffic meant for that instance can be drawn to the appliance instead. This is not only about what the appliance can send.

What to do instead. Do not use source-based rules as the boundary between this instance and anything that matters. Keep it a dedicated appliance rather than a shared workload host, put what has to be protected from it in a different VPC, and where it has to share one, require authentication it cannot forge. There is no separate list of the instances holding this permission: it is exactly the set of next hops in fm network vpc route list, so review that list the way you would review an access grant.

When it goes away. When you remove the last route naming that address — that is the only thing that withdraws it. It is not bounded by the instance's lifetime. It is derived onto whichever port holds the address, so if you replace the instance and the same address comes back, forwarding stops only until the platform derives it again, normally within ten minutes and with nothing for you to do. If the replacement comes up on a different address, the route still reads fine and never forwards; repoint it. And if you give an appliance's address to some other instance while the route stands, that instance inherits the permission.

A route whose next hop is internet grants nothing — this applies only to a route naming an address inside the VPC.

Public IPs in this VPC stop serving

A default route captures all traffic leaving the VPC, replies included. An instance with a public IP still receives inbound traffic, but its reply is routed by this same table — the destination is the internet client, so it matches your default route and goes to your appliance instead of out the gateway. Public IPs in this VPC stop serving for as long as the default route exists, and start working again when you remove it.

Platform DNS and managed services keep working: they use routes more specific than a default route, which therefore win.

A default route also counts as two against this VPC's route limit.

Remember that the second route is matched on its destination, so it takes every instance in the VPC off the appliance for that one address — not just the appliance.

If the routes look right and nothing forwards ​

The permission above is derived from your routes, and there are a few ways to end up with a route that is accepted and forwards nothing. Security groups do not come into it: source filtering on the interface is a separate mechanism, and a group that allows everything does not relax it.

  • The next hop has to be an address an instance actually holds. It only has to be a valid host address on an attached subnet, so a route naming an address nobody has is accepted and silently forwards nothing. Check it against the address on the appliance's interface.
  • The permission lands on the interface the route names, not on the whole instance. An appliance with a second interface on another subnet does not have it there — if traffic leaves by that interface, point a route at that interface's address too.
  • A shared virtual address is not supported. Two appliances failing a VIP over between them with keepalived or VRRP cannot work: no interface holds the VIP, so a route naming it forwards nothing, and a route naming one appliance's own address does not follow a failover. The platform owns this permission set and rewrites it in full from your routes, so setting it on the interface by hand is no way round that.
  • At most ten ranges per appliance address. The VPC's attached subnets of the same address family are counted first, and a default route counts as two, so a VPC with many subnets can reach the ceiling with a single route — eight attached subnets alongside a default route, nine alongside an ordinary one. Above that the route write is refused. Point some routes at a second appliance, or remove some. Merging destinations into fewer, larger ranges helps only when destinations are what fills the set, and a wider destination is a wider range the appliance may use as a source.

Write 0.0.0.0/0, not the halves

Internally the platform stores a default route as two equivalent halves that between them cover the same addresses, so that it wins over the platform's own default route outright rather than sharing traffic with it. You never have to think about this: you write 0.0.0.0/0, you read back 0.0.0.0/0, and writing or deleting one of the halves directly is refused. That is deliberate — a route you wrote coming back as a different one is exactly what breaks a tool that converges on the routes you declared.

Routes you cannot see or change ​

Some routes belong to the platform. They are how a VPC reaches platform DNS and managed services, and how a VPC with a Gateway reaches the internet.

They are not listed among your routes, they cannot be removed, and a destination or next hop that collides with one is refused. That is deliberate: showing you a route you could not delete would be worse than not showing it.

Two consequences worth knowing:

  • A destination inside a range the platform routes is refused permanently, and so is any destination inside Frostmoln's own public address range — another customer's public IP and your own alike, whatever next hop you give it. Retrying will not help. Choose a destination in your own address space, or reach that address over the VPC's normal path rather than a route of yours.
  • If your VPC has an internet-facing Gateway, it already sends everything else to the internet. A 0.0.0.0/0 route via internet is therefore refused — there is nothing to add. To route the VPC through your own appliance, point the default route at an address inside the VPC, as above — and read the note in that section first.

A destination that is, or falls inside, a subnet attached to this VPC is refused too: that subnet already delivers it directly, without a route.

Remove a route ​

bash
fm network vpc route remove <vpc-id> 203.0.113.0/24

Removing a route takes away the path instances were using for that destination. Traffic then follows whatever less specific route remains — the platform's own default route, if the VPC has a Gateway, or nowhere at all if it does not.

Because a removal is applied by writing the VPC's whole remaining route set, every route in it is checked again — so a removal can be refused because of a route you already had rather than the one you are removing, and the fix is to list the routes and correct or remove that one.

A default route is removed whole. 0.0.0.0/0 takes out both of the rows the platform stores it as, in one write, or neither — so a removal cannot leave half a default route behind. Removing it hands egress back to this VPC's own Gateway, and Public IPs on instances here start serving again.

Limits ​

There is a limit on how many routes a VPC can have. It counts your routes only; the platform's own do not use it up. The same limit applies to every VPC on the platform rather than being set per customer, so if it is genuinely too low for what you are building, contact support.

For the same reason, a removal is refused if the VPC's stored routes are over the limit already: the set is still over it once one route goes. Removing them one at a time cannot get back under the limit, so contact support to have the set replaced in a single write.

A default route counts as two, because the platform stores it as two halves — so one 0.0.0.0/0 in your list uses two of the allowance.