Create nested VMs
Stay organized with collections
Save and categorize content based on your preferences.
Linux
Nested virtualization is allowed by default, so unless somebody modifies the
constraint for nested virtualization, you do not need to make any changes before
you create nested VMs in an organization, folder, or project. If your project
doesn't belong to an organization, nested virtualization is allowed by default
and you can't change the constraint. For information about how to modify the
constraint that determines whether you can create nested VMs, see Manage the nested virtualization constraint.
After creating an L1 VM that has nested virtualization enabled, you can do any
of the following:
Create an L2 VM with external network access
Create an L2 VM with a private network bridge to the L1 VM
Create an L2 VM with network access from outside the L1 VM
Before you begin
If you haven't already, set up authentication.
Authentication verifies your identity for access to Google Cloud services and APIs. To run
code or samples from a local development environment, you can authenticate to
Compute Engine by selecting one of the following options:
Select the tab for how you plan to use the samples on this page:
gcloud
Install the Google Cloud CLI.
After installation,
initialize the Google Cloud CLI by running the following command:
Create an L2 VM with external network access by using the following procedure.
This procedure uses qemu-system-x86_64 to start the L2 VM. If you are using
another procedure to create an L2 VM and are experiencing trouble, reproduce the
issue using this procedure before contacting Support.
Replace IMAGE_NAME with the name of the
QEMU-compatible OS image to use for the L2 VM.
Test that your L2 VM has external access:
user@nested-vm:~$ host google.com
Creating an L2 VM with a private network bridge to the L1 VM
Create an L2 VM with a private network bridge to the previously created L1 VM by
using the following procedure. For information about changing the default
maximum transmission unit (MTU) for your VPC network, see the maximum transmission unit overview.
Replace IMAGE_NAME with the name of the
QEMU-compatible OS image to use for the L2 VM.
On the L2 VM, run ip addr show to confirm that the VM has an address in the
virbr0 space—for example, 192.168.122.89:
user@nested-vm:~$ ip addr
Start a placeholder web server on port 8000:
user@nested-vm:~$ python -m http.server
Detach from the screen session with Ctrl+A, Ctrl+D.
Test that your L1 VM can ping the L2 VM, replacing the following IP address
with the IP address of the L2 VM:
curl 192.168.122.89:8000
The output is similar to the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ol>
<li><a href=".aptitude/">.aptitude/</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".profile">.profile</a>
</ol>
<hr>
</body>
</html>
Creating an L2 VM with network access from outside the L1 VM
Permissions required for this task
To perform this task, you must have the following
permissions:
compute.instances.create permissions on the project, folder, or
organization
You can set up an L2 VM with an alias IP so that VMs outside the L1 VM can
access the L2 VM. Use the following procedure to create an L2 VM with network
access by way of an alias IP from outside the previously created L1 VM. For
information about creating alias IP addresses, see Configure alias IP ranges.
The following procedure assumes a previously created subnet called subnet1. If
you already have a subnet with a different name, replace subnet1 with the name
of your subnet, or create a new subnet named subnet1.
Create an L1 VM with nested virtualization enabled and include an alias IP
range and support for HTTP/HTTPS traffic:
Use the gcloud compute ssh command to
connect to the VM. If you have trouble connecting to the VM, try resetting
the VM or modifying the firewall rules.
gcloud compute ssh VM_NAME
Replace VM_NAME with the name of the VM to connect
to.
Replace IMAGE_NAME with the name of the
QEMU-compatible OS image to use for the L2 VM.
On the L2 VM, run ip addr to confirm that the L2 VM has an address in the
virbr0 space, such as 192.168.122.89:
user@nested-vm:~$ ip addr
Start a placeholder web server on port 8000:
user@nested-vm:~$ python -m http.server
Detach from the screen session with Ctrl+A, Ctrl+D.
Test that your L1 VM can ping the L2 VM, replace the IP address below with
the IP address of the L2 VM:
curl 192.168.122.89:8000
Verify that the response from the L2 VM is similar to the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ol>
<li><a href=".aptitude/">.aptitude/</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".profile">.profile</a>
</ol>
<hr>
</body>
</html>
On the L1 VM, set up iptables to allow forwarding from the L1 VM to the L2
VM. For the L2 OS image used in these instructions, you must flush the IP
tables:
sudo iptables -F
Determine the L1 VM's alias IP:
ip route show table local
Verify that the output is similar to the following. For this example, there
are two IP addresses associated with the L2 VM's eth0 ethernet device. The
first, 10.128.0.2, is the L2 VM's primary IP address, which is returned by
sudo ifconfig -a. The second, 10.128.0.13, is the L2 VM's alias IP
address.
local 10.128.0.2 dev eth0 proto kernel scope host src 10.128.0.2
broadcast 10.128.0.2 dev eth0 proto kernel scope link src 10.128.0.2
local 10.128.0.13/30 dev eth0 proto 66 scope host
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
broadcast 192.168.122.0 dev virbr0 proto kernel scope link src
192.168.122.1 linkdown
local 192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1
broadcast 192.168.122.255 dev virbr0 proto kernel scope link src
192.168.122.1 linkdown
Run the following commands to forward traffic from the 10.128.0.13 example
alias IP to the 192.168.122.89 example IP for the L2 VM:
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A PREROUTING -d 10.128.0.13 -j DNAT --to-destination 192.168.122.89
sudo iptables -t nat -A POSTROUTING -s 192.168.122.89 -j MASQUERADE
sudo iptables -A INPUT -p udp -j ACCEPT
sudo iptables -A FORWARD -p tcp -j ACCEPT
sudo iptables -A OUTPUT -p tcp -j ACCEPT
sudo iptables -A OUTPUT -p udp -j ACCEPT
Verify L2 VM access from outside the L1 VM by logging onto another VM that is
on the same network as the L1 VM, and making a curl request to the alias
IP, replacing the IP address below with the L2 VM's alias IP:
user@another-vm:~$ curl 10.128.0.13:8000
Verify that the curl response is similar to the following:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ol>
<li><a href=".aptitude/">.aptitude/</a>
<li><a href=".bashrc">.bashrc</a>
<li><a href=".profile">.profile</a>
</ol>
<hr>
</body>
</html>
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-06-09 UTC."],[],[]]