Skip to main content
By default, traffic from your Nebius AI Cloud resources to public IP addresses is routed to the internet through the default egress gateway. You can set up a Compute virtual machine (VM) as a custom gateway for traffic from specific subnets to the internet. The gateway is called a NAT gateway because it uses network address translation (NAT) to change the egress traffic’s source IP address. This change causes the traffic to appear as if it were sent from the public IP address of the gateway VM rather than the private IP address of the originating resource.

Prerequisites

  1. Install and configure the Nebius AI Cloud CLI.
  2. Make sure you are in a group that has at least the editor role within your tenant; for example, the default editors group. You can check this in the Administration → IAM section of the web console.

Steps

Create a gateway virtual machine

  1. Get the ID of the network that contains the subnets for which you want to set up routing:
    nebius vpc network list
    
    Save the network’s ID from the .metadata.id field.
  2. Create a subnet for the gateway virtual machine (VM):
    nebius vpc subnet create --name gateway-subnet --network-id <network_ID>
    
    Save the subnet’s ID from the .metadata.id field.
    The subnet for the gateway VM must be a separate subnet. In later steps, we create a routing table (route table) and assign it to subnets to which new routing should apply; assigning this routing table to the gateway VM’s subnet leads to routing loops.
  3. Create a private allocation for the gateway VM:
    nebius vpc allocation create \
       --name gateway-allocation \
       --ipv4-private-subnet-id <gateway_subnet_ID>
    
    Save the allocation’s ID from the .metadata.id field.
  4. Create the gateway VM. It must have a network interface that is located in the created subnet, has the allocated private IP address and a public IP address:
    nebius compute instance create \
       --name gateway-vm \
       --network-interfaces "[{
         \"name\": \"eth0\",
         \"ip_address\": {
           \"allocation_id\": \"<gateway_allocation_ID>\"
         },
         \"subnet_id\": \"<gateway_subnet_ID>\",
         \"public_ip_address\": {}
       }]" \
       <other_parameters>
    
    VM_BOOT_DISK_ID=$(nebius compute disk create \
       --name gateway-boot-disk \
       --size-gibibytes 50 \
       --type network_ssd \
       --source-image-family-image-family ubuntu24.04-cuda12 \
       --block-size-bytes 4096 \
       --format json | jq -r ".metadata.id")
    
    nebius compute instance create \
       --name gateway-vm-example \
       --resources-platform cpu-d3 \
       --resources-preset 4vcpu-16gb \
       --boot-disk-existing-disk-id $VM_BOOT_DISK_ID \
       --boot-disk-attach-mode read_write \
       --boot-disk-device-id boot-disk \
       --network-interfaces "[{
         \"name\": \"eth0\",
         \"ip_address\": {
           \"allocation_id\": \"<gateway_allocation_ID>\"
         },
         \"subnet_id\": \"<gateway_subnet_ID>\",
         \"public_ip_address\": {}
       }]" \
       --cloud-init-user-data "users:
         - name: $USER
           sudo: ALL=(ALL) NOPASSWD:ALL
           shell: /bin/bash
           ssh_authorized_keys:
            - $(cat ~/.ssh/id_ed25519.pub)"
    
    For more details about VM parameters, see How to create a virtual machine in Nebius AI Cloud.

Set up the gateway VM

  1. Connect to the gateway VM by using SSH:
    ssh <username>@<public_IP_address>
    
    For more details, see How to connect to virtual machines in Nebius AI Cloud.
  2. Enable IPv4 routing and make this change persistent:
    sudo sysctl -w net.ipv4.ip_forward=1
    sudo sed -i -E 's/^(#\s?)?net.ipv4.ip_forward.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf 
    
  3. Enable egress NAT and make this change persistent:
    sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
    sudo apt-get install iptables-persistent
    
    The latter command asks you whether to save your current iptables IPv4 and IPv6 rules to files. Answer “yes” to both.
  4. Disconnect from the gateway VM:
    exit
    

Set up routing

  1. Create a routing table in the network:
    nebius vpc route-table create \
       --name gateway-table \
       --network-id <network_ID>
    
    Save the routing table’s ID from the .metadata.id field.
  2. Create a route in the routing table to send egress traffic to the gateway private allocation:
    nebius vpc route create \
       --name route-to-allocation \
       --parent-id <routing_table_ID> \
       --destination-cidr 0.0.0.0/0 \
       --next-hop-allocation-id <gateway_allocation_ID>
    
  3. Assign the routing table to the subnets that should use the NAT gateway:
    nebius vpc subnet update <subnet_ID> \
       --route-table-id <routing_table_ID>
    
    Repeat for each subnet as needed. Do not assign the routing table to the subnet of the gateway VM (gateway-subnet).

Test routing

To test that the routing table works, send traffic from a VM in a subnet to which you assigned the routing table (a test VM) and check its source IP address:
  1. Connect to the test VM by using the gateway VM as the jump host:
    ssh -J <username>@<gateway_public_IP_address> <username>@<VM_private_IP_address>
    
  2. Verify that egress traffic from the test VM to the internet is routed through the gateway VM, by using a public service that looks up the traffic’s source IP address:
    curl ifconfig.me
    
    The command should return the public IP address of the gateway VM. If it returns the private address of the test VM instead:
    • Check that you assigned the routing table to the subnet: run nebius vpc route-table get <routing_table_ID> and then find the subnet in the .status.assignment.subnets field.
    • Check that the test VM belongs to this subnet: run nebius compute instance get <VM_ID> and then find the subnet in the .spec.network_interfaces[0].subnet_id field.
    • Check that you specified the gateway VM’s private allocation as the next hop in the route: run nebius vpc route list --parent-id <routing_table_ID> and then find the allocation in the .spec.next_hop.allocation.id field.