---
title: "Using Routing Rules"
description: "Exoscale VPC routing: VPC vs Subnet routes, route priority, sending traffic through a router instance and isolating Subnets from each other."
url: https://community.exoscale.com/product/networking/vpc/how-to/using-routing-rules/
product: "VPC"
section: product
last_updated: 2026-10-26
---
> For AI agents: the documentation index is at https://community.exoscale.com/llms.txt. Every page is available as markdown at `<page URL>index.md` or with `Accept: text/markdown`.

# 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 by | Exoscale, when a Subnet is added | You |
| Scope | Every Subnet of the VPC | The Subnet it is created in |
| Destination | The IPv4 block of the Subnet it was created for | Any IPv4 CIDR, including `0.0.0.0/0` |
| Target | `cidr=<Subnet block>` | `ip=<IPv4 address>` |
| Can be deleted | No, it is removed along with its Subnet | Yes |

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=`.

```console
$ 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](#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:

| Kind | Destination | Target |
| -------- | --------------- | ------------------- |
| Vpc | `10.0.0.0/24` | `cidr=10.0.0.0/24` |
| Vpc | `10.0.1.0/24` | `cidr=10.0.1.0/24` |
| Vpc | `10.0.2.0/24` | `cidr=10.0.2.0/24` |
| Subnet | `0.0.0.0/0` | `ip=10.0.0.10` |
| Subnet | `10.0.2.0/24` | `ip=10.0.3.10` |

| Packet destination | Selected route | Delivered to |
| -------------------- | --------------------------------- | --------------------- |
| `10.0.1.25` | Vpc `10.0.1.0/24` | `10.0.1.25` |
| `10.0.0.40` | Vpc `10.0.0.0/24` | `10.0.0.40` |
| `10.0.2.7` | Subnet `10.0.2.0/24` (wins tie) | `10.0.3.10` |
| `1.1.1.1` | Subnet `0.0.0.0/0` | `10.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.

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


**Forwarding enabled in the operating system.** On Linux:

```console
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](https://community.exoscale.com/product/networking/vpc/how-to/cross-subnet-communication/index.md).
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:

```console
$ 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

```console
$ 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
```console
$ 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](https://datatracker.ietf.org/doc/html/rfc5737). 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:

```console
$ 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](#how-a-route-is-selected)). The other VPC routes are untouched:

| Between | Result |
| -------------------------- | --------- |
| `subnet-a` ↔ `subnet-b` | Allowed |
| `subnet-b` ↔ `subnet-c` | Allowed |
| `subnet-a` ↔ `subnet-c` | Dropped |
| Inside each Subnet | Allowed |

> [!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](https://community.exoscale.com/product/networking/vpc/recipes/index.md) show more complete setups:

- [NAT gateway](https://community.exoscale.com/product/networking/vpc/recipes/nat-gateway/index.md)
- [Connecting a VPC to external networks](https://community.exoscale.com/product/networking/vpc/recipes/wireguard-gateway/index.md)

## 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).

