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 withAuthorization: Bearer <token>(scopesnetwork:read/network:write, plusvps:writeto attach a server), and addX-Requested-With: XMLHttpRequeston 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
/8and/24. ip_rangemust be the true network address for that prefix (for/24,10.0.0.0is valid,10.0.0.5is 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:
| Field | Meaning |
|---|---|
destination | The target CIDR, e.g. 0.0.0.0/0 (everything) or 192.168.50.0/24 |
next_hop_type | ip, vps, or baremetal |
next_hop_target | An 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/0is fine. - An
ipnext hop must be inside the network's CIDR, and can't be the network address (.0), the broadcast, or the gateway (.1). - A
vps/baremetalnext 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
destinationcan 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
| Thing | Limit |
|---|---|
| Networks per organization | 3 |
| Network prefix | /8 to /24 |
| Routes per network | 30 |
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
| Symptom | Likely 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 create | You already have 3 networks; delete one or reuse it |
| Can't attach a server | It's in another project/location, or it isn't active/stopped; it also needs a restart afterward |
| Servers attached but can't reach each other | One 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 route | It's a NAT Gateway managed route; delete the NAT Gateway instead |
| Can't delete a network | A 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.
