<p>I have a running Rancher setup as the following:</p>

<ul>
<li>Host machine (running <a href="https://github.com/rancher/rancher" rel="noreferrer">rancher/rancher</a> container) on a public IP;</li>
<li>Nodes in an exclusive network (10.1.1.0/24) not accessible from the Internet.</li>
</ul>

<p>My goal is to serve a web application using the Rancher Load Balancing or whatever similar stuff.
For that, I've perfomed the following steps:</p>

<ul>
<li>Deploy workload using the "rancher/hello-world" image on 3 pods mapping port 80/tcp as a NodePort (listening port is random) named "web-app";</li>
<li>Add Ingress named "hello" in same namespace selecting "Automatically generate a <code>.xip.io</code> hostname" and adding route "/" to the "web-app" on port 80.</li>
</ul>

<p>This works on the local network, since I get an address like <a href="http://hello.gabriel-milan.10.1.1.14.xip.io/" rel="noreferrer">http://hello.gabriel-milan.10.1.1.14.xip.io/</a> that would resolve to 10.1.1.14, which is local.</p>

<p>I wanted to expose this service for one of my public IPs. How can I do that?</p>

<blockquote>
<p>Edit 2021-09-27: <code>xip.io</code> is gone, but I'm leaving those references in my response because the OP asked about <code>xip.io</code>. Alternatives are <code>sslip.io</code> and <code>nip.io</code>, which both function the same way. You can replace <code>xip.io</code> in my response with either of those to achieve the same results.</p>
</blockquote>
<p>There are a couple ways of doing this. Based on your use of a private network that is not accessible from the Internet, the nodes don't have public IPs, and therefore Kubernetes doesn't know anything about whatever public IP is mapped to them. This is how it works in EC2, or anywhere that has a NAT happening off the nodes.</p>
<p>If those nodes are a Custom cluster (where you install Docker and then use the <code>docker run</code> command from Rancher to install RKE and join the cluster to Rancher), then before you install, you can click the Advanced Options link in the bottom right corner and set the public and private IPs for each node.</p>
<p>When you do this, the nodes receive a label that holds the public IP, and that address will be used with your <code>xip.io</code> hostname that you generate when setting up the Ingress.</p>
<p>Without that label, the <code>xip.io</code> hostname picks up the primary IP of the node, which in this case is on the private network.</p>
<p>If you do this, though, your traffic will only go to one node on the cluster, even if your ingress controller is listening on multiple nodes.</p>
<p>Instead, when running a multi-node cluster, I recommend that you put a Layer 4 load balancer in front of all worker nodes (or the nodes where the ingress controller is listening if it's not listening on every node). Punch through 80 and 443, and then use that as the target for your domain.</p>
<p><code>domain.com -&gt; load balancer -&gt; ingress controller (on all nodes) -&gt; Service -&gt; Pods</code></p>
<p>Your ingress controller is listening on 80/443 for HTTP traffic, which also means that your Service doesn't have to be NodePort. It can be ClusterIP because traffic goes through the ingress controller and then is routed inside the cluster.</p>
<p>NodePort services are used when you have an external load balancer and you need to direct traffic to a <em>specific</em> service. In that scenario, the external load balancer replaces the ingress controller. You create NodePort services for each of your apps, and then you tell the load balancer to send traffic for App A to each node on port 30547 or whatever the NodePort is for that service.</p>
<p>Incidentally, if you're in a cloud provider, you can combine these into a LoadBalancer Service. That will create a NodePort Service on the nodes and then reach out to the cloud provider's API and deploy a cloud load balancer and then program it with the nodes, the port for the Service, and maintain that configuration for the life of the Service.</p>
<p>To recap:</p>
<ul>
<li>Your nodes don't know their public IP, so the <code>xip.io</code> hostname can't know it either</li>
<li>Put a Layer 4 load balancer in front of your nodes and send traffic to 80/443 on all nodes</li>
<li>Change your Service to be ClusterIP</li>
<li>Send traffic to the load balancer</li>
</ul>
<p>Also, as a workaround if you don't want to deploy a load balancer, you can delete the Ingress and recreate it, but instead of creating an <code>xip.io</code> hostname automatically, choose &quot;Set a hostname&quot; and create it manually. If one node's public IP is <code>1.2.3.4</code>, then you can set it to <code>any.thing.you.want.1.2.3.4.xip.io</code> and it'll return <code>1.2.3.4</code> to DNS queries.</p>
<p>You just can't edit an existing <code>xip.io</code> Ingress and change it to a different manual <code>xip.io</code> hostname. You have to recreate it.</p>
<p>In this workaround traffic is still coming in to the ingress controller, so you can still change your Service from NodePort to ClusterIP.</p>
<p>Disclosure: I work for Rancher.</p>
