Skip to content

Using Routing Rules

Routes decide where the platform delivers a packet that leaves an instance through a VPC interface. Every VPC comes with routes that make its Subnets reachable from each other. Most of the time you don’t need to touch the VPC routing rules, but for some advanced use cases, you can add your own routes to send traffic through an instance of your choice, such as a NAT gateway, a firewall, or a VPN endpoint.

How VPC Routing Works

VPC Routes and Subnet Routes

A VPC has two kinds of routes:

VPC route (implicit)Subnet route (custom)
Created byExoscale, when a Subnet is addedYou
ScopeEvery Subnet of the VPCThe Subnet it is created in
DestinationThe IPv4 block of the Subnet it was created forAny IPv4 CIDR, including 0.0.0.0/0
Targetcidr=<Subnet block>ip=<IPv4 address>
Can be deletedNo, it is removed along with its SubnetYes

A VPC route with the target cidr=<block> means deliver the packet directly to its destination address. You will only see this target in the output of exo networking vpc route list. Routes you create always use ip=.

$ exo net vpc show my-first-vpc
┼─────────────┼──────────────────────────────────────┼
│     VPC     │                                      │
┼─────────────┼──────────────────────────────────────┼
│ ID          │ 53df4f25-365e-4d48-be28-45f5de1c0bd1 │
│ Name        │ my-first-vpc                         │
│ Description │                                      │
│ Default     │ false                                │
│ Zone        │ ch-gva-2                             │
│ Created At  │ 2026-08-12 07:32:45 +0000 UTC        │
│ Labels      │ n/a                                  │
│ Subnets     │                                      │
│             │   my-first-subnet    10.42.0.0/16    │
│             │   my-second-subnet   10.26.0.0/16    │
│             │                                      │
┼─────────────┼──────────────────────────────────────┼
$ exo net vpc route list my-first-vpc
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│                  ID                  │ KIND │ DESTINATION  │      TARGET       │                          DESCRIPTION                          │
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│ 052c8d9e-be35-4fea-9fc0-03925494612c │ Vpc  │ 10.26.0.0/16 │ cidr=10.26.0.0/16 │ Default route for subnet 366f2dab-f52b-46bb-a8e3-49220ef8b5ff │
│ b8b6b692-07c5-4118-9134-ed80bccaa604 │ Vpc  │ 10.42.0.0/16 │ cidr=10.42.0.0/16 │ Default route for subnet 1ea45a36-9085-4766-95a1-4397c208480a │
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼

A Subnet route with the target ip=<IPv4 address> means deliver the packet to this next hop. The packet is not modified. It reaches the next hop with its original destination address, and the next hop decides what to do with it.

Which Routes Apply to an Instance

Routes are evaluated when a packet leaves an instance through a VPC interface. For that interface, the platform merges:

  • all the VPC routes of the VPC, and
  • the Subnet routes of the Subnet this interface is attached to.

If an instance is attached to several Subnets, each of its interfaces uses the routes of its own Subnet and it’s the instance’s operating system that chooses the interface the packet leaves from.

Traffic in the other direction is routed with the routes of the replying instance’s Subnet. Keep this in mind when you insert an appliance in the path (see Keep routing symmetric).

How a Route Is Selected

When several routes match the destination of a packet:

  1. The most specific route (the longest prefix) wins.
  2. If two routes have the same destination, the Subnet route wins over the VPC route.
  3. If no route matches, the packet is dropped.

Because of rule 2, you can override the implicit route to a Subnet by adding a Subnet route with the same destination.

For example, suppose the instances of the Subnet app (10.0.1.0/24) see these routes:

KindDestinationTarget
Vpc10.0.0.0/24cidr=10.0.0.0/24
Vpc10.0.1.0/24cidr=10.0.1.0/24
Vpc10.0.2.0/24cidr=10.0.2.0/24
Subnet0.0.0.0/0ip=10.0.0.10
Subnet10.0.2.0/24ip=10.0.3.10
Packet destinationSelected routeDelivered to
10.0.1.25Vpc 10.0.1.0/2410.0.1.25
10.0.0.40Vpc 10.0.0.0/2410.0.0.40
10.0.2.7Subnet 10.0.2.0/24 (wins tie)10.0.3.10
1.1.1.1Subnet 0.0.0.0/010.0.0.10

Preparing an Instance to Act as a Next Hop Router

The target of a Subnet route must be the VPC address of an instance attached to the same VPC. That instance receives packets addressed to other machines and sends them back out with a source address that is not its own. Four things must be in place for this to work.

Ensure IP forwarding is enabled on the instance. By default, the Exoscale platform drops any packet an instance sends through a VPC interface with a source address that is not the instance’s own. An instance used as a next hop must be created with VPC IP forwarding enabled. This setting can only be chosen when the instance is created.

exo compute instance create gateway-vm --ip-forwarding

Forwarding enabled in the operating system. On Linux:

ubuntu@appliance:~$ sudo sysctl -w net.ipv4.ip_forward=1

To keep this setting across reboots, add net.ipv4.ip_forward=1 to a file in /etc/sysctl.d/.

Security Group rules that allow the forwarded traffic. Security Groups filter the next hop’s VPC interface like any other interface. Add ingress rules on the next hop for the traffic it should forward, matching the source Subnets.

Operating system routes that use the VPC interface. This is the limitation described in Cross Subnet communication. The operating system must send VPC-bound traffic through a VPC interface, not through the public interface. This applies to the next hop and to the instances sending traffic to it.

Tip

Attach your appliances to a dedicated Subnet. Subnet routes only apply to the Subnet they are created in, so the traffic you steer to an appliance is never sent back to the appliance itself.

Managing Subnet Routes with the CLI

Create a Subnet route:

$ exo networking vpc route create my-first-vpc \
	--subnet my-first-subnet \
	--destination 0.0.0.0/0 \
	--target ip=10.26.0.10 \
	--description "Some route to a home-made NAT gateway"

Now we can see this route in the list of routes of the subnet

$ exo networking vpc route list my-first-vpc --subnet my-first-subnet
┼──────────────────────────────────────┼────────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│                  ID                  │  KIND  │ DESTINATION  │      TARGET       │                          DESCRIPTION                          │
┼──────────────────────────────────────┼────────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│ 052c8d9e-be35-4fea-9fc0-03925494612c │ Vpc    │ 10.26.0.0/16 │ cidr=10.26.0.0/16 │ Default route for subnet 366f2dab-f52b-46bb-a8e3-49220ef8b5ff │
│ b8b6b692-07c5-4118-9134-ed80bccaa604 │ Vpc    │ 10.42.0.0/16 │ cidr=10.42.0.0/16 │ Default route for subnet 1ea45a36-9085-4766-95a1-4397c208480a │
│ ad2a856f-0d23-475d-8635-41b5d7a89270 │ Subnet │ 0.0.0.0/0    │ ip=10.26.0.10     │ Some route to a home-made NAT gateway                         │
┼──────────────────────────────────────┼────────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼

And if we list the routes of the other subnet, we can see that it isn’t impacted by the route

$ exo networking vpc route list my-first-vpc --subnet my-second-subnet
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│                  ID                  │ KIND │ DESTINATION  │      TARGET       │                          DESCRIPTION                          │
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼
│ 052c8d9e-be35-4fea-9fc0-03925494612c │ Vpc  │ 10.26.0.0/16 │ cidr=10.26.0.0/16 │ Default route for subnet 366f2dab-f52b-46bb-a8e3-49220ef8b5ff │
│ b8b6b692-07c5-4118-9134-ed80bccaa604 │ Vpc  │ 10.42.0.0/16 │ cidr=10.42.0.0/16 │ Default route for subnet 1ea45a36-9085-4766-95a1-4397c208480a │
┼──────────────────────────────────────┼──────┼──────────────┼───────────────────┼───────────────────────────────────────────────────────────────┼

Route changes apply to running instances without a reboot and are usually propagated within a minute.

Keep Routing Symmetric

Each direction of a connection is routed by the Subnet of the instance that sends it. Suppose a Subnet route on Subnet A sends the traffic for Subnet B through an appliance. If Subnet B has no matching route, the replies from B follow the VPC route and go straight back to A, bypassing the appliance. A stateful appliance, such as a firewall, that sees only half of a connection usually drops it. When you insert an appliance between two Subnets, add a route pointing to it on both sides.

Example: Isolating Subnets from Each Other

By default, every Subnet of a VPC can reach every other Subnet. Security Groups are the main way to restrict this traffic. If you want to be sure that two Subnets can never communicate, you can add Subnet routes that point their traffic to an address where no instance will ever exist. Packets sent to such a target are dropped by the platform, whatever the Security Group rules allow.

Use an address outside the RFC 1918 ranges as the target, for example 192.0.2.1 from the documentation range defined in RFC 5737. Subnet blocks are always in the RFC 1918 ranges, so no instance can ever be attached with this address.

For example, take a VPC my-vpc with three Subnets:

  • subnet-a (10.1.0.0/16)
  • subnet-b (10.2.0.0/16)
  • subnet-c (10.3.0.0/16)

To let subnet-b talk to both of the others while keeping subnet-a and subnet-c apart, add a route on each side of the forbidden pair:

$ exo networking vpc route create my-vpc \
	--subnet subnet-a \
	--destination 10.3.0.0/16 \
	--target ip=192.0.2.1 \
	--description "Isolate from subnet-c"
$ exo networking vpc route create my-vpc \
	--subnet subnet-c \
	--destination 10.1.0.0/16 \
	--target ip=192.0.2.1 \
	--description "Isolate from subnet-a"

Each route has the same destination as the VPC route of the other Subnet, so it takes precedence (see How a route is selected). The other VPC routes are untouched:

BetweenResult
subnet-a ↔ subnet-bAllowed
subnet-b ↔ subnet-cAllowed
subnet-a ↔ subnet-cDropped
Inside each SubnetAllowed

Note

A route only applies to the traffic leaving the Subnet it is created in. With a route on one side only, connections still fail because the replies are dropped, but one-way traffic, such as UDP, still gets through from the other side. Add a route on both Subnets of the forbidden pair.

Warning

An instance attached to both subnet-a and subnet-c can still reach both Subnets directly through its own interfaces. Do not attach instances to both Subnets of a pair you want to isolate.

To allow subnet-a and subnet-c to communicate again, delete these two routes.

Other Examples

The VPC recipes show more complete setups:

Troubleshooting

When traffic doesn’t get through, check that:

  • A route matches the destination. Packets with no matching route are dropped, for example internet traffic from a Subnet without a 0.0.0.0/0 route,
  • The target IP belongs to an instance attached to the VPC. Packets sent to any other target are dropped,
  • The next hop was created with VPC IP forwarding enabled, and forwarding is enabled in its operating system,
  • The Security Groups of the next hop and of the destination allow the traffic,
  • The operating system of each instance sends the traffic through its VPC interface (ip route get <destination> shows the interface used).
Last updated on