<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Farhan Ahmed</title>
    <description>The latest articles on DEV Community by Farhan Ahmed (@itsfarhan).</description>
    <link>https://dev.to/itsfarhan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3016656%2F2db7764f-d275-4beb-b11f-410388bd9fad.png</url>
      <title>DEV Community: Farhan Ahmed</title>
      <link>https://dev.to/itsfarhan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/itsfarhan"/>
    <language>en</language>
    <item>
      <title>Create basic cluster with Kubeadm on AWS EC2 Instance</title>
      <dc:creator>Farhan Ahmed</dc:creator>
      <pubDate>Sat, 05 Jul 2025 10:11:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/create-basic-cluster-with-kubeadm-on-aws-ec2-instance-2l1p</link>
      <guid>https://dev.to/aws-builders/create-basic-cluster-with-kubeadm-on-aws-ec2-instance-2l1p</guid>
      <description>&lt;h2&gt;
  
  
  Installing &lt;strong&gt;Kubernetes 1.31&lt;/strong&gt; and &lt;strong&gt;create a cluster using &lt;code&gt;kubeadm&lt;/code&gt; (with Containerd and Calico CNI)&lt;/strong&gt;, here's for setting up a basic cluster (1 master + N workers):
&lt;/h2&gt;

&lt;h2&gt;
  
  
  🖥️ EC2 Instance Setup for Kubeadm
&lt;/h2&gt;

&lt;p&gt;Follow these steps to launch and configure EC2 instances for setting up a Kubernetes cluster using &lt;code&gt;kubeadm&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Step 1: Launch EC2 Instances
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Login to AWS Console&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;EC2 &amp;gt; Instances &amp;gt; Launch Instance&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure the instance as below:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;| Setting            | Value                            |&lt;br&gt;
   | ------------------ | -------------------------------- |&lt;br&gt;
   | &lt;strong&gt;Name&lt;/strong&gt;           | &lt;code&gt;Kubernetes&lt;/code&gt;                     |&lt;br&gt;
   | &lt;strong&gt;OS&lt;/strong&gt;             | &lt;code&gt;Ubuntu 24.04 LTS&lt;/code&gt;               |&lt;br&gt;
   | &lt;strong&gt;Instance Type&lt;/strong&gt;  | &lt;code&gt;t3.medium&lt;/code&gt;                      |&lt;br&gt;
   | &lt;strong&gt;Key Pair&lt;/strong&gt;       | Create or select an existing     |&lt;br&gt;
   | &lt;strong&gt;Security Group&lt;/strong&gt; | Create or select one (see below) |&lt;/p&gt;


&lt;h3&gt;
  
  
  🔐 Step 2: Create Security Group
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;VPC &amp;gt; Security &amp;gt; Security Groups&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Security Group&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure like below:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security Group Name&lt;/strong&gt;: &lt;code&gt;kubernetes-security&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
  
  
  🔽 Inbound Rules
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port Range&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;td&gt;TCP&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;Anywhere (0.0.0.0/0)&lt;/td&gt;
&lt;td&gt;For SSH access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All Traffic&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Custom (your VPC CIDR)&lt;/td&gt;
&lt;td&gt;Allow all communication between nodes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;Note&lt;/strong&gt;: If you're testing, you can temporarily use &lt;code&gt;Anywhere&lt;/code&gt; for "All Traffic" but limit it for production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  🔼 Outbound Rules
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Protocol&lt;/th&gt;
&lt;th&gt;Port Range&lt;/th&gt;
&lt;th&gt;Destination&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;All Traffic&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Anywhere (0.0.0.0/0)&lt;/td&gt;
&lt;td&gt;Allow all outgoing traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;h3&gt;
  
  
  🛠️ Step 3: Finalize Instance Launch
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;On the &lt;strong&gt;Launch Instance&lt;/strong&gt; page, under &lt;strong&gt;Number of Instances&lt;/strong&gt; of summary section, set it to &lt;code&gt;2&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;🔸 One will be used as &lt;strong&gt;Control Plane&lt;/strong&gt;, the other as &lt;strong&gt;Worker Node&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Select the &lt;strong&gt;&lt;code&gt;kubernetes-security&lt;/code&gt;&lt;/strong&gt; group you just created.&lt;/li&gt;
&lt;li&gt;Use the same key pair for both instances.&lt;/li&gt;
&lt;li&gt;Once the instances are launched, &lt;strong&gt;rename&lt;/strong&gt; them for clarity:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;controlplane&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;workernode&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx42lpkjcjs2s249p0fcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx42lpkjcjs2s249p0fcl.png" alt="Image description" width="398" height="242"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Prerequisites for Using Kubeadm
&lt;/h2&gt;

&lt;p&gt;Before using Kubeadm to initialize your Kubernetes cluster, ensure that the following requirements are available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Operating System: Ubuntu, CentOS, or other Linux distributions (with a supported kernel version).&lt;/li&gt;
&lt;li&gt;At least 2 GB of RAM for the master node.&lt;/li&gt;
&lt;li&gt;At least 1 CPU (for both the master and worker nodes).&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Connect both instances and walkthrough below detailed guide.&lt;/p&gt;
&lt;h2&gt;
  
  
  🚀 Setup Kubeadm on EC2 instances
&lt;/h2&gt;

&lt;p&gt;Ensure these are done on &lt;strong&gt;all nodes (control plane and workers):&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  🧱 1. Update System Packages
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get upgrade &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📦 2. Install Required Packages
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; apt-transport-https ca-certificates curl software-properties-common gnupg2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🔧 3. Disable Swap (Required for K8s)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;swapoff &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'/ swap / s/^\(.*\)$/#\1/g'&lt;/span&gt; /etc/fstab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;Why?&lt;/strong&gt; Kubernetes requires swap to be disabled for optimal memory management.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h3&gt;
  
  
  📦 4. Install and Configure &lt;code&gt;containerd&lt;/code&gt;
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; containerd
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /etc/containerd
&lt;span class="nb"&gt;sudo &lt;/span&gt;containerd config default | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/containerd/config.toml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Enable &lt;code&gt;SystemdCgroup&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo sed&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'s/SystemdCgroup = false/SystemdCgroup = true/g'&lt;/span&gt; /etc/containerd/config.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart and enable service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart containerd
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;containerd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  📦 5. Add Kubernetes v1.31 APT Repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://pkgs.k8s.io/core:/stable:/v1.31/deb/Release.key |
&lt;span class="nb"&gt;sudo &lt;/span&gt;gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /etc/apt/keyrings/kubernetes-apt-keyring.gpg
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.31/deb/ /'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/kubernetes.list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  📦 6. Install Kubernetes Components
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; kubelet kubeadm kubectl
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-mark hold kubelet kubeadm kubectl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;✅ &lt;code&gt;apt-mark hold&lt;/code&gt; ensures these packages aren’t upgraded unintentionally.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  🧠 7. Load Required Kernel Modules
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe overlay
&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe br_netfilter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🌐 8. Configure Network Settings for Kubernetes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;sysctl &lt;span class="nt"&gt;--system&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;[!NOTE] Kubernetes Setup Script&lt;br&gt;
The above can be saved as kubernetes-setup.sh file.&lt;br&gt;
You can run this on worker nodes to avoid redundancy.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  🧭 Next Steps (Master Node)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1️⃣ Initialize Kubernetes Control Plane
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kubeadm init &lt;span class="nt"&gt;--pod-network-cidr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;192.168.0.0/16 &lt;span class="nt"&gt;--apiserver-advertise-address&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PRIVATE_IP&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2️⃣ Set up &lt;code&gt;kubectl&lt;/code&gt; for your user
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube
&lt;span class="nb"&gt;sudo cp&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; /etc/kubernetes/admin.conf &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.kube/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3️⃣ Install Calico CNI (For v1.31 Compatibility)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/custom-resources.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://raw.githubusercontent.com/projectcalico/calico/v3.28.1/manifests/calico.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4️⃣ Check pods Status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5️⃣ Verify Kubernetes Cluster Status
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🧩 Join Worker Nodes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  📍 1. Run the same setup script on all worker nodes.
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;br&gt;
Like mentioned above, once you create kubernetes-setup.sh file on worker node. Use below command to make script ready to run and use.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x kubernetes-setup.sh

./kubernetes-setup.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📍 2. On master node instance, get the join command:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubeadm token create &lt;span class="nt"&gt;--print-join-command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📍 3. Run the join command on worker node
&lt;/h3&gt;

&lt;p&gt;Copy paste the join command generated on MasterNode&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;kubeadm &lt;span class="nb"&gt;join&lt;/span&gt; &amp;lt;master-ip&amp;gt;:6443 &lt;span class="nt"&gt;--token&lt;/span&gt; &amp;lt;token&amp;gt; &lt;span class="nt"&gt;--discovery-token-ca-cert-hash&lt;/span&gt; sha256:&amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📍 4. Verify from Master
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;blockquote&gt;
&lt;p&gt;[!Seperate instances for control plane and worker node]&lt;br&gt;
If you're intend to have separate instance for control plane and workernode with separate security groups for your nodes make sure these ports are added as inbound rules.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🔐 AWS EC2 Security Group Settings
&lt;/h2&gt;

&lt;p&gt;Ensure the following ports are open between your EC2 nodes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;6443&lt;/td&gt;
&lt;td&gt;Kubernetes API Server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2379-2380&lt;/td&gt;
&lt;td&gt;etcd&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10250&lt;/td&gt;
&lt;td&gt;Kubelet API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10251&lt;/td&gt;
&lt;td&gt;kube-scheduler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10252&lt;/td&gt;
&lt;td&gt;kube-controller-manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;179&lt;/td&gt;
&lt;td&gt;Calico BGP&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ✅ Wrapping Up
&lt;/h2&gt;

&lt;p&gt;That’s it!!! your kubeadm setup on EC2 is ready!&lt;/p&gt;

&lt;p&gt;You now have a basic Kubernetes cluster with a control plane and a worker node. This setup is great for getting hands-on experience and understanding how Kubernetes works under the hood.&lt;/p&gt;

&lt;p&gt;Feel free to explore more, try deploying apps, and break things to learn.&lt;/p&gt;

&lt;p&gt;Thanks for following along. I really hope this guide helped! 🙌&lt;/p&gt;




&lt;h2&gt;
  
  
  🤝🏻 Stay Connected
&lt;/h2&gt;

&lt;p&gt;If you find the content helpful, consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Following me on &lt;a href="https://github.com/itsfarhan" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Connecting on &lt;a href="https://linkedin.com/in/itsfarhan" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ko-fi.com/itsfarhan" rel="noopener noreferrer"&gt;Supporting my work&lt;/a&gt; if you find it valuable.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>aws</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>How I Deployed My Portfolio Using AWS S3 + CloudFront + Cloudflare (Free SSL &amp; Email!)</title>
      <dc:creator>Farhan Ahmed</dc:creator>
      <pubDate>Sun, 25 May 2025 04:00:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/how-i-deployed-my-portfolio-using-aws-s3-cloudfront-cloudflare-free-ssl-email-c3c</link>
      <guid>https://dev.to/aws-builders/how-i-deployed-my-portfolio-using-aws-s3-cloudfront-cloudflare-free-ssl-email-c3c</guid>
      <description>&lt;p&gt;Hey there! 👋 I am Farhan, and in this blog, I’ll walk you through how I deployed my personal portfolio website &lt;a href="https://farhanahmed.pro/" rel="noopener noreferrer"&gt;farhanahmed.pro&lt;/a&gt; using simple tools from AWS and Cloudflare.&lt;/p&gt;

&lt;p&gt;This guide is beginner-friendly. If you're just starting out with web hosting and cloud stuff, you’re in the right place. Let’s go step by step. 🛠️&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 What This Project Is
&lt;/h2&gt;

&lt;p&gt;What I wanted for my portfolio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fast and secure hosting
&lt;/li&gt;
&lt;li&gt;My own domain name
&lt;/li&gt;
&lt;li&gt;Free SSL (HTTPS)
&lt;/li&gt;
&lt;li&gt;Professional email like &lt;code&gt;hello@farhanahmed.pro&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS S3&lt;/strong&gt; to store my site files (HTML, CSS, JS, images)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CloudFront&lt;/strong&gt; to serve those files globally (CDN)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS ACM&lt;/strong&gt; (certificate) for free HTTPS
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; for domain DNS + email routing
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ✈️ Steps Overview
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Host your site files in an &lt;strong&gt;S3 bucket&lt;/strong&gt; (private)
&lt;/li&gt;
&lt;li&gt;Set up &lt;strong&gt;CloudFront&lt;/strong&gt; (to make the site fast and use HTTPS)
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;ACM&lt;/strong&gt; (for free HTTPS certificate)
&lt;/li&gt;
&lt;li&gt;Set up &lt;strong&gt;Cloudflare&lt;/strong&gt; (for DNS and custom email)
&lt;/li&gt;
&lt;li&gt;Point Cloudflare to AWS
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h6h1fp6i9uykhvqwxhj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6h6h1fp6i9uykhvqwxhj.png" alt="S3 to CloudFront" width="800" height="428"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 What Are These Tools (In Simple Terms)
&lt;/h2&gt;

&lt;h2&gt;
  
  
  🪣 S3 (Simple Storage Service)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Think of it as an online folder where you keep all your website files.
&lt;/li&gt;
&lt;li&gt;It’s secure and reliable. But by default, files are private.
&lt;/li&gt;
&lt;li&gt;You upload files like &lt;code&gt;index.html&lt;/code&gt;, images, videos, and they stay there until someone requests them via a browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💡 Tip: If you're using React or any frontend framework, first run &lt;code&gt;npm run build&lt;/code&gt; and upload the &lt;code&gt;dist/&lt;/code&gt; or &lt;code&gt;build/&lt;/code&gt; folder contents.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://s3.console.aws.amazon.com/" rel="noopener noreferrer"&gt;AWS S3 Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create two buckets:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;yourdomain.com&lt;/code&gt; (main site)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;www.yourdomain.com&lt;/code&gt; (redirect bucket)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;main domain bucket&lt;/strong&gt; → &lt;code&gt;farhanahmed.pro&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Properties&lt;/strong&gt;, scroll down
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Static Website Hosting&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Upload your website files (&lt;code&gt;index.html&lt;/code&gt;, images, CSS, etc.)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe14fxwqqno6190fihhzi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe14fxwqqno6190fihhzi.png" alt="S3 Bucket Config" width="800" height="163"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 CloudFront (CDN)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CloudFront = Content Delivery Network (CDN)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Speeds up your website and protects your S3 bucket
&lt;/li&gt;
&lt;li&gt;Delivers your content fast anywhere in the world
&lt;/li&gt;
&lt;li&gt;Enables HTTPS via SSL certificate&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🛡️ OAI = Origin Access Identity
&lt;/h3&gt;

&lt;p&gt;Allows &lt;strong&gt;only CloudFront&lt;/strong&gt; to fetch content from your private S3 bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.aws.amazon.com/cloudfront" rel="noopener noreferrer"&gt;CloudFront Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Distribution&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose origin as your &lt;strong&gt;main S3 bucket&lt;/strong&gt; (not the www one)
&lt;/li&gt;
&lt;li&gt;For Origin Access, select &lt;strong&gt;Legacy Access Identity → Create new OAI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;CloudFront will update S3 permissions automatically
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Redirect HTTP to HTTPS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Attach an &lt;strong&gt;ACM Certificate&lt;/strong&gt; (next step 👇)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔒 ACM (AWS Certificate Manager)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Provides the &lt;strong&gt;lock icon&lt;/strong&gt; in browsers (HTTPS)
&lt;/li&gt;
&lt;li&gt;It's &lt;strong&gt;free&lt;/strong&gt; when used with AWS
&lt;/li&gt;
&lt;li&gt;Boosts trust &amp;amp; security&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://console.aws.amazon.com/acm/" rel="noopener noreferrer"&gt;ACM Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;us-east-1&lt;/strong&gt; region (Important!)
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Request a certificate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;*.yourdomain.com&lt;/code&gt;
(&lt;em&gt;Wildcard &lt;code&gt;*&lt;/code&gt; lets you add subdomains in future&lt;/em&gt;)
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;DNS Validation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;strong&gt;CNAME records&lt;/strong&gt; ACM gives
&lt;/li&gt;
&lt;li&gt;Paste them into Cloudflare DNS settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example DNS record for validation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Target&lt;/th&gt;
&lt;th&gt;Proxy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_xxxx.yourdomain.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;_yyy.acm-validation.aws&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not Proxied&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Wait for status to change to ✅ &lt;strong&gt;Issued&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go back to CloudFront and attach this certificate.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 Setup DNS in Cloudflare
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ✅ Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to your Cloudflare dashboard
&lt;/li&gt;
&lt;li&gt;Add 2 &lt;strong&gt;CNAME records&lt;/strong&gt; like below:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Proxy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;your-cloudfront-domain.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not Proxied&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CNAME&lt;/td&gt;
&lt;td&gt;&lt;code&gt;www&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;@&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Not Proxied&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;strong&gt;SSL/TLS&lt;/strong&gt; to &lt;strong&gt;Full&lt;/strong&gt; or &lt;strong&gt;Off&lt;/strong&gt; (Let AWS handle HTTPS)&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  📧 Setup Free Email with Cloudflare
&lt;/h2&gt;

&lt;p&gt;Want a professional email like &lt;code&gt;hello@yourdomain.com&lt;/code&gt;?&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Steps:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Email&lt;/strong&gt; → &lt;strong&gt;Email Routing&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add sender address: &lt;code&gt;hello@yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set the destination as your personal Gmail (or any inbox)
&lt;/li&gt;
&lt;li&gt;Cloudflare gives you &lt;strong&gt;MX records&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy-paste those into the &lt;strong&gt;DNS tab&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Catch-All&lt;/strong&gt; to receive all mail&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now you’ll receive all emails to your personal inbox!&lt;/p&gt;




&lt;h2&gt;
  
  
  ☁️ Bonus: Using Cloudflare with Domains Bought Elsewhere
&lt;/h2&gt;

&lt;p&gt;Say you bought a domain from &lt;a href="https://namecheap.com" rel="noopener noreferrer"&gt;Namecheap&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to your &lt;strong&gt;domain settings&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Nameservers&lt;/strong&gt;, set it to &lt;code&gt;Custom DNS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add Cloudflare’s nameservers:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;xxx.ns.cloudflare.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;yyy.ns.cloudflare.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Save the settings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cloudflare now manages your domain!&lt;/p&gt;




&lt;h2&gt;
  
  
  🎉 That’s a Wrap!
&lt;/h2&gt;

&lt;p&gt;This was the full journey of hosting my website from scratch using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;S3&lt;/strong&gt; for file storage
&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;CloudFront&lt;/strong&gt; for performance &amp;amp; HTTPS
&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Cloudflare&lt;/strong&gt; for DNS and email routing
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading 🙏&lt;/p&gt;

&lt;p&gt;Drop by 👉 &lt;a href="https://farhanahmed.pro/" rel="noopener noreferrer"&gt;https://farhanahmed.pro&lt;/a&gt; and feel free to reach out.&lt;/p&gt;

&lt;p&gt;Happy building! 💻✨&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>aws</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
