Get Rewarded! We will reward you with up to €50 credit on your account for every tutorial that you write and we publish!

How to set up NAT gateway for private Cloud Networks

profile picture
Author
Hetzner Online
Published
2023-03-22
Time to read
10 minutes reading time

Introduction

This tutorial shows how to setup a generic NAT gateway for Cloud Servers via private Cloud Networks. It explains how to create the Network and Cloud Servers, how to setup the routing, and how to achieve a persistent configuration.

By the end of this tutorial, you will be able to access the public network from your private-network-only server (client server) by routing traffic via a server with a public IP address (NAT server). Both servers have to be in the same private Cloud Network.

If you are specifically interested in using pfSense, you can use this tutorial.

Prerequisites

  • Hetzner Cloud account

  • This tutorial is written for:

    • Ubuntu 18.04, 20.04, 22.04, and 24.04
    • Debian 10, 11 and 12
    • CentOS 7
    • CentOS Stream 8 and 9
    • Fedora 36 and 37
    • Rocky Linux 8 and 9.

Example terminology

  • Network: 10.0.0.0/16
  • Gateway: 10.0.0.1
  • NAT server: 10.0.0.2

Please replace 10.0.0.0/16 with your own network, 10.0.0.1 with your own network gateway IP, and 10.0.0.2 with the private IP of your own NAT server in all example commands.

Step 1 - Creating the Network and servers

Open the Hetzner Cloud Console and select your project.

You can create your Network first or, alternatively, together with your servers at server creation.

  • Create a Network

    In your project, select:

    Networks > Create network

    create_network


  • Create the servers

    In your project, select:

    Servers > Add Server

    You need at least two servers. The NAT server needs an IPv4 address, the other servers don't.

    Under Networking, you have to select the network you just created.

    If you don't want to setup the routes manually as explained in the steps below, you can use cloud-init as explained in "Step 6 - Cloud-init" instead.

    create_server

Step 2 - Adding the route to the Network

In order for our setup to work properly, we need to add the following route to the Network:

Destination: 0.0.0.0/0
Gateway: 10.0.0.2

The gateway should be the IP address of the NAT server on which you configure masquerading.

add_network_route

Step 3 - Configuring NAT

To configure the NAT server, we will use the following commands:

  • Enable IP forwarding, since it is disabled by default

    echo 1 > /proc/sys/net/ipv4/ip_forward
  • Add a rule to the 'nat' table

    iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE

    Let's look at the second command in more detail:

    • iptables ➜ the program we are using
    • -t nat ➜ choose the table 'nat'
    • -A POSTROUTING ➜ add a rule to postrouting
    • -s '10.0.0.0/16' ➜ target packets from the source '10.0.0.0/16'
    • -o eth0 ➜ output at 'eth0'
    • -j MASQUERADE ➜ masquerade the packages with the 'routers' IP

To configure the client servers, we only need to add a default route.

  • For example, like this:

    ip route add default via 10.0.0.1
    Click here, if you get RTNETLINK answers: File exists

    If you get the error RTNETLINK answers: File exists, run this command to check if you already have a default route:

    ip route

    Example output:

    default via 172.31.1.1 dev eth0
    10.0.0.0/16 via 10.0.0.1 dev enp7s0
    10.0.0.1 dev enp7s0 scope link
    172.31.1.1 dev eth0 scope link

    You can remove the existing default route with this command:

    ip route del default

    After it was removed, you can try adding the new route again:

    ip route add default via 10.0.0.1

Step 4 - Achieving a persistent configuration

The example commands below for Debian and Ubuntu use vim, which can be installed using: apt install vim


The next steps depend on the OS of your server:

Debian 10 / 11 / 12, and Ubuntu 18.04
  • Update

    First, the system needs to be updated:

    apt update && apt upgrade -y

    Ubuntu 22.04 additionally requires:

    apt install ifupdown

  • On the NAT server

    To make everything persistent, we open the following file:

    vim /etc/network/interfaces

    To enter the insert mode in vim, press i and append the following to the file:

    auto eth0
    iface eth0 inet dhcp
        post-up echo 1 > /proc/sys/net/ipv4/ip_forward
        post-up iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE

    To save the file, press esc to escape the insert mode, then type :x or :wq and hit ENTER.


  • On the client servers

    Since we also want the route to be persistent, we edit the following file:

    vim /etc/network/interfaces

    And append:

    auto ens10
    iface ens10 inet dhcp
        post-up ip route add default via 10.0.0.1

Ubuntu 22.04 / 24.04
  • Update

    First, the system needs to be updated:

    apt update && apt upgrade -y

  • On the NAT server

    To make everything persistent, we open the file in /etc/netplan:

    vim /etc/netplan/50-cloud-init.yaml

    Check the following information. If everything looks fine, press esc followed by :q and ENTER to close the file. To enter the insert mode in vim, press i.

    network:
        version: 2
        ethernets:
            eth0:
                dhcp4: true

    To save the file, press esc to escape the insert mode, then type :x or :wq and hit ENTER.

    Now create a new file in /etc/networkd-dispatcher/routable.d:

    vim /etc/networkd-dispatcher/routable.d/10-eth0-post-up

    To enter the insert mode in vim, press i and add the following to the file:

    #!/bin/bash
    
    echo 1 > /proc/sys/net/ipv4/ip_forward
    iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE

    To save the file, press esc to escape the insert mode, then type :x or :wq and hit ENTER.

    Now add execute permissions:

    chmod +x /etc/networkd-dispatcher/routable.d/10-eth0-post-up

  • On the client servers

    Since we also want the route to be persistent, we edit the following file:

    vim /etc/systemd/network/10-ens10.network

    And add:

    [Match]
    Name=ens10
    
    [Network]
    DHCP=yes
    Gateway=10.0.0.1

Ubuntu 20.04
  • Update

    First, the system needs to be updated:

    apt update && apt upgrade -y

    Ubuntu 20.04 uses netplan instead of /etc/interfaces by default. To achieve persistent configuration, the networkd-dispatcher is being used.

    As mentioned in the netplan FAQ, the networkd-dispatcher equivalent of post-up is placing a script in /etc/networkd-dispatcher/routable.d/. In this tutorial, we call the script 50-masq but the name doesn't matter.


  • On the NAT server

    Create the file:

    vim /etc/networkd-dispatcher/routable.d/50-masq

    To enter the insert mode in vim, press i and append the following to the file:

    #!/bin/sh
    
    /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
    /sbin/iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE

    To save the file, press esc to escape the insert mode, then type :x or :wq and hit ENTER.

    The following command is required to make the script executable, otherwise it will not work:

    chmod +x /etc/networkd-dispatcher/routable.d/50-masq

  • On the client servers

    Create the file:

    vim /etc/networkd-dispatcher/routable.d/50-masq

    And append:

    #!/bin/sh
    
    /sbin/ip route add default via 10.0.0.1

    Finally, make it executable:

    chmod +x /etc/networkd-dispatcher/routable.d/50-masq

CentOS 7, CentOS Stream 8 / 9, Rocky Linux 8 / 9, Fedora 36 / 37
  • Update

    First, the system needs to be updated:

    yum update -y && yum upgrade -y

    We use the NetworkManager's dispatcher.d to run our scripts automated on start. This is done by placing the script into the folder /etc/NetworkManager/dispatcher.d/. Here, the name determines the execution condition of the script. More information can be found here.

    In this tutorial we use the name ifup-local where ifup is the condition for the script to get executed.


  • On the NAT server

    Fedora 36 / 37 additionally require:

    yum install iptables -y

    Create the file:

    vi /etc/NetworkManager/dispatcher.d/ifup-local

    And append:

    #!/bin/sh
    
    /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
    /sbin/iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE

    The following command is required to make the script executable, otherwise it will not work:

    chmod +x /etc/NetworkManager/dispatcher.d/ifup-local

  • On the client servers

    CentOS Stream 8 / 9, Rocky Linux 8 / 9, and Fedora 36 / 37 additionally require:

    yum remove hc-utils -y

    This also goes for other methods to add a route to the OS.

    Create the file:

    vi /etc/NetworkManager/dispatcher.d/ifup-local

    And append:

    #!/bin/sh
    
    /sbin/ip route add default via 10.0.0.1

    Finally, make it executable:

    chmod +x /etc/NetworkManager/dispatcher.d/ifup-local

Step 5 - Adding nameservers

To add nameservers on the client server, edit the file /etc/systemd/resolved.conf. In the section [Resolve], there should be the line #DNS=. Un-comment this line by removing the # and add some DNS servers or use the DNS servers by Hetzner:

DNS=185.12.64.2 185.12.64.1

Save the file and restart the server.

Step 6 - Cloud-init

If you don't want to setup the routes manually, you can use cloud-init and add the scripts below in the cloud config text box when you create new servers in Cloud Console.

Debian 10 / 11 / 12, and Ubuntu 18.04
  • NAT server

    Replace 10.0.0.0/16 as needed.

    #cloud-config
    packages:
      - ifupdown
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/network/interfaces
        auto eth0
        iface eth0 inet dhcp
            post-up echo 1 > /proc/sys/net/ipv4/ip_forward
            post-up iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE
        EOF
      - reboot
  • Client server

    Replace 10.0.0.1 as needed.

    #cloud-config
    packages:
      - ifupdown
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/network/interfaces
        auto ens10
        iface ens10 inet dhcp
            post-up echo "Waiting..."
            post-up ip route add default via 10.0.0.1
        EOF
      - reboot

Ubuntu 22.04 / 24.04
  • NAT server

    Replace 10.0.0.0/16 as needed.

    #cloud-config
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/networkd-dispatcher/routable.d/10-eth0-post-up
        #!/bin/bash
        
        echo 1 > /proc/sys/net/ipv4/ip_forward
        iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE
        EOF
        chmod +x /etc/networkd-dispatcher/routable.d/10-eth0-post-up
      - reboot
  • Client server

    Replace 10.0.0.1 as needed.

    #cloud-config
    packages:
      - ifupdown
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/systemd/network/10-ens10.network
        [Match]
        Name=ens10
        
        [Network]
        DHCP=yes
        Gateway=10.0.0.1
        EOF
      - reboot

Ubuntu 20.04
  • NAT server

    Replace 10.0.0.0/16 as needed.

    #cloud-config
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/networkd-dispatcher/routable.d/50-masq
        #!/bin/sh
        
        /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
        /sbin/iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE
        EOF
      - chmod +x /etc/networkd-dispatcher/routable.d/50-masq
      - reboot
  • Client server

    Replace 10.0.0.1 as needed.

    #cloud-config
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/networkd-dispatcher/routable.d/50-masq
        #!/bin/sh
        
        /sbin/ip route add default via 10.0.0.1
        EOF
      - chmod +x /etc/networkd-dispatcher/routable.d/50-masq
      - reboot

CentOS 7, CentOS Stream 8 / 9, Rocky Linux 8 / 9, Fedora 36 / 37
  • NAT server

    Replace 10.0.0.0/16 as needed.

    #cloud-config
    packages:
      - iptables
    package_update: true
    package_upgrade: true
    runcmd:
      - |
        cat <<'EOF' >> /etc/NetworkManager/dispatcher.d/ifup-local
        #!/bin/sh
        
        /bin/echo 1 > /proc/sys/net/ipv4/ip_forward
        /sbin/iptables -t nat -A POSTROUTING -s '10.0.0.0/16' -o eth0 -j MASQUERADE
        EOF
      - chmod +x /etc/NetworkManager/dispatcher.d/ifup-local
      - reboot
  • Client server

    Replace 10.0.0.1 as needed.

    #cloud-config
    package_update: true
    package_upgrade: true
    runcmd:
      - yum remove hc-utils -y
      - |
        cat <<'EOF' >> /etc/NetworkManager/dispatcher.d/ifup-local
        #!/bin/sh
        
        /sbin/ip route add default via 10.0.0.1
        EOF
      - chmod +x /etc/NetworkManager/dispatcher.d/ifup-local
      - reboot

After the servers are created, you can use iptables -t nat -L on the NAT server and ip route show on the client server to check if the rules were added as expected.

Next, add the route mentioned in step 2 to your private Network and you're done!

Conclusion

If you followed all these steps, you have successfully configured your system to behave as a NAT router in your private Cloud Network.

Want to contribute?

Get Rewarded: Get up to €50 in credit! Be a part of the community and contribute. Do it for the money. Do it for the bragging rights. And do it to teach others!

Report Issue
Try Hetzner Cloud

Get €20/$20 free credit!

Valid until: 31 December 2024 Valid for: 3 months and only for new customers
Get started
Want to contribute?

Get Rewarded: Get up to €50 credit on your account for every tutorial you write and we publish!

Find out more