{"id":333,"date":"2020-09-03T00:13:24","date_gmt":"2020-09-02T22:13:24","guid":{"rendered":"https:\/\/raulbalanza.me\/?p=333"},"modified":"2024-01-18T23:18:42","modified_gmt":"2024-01-18T22:18:42","slug":"hiding-a-servers-ip-by-means-of-a-reverse-proxy","status":"publish","type":"post","link":"https:\/\/raulbalanza.me\/es\/2020\/09\/03\/hiding-a-servers-ip-by-means-of-a-reverse-proxy\/","title":{"rendered":"Hiding a server&#8217;s IP by means of a reverse proxy"},"content":{"rendered":"<p><em>Este art\u00edculo fue escrito originalmente en Ingl\u00e9s. Sin embargo, una versi\u00f3n traducida autom\u00e1ticamente se encuentra&nbsp;<a href=\"https:\/\/translate.google.com\/translate?sl=en&amp;tl=es&amp;u=https%3A%2F%2Fraulbalanza.me%2F2020%2F09%2F03%2Fhiding-a-servers-ip-by-means-of-a-reverse-proxy%2F\">aqu\u00ed<\/a>.<\/em><\/p>\n\n\n\n<p>When it comes to <strong>hosting public services online<\/strong> (such as a website, the backend of an application&#8230;), several options can be considered. The most common one is to rent a dedicated server from a hosting company and to host the desired service there. However, this option can end up being too costly depending on the hardware and software needs of such service, that could lead us to consider an alternative option.<\/p>\n\n\n\n<p>A great choice could be to <strong>host our own server<\/strong>, either at home or in the office. In that case, two problems arise: having a dynamic IP, which is what most ISPs offer to the general public (and could be solved by using Dynamic DNS); and the hassle of sharing the public IP of our office\/home, so that anyone can connect to the service (and also attack it).<\/p>\n\n\n\n<p>Moreover, due to the <strong>IPv4 address exhaustion problem<\/strong><sup>[1]<\/sup>, lately several ISPs are starting to implement a network design approach known as <em>Carrier-Grade NAT<\/em><sup>[2]<\/sup> (or CG-NAT), that groups several clients in the same public IP, which does not allow for port forwarding, and could make it impossible to host any public service from our local network.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/cgnat.png\" alt=\"\" class=\"wp-image-361\" width=\"397\" height=\"216\" srcset=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/cgnat.png 600w, https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/cgnat-300x164.png 300w\" sizes=\"(max-width: 397px) 85vw, 397px\" \/><figcaption class=\"wp-element-caption\">Figure 1. CG-NAT scheme<\/figcaption><\/figure><\/div>\n\n\n<p>In those cases, or in any other in which it is of our interest to hide the IP of a computer that hosts a public service, a <strong>reverse proxy<\/strong> could be the solution to that problem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Definition<\/h2>\n\n\n\n<p>A <strong>reverse proxy<\/strong><sup>[3]<\/sup> can be defined as a <em>type of proxy server that retrieves resources on behalf of a client from one or more servers. These resources are then returned to the client, appearing as if they originated from the server itself<\/em>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-medium is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/reverse_proxy-300x110.png\" alt=\"\" class=\"wp-image-337\" width=\"548\" height=\"201\" srcset=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/reverse_proxy-300x110.png 300w, https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/reverse_proxy-1024x376.png 1024w, https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/reverse_proxy-768x282.png 768w, https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/reverse_proxy.png 1168w\" sizes=\"(max-width: 548px) 85vw, 548px\" \/><figcaption class=\"wp-element-caption\">Figure 2. Reverse proxy diagram<\/figcaption><\/figure><\/div>\n\n\n<p>The process of interchanging network packets would be as follows:<\/p>\n\n\n\n<ol>\n<li>The <strong>client <\/strong>connects to the <strong>proxy<\/strong>&#8216;s IP, sending some packets<\/li>\n\n\n\n<li>The <strong>proxy <\/strong>redirects those packets to the <strong>final server<\/strong> through a VPN.<\/li>\n\n\n\n<li>The <strong>final server<\/strong> processes the request and returns the packets to the <strong>proxy<\/strong>.<\/li>\n\n\n\n<li>The <strong>proxy <\/strong>sends the reply to the <strong>client<\/strong>, who sees from his perspective that the packets have been processed in the proxy.<\/li>\n<\/ol>\n\n\n\n<p>Using this method, the IP that would be exposed to the Internet would be the proxy one, so in case of receiving an attack, it would be enough to shutdown the proxy machine in order to stop the attack and to save the local network from going down.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installation<\/h2>\n\n\n\n<p>For the installation process<sup>[4]<\/sup>, it is assumed that both systems run a Debian-based Linux distribution. The following steps are divided into two parts: the <strong>proxy <\/strong>server and the <strong>final server<\/strong> side.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1: Proxy server<\/h3>\n\n\n\n<p>For the proxy server, <em>iptables <\/em>will be the software in charge of routing the packets to the final server. Although it comes preinstalled in most Linux distributions, we will make sure by running:<\/p>\n\n\n\n<p><strong>sudo apt-get install iptables<\/strong><\/p>\n\n\n\n<p>Once the installation ends, the next step is to install the VPN server that will establish the connection between the proxy and the final server, which in this case is <em>OpenVPN<\/em>. To do so, we will run the following command<sup>[5]<\/sup>:<\/p>\n\n\n\n<p><strong>wget https:\/\/git.io\/vpn -O openvpn-install.sh &amp;&amp; bash openvpn-install.sh<\/strong><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" loading=\"lazy\" src=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/openvpn_script.png\" alt=\"\" class=\"wp-image-381\" width=\"599\" height=\"488\" srcset=\"https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/openvpn_script.png 765w, https:\/\/raulbalanza.me\/wp-content\/uploads\/2020\/09\/openvpn_script-300x244.png 300w\" sizes=\"(max-width: 599px) 85vw, 599px\" \/><figcaption class=\"wp-element-caption\">Figure 3. OpenVPN install script<\/figcaption><\/figure><\/div>\n\n\n<p>The installer will ask for several preferences, that you can mostly leave with their default values. When the server finishes its installation, it will be automatically started, and a VPN profile with the &#8216;<strong><em>.ovpn<\/em><\/strong>&#8216; extension will be created. That file needs to be transferred to the <strong>final server<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2: Final server<\/h3>\n\n\n\n<p>Now that we already have the VPN up and running, we can connect to it from our final server. To do so, first of all the OpenVPN client must be installed, by running:<\/p>\n\n\n\n<p><strong>sudo apt-get install openvpn<\/strong><\/p>\n\n\n\n<p>When the installation finishes, we can now connect to the server. We will navigate to the folder in which the previous &#8216;<strong><em>.ovpn<\/em><\/strong>&#8216; file is now located, and then the connection can be started by running:<\/p>\n\n\n\n<p><strong>sudo openvpn profile.ovpn<\/strong><\/p>\n\n\n\n<p>At this time the tunnel between the proxy and the final server is already created, and only packet redirection is left to configure. For the last part of the installation in the proxy server, we need to get the IP address that the VPN adapter has assigned to the final server. This address can be obtained by using:<\/p>\n\n\n\n<p><strong>sudo ip a<\/strong><\/p>\n\n\n\n<p>And then it will be located in the <strong><em>inet<\/em> <\/strong>section of the corresponding adapter, that will have a name like &#8216;<strong>tun0<\/strong>&#8216;. You should take note of it, as it will be required in further steps.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3: Proxy server<\/h3>\n\n\n\n<p>Once we have the VPN tunnel already set up, the last step is to create the forwarding rules that will route packets from the proxy to the final server. To do it, we will change the <em>iptables<\/em>&#8216; configuration.<\/p>\n\n\n\n<p>First, export your current configuration by executing the following command:<\/p>\n\n\n\n<p><strong>sudo iptables-save &gt; \/path\/to\/config.cfg<\/strong><\/p>\n\n\n\n<p>After the previous command, the current configuration will be stored in the specified path. Next up, open it with a text editor and modify the &#8216;<strong>*nat<\/strong>&#8216; section with the following values:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">*nat\n:PREROUTING ACCEPT [0:0]\n:INPUT ACCEPT [0:0]\n:OUTPUT ACCEPT [0:0]\n:POSTROUTING ACCEPT [0:0]\n# Forwarding incoming port 80 on proxy to final server IP's port 8080 through it's VPN IP\n-A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination <b>IP_VPN_FINAL<\/b>:8080\n# Change source ips from VPN IP to VPS' IP for all outbound traffic\n-A POSTROUTING -s 10.8.0.0\/24 -j SNAT --to-source <b>VPS_PUBLIC_IP<\/b><\/pre>\n\n\n\n<p>The previous example contains a forwarding rule that redirects connections arriving to proxy&#8217;s port 80, to final server&#8217;s port 8080 in the TCP protocol. However, several lines can be added to allow for different ports and protocols to be forwarded, following this pattern:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">-A PREROUTING -p <b>PROTOCOL<\/b> -m <b>PROTOCOL<\/b> --dport <b>PROXY_PORT<\/b> -j DNAT --to-destination <strong>IP_VPN_FINAL<\/strong>:<b>SERVER_PORT<\/b><\/pre>\n\n\n\n<p>In that configuration example, some values must be also replaced depending on your own addresses:<\/p>\n\n\n\n<ul>\n<li><strong><em>IP_VPN_FINAL<\/em><\/strong> corresponds to the previously noted VPN adapter&#8217;s IP of the final server.<\/li>\n\n\n\n<li><strong><em>VPS_PUBLIC_IP<\/em><\/strong> corresponds to the public IP of the proxy, the one that will be shared for the users to connect to the server.<\/li>\n<\/ul>\n\n\n\n<p>If you do not know the public IP of the proxy server, it can be obtained by using this command:<\/p>\n\n\n\n<p><strong>dig +short myip.opendns.com @resolver1.opendns.com<\/strong><\/p>\n\n\n\n<p>When all the desired ports are configured with their respective rules, save the file and execute the following command to import it into <em>iptables<\/em>:<\/p>\n\n\n\n<p><strong>sudo iptables-restore &lt; \/path\/to\/config.cfg<\/strong><\/p>\n\n\n\n<p>You must ensure that the proxy server has the required incoming ports and the VPN port (normally 1194 &#8211; UDP) open, to allow for the users and the final server to connect to the proxy, respectively. Furthermore, the hosted server(s) must be listening for connections on the VPN IP.<\/p>\n\n\n\n<p>Once the configuration is saved, the installation of the reverse proxy is complete, and the real IP of the final server will not be visible from external clients, as from their perspective it is the proxy who processes the requests.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Known issues<\/h2>\n\n\n\n<ul>\n<li>During the configuration of this proxy on my own servers, the final server could not resolve DNS queries once connected to the VPN tunnel. Changing the DNS servers in the operating system&#8217;s configuration to Google DNS solved the problem.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul>\n<li><sup>[1]<\/sup><a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/IPv4_address_exhaustion\" target=\"_blank\">IPv4 address exhaustion<\/a> on <em>Wikipedia<\/em><\/li>\n\n\n\n<li><sup>[2]<\/sup><a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Carrier-grade_NAT\" target=\"_blank\">Carrier-grade NAT<\/a> on <em>Wikipedia<\/em><\/li>\n\n\n\n<li><sup>[3]<\/sup><a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Reverse_proxy\" target=\"_blank\">Reverse proxy<\/a> on <em>Wikipedia<\/em><\/li>\n\n\n\n<li><sup>[4]<\/sup><a rel=\"noreferrer noopener\" href=\"https:\/\/www.reddit.com\/r\/homelab\/comments\/6zmke1\/vps_reverse_proxy_via_vpn_tunnel\/\" target=\"_blank\">Installation process idea<\/a> by <em>\/u\/Butterface_Fixer<\/em> on <em>Reddit<\/em><\/li>\n\n\n\n<li><sup>[5]<\/sup><a href=\"https:\/\/github.com\/Nyr\/openvpn-install\" target=\"_blank\" rel=\"noreferrer noopener\">OpenVPN installation script<\/a> by <em>Nyr<\/em> on <em>Github<\/em><\/li>\n<\/ul>\n\n\n\n<p><\/p>","protected":false},"excerpt":{"rendered":"<p>This article was originally written in English. However, an automatically translated version can be found&nbsp;here. When it comes to hosting public services online (such as a website, the backend of an application&#8230;), several options can be considered. The most common one is to rent a dedicated server from a hosting company and to host the &hellip; <a href=\"https:\/\/raulbalanza.me\/es\/2020\/09\/03\/hiding-a-servers-ip-by-means-of-a-reverse-proxy\/\" class=\"more-link\">Continuar leyendo<span class=\"screen-reader-text\"> &#8220;Hiding a server&#8217;s IP by means of a reverse proxy&#8221;<\/span><\/a><\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/posts\/333"}],"collection":[{"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/comments?post=333"}],"version-history":[{"count":55,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/posts\/333\/revisions"}],"predecessor-version":[{"id":577,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/posts\/333\/revisions\/577"}],"wp:attachment":[{"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/media?parent=333"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/categories?post=333"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/raulbalanza.me\/es\/wp-json\/wp\/v2\/tags?post=333"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}