How networking works
Every instance gets its address, its neighbors, and its reachability from a virtual private cloud (VPC) that you own. This page explains what the network objects are, how they nest, what the platform decides for you, and what happens to a packet between the guest and the wire.
The objects you own
Networking is built from seven tenant-visible objects. Each one belongs to a project, and every project belongs to a tenant. You never name your tenant when you use the CLI: it is carried in your credentials.
| Object | What it is | Parent |
|---|---|---|
| VPC | An isolated network with its own address plan | Project |
| Subnet | A block carved out of the VPC that instances attach to | VPC |
| Route table | A named set of routes | VPC |
| Route | One destination CIDR and where to send it | Route table |
| Firewall rule | One allow or deny match | VPC |
| NAT gateway | A public source address for outbound traffic | VPC |
| Floating IP | A public address you attach to one instance NIC | Project |
A VPC carries a 24-bit Geneve virtual network identifier (VNI) that the platform
assigns at create time. Tenant VNIs come from the range at or above 4096; values
below that are reserved for platform use. The VNI is what keeps two tenants both
using 10.0.0.0/16 from ever seeing each other's packets. It is stamped into the
outer header of every encapsulated frame and bound before the dataplane engine
sees the packet.
Two more project objects use the network: an external IP, a public address held in the project and bound to at most one consumer, and a load balancer, which sits in one subnet and sends traffic from its listeners to pools of instances. This page does not cover them.
The API addresses every object by UUID. tritonctl also accepts a name or a UUID
prefix, and resolves it by listing the objects of your project.
VPCs and subnets can be renamed and given a new description, and a subnet's SSH relay can be turned on or off. Their address blocks, and a VPC's VNI, never change. A firewall rule can be changed in place, and a subnet can be moved to another route table in its VPC. Route tables, routes, NAT gateways, and floating IPs have no update operation. Changing one means deleting it and creating its replacement.
Address plans nest strictly
A VPC declares an IPv4 block, an IPv6 block, or both. At least one is required; a VPC with neither is rejected, because the dataplane has no way to represent it.
Both blocks must come from private address space: 10.0.0.0/8, 172.16.0.0/12,
192.168.0.0/16, or 100.64.0.0/10 for IPv4, and fd00::/8 for IPv6. A VPC
holding a public prefix would capture traffic meant for that prefix on the
internet, so a public block is rejected at create time.
Each subnet then carves blocks out of the parent. Three rules are enforced when the subnet is created, not when the first packet moves:
- A subnet block must sit inside the VPC's block of the same family. A
10.0.1.0/24subnet inside a10.0.0.0/16VPC is valid; inside a10.1.0.0/16VPC it is rejected. - A subnet cannot declare a family the VPC does not have. An IPv4-only VPC cannot host an IPv6 subnet.
- Two subnets in the same VPC cannot overlap in either family.
Subnets are where instances attach. An instance names one subnet as its primary when you create it, and the platform allocates that instance a NIC with a MAC address and one address per family the subnet carries. The MAC is locally-administered, generated by the control plane, and unique across the whole installation, because the dataplane resolves each frame by its VNI and MAC pair.
Addresses are assigned, not requested
No DHCP server runs on your network. The control plane picks the address when it creates the NIC, and the compute node hosting the instance synthesizes the DHCP reply from that assignment when the guest asks for one. The reply always carries the address the platform already recorded, and a request asking for a different address is refused.
Three addresses in every IPv4 subnet are never handed out:
- the network address,
- the network address plus one, which is the virtual gateway,
- the broadcast address.
The virtual gateway is the default gateway your guest sees. It is not a device anywhere on the network. It is a set of rules inside the compute node's dataplane that answers ARP for that address and terminates traffic sent to it, which means the gateway has no failure mode independent of the compute node itself.
The synthesized reply carries a default lease of 86400 seconds, an MTU of 1500,
the virtual gateway as both the router and the sole DNS server, and a domain name
of your VPC's name followed by .vpc.local. The lease and additional raw DHCP
options are tunable per VPC and per MAC address through the API; tritonctl has
no command for that surface.
Routing is per subnet, and an absent route drops
Creating a VPC also creates its route table, named main, in the same operation.
Every new subnet starts out associated with that table. The main table cannot be
deleted on its own; it goes away with the VPC.
A route pairs a destination CIDR with a target. Four targets are available to you:
| Target | Behavior |
|---|---|
| Virtual gateway | Hand the packet to the VPC's virtual gateway |
| NAT gateway | Forward to a NAT gateway in the same VPC |
| Blackhole | Drop the packet |
| Reject | Drop the packet |
A fifth target, floating IP, exists in the data model but is reserved for routes the platform installs. Creating one through the API is rejected. Blackhole and Reject are distinct in the data model and describe different intents, but the dataplane compiles both to a drop today; neither returns an ICMP unreachable.
Lookup is longest-prefix match: a /24 route wins over a /0 route for an address
both cover. Two properties of this layer are worth internalizing.
A packet with no matching route is dropped. Outbound routing is default-deny. A newly created route table is empty, so a fresh VPC gives its instances no path off the VPC until you add a route or attach a floating IP.
Traffic inside the VPC does not depend on your routes. The platform adds permits covering the port's own subnet blocks, so instances in a subnet can always reach each other even when the route table is empty. An explicit route you write that covers the same prefix takes precedence over the synthesized permit.
Several other entries appear in the compiled table that never show up in your route listings, because they describe the wire rather than your intent: a route covering the local subnet for cross-compute-node delivery, a host route for the instance metadata address when metadata is enabled, and a default route out the compute node's external link when a floating IP is attached to that NIC. They are recomputed on every apply and never stored.
Route tables other than main can be created and deleted. A subnet starts on the
VPC's main table, and the API can move it to any other table in the same VPC
(PUT /v1/subnets/{subnet_id}/route-table), which changes the routes every NIC on
that subnet gets. A table in another VPC is refused. tritonctl has no command
for the move, so from the CLI a second route table holds routes that no packet
consults.
Firewall rules are per VPC and stateful
A firewall rule belongs to a VPC. An inbound rule applies to the instances whose address is inside its destination CIDR, and an outbound rule to the instances inside its source CIDR. A rule with no CIDR on that side applies to every instance in the VPC. There are no security groups to attach.
A rule matches on direction (inbound or outbound), protocol (any, tcp, udp,
icmp4, or icmp6), a source CIDR, a destination CIDR, and inclusive source and
destination port ranges. An omitted CIDR matches anything. Port ranges are valid
only with tcp or udp; a rule that sets ports on any other protocol, including
the default any, returns 409 Conflict. The API also accepts an ICMP type and code
filter, valid only when the protocol is icmp4 or icmp6; tritonctl does not
set it.
Every rule carries a required priority, from 0 to 1000. Priorities from 30000
up are reserved for the platform. Higher values are evaluated first. When rules of the same direction share a priority, an inbound
allow wins over an inbound deny, and an outbound deny wins over an outbound allow.
A rule can be disabled without deleting it. A disabled rule stays listed but has
no effect.
Allow rules are stateful. The dataplane installs a flow entry so return traffic is recognized without re-evaluating the rule table, and for TCP it runs a connection state machine that drops out-of-state packets.
Outbound traffic is allowed by default. No rule is needed for an instance to initiate connections. What stops outbound traffic is the routing layer, or an egress limit that the operator of your cloud sets. You cannot widen an operator egress limit with a firewall rule.
Inbound traffic is denied by default. Only traffic that matches an allow rule gets
in. A new VPC gets the two intra-VPC rules below, and each new overlay subnet adds
its platform-access- rules:
| Rule | Allows |
|---|---|
default-allow-intra-vpc | All inbound traffic from the VPC's own IPv4 block |
default-allow-intra-vpc-v6 | The same for the VPC's IPv6 block, when it has one |
platform-access-<SUBNET_UUID> | TCP port 22 from the platform SSH relay address of one subnet, to the instances in that subnet |
platform-access-<SUBNET_UUID>-v6 | The same over IPv6, when the subnet has an IPv6 relay address |
External subnets get no platform-access- rules.
The intra-VPC rules belong to you. Delete them to stop instances in the VPC from
reaching each other. Delete a platform-access- rule to withdraw SSH access
through the platform relay for that subnet. If a VPC has no enabled rules at
all, the dataplane still allows traffic from inside the VPC. Apart from the ICMP messages
the network needs to work (IPv4 destination unreachable, IPv6 packet too big, and
IPv6 neighbor discovery), nothing from outside the VPC reaches an instance until
you add an allow rule for it.
Reaching the outside
Two objects give a VPC a path off itself, and they solve different problems.
A floating IP is a public address owned by your project, not by any instance. You allocate it, then attach it to one NIC. The attachment is one-to-one NAT: outbound packets from that NIC get their source rewritten to the floating IP, and inbound packets to the floating IP get their destination rewritten to the NIC's private address. Attaching also gives that NIC a default route out the compute node's external link, which is what makes the address usable for outbound traffic and not for inbound traffic alone.
Because the address belongs to the project, deleting an instance detaches the floating IP but never releases it, and attaching it to a replacement instance keeps the address stable. Attaching to a second NIC replaces the binding in a single transaction rather than passing through a detached state, and moving one between compute nodes always releases the old binding before the new one is allowed to claim it. Deleting a floating IP requires it to be detached first.
A NAT gateway is a public source address for a VPC's outbound traffic. It reserves one public IPv4 address when you create it, and it carries no traffic until a route names it as a target. NAT gateways serve IPv4 only.
Unlike a floating IP, a NAT gateway does not terminate on the compute node hosting your instance. The control plane realizes each one as a gateway zone: an instance the platform owns, with a NIC in one of the VPC's subnets, placed on an ordinary compute node. The zone runs the NAT daemon and faces the public network. Your router lets traffic for a NAT gateway route through, and the overlay encapsulates it to the gateway zone, which sends it on from the gateway's public address.
The zone lives in one subnet but serves every subnet whose routes point at the gateway. Deleting the subnet that holds it is refused while other subnets depend on it for egress.
A floating IP takes an address family when you create it, v4 or v6, and
defaults to v4.
The path a packet takes
Every instance NIC corresponds to one port in the compute node's kernel dataplane. Outbound packets traverse six layers in a fixed order, and inbound packets traverse them in reverse. The gateway and egress guard layers act on outbound packets only. This diagram shows where an outbound packet can leave the chain and where it can die.
Five things in that chain deserve attention.
ARP and DHCP never reach the network. The gateway layer recognizes them and answers locally, which is why the virtual gateway is always up and never a bottleneck.
The egress guard is the operator's policy, not yours. It runs before your firewall because an allowed outbound packet makes the firewall record connection state that admits the return traffic. A packet the operator's policy drops never reaches the firewall, so it never opens that inbound path. No firewall rule can widen or reorder the guard.
The anti-spoof check requires the source MAC and source IP together to be the pair the platform assigned to that NIC. A packet with the right MAC and a forged IP matches neither the IPv4 nor the IPv6 permit and is dropped by the layer's default-deny. This is what stops one instance from impersonating another inside a shared VPC.
Two instances on the same compute node never touch the physical network. The dataplane recognizes that the destination's underlay address is its own, rewrites the inner destination MAC, and delivers the frame directly with no encapsulation and no round trip to the switch.
An in-VPC destination the compute node has not yet resolved to a peer is dropped rather than sent outward. The boundary tested is the whole VPC block, not the local subnet, so an instance with a floating IP talking to a sibling subnet is never diverted out the public link while that resolution is in flight.
The mapping from a peer's private address to the compute node holding it is pushed to each node by the control plane. It is never learned from the outer header of an arriving packet.
What you decide and what the platform decides
| You decide | The platform decides |
|---|---|
| VPC and subnet address plans | The VNI, and which compute node hosts an instance |
| Which subnet an instance attaches to | The NIC's MAC address and IP addresses |
| Route tables and the routes in them | Routes for the local subnet, metadata, and floating IP egress |
| Firewall rules and their priorities | The stateful return path and the empty-VPC default |
| Whether to allocate a floating IP or a NAT gateway | Which public address you get, and where it terminates |
Changes converge, they do not apply instantly
A network change is not a synchronous edit to a running dataplane. The control plane records your intent and stamps a monotonically increasing generation on every affected port. The compute node fetches the recomputed configuration for that port and applies it, and the kernel refuses anything arriving at a generation it has already passed. Concurrent changes to the same port each bump the generation and each recompute the whole port, so the newest one wins rather than the last one to arrive.
A NAT gateway reports this convergence in its own record: alongside the generation the control plane wants, it carries the highest generation any realizer has confirmed applying, and a per-realizer breakdown. A newly created object is a statement of intent; those two generations meeting is the signal that the wire agrees.
Current limits
These are properties of the shipped code, not permanent design decisions.
tritonctlscopes a firewall rule by direction, protocol, CIDR, and port. The API also accepts target lists that name instances, tags, or subnets, but notritonctlflag sets them.tritonctlhas no command to move a subnet to another route table. The API does, so from the CLI route tables other thanmainhold routes that nothing consults.- Route tables, routes, NAT gateways, and floating IPs cannot be updated; they can only be created and deleted. VPC and subnet address blocks cannot change.
- NAT gateways serve IPv4 only.
- An instance's NICs are fixed at create time. There is no operation to attach or
detach a NIC afterward, and
tritonctl instance createattaches exactly one. - Blackhole and Reject behave identically today. Neither sends an ICMP response.
See also
- Creating an instance for attaching an instance to a subnet.
- Networking commands for the flags and fields behind every object on this page.
- Your first instance for a guided path through a working setup.
- How instance metadata works for the metadata route
and what answers at
169.254.169.254.