<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jim Ryan&apos;s Blog</title>
    <description>Jim Ryan&apos;s Blog</description>
    <link>https://jimryan.ie/</link>
    <atom:link href="https://jimryan.ie/rss.xml" rel="self" type="application/rss+xml" />
    <lastBuildDate>Sat, 05 Sep 2026 11:05:26 GMT</lastBuildDate>
    <item>
      <title>Perfect magic hypercube centre</title>
      <description>A Lean proof about the centre of a perfect magic hypercube.</description>
      <link>https://jimryan.ie/hypercube-center-proof/</link>
      <guid isPermaLink="true">https://jimryan.ie/hypercube-center-proof/</guid>
      <pubDate>Sat, 05 Sep 2026 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>For <code>k >= 1</code>, the central entry of a perfect magic hypercube of order <code>2k+1</code> and dimension <code>k+1</code> is the average of all its entries.</p>
<p>This is the centre value question in <a href="http://www.multimagie.com/English/Problems.htm#SquaresOfSquares">Christian Boyer's Problem 10</a>. The <a href="https://github.com/j1m-ryan/hypercube-center-proof">Lean proof is on GitHub</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>NGINX Ingress Controller Home Server (Part 1 - Networking)</title>
      <description>Using NGINX Ingress Controller to host a home server. In this part, I will be setting up the networking for the home server, using MetalLB and k0s.</description>
      <link>https://jimryan.ie/nic-home-server-part-1/</link>
      <guid isPermaLink="true">https://jimryan.ie/nic-home-server-part-1/</guid>
      <pubDate>Fri, 01 Mar 2024 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Introduction</h2>
<p>Welcome to this series of blog posts where I will be documenting my journey of setting up a home server using Kubernetes and <a href="https://github.com/nginxinc/kubernetes-ingress">NGINX Ingress Controller</a>. This is the first part of the series where I will be setting up the networking for the home server.</p>
<p>I have chosen to use <a href="https://k0sproject.io/">k0s</a> as the Kubernetes distribution for this project. k0s allows me to set up a multi-node (or single node) Kubernetes cluster by specifying the IP addresses of the nodes in the <code>k0sctl.yaml</code> file. I will also be using <a href="https://metallb.universe.tf/">MetalLB</a> which allow creation of Services of type LoadBalaner on the cluster. More specifically, it will allows the NGINX Ingress Controller service to have an external IP address, otherwise this will show up as <code>pending</code>.</p>
<h2>Installing the Operating System</h2>
<p>The first step is to install an operating system on the servers that will be used as part of the cluster. I have installed Ubuntu 23.10 on my two nodes. One is a Raspberry Pi 4 (with 4GB of ram) and the other is a <a href="https://www.bee-link.com/catalog/product/buy?id=540">Beelink SER7 7840HS</a> with 32 GB of ram.</p>
<p>The current supported operating systems and architectures for k0s nodes are listed <a href="https://docs.k0sproject.io/head/system-requirements/">here</a>.</p>
<p>After installing your operating system, make sure to connect the nodes to the same network and give them static IP addresses. You can lock the IP addresses to the MAC addresses of the nodes in your router settings.</p>
<p>It is also important to give the nodes a unique hostname. You can do this by editing the <code>/etc/hostname</code> file. I have named my SER7 node <code>hendrix</code> and my Raspberry Pi 4 node <code>rpi</code>.</p>
<h2>Setting up SSH</h2>
<p>In order for <code>k0sctl</code> to work, it needs to be able to SSH into the nodes as the root user. From your primary machine (which should also be on the same network), copy your SSH public key to the nodes. You can do this by running the following command:</p>
<pre><code class="hljs language-bash">ssh-copy-id root@&#x3C;node-ip>
</code></pre>
<p>Do this for each node you have in your cluster. You should now be able to SSH into the nodes without needing to enter a password.</p>
<pre><code class="hljs language-bash">ssh root@&#x3C;node-ip>
</code></pre>
<h2>Installing k0s on the Nodes</h2>
<p><code>k0s</code> has a tool called <code>k0sctl</code> which is used to install and manage the k0s cluster. You can download this tool on your primary machine (outside the cluster) using the instructions in its <a href="https://github.com/k0sproject/k0sctl">GitHub repository</a>.</p>
<p>Now, create a <code>k0sctl.yaml</code> file with the following content:</p>
<pre><code class="hljs language-yaml:title=k0sctl.yaml">apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: k0s-cluster
spec:
  hosts:
  - ssh:
      address: 192.168.1.160
      user: root 
      port: 22
      keyPath: ~/.ssh/id_ed25519
    role: controller+worker
  - ssh:
      address: 192.168.1.106
      user: root 
      port: 22
      keyPath: ~/.ssh/id_ed25519
    role: worker
  k0s:
    version: ""
    config:
      spec:
        extensions:
          helm:
            repositories:
            - name: metallb
              url: https://metallb.github.io/metallb
            charts:
            - name: metallb
              chartname: metallb/metallb
              namespace: metallb-system
</code></pre>
<p>Replace the <code>address</code> field with the IP addresses of your nodes. The <code>role</code> field specifies the role of the node. In this case, the first node is both a controller and a worker, and the second node is just a worker. k0s has a helm extension which allows you to install helm charts on the cluster. Here, I am installing the MetalLB helm chart to the cluster via k0sctl.</p>
<p>Now, run the following command to install the k0s cluster:</p>
<pre><code class="hljs language-bash">k0sctl apply --config k0sctl.yaml
</code></pre>
<p>After running this command, you should see the k0s cluster being installed on your nodes.</p>
<h2>Using your KubeConfig</h2>
<p><code>k0sctl kubeconfig</code> will generate a kubeconfig file for you to use to interact with the cluster. You can then interact with the cluster using <code>kubectl</code>.
The easiest way to do this is to copy the kubeconfig file to <code>~/.kube/config</code> on your primary machine, with the following command:</p>
<pre><code class="hljs language-bash">k0sctl kubeconfig > ~/.kube/config
</code></pre>
<p>You can now interact with the cluster using <code>kubectl</code>:</p>
<pre><code class="hljs language-bash">kubectl get nodes
</code></pre>
<p><img src="https://jimryan.ie/images/blog/nic-home-server-part-1/getnodes.png" alt="kubectl get nodes"></p>
<h2>Applying the MetalLB Config</h2>
<p>The last step before installing the NGINX Ingress Controller is to apply the MetalLB configuration. This will allow the NGINX Ingress Controller service to have an external IP address.</p>
<p>Before applying the MetalLB configuration, you need to decide on a range of IP addresses that MetalLB can use. This range should be within the IP address range of your network. I have chosen the range <code>192.168.1.180-192.168.1.199</code>. Ensure that these IP addresses that you choose are not already in use on your network.</p>
<pre><code class="hljs language-yaml:title=metallb-config.yaml">apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: my-ip-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.1.180-192.168.1.199
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: my-l2advertisement
  namespace: metallb-system
</code></pre>
<p>Apply the MetalLB configuration using the following command:</p>
<pre><code class="hljs language-bash">kubectl apply -f metallb-config.yaml
</code></pre>
<p>Now, you should be able to see the MetalLB pods running in the <code>metallb-system</code> namespace:</p>
<pre><code class="hljs language-bash">kubectl get pods --namespace metallb-system
</code></pre>
<p><img src="https://jimryan.ie/images/blog/nic-home-server-part-1/metallb.png" alt="kubectl get metallb pods"></p>
<h2>Installing the NGINX Ingress Controller</h2>
<p>Now that we have MetalLB installed, we can install NGINX Ingress Controller. The default installation of NGINX Ingress Controller via helm uses a LoadBalancer service type, which is why we needed to install MetalLB first.</p>
<h3>Adding the NGINX Helm Repository</h3>
<pre><code class="hljs language-bash">helm repo add nginx-stable https://helm.nginx.com/stable
helm repo update
</code></pre>
<p>As we are going to be modifying the default helm chart, we need to first download the helm chart to our local machine. You can do this by running the following command:</p>
<pre><code class="hljs language-bash">helm pull nginx-stable/nginx-ingress --untar
</code></pre>
<h3>Modifying the Helm Chart</h3>
<p>I need to add a toleration under the <code>controller</code> section of the <code>values.yaml</code> file. This is because NGINX Ingress Controller could end up on my <code>controller+worker</code> node that I defined in <code>k0sctl.yaml</code>.</p>
<pre><code class="hljs language-yaml:title=values.yaml">controller:
  tolerations:
    - key: "node-role.kubernetes.io/master"
      operator: "Exists"
      effect: "NoSchedule"
</code></pre>
<h3>Installing the NGINX Ingress Controller helm chart</h3>
<pre><code class="hljs language-bash">helm install nginx-ingress ./nginx-ingress --namespace nginx-ingress --create-namespace
</code></pre>
<p>Now NGINX Ingress Controller should be installed on your cluster.</p>
<p>You can check the status of the NGINX Ingress Controller pods by running the following command:</p>
<pre><code class="hljs language-bash">kubectl get pods --namespace nginx-ingress
</code></pre>
<p>To get the <code>externalIP</code> address of the NGINX Ingress Controller LoadBalancer service, run the following command:</p>
<pre><code class="hljs language-bash">kubectl get svc --namespace nginx-ingress
</code></pre>
<p>You should now be able to access the NGINX Ingress Controller using the <code>externalIP</code> address. This will show a default 404 page.</p>
<pre><code class="hljs language-bash">curl -I &#x3C;externalIP>
</code></pre>
<h2>Exposing NGINX Ingress Controller to the Internet</h2>
<p>The last step is to expose the NGINX Ingress Controller to the internet. This can be done by setting up port forwarding on your router. You will need to forward ports <code>80</code> and <code>443</code> to the <code>externalIP</code> address of the NGINX Ingress Controller LoadBalancer service, or use the <code>externalIP</code> address as the DMZ host.</p>
<p><img src="https://jimryan.ie/images/blog/nic-home-server-part-1/dmz.png" alt="DMZ"></p>
<p>After this, you should be able to access the NGINX Ingress Controller from the internet, via your public IP address.</p>
<h2>Conclusion</h2>
<p>In this part, I have set up the networking for the home server. I have installed k0s on the nodes, set up MetalLB to allow the NGINX Ingress Controller service to have an external IP address, and installed the NGINX Ingress Controller. In the next part, I will be setting up the external-dns and cert-manager.</p>]]></content:encoded>
    </item>
  </channel>
</rss>