Mastering Connectivity: CG-NAT Solutions with Tailscale
Tags: cloudskills, networking, tutorial, aws
Published: 2024-01-29 14:01:15

Recently, the CEO of Supabase tweeted about the importance of transitioning from `IPv4` to `IPv6`. This is due to the shortage of `IPv4` addresses, and major cloud providers like AWS are set to start charging for `IPv4` addresses starting from **February 1, 2024**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1bxh6fhw20qsx23ocm9f.png)
Not everyone is fully ready to adopt `IPv6` because of its complexities. To lawfully and technically circumvent these issues, I will demonstrate two methods in two clouds which I learned in [The Cloud Seminar](https://thecloudseminar.com/) recently. These solutions don't always work, but in most cases, one can definitely bypass the restrictions.

First, I will discuss what tailscale is and how we can use tailscale to translate a private `IPv4` address to public `IPv4` address using **CGNAT** CIDR.

## Tailscale

**Tailscale** is a _VPN_ service that enables encrypted point-to-point connections using the open source **WireGuard** protocol, making devices and applications accessible anywhere in the world, securely and effortlessly. It offers speed, stability, and simplicity over traditional VPNs.

We will use tailsacle to convert our private `IPV4` address to public `IPV4` address using **CGNAT** CIDR. So, what **CGNAT** does is it involves the translation of private IP addresses used within a local network into a smaller set of public IP addresses when the traffic passes through the ISP's network.

## Cloud Machine Access via Console Connect

Now, I will be working in the **Hetzner** cloud to demonstrate how we can **SSH** into our cloud machine without a public IP using tailscale.

### Steps:

- Login to the console and create a project in the cloud.
- Start creating your server by adding the required machine details. ( I picked an ubuntu machine)
 
While creating the server in my **Hetzner** Cloud console, I unchecked the Public `IPv4` option and only checked the public `IPv6` option because it was charging me a certain amount of money to enable it.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sknxfm8nssmbknt0azsk.png)

- Finally, create the server after filling in all the required details for the machine you need.
- After creating your server, your server dashboard will be visible. (I named my server tailscale-connect)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j4o8j9j4iw4z4acyrdpv.png)

- At the top of your server dashboard you will see a console connect option, **click** on that.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cft6oeom3pg4w33kj3p4.png)

- The instance connection will open and you will see the following screen:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ue8i4qajex2x2ifgtp1.png)
 
Now, to log in to the server, it asks for a login username and login password, which we don't know. We will reset the login username and password to connect to the server.

- Navigate to the rescue screen on your server dashboard and click `"Reset Root Password."` (After clicking, you will receive a new root password. Save it somewhere.)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swij4k94in94ei8mqkpo.png)

- Now, refresh the page and open the console connect terminal again to login with the new root password. (Type your new root password which you generated in the previous step.)

- You will see the following screen after successfully logging into your server- 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1szfv3xsycgfb9veogh5.png)

> - The top arrow indicates the private `IPv4` address, and the arrow below indicates the `IPv6` address that the cloud provided us.
> - Since, we didn't enable the public `IPv4` address(because of extra cost) we didn't get one.

Even though we connected to the instance through the console, we still haven't connected it through our machine, and it is not possible to do so without a public `IPv4` address. To circumvent this issue, we will use **tailscale**.

### Tailscale installation 

Head to the terminal and install tailscale on your linux machine with the following command:

```
curl -fsSL https://tailscale.com/install.sh | sh
```
- Once your installation is complete, type `tailscale up` and go to the link that tailscale provided in the terminal.
- You will see the following screen:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cr5qhvl3tf2wqgprg7m4.png)

- **Sign in** to tailscale using any of the provided methods.
- You will see the following screen after singing up-

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwbghgrjr7gfbmop3i78.png)

- The tailscale dashboard displays all the devices connected to your network.(Currently it's only your local machine)
- Now, we will connect the cloud machine to the same network and then access it through our local machine without a public `IPv4` address.

Let's see how to do that in the next steps.

## Tailscale: SSH connect without Public IP

- Head to the cloud machine terminal that we logged into earlier.
- We will install tailscale on this machine and connect it to the network that we created previously.
- Type the following command to install tailscale on your cloud machine

```
curl -fsSL https://tailscale.com/install.sh | sh
```
- Once your installation is complete, type `tailscale up` and go to the link that tailscale provided in the terminal.
- On the sign-up page, sign in with the same account that you used to sign up on your local machine.( In my case, I used my **github** account.)
- Once you have signed in, you will now see two machines on the dashboard: one being your local machine and the other being your cloud machine.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvxlnsc3wff1l5b2z9aj.png)
   
- Now that we have connected the two machines on the same network, we can access the cloud machine through our local machine without requiring a public `IPv4` address.

- Copy the CGNAT IP of your cloud machine provided by Tailscale from your dashboard.

- Open your terminal and type the following to connect to your cloud machine

```
ssh root@[CGNAT-IP]
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffbkdjmo0tg0u00n67e3.png)

- Now, you have successfully connected to your cloud machine through your local machine without requiring a public `IPv4` address. How cool is that?!!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9sx4y2emuzq6y9xfw2rt.png)

We don't need the console login terminal anymore, so we can close it and directly access the machine via our machine terminal.

## EC2: SSH connect without public `IPv4` 

Now, to implement the above method, we need to log in to the server using the cloud provider's console connect. Unfortunately, **AWS** console connect doesn't support public `IPv6` addresses, only `IPv4`. AWS will charge $0.005 per IP per hour for public `IPv4`, leading to high costs. To address this, create a Jump box (Bastion Host) in the public subnet using a public `IPv4` address and connect other machines through it using private IPs. This reduces costs, as only one machine is billed for the public `IPv4` address, with others connected via private IPs.

### Steps:

- Log into your **AWS** console.
- Head over to the _VPC_ section and create a _VPC_ for your instances.
- In the _VPC_ section, create two **subnets** (Public & Private) allowing `IPv4` **CIDR** blocks for both and a `IPv6` **CIDR** block for private only.
- Create an Internet gateway (**IGW**) and attach it to your VPC.
- Create a **route table** and associate it with the public subnet. Edit the route and add a destination of `0.0.0.0`, choosing the destination as the **IGW** you created in the previous step.
- Similarly, create a Route table and associate it with the private subnet. No need to edit route here.
- Head over to **EC2** instances and create a key pair first.
- Create an EC2 instance (**JUMPBOX**) in the public subnet of your VPC, allowing the option for auto-assigning a `public IPv4`. In the security group, allow SSH from my IP.
- Try to **SSH** into it from your terminal and see if it's working.
    
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmjag44g9jpil1tl28bd.png)

- Next, create one or two instances (test instances) in the private subnet of your _VPC_. Disable the auto-assign public `IPv4` address and enable the auto-assign `IPv6` address.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qlv3euxx15s0zre2wrk2.png)

- We cannot SSH into the Test instances because we have disabled the public `IPv4` option. We only have a private `IPv4` address and an `IPv6` address. To SSH into the test instances, we will use the **JUMPBOX**, which has an `IPv4` address assigned to it.
- Head over to config file in the .ssh folder.

```
cd .ssh
code .
```
- Paste the following in the config file

```bash
Host JUMPBOX
  HostName [Public IP of JUMPBOX]
  ForwardAgent yes
  StrictHostKeyChecking ask
  IdentityFile ~/.ssh/[private-key]
  User ubuntu

Host [Private IP of test instance]
  ProxyCommand ssh -q -W %h:%p JUMPBOX
  ForwardAgent yes
  IdentityFile ~/.ssh/[private-key]
  User ubuntu

Host [Private IP of 2nd test instance]
  ProxyCommand ssh -q -W %h:%p JUMPBOX
  ForwardAgent yes
  IdentityFile ~/.ssh/[private-key]
  User ubuntu
```
- Please update the above file with the details of your own machine and then save and exit.
- Add the following rule in the security group of your test instances and then save it.(Custom IP is the CIDR of your VPC)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e1idzs8k3verwtbqikdw.png)

- Now, head over to the terminal and ssh into your test instances through your **private IP**.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5nvwy9baqmd4b9e4000.png)

- This is how we can **SSH** into our instances without a public `IPv4` address. This method can reduce the cost to a great extent. You can also install a **NAT gateway** in your public subnet to access the internet on these machines.

## Conclusion

In this blog, I discussed how we can **SSH** into our cloud machines from our local machine without the use of public `IPv4` addresses, and with the help of Tailscale using the **CGNAT** CIDR, thus saving the cost of using a public IPv4 address. I also discussed how we can create a **JUMPBOX** to do the same but with the cost of paying for only one `IPv4` network rather than paying for `IPv4` addresses for all the machines. These are some great alternatives to save the extra cost without transitioning into `IPv6` addresses.