Private Networks (VPC) and Routes: Connect Your Servers Privately

A Private Network gives your servers an isolated Layer 3 network they can talk over using internal IPs, with no traffic leaving CubePath and nothing exposed to the public internet. Add Routes on top and you control where traffic for any CIDR goes: through a firewall VPS, a NAT Gateway, or a routing appliance you run yourself.

It's the standard building block for multi-tier apps (web in front, database on a private subnet), private clusters, NAT egress, and any setup where servers should reach each other without public IPs.

How it works

You create a private network inside a project, in one location, with a private CIDR you choose (for example 10.0.0.0/24). Servers in that same project and location can be attached to it; each one gets an internal IP from the range and can reach the others directly, with .1 reserved as the gateway. By default a private network only carries traffic for its own CIDR. When you need traffic for other destinations to flow through a specific box (a firewall, a NAT Gateway, an on-prem tunnel), you add a Route: a destination CIDR plus a next hop, which is either an IP inside the network or one of your servers. You manage all of this in the dashboard or over the API; nothing is installed by hand.

Before you start

  • In the dashboard: my.cubepath.com → Networks (networks live inside a project).
  • Over the API: base URL https://api.cubepath.com, authenticate with Authorization: Bearer <token> (scopes network:read / network:write, plus vps:write to attach a server), and add X-Requested-With: XMLHttpRequest on writes. Get a token under Account → API Tokens.

Part 1: Create a private network

A network belongs to one project and one location, and has a private CIDR made of an ip_range (the network address) and a prefix.

curl -X POST https://api.cubepath.com/networks/create_network \
  -H "Authorization: Bearer $CUBEPATH_TOKEN" \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "backend-net",
    "label": "Backend Network",
    "location_name": "us-mia-1",
    "ip_range": "10.0.0.0",
    "prefix": 24
  }'

Rules to keep in mind:

  • Name is 3 to 64 characters.
  • Prefix is between /8 and /24.
  • ip_range must be the true network address for that prefix (for /24, 10.0.0.0 is valid, 10.0.0.5 is not). Use a private range (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16).
  • You can have up to 3 networks per organization.

Inside the range, .1 is the gateway and is reserved, along with the network address (.0) and the broadcast address. Everything else is assignable to servers.

You can rename a network (PUT /networks/{id}, name and label only) or move it to another project in the same organization (POST /networks/{id}/move-project).

Attach servers

A server joins a network from the server side. The server must be in the same project and location as the network, and must be active or stopped.

curl -X POST https://api.cubepath.com/vps/<vps_id>/network \
  -H "Authorization: Bearer $CUBEPATH_TOKEN" \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{ "network_id": 42 }'

The server gets the next free internal IP from the range. Restart it for the change to take effect. Bare metal servers attach the same way. To remove it, DELETE /vps/<vps_id>/network (also needs a restart).

Part 2: Routes

By default a network only knows how to reach its own CIDR. A route tells it to send traffic for some other destination through a next hop you pick.

A route has three parts:

FieldMeaning
destinationThe target CIDR, e.g. 0.0.0.0/0 (everything) or 192.168.50.0/24
next_hop_typeip, vps, or baremetal
next_hop_targetAn IP inside the network (for ip), or the numeric server id (for vps / baremetal)

Examples

Send all outbound traffic through a firewall/NAT VPS in the network:

curl -X POST https://api.cubepath.com/networks/42/routes \
  -H "Authorization: Bearer $CUBEPATH_TOKEN" \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{ "destination": "0.0.0.0/0", "next_hop_type": "vps", "next_hop_target": "123", "description": "Egress via firewall" }'

Route a remote subnet through an appliance's internal IP:

curl -X POST https://api.cubepath.com/networks/42/routes \
  -H "Authorization: Bearer $CUBEPATH_TOKEN" \
  -H "X-Requested-With: XMLHttpRequest" \
  -H "Content-Type: application/json" \
  -d '{ "destination": "192.168.50.0/24", "next_hop_type": "ip", "next_hop_target": "10.0.0.5" }'

List routes with GET /networks/42/routes (each one shows its resolved_next_hop_ip), and remove one with DELETE /networks/42/routes/{route_id}.

What's allowed

  • The destination can't be the network's own CIDR (that's already a connected route) and can't sit inside a reserved range (loopback, link-local, multicast). A supernet like 0.0.0.0/0 is fine.
  • An ip next hop must be inside the network's CIDR, and can't be the network address (.0), the broadcast, or the gateway (.1).
  • A vps / baremetal next hop must be in the same project, in a usable state, and already attached to this network. Otherwise it's unreachable and the route is rejected.
  • Address families must match (an IPv4 destination needs an IPv4 next hop).
  • Up to 30 routes per network. The same destination can have more than one next hop (treated as equal-cost paths); only an exact duplicate of destination + type + target is refused.

Routes created automatically by a NAT Gateway are managed for you and can't be deleted directly. Delete the NAT Gateway instead and its routes are cleaned up with it.

Limits

ThingLimit
Networks per organization3
Network prefix/8 to /24
Routes per network30

What this doesn't do

  • It isn't a public network. Private IPs are reachable only by your attached servers in the same location, not from the internet. To go out to the internet from a private-only server, route through a NAT Gateway.
  • It doesn't span locations. A network lives in one location; servers in another location can't join it. Connect locations with a routing appliance and routes.
  • Routes don't reconfigure your server's firewall. They steer where the network sends traffic; the next-hop box still has to be set up to forward, NAT, or filter as you intend.

Troubleshooting

SymptomLikely cause
400 creating a network, "invalid range"ip_range isn't the network address for the prefix (use 10.0.0.0 for a /24, not 10.0.0.5)
400 "limit reached" on createYou already have 3 networks; delete one or reuse it
Can't attach a serverIt's in another project/location, or it isn't active/stopped; it also needs a restart afterward
Servers attached but can't reach each otherOne or both haven't been restarted since attaching
400 creating a route, "next_hop_target must be inside this network's CIDR"An ip next hop has to be an address within the network, and not .0/.1/broadcast
400 "must be attached to this private network"The target VPS/baremetal isn't on this network; attach it first
409 deleting a routeIt's a NAT Gateway managed route; delete the NAT Gateway instead
Can't delete a networkA non-deleted VPS, bare metal, or NAT Gateway is still attached; detach or delete those first

API reference

POST   /networks/create_network            { name, location_name, ip_range, prefix }  Create a network. (scope: network:write)
PUT    /networks/{id}                       { name, label }                            Rename a network. (scope: network:write)
POST   /networks/{id}/move-project          { project_id }                             Move to another project. (scope: network:write)
DELETE /networks/{id}                                                                  Delete a network. (scope: network:write)
GET    /networks/{id}/routes                                                           List routes. (scope: network:read)
POST   /networks/{id}/routes                { destination, next_hop_type, next_hop_target }  Add a route. (scope: network:write)
DELETE /networks/{id}/routes/{route_id}                                                Remove a route. (scope: network:write)
POST   /vps/{vps_id}/network                { network_id }                             Attach a server. (scope: vps:write)
DELETE /vps/{vps_id}/network                                                           Detach a server. (scope: vps:write)

All requests authenticate with Authorization: Bearer <token> (or X-API-Key). Write requests also need X-Requested-With: XMLHttpRequest.