> For the complete documentation index, see [llms.txt](https://docs.glesys.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.glesys.com/products/compute/kvm-virtual-machines/how-tos/manage-private-networks/build-your-own-gateway-for-your-private-network.md).

# Build your own gateway for your private network

***

Virtual networks themselves are merely a transport mechanism for your network packets; they become a powerful infrastructure component only when you populate them with content and functionality. When you create virtual networks, they have no communication with the outside world. To enable internet access for servers that only have private IP addresses, you need to insert some kind of gateway into your virtual network.

We’ll build a gateway using a standard Debian server, but you can of course use a Windows server or a ready‑made solution such as pfSense or another commercial product.

## NAT — Network Address Translation

The technology that gives your servers access to the Internet is called NAT. The idea is to let your servers use your gateway’s Internet connection to reach the outside world. The configuration is fairly straightforward and not especially complicated.

We assume you have a freshly installed Debian server (version 10 or above) with at least two network interfaces—one connected to the Internet and the other to your local network.

Set the private network adapter on the gateway to a static IP address in `/etc/network/interfaces.d/50-cloud-init` like this:

{% code title="Last three lines in  /etc/network/interfaces.d/50-cloud-init" %}

```
auto ens2
iface ens2 inet static
        address 10.1.1.1/24
```

{% endcode %}

Then, enable IPv4 forwarding on the gateway machine:

{% code title="Multiple commands" %}

```
sudo sh -c 'echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf'
sudo sysctl -p
```

{% endcode %}

For the gateway to perform NAT you also need to add some firewall rules. Edit the `/etc/nftables.conf` so that it looks like the code below. In this example, `ens1` is connected to the internet, and `ens2` is connected to the private network.

{% code title="/etc/nftables.conf" %}

```
#!/usr/sbin/nft -f

flush ruleset

table ip nat {
    chain POSTROUTING {
        type nat hook postrouting priority 100;
        oifname "ens1" masquerade
    }
}

table ip filter {
    chain FORWARD {
        type filter hook forward priority 0; policy drop;
        iifname "ens1" oifname "ens2" ct state related,established accept
        iifname "ens2" oifname "ens1" accept
    }
}
```

{% endcode %}

Enable and start the firewall:

{% code title="Multiple commands" %}

```
sudo systemctl enable nftables.service
sudo systemctl start nftables.service
```

{% endcode %}

### Trying out a client

Before setting up DHCP, you can try out the gateway and see if it's working. On one of the machines in your private network, set up the private network adapter with a private address, and comment out the network adapter connected to the internet. For example, set up `/etc/network/interfaces.d/50-cloud-init` like this on a client machine:

{% code title="/etc/network/interfaces.d/50-cloud-init" %}

```
auto lo
iface lo inet loopback

#auto ens1
#iface ens1 inet dhcp

# control-alias ens1
#iface ens1 inet6 dhcp

auto ens2
iface ens2 inet static
        address 10.1.1.2/24
        gateway 10.1.1.1
```

{% endcode %}

Then, reboot the client machine to make sure it loses its public IP address. Once the machine is rebooted, log back in using either the console or through the gateway machine over the private network. Now it's time to try the connectivity. Start by making sure that `10.1.1.1` is the default router.

{% code title="Command" %}

```
ip route
```

{% endcode %}

The output should look like this:

{% code title="Output" %}

```
default via 10.1.1.1 dev ens2 onlink
10.1.1.0/24 dev ens2 proto kernel scope link src 10.1.1.2
```

{% endcode %}

Now, try to ping `8.8.8.8`.

{% code title="Command" %}

```
ping -c 3 8.8.8.8
```

{% endcode %}

If the ping succeeded, the gateway is working and the client is using it.

## DHCP – Dynamic Host Configuration Protocol

To set up DHCP in the private network, we'll use isc-dhcp-server. On the gateway machine, install and set up isc-dhcp-server:

{% code title="Command" %}

```
sudo apt install isc-dhcp-server
```

{% endcode %}

The first thing you should do is configure which IP family and which network interface the DHCP server should listen to. This is configured in `/etc/default/isc-dhcp-server`. Make sure this file only has the following line (this turns off DHCP for IPv6 and limits DHCP on IPv4 to only `ens2`):

{% code title="/etc/default/isc-dhcp-server" %}

```
INTERFACESv4="ens2"
```

{% endcode %}

Then, edit the main configuration file for isc-dhcp-server by editing `/etc/dhcp/dhcpd.conf`. The entire file should look like the configuration below. Change the name servers depending on which data center your machine is in. For Falkenberg, it's `79.99.4.100` and `79.99.4.101`. For Stockholm, it's `195.20.206.80` and `195.20.206.81`.

{% code title="/etc/dhcp/dhcpd.conf" %}

```
option domain-name "localdomain.tld";
option domain-name-servers 79.99.4.100, 79.99.4.101;

default-lease-time 600;
max-lease-time 7200;

ddns-update-style none;

authoritative;

subnet 10.1.1.0 netmask 255.255.255.0 {
  range 10.1.1.10 10.1.1.20;
  option routers 10.1.1.1;
}
```

{% endcode %}

After saving the file, restart isc-dhcp-server using:

```
sudo systemctl restart isc-dhcp-server
```

### Reconfigure a client machine to use the DHCP server

Change the configuration file `/etc/network/interfaces.d/50-cloud-init` on the client machine so that it looks like this:

{% code title="/etc/network/interfaces.d/50-cloud-init" %}

```
auto lo
iface lo inet loopback

#auto ens1
#iface ens1 inet dhcp

# control-alias ens1
#iface ens1 inet6 dhcp

auto ens2
iface ens2 inet dhcp
```

{% endcode %}

This disables the static configuration and instead enables DHCP.

Follow the DHCP server's log (on the gateway machine) using the command below while you restart the client machine. The logs will show you which IP address the client received.

{% code title="Command" %}

```
sudo journalctl -u isc-dhcp-server --follow
```

{% endcode %}

When the client reboots, you should see something similar to this:

```
Nov 13 14:19:39 gateway dhcpd[1703]: DHCPDISCOVER from 12:c3:44:cf:2b:02 via ens2
Nov 13 14:19:40 gateway dhcpd[1703]: DHCPOFFER on 10.1.1.10 to 12:c3:44:cf:2b:02 (client1) via ens2
Nov 13 14:19:40 gateway dhcpd[1703]: DHCPREQUEST for 10.1.1.10 (10.1.1.1) from 12:c3:44:cf:2b:02 (client1) via ens2
Nov 13 14:19:40 gateway dhcpd[1703]: DHCPACK on 10.1.1.10 to 12:c3:44:cf:2b:02 (client1) via ens2
```

In this case, the client machine called `client1` received the IP address `10.1.1.10`.

That's it. Everything is now set up and working!

You should also secure your gateway machine using firewall rules. More information can be found in [Set up a firewall on Debian 11 or newer using nftables](/products/compute/guides-for-server-management/set-up-a-firewall-on-debian-11-or-newer-using-nftables.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.glesys.com/products/compute/kvm-virtual-machines/how-tos/manage-private-networks/build-your-own-gateway-for-your-private-network.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
