<title>How to Bypass CGNAT - Exposing your home server to the internet with TLS/SSL pass through | Aiquiral's Blog</title>
<metaname="description"content="You've set up a home server, and are hosting some services like Vaultwarden, or Jellyfin, or perhaps Nextcloud. But now, you want to share it with friends and family, or maybe you just need the ability to access it remotely. So, you decided to expose it to the internet, but your ISP does not let you do that. Issues like dynamic IP can be resolved using a service like Duck DNS or No-IP, but if your ISP does not let you forward your ports, then you have to rely on third-parties to forward your traffic.">
<h1class="post-heading">How to Bypass CGNAT - Exposing your home server to the internet with TLS/SSL pass through</h1>
<pclass="post-date">07 October 2023 | Linux Guide, Privacy, Self-hosting</p>
<imgsrc="/assets/posts/2023-10-07-bypass-cgnat/bypass-cgnat.avif"class="featured"alt="A view of server racks with a text overlay reading “Bpass CGNAT - Privactely Expose Services Hosted on Your Homeserver”."title="How to Bypass CGNAT - Exposing your home server to the internet with TLS/SSL pass through"/>
<h2id="disclaimer">Disclaimer</h2>
<p>Exposing your home server to the internet can be dangerous. Look up some online guides about securing your servers before you do anything stupid. You have been warned. Also, I have not included any instructions related to SELinux.</p>
<li><ahref="#testing-and-finalising-the-wireguard-connection">Testing and finalising the WireGuard connection</a></li>
<li><ahref="#optional-configuration-of-home-server">Optional configuration of home server</a>
<ul>
<li><ahref="#haproxy">HAProxy</a></li>
<li><ahref="#certbot">Certbot</a></li>
</ul>
</li>
<li><ahref="#references">References</a></li>
</ol>
<h2id="introduction">Introduction</h2>
<p>You’ve set up a home server, and are hosting some services like Vaultwarden, or Jellyfin, or perhaps Nextcloud. But now, you want to share it with friends and family, or maybe you just need the ability to access it remotely. So, you decided to expose it to the internet, but your ISP does not let you do that. Issues like dynamic IP can be resolved using a service like Duck DNS or No-IP, but if your ISP does not let you forward your ports, then you have to rely on third-parties to forward your traffic.</p>
<h3id="easy-solutions">Easy Solutions</h3>
<p>There are many easy solutions to this problem. Cloudflare Tunnel is a free and popular solution. And if you just want remote access, Tailscale is another good option. If Tailscale’s backend servers are not being open-source is an issue, people can rely on Headscale.</p>
<p>But there is something you must know before considering these solutions. All these rely on TLS/SSL termination, which means your data is decrypted in the servers owned by these third parties.</p>
<p>Let me explain this in detail with taking Cloudflare Tunnel as an example.</p>
<p>One of the reasons we use SSL certificates on our websites to ensure that when the client requests data from the servers, or sends any data back to us, nobody else can look at that it, ensuring the client’s privacy. When we use Cloudflare Tunnel, the data may be encrypted on our server, but it is decrypted on Cloudflare’s servers, then re-encrypted and sent to the client. And when client enters any data like passwords, or upload any image, that data is, again, decrypted on Cloudflare’s servers (e2ee services are different, discussed below), then re-encrypted and sent back to us.</p>
<p>If you set up a Let’s Encrypt certificate on your server and route your traffic through a Cloudflare Tunnel, your clients will see a Cloudflare certificate. If you want them to see your Let’s Encrypt certificate, you will have to subscribe to their Business or Enterprise plan.</p>
<p>Take a look at this diagram for better understanding:</p>
<p>Diag</p>
<divclass=important-notestyle="padding-top: 0px">
<h4id="eli5">ELI5</h4>
<p>Let’s say you want to send your friend a message, but you don’t want anyone else to read it while in transit. So, you put the message in a locked box. So, if the box gets stolen on the way others won’t be able to read the message. That is what SSL certificates do.</p>
<p>But, let’s say you cannot go out of your house to deliver the box yourself, because your parents, that is, your ISP, won’t let you. So, you hire someone else, say, Cloudflare. But what Cloudflare says, is that they will look inside the box before if you want them to deliver it for free, If you want the box locked, you will have to pay them money.</p>
<p>There are some applications, like Vaultwarden, and Nextcloud with end-to-end encryption plugin, that are not affected with this because they encrypt the data themselves in the clients’ devices, using their own algorithms.</p>
</div>
<h3id="my-solution">My solution</h3>
<p>Earlier, I used to do the same thing, but manually. I rented a VPS on Hetzner and connected it to my home server using WireGuard. But since, the certificate management was handled by the VPS using Nginx Proxy Manager my VPS provider, Hetzner, could look at the data. So, I decided to learn about implementing TLS passthrough.</p>
<p>Now, my current setup is – I host services on my home server, manage certificates locally, and use the VPS to pass the data to the client without terminating the TLS/SSL connection.</p>
<p>Here is a diagram to explain my setup:</p>
<p>Diag</p>
<h2id="prerequisites">Prerequisites</h2>
<p>If you have looked at the diagram above, you may have already understood what you need to replicate my setup. Here are the details:</p>
<ul>
<li>A home server.</li>
<li>A VPS to route your traffic.
<ul>
<li><ahref="https://developer.oracle.com/free.html">Oracle Cloud</a>’s and <ahref="https://cloud.google.com/free">Google Cloud</a>’s free tier is an option if you are not willing to spend any money. But they are neither performant as they have weak vCPUs and limited bandwidth speed, nor reliable as there have been many reports of Oracle randomly shutting down free tier VPS allotments. Another reason I do not use them is because I would like to stay away from them as much as possible due to their privacy invading history. (Read –<ahref="https://wikiless.northboot.xyz/wiki/Privacy_concerns_regarding_Google">Google</a>, <ahref="https://techhq.com/2022/08/oracle-facing-data-backlash-for-violating-the-privacy-of-billions/">Oracle</a>)</li>
<li>Personally, I use Hetzner (here is my <ahref="https://hetzner.cloud/?ref=axsjWq6L448M">referral link</a>, which will give you €20 credit for 3 months). I have been using their services for a long time and never had any issue. Also, their privacy policy is far better than others. Their cheapest ARM servers cost €3.29/mo which have 2 vCPUs and 4 GB RAM.</li>
<li>Other options are Digital Ocean, Vultr, or any VPS provider who will give you root access.</li>
</ul>
</li>
<li>Basic command line knowledge.</li>
<li>WireGuard on both, your home server and the VPS, and iptables on the VPS. Instructions are provided below.</li>
<li>Optionally, HAProxy and Certbot on your home server.</li>
</ul>
<h2id="preparing-the-servers">Preparing the servers</h2>
<p>I am assuming you have already updated and secured both of your machines and have access to both using <codeclass="language-plaintext highlighter-rouge">ssh</code> or <codeclass="language-plaintext highlighter-rouge">dropbear</code>.</p>
<p>Make sure <codeclass="language-plaintext highlighter-rouge">net.ipv4.ip_forward=1</code> is present. If it is not, type it at the end of the file. It might also be the case that it is present but has a pound sign (#) at the start of the line. This means that it is commented, and not enabled. Removing the sign will enable it.</p>
<p>Tip – If the file is too big, and you cannot find this line, you can press <codeclass="language-plaintext highlighter-rouge">ctrl + w</code> to find it.</p>
<p>Save and close the file by pressing <codeclass="language-plaintext highlighter-rouge">ctrl + x</code>, then <codeclass="language-plaintext highlighter-rouge">y</code>, and then <codeclass="language-plaintext highlighter-rouge">enter</code>. If you have not made any changes to the file, pressing <codeclass="language-plaintext highlighter-rouge">ctrl + x</code> will simply close the file.</p>
<p>If you made any changes to the file, run the following command:</p>
<p>Now, let us set up WireGuard. The basic idea is, the both servers will generate a pair of private and public keys. The WireGuard configuration files on both servers will contain their own private key and each other’s public key. There are many ways of doing it, but I find this way to be the easiest.</p>
<p>Run the following commands:</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
</code></pre></div></div>
<p>The first command generates the private key of the VPS, and it will be saved in a specific location. The second command removes any permissions on the file for users and groups other than the root user to ensure that only it can access the private key. And the third command generates the public key of the VPS, and it will be saved in the same location as the private key.</p>
<p>Now, create a new wireguard configuration file using</p>
<p>Replace the <codeclass="language-plaintext highlighter-rouge">SERVER-IP</code>, at the end of those lines, with the public IP address of your VPS. For now, we will keep the PrivateKey and PublicKey empty.</p>
<p>Press <codeclass="language-plaintext highlighter-rouge">ctrl +x</code>, then <codeclass="language-plaintext highlighter-rouge">y</code>, and then <codeclass="language-plaintext highlighter-rouge">enter</code>, to save the configuration file.</p>
<h3id="setting-up-your-home-server">Setting up your home server</h3>
<p>Run the same commands as we did on the VPS to generate public and private keys.</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
</code></pre></div></div>
<p>Create a new wireguard configuration file using</p>
<p>Press <codeclass="language-plaintext highlighter-rouge">ctrl +x</code>, then <codeclass="language-plaintext highlighter-rouge">y</code>, and then <codeclass="language-plaintext highlighter-rouge">enter</code>, to save the configuration file.</p>
<p>Now, we will insert the public and private keys in the config files. We will have to go back and forth in your home server and the VPS to print keys and change the configuration files.</p>
<p>Now, you can point your domain(s) and/or subdomains to the public IP address of your VPS.</p>
<h2id="optional-configuration-of-home-server">Optional configuration of home server</h2>
<h3id="haproxy">HAProxy</h3>
<p>For a reverse proxy, any solution would work. But personally, I shifted from Nginx Proxy Manager to HAProxy because, In my opinion, it is faster, lightweight and provides more control.</p>
<p>To install HAProxy, use your default package manager.</p>
<p>If you are using my config file, you will see that I have added a location for an SSL certificate. If you restart the service without providing a valid SSL certificate, it will throw an error and the service will stop.</p>
<p>Now, let us jump to generating an SSL certificate.</p>
<h3id="certbot">Certbot</h3>
<p>The official documentation states that you must install certbot using Snap package manager. I do not like it at all due to its back-end being proprietary. I used my distibution’s (Fedora’s) package manager to install certbot and it works fine. So, I leave the installtion of certbot to you.</p>
<p>There are many ways to generate a certbot certificate, depending upon your requirements. I recommend setting up a wildcard certificate. You will need your domain provider’s API key. A simple search on your search engine will help you find a decent guide. Generate a certificate using <codeclass="language-plaintext highlighter-rouge">certbot certonly</code> command, as we are going to set up HAProxy with the certificate ourselves.</p>
<p>Certbot will generate a private key and a public key certificate in <codeclass="language-plaintext highlighter-rouge">/etc/letsencrypt/live/YOURDOMAIN.COM</code> folder. We will have to pipe both of them into a single file.</p>
<p>Run the following commands, after replacing <codeclass="language-plaintext highlighter-rouge">YOURDOMAIN.COM</code> with your actual domain and providing a proper path to certificate:</p>
<divclass="language-plaintext highlighter-rouge"><divclass="highlight"><preclass="highlight"><code>sudo cat /etc/letsencrypt/live/YOURDOMAIN.COM/fullchain.pem /etc/letsencrypt/live/YOURDOMAIN.COM/privkey.pem | sudo tee /path/to/certificate.pem
</code></pre></div></div>
<p>After making sure that certbot will be autorenewing your certificate, you can add this command in your root user’s crontab. Run the following to create a new cronjob:
sudo crontab -e</p>
<p>Add the above command with proper syntax. Add</p>
<p>That is it. You are done. Whenever you create new services, make sure you update your HAProxy configuration file and restart the HAProxy service.</p>
<p>Although, you do not have to touch your VPS anymore, I still recommend loging into the machine updating and rebooting it regularly.</p>
<p>If you have any questions, or suggestions, leave a comment down below, or reach out to me <ahref="https://aiquiral.me/contact">directly</a>.</p>
<h3style="color: #25252d;">How to Bypass CGNAT - Exposing your home server to the internet with TLS/SSL pass through</h3>
<p>07 October 2023 | Linux Guide, Privacy, Self-hosting</p>
<p>You've set up a home server, and are hosting some services like Vaultwarden, or Jellyfin, or perhaps Nextcloud. But now, you want to share it...</p>
<h3style="color: #25252d;">Proton VPN Linux Guide – How to install, configure, use and auto-connect?</h3>
<p>19 May 2023 | Linux Guide, Privacy</p>
<p>The official Proton VPN Linux client lacks a lot of features, like changing the connection protocol, quickly connecting to the fastest server of a specific...</p>