<?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>Forem: M. Oly Mahmud</title>
    <description>The latest articles on Forem by M. Oly Mahmud (@olymahmud).</description>
    <link>https://forem.com/olymahmud</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%2F1033159%2Fa165d29a-b900-4d22-bb88-59336a84013a.jpeg</url>
      <title>Forem: M. Oly Mahmud</title>
      <link>https://forem.com/olymahmud</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/olymahmud"/>
    <language>en</language>
    <item>
      <title>Running Kubernetes in Docker (KIND) Locally While Your Cluster Lives in Google Cloud Shell</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Tue, 31 Mar 2026 08:07:54 +0000</pubDate>
      <link>https://forem.com/olymahmud/running-kubernetes-in-docker-kind-locally-while-your-cluster-lives-in-google-cloud-shell-4nia</link>
      <guid>https://forem.com/olymahmud/running-kubernetes-in-docker-kind-locally-while-your-cluster-lives-in-google-cloud-shell-4nia</guid>
      <description>&lt;p&gt;You want to develop with Kubernetes locally using KIND, but your laptop doesn't have enough resources. Google Cloud Shell has plenty of compute, but it's not meant for long-running clusters. So run KIND in Cloud Shell and control it from your machine.&lt;/p&gt;

&lt;p&gt;The benefits of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Shell has more compute than your dev machine&lt;/li&gt;
&lt;li&gt;Your laptop stays clean&lt;/li&gt;
&lt;li&gt;No Docker Desktop overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Create Your KIND Cluster in Cloud Shell&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, the cluster config. The important part is extraPortMappings—this exposes ports 80 and 443 to Cloud Shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cluster&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kind.x-k8s.io/v1alpha4&lt;/span&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;streamx-cluster&lt;/span&gt;
&lt;span class="na"&gt;nodes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;control-plane&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kindest/node:v1.35.1&lt;/span&gt;
    &lt;span class="na"&gt;extraPortMappings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;hostPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
        &lt;span class="na"&gt;hostPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;443&lt;/span&gt;
        &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;worker&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kindest/node:v1.35.1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;worker&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kindest/node:v1.35.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create it and verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kind create cluster &lt;span class="nt"&gt;--config&lt;/span&gt; kind-config.yaml
kubectl cluster-info &lt;span class="nt"&gt;--context&lt;/span&gt; kind-streamx-cluster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Export the Kubeconfig&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;KIND generates a kubeconfig automatically. Export it to a file you can move:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kind &lt;span class="nb"&gt;export &lt;/span&gt;kubeconfig &lt;span class="nt"&gt;--name&lt;/span&gt; streamx-cluster &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; my-cluster-config.yaml
&lt;span class="nb"&gt;cat &lt;/span&gt;my-cluster-config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Copy the Kubeconfig to Your Local Machine&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud cloud-shell scp cloudshell:~/my-cluster-config.yaml localhost:~/my-cluster-config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Set Up Port Forwarding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your cluster's API server is in Cloud Shell on 127.0.0.1:46151 (check your kubeconfig). Tunnel it through SSH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud cloud-shell ssh &lt;span class="nt"&gt;--ssh-flag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-f"&lt;/span&gt; &lt;span class="nt"&gt;--ssh-flag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-N"&lt;/span&gt; &lt;span class="nt"&gt;--ssh-flag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-T"&lt;/span&gt; &lt;span class="nt"&gt;--ssh-flag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-L 46151:127.0.0.1:46151"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-f&lt;/code&gt; runs in the background&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-N&lt;/code&gt; just forward ports, don't run a remote command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-T&lt;/code&gt; no pseudo-terminal&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-L 46151:127.0.0.1:46151&lt;/code&gt; forwards your local port to the remote one&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tunnel stays open as long as your Cloud Shell session is active.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect kubectl Locally&lt;/strong&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;export &lt;/span&gt;&lt;span class="nv"&gt;KUBECONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/my-cluster-config.yaml"&lt;/span&gt;
kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see your control plane and worker nodes. If you get a certificate error, check that your SSH tunnel is running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploy Nginx&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create nginx-deployment.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:latest&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And nginx-service.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-nodeport-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deploy it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; nginx-deployment.yaml
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; nginx-service.yaml
kubectl port-forward svc/nginx-nodeport-service 8080:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:8080" rel="noopener noreferrer"&gt;http://localhost:8080&lt;/a&gt;. You're looking at Nginx running in a pod in Cloud Shell.&lt;/p&gt;




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

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>googlecloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Part-4: Automating EC2 Infrastructure using Terraform | Amazon Web Services (AWS)</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Thu, 19 Feb 2026 06:11:34 +0000</pubDate>
      <link>https://forem.com/olymahmud/part-4-automating-ec2-infrastructure-using-terraform-amazon-web-services-aws-190a</link>
      <guid>https://forem.com/olymahmud/part-4-automating-ec2-infrastructure-using-terraform-amazon-web-services-aws-190a</guid>
      <description>&lt;p&gt;Earlier, we created an EC2 instance by hand in the AWS Console. Now we’ll do the same thing with Terraform.&lt;/p&gt;

&lt;p&gt;In this guide, we will walk through how to use Terraform to create an EC2 instance on AWS, generate an SSH key, and install Nginx when the server boots. All of it is automated using code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You should have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;An AWS account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform installed on your machine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An IAM user with an access key and secret key&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A general idea of how EC2 works&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A basic understanding of Terraform (providers, resources, variables, outputs)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Directory Structure
&lt;/h2&gt;

&lt;p&gt;Here’s the Terraform project layout we will use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── instance.tf
├── key_pair.tf
├── output.tf
├── provider.tf
├── terraform.tfvars
└── variables.tf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each file handles a specific part of the deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provider Configuration
&lt;/h2&gt;

&lt;p&gt;Start with the provider definition in &lt;code&gt;provider.tf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"6.15.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;region&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;region&lt;/span&gt;
  &lt;span class="nx"&gt;access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;access_key&lt;/span&gt;
  &lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secret_key&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Terraform to use the AWS provider and defines how to authenticate.&lt;br&gt;
In practice, you should avoid storing credentials in code or &lt;code&gt;tfvars&lt;/code&gt; files — use the AWS CLI (&lt;code&gt;aws configure&lt;/code&gt;) or environment variables for safer authentication.&lt;/p&gt;
&lt;h2&gt;
  
  
  Defining Variables
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;variables.tf&lt;/code&gt;, define the parameters Terraform will use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"access_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"secret_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"region"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-north-1"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"file_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Local file name for private key"&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These variables make the configuration reusable. For example, you can switch AWS regions or key names without touching the main code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating an SSH Key Pair
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;key_pair.tf&lt;/code&gt; handles SSH key generation and registration with AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"tls_private_key"&lt;/span&gt; &lt;span class="s2"&gt;"rsa-4096-key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;algorithm&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"RSA"&lt;/span&gt;
  &lt;span class="nx"&gt;rsa_bits&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"local_file"&lt;/span&gt; &lt;span class="s2"&gt;"tf_key"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;content&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tls_private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rsa-4096-key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;private_key_pem&lt;/span&gt;
  &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_key_pair"&lt;/span&gt; &lt;span class="s2"&gt;"demo-key-pair-tf"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"demo-key-pair-tf"&lt;/span&gt;
  &lt;span class="nx"&gt;public_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tls_private_key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rsa-4096-key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_key_openssh&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;TLS provider&lt;/strong&gt; generates a 4096-bit RSA key.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;local_file&lt;/strong&gt; resource writes the private key locally as a &lt;code&gt;.pem&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;aws_key_pair&lt;/strong&gt; resource uploads the public key to AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once deployed, you’ll use the &lt;code&gt;.pem&lt;/code&gt; file for SSH access to your EC2 instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining the EC2 Instance
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;instance.tf&lt;/code&gt; defines both the EC2 instance and the security group.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"web-server"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ami&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ami-0a716d3f3b16d290c"&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t3.micro"&lt;/span&gt;
  &lt;span class="nx"&gt;key_name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_key_pair&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demo-key-pair-tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key_name&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demo-sg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;user_data&lt;/span&gt; &lt;span class="p"&gt;=&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;
  #!/bin/bash
  apt update -y
  apt install nginx -y
  systemctl enable nginx
  systemctl start nginx
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"web-server"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens here
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Terraform launches an &lt;strong&gt;Ubuntu 24.04&lt;/strong&gt; EC2 instance using the AMI ID above.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;user_data&lt;/strong&gt; script runs automatically on boot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Updates packages&lt;/li&gt;
&lt;li&gt;Installs and starts Nginx&lt;/li&gt;
&lt;li&gt;Enables it to start on boot&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;By the time Terraform finishes, Nginx is already serving traffic.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Group
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"demo-sg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"demo-sg"&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SSH access"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP access"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTPS access"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSH (22)&lt;/strong&gt; for remote access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP (80)&lt;/strong&gt; and &lt;strong&gt;HTTPS (443)&lt;/strong&gt; for web traffic&lt;/li&gt;
&lt;li&gt;All outbound traffic for updates and package installations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Outputting Useful Information
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;output.tf&lt;/code&gt;, display key connection details after provisioning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance_public_ip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web-server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_ip&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;output&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance_public_dns"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;web-server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public_dns&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After &lt;code&gt;terraform apply&lt;/code&gt;, you’ll see the public IP and DNS name printed on your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying the Infrastructure
&lt;/h2&gt;

&lt;p&gt;Create a &lt;code&gt;terraform.tfvars&lt;/code&gt; file to provide variable values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;region&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"eu-north-1"&lt;/span&gt;

&lt;span class="nx"&gt;access_key&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_ACCESS_KEY"&lt;/span&gt;
&lt;span class="nx"&gt;secret_key&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"YOUR_SECRET_KEY"&lt;/span&gt;
&lt;span class="nx"&gt;file_name&lt;/span&gt;  &lt;span class="err"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"demo-key.pem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use environment variables to assign values for &lt;code&gt;access_key&lt;/code&gt; and &lt;code&gt;secret_key&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;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_ACCESS_KEY"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;TF_VAR_secret_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_SECRET_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once all files are in place, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform init
terraform plan
terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Terraform will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a key pair&lt;/li&gt;
&lt;li&gt;Create a security group&lt;/li&gt;
&lt;li&gt;Launch the EC2 instance&lt;/li&gt;
&lt;li&gt;Run the Nginx installation script&lt;/li&gt;
&lt;li&gt;Print the public IP and DNS&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open the public IP in your browser.&lt;br&gt;
You should see the &lt;strong&gt;Nginx welcome page&lt;/strong&gt; — that confirms a successful automated deployment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Verifying from the Instance
&lt;/h2&gt;

&lt;p&gt;You can SSH in if you want to verify Nginx status:&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;chmod &lt;/span&gt;400 demo-key.pem
ssh &lt;span class="nt"&gt;-i&lt;/span&gt; demo-key.pem ubuntu@&amp;lt;public_ip&amp;gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cleaning Up
&lt;/h2&gt;

&lt;p&gt;When you’re done testing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;terraform destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes the instance, key pair, and security group.&lt;br&gt;
Terraform tracks all managed resources, so cleanup is safe and predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We've automatically deployed a secure, Nginx-powered EC2 instance using Terraform.&lt;/p&gt;

</description>
      <category>awschallenge</category>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS Elastic Compute Cloud (EC2) | Amazon Web Services (AWS)</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Mon, 15 Dec 2025 15:53:42 +0000</pubDate>
      <link>https://forem.com/olymahmud/aws-elastic-compute-cloud-ec2-amazon-web-service-aws-41h8</link>
      <guid>https://forem.com/olymahmud/aws-elastic-compute-cloud-ec2-amazon-web-service-aws-41h8</guid>
      <description>&lt;p&gt;Amazon EC2 offers cloud-based virtual machines, commonly found within AWS. Rather than using real computers, users run these on remote systems. We'll guide you through setting up an Nginx web host gradually. During this process, key concepts will be explained clearly but briefly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Sign in to AWS Console
&lt;/h2&gt;

&lt;p&gt;Head to the &lt;a href="https://aws.amazon.com/console/" rel="noopener noreferrer"&gt;AWS Management Console&lt;/a&gt; then sign in. This interface serves as your central hub for using AWS tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Go to EC2 Dashboard
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Amazon EC2 (Elastic Compute Cloud)&lt;/strong&gt; offers on-demand computing power in the cloud. It's like leasing virtual servers from Amazon’s infrastructure, yet you can adjust resources anytime based on demand.&lt;/p&gt;

&lt;p&gt;With EC2, pricing follows usage - no need to buy fixed hardware. Instances start or stop within minutes, offering flexibility through scalable access instead of permanent setups&lt;/p&gt;

&lt;p&gt;Look up &lt;strong&gt;EC2&lt;/strong&gt; and open it. &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%2Ff2w1ey7jxc9rsoxp2wku.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%2Ff2w1ey7jxc9rsoxp2wku.png" alt=" " width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll notice a sight similar to this one.&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%2F3chjc7m0z9cyzytbxulg.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%2F3chjc7m0z9cyzytbxulg.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, select instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Launch a New Instance
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;instance&lt;/strong&gt; is basically a virtual computer hosted on AWS systems. While setting up one, you’re reserving hardware resources such as processing power, RAM, disk space, along with software to run it.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Launch Instance&lt;/strong&gt;.&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%2Fz3e1w3n1zahc6tzkhevp.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%2Fz3e1w3n1zahc6tzkhevp.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Name the Instance
&lt;/h2&gt;

&lt;p&gt;Assign a name - such as &lt;code&gt;web-server&lt;/code&gt;- to the instance. Use this tag to recognize it within the AWS dashboard.&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%2Fu4p41tcylhed21zp889a.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%2Fu4p41tcylhed21zp889a.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Choose an AMI
&lt;/h2&gt;

&lt;p&gt;An AMI serves as a ready-made blueprint for launching virtual machines. It includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The operating system (like Ubuntu, Amazon Linux, or Windows)&lt;/li&gt;
&lt;li&gt;Optional application software&lt;/li&gt;
&lt;li&gt;Configuration settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, choosing &lt;strong&gt;Ubuntu 24.04&lt;/strong&gt; means your instance will boot up with that OS installed, ready for use.&lt;/p&gt;

&lt;p&gt;Select an &lt;strong&gt;AMI (Amazon Machine Image)&lt;/strong&gt;.&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%2Fsndh7seofyxu0awzuorq.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%2Fsndh7seofyxu0awzuorq.png" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Choose Instance Type
&lt;/h2&gt;

&lt;p&gt;Instance types define processing speed, RAM size, connection efficiency, or disk space.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;t3.micro&lt;/strong&gt;: compact, affordable - ideal for practice or light tasks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;m5.large&lt;/strong&gt;: a solid choice for everyday applications due to its well-rounded performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;c6g.xlarge&lt;/strong&gt;: built for intense computing workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS provides various instance type groups tailored to specific needs - like general computing, high-performance processing, or enhanced memory capabilities - alongside options powered by GPUs.&lt;/p&gt;

&lt;p&gt;Select an instance type - it sets the hardware for your server. I’ll go with t3.micro this time.&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%2Fb3jcm8szfjh1w366kmd2.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%2Fb3jcm8szfjh1w366kmd2.png" alt=" " width="800" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: Create a Key Pair
&lt;/h2&gt;

&lt;p&gt;Upon logging into a regular computer, one enters a username followed by a password. In contrast, EC2 relies on key pairs - set up by AWS - for verification. Each key pair includes two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;public key&lt;/strong&gt; stored in AWS&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;private key&lt;/strong&gt; (a &lt;code&gt;.pem&lt;/code&gt; file) save it on your computer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While connecting via SSH, AWS verifies your private key against the one stored publicly on the machine - confirming alignment without requiring a password. That method allows safe login through cryptographic validation instead of credentials.&lt;/p&gt;

&lt;p&gt;If access is lost to the private key file, login becomes impossible - store it securely. Alternatively, losing this file blocks entry entirely; handle with care.&lt;/p&gt;

&lt;p&gt;Select &lt;strong&gt;create key pair&lt;/strong&gt; then proceed.&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%2F2z7xqrhc17mjiqnizhfg.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%2F2z7xqrhc17mjiqnizhfg.png" alt=" " width="800" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Call it something. Leave the rest as is.&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%2Fq6si4508pmvpajmatg17.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%2Fq6si4508pmvpajmatg17.png" alt=" " width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generate the key pair now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 8: Configure Security Groups
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;security group&lt;/strong&gt; acts like a digital barrier, managing data flow to your system. This setup specifies accessible ports alongside permitted users. While it blocks unwanted connections, it allows approved communications through designated channels.&lt;/p&gt;

&lt;p&gt;With this arrangement, it’s necessary to permit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSH (port 22)&lt;/strong&gt;: this allows terminal access to your instance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP (port 80)&lt;/strong&gt;: this means users reach the web server through a browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For practice, allow these ports from any IP address (0.0.0.0/0). In real use, restrict SSH access to just your IP - this improves safety.&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%2Frvt1aee5cwihrc1ryxhg.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%2Frvt1aee5cwihrc1ryxhg.png" alt=" " width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 9: Launch the Instance
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Launch Instance&lt;/strong&gt;. After that, AWS sets up your virtual machine.&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%2F3fe61eymkyvixes06977.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%2F3fe61eymkyvixes06977.png" alt=" " width="800" height="114"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In just moments, you’ll see it appear on your EC2 dashboard.&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%2Fr2mkasdlspc0smmnio63.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%2Fr2mkasdlspc0smmnio63.png" alt=" " width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 10: Connect to the Instance
&lt;/h2&gt;

&lt;p&gt;Select an instance, then choose &lt;strong&gt;Connect&lt;/strong&gt;. With the &lt;strong&gt;SSH Client&lt;/strong&gt; option selected, execute the AWS-provided command in your terminal - it appears as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"demo-key-pair.pem"&lt;/span&gt; ubuntu@&amp;lt;Public-IP&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This links your computer to the EC2 server safely; alternatively, different choices are available.&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%2F2co5cwhygzbgb9ai1qat.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%2F2co5cwhygzbgb9ai1qat.png" alt=" " width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 11: Install Nginx
&lt;/h2&gt;

&lt;p&gt;Once linked, execute this command :&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;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This refreshes your package manager while setting up the Nginx web server.&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%2Fq3u8jowcd0n7lvt110mi.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%2Fq3u8jowcd0n7lvt110mi.png" alt=" " width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 12: Access the Server in a Browser
&lt;/h2&gt;

&lt;p&gt;Take the &lt;strong&gt;Public IPv4 address&lt;/strong&gt; from your instance on the EC2 dashboard - enter it into a web browser.&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%2Fgy8rz4bu9svu56pzz1n7.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%2Fgy8rz4bu9svu56pzz1n7.png" alt=" " width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You ought to view the Nginx welcome screen - this shows the server’s active and reachable online.&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%2Fzrdp6oxn6yxbet0313e0.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%2Fzrdp6oxn6yxbet0313e0.png" alt=" " width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 13: Terminate the Instance
&lt;/h2&gt;

&lt;p&gt;Once testing finishes, shut down the instance - skipping this step could lead to ongoing charges. Here's how:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the EC2 dashboard&lt;/li&gt;
&lt;li&gt;Select your instance&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Instance State → Terminate instance&lt;/strong&gt;
&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%2Ftab98kqefpfkwqd59o4t.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%2Ftab98kqefpfkwqd59o4t.png" alt=" " width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Terminating a server removes it forever. When temporary shutdown is needed, use Stop instead - this keeps your data safe. Choosing one action or another depends on whether files should stay intact after halting operations.&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%2Fas64hd2mjxzaoxawdkfy.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%2Fas64hd2mjxzaoxawdkfy.png" alt=" " width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;So, we've explored:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EC2&lt;/strong&gt; delivers adjustable virtual machines through the cloud&lt;/li&gt;
&lt;li&gt;A single instance means a virtual machine actively operating within the cloud environment&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;AMI&lt;/strong&gt; serves as the operating system plus application blueprint needed to start instances&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instance types&lt;/strong&gt; define the hardware power and performance of your server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key pairs&lt;/strong&gt; protect access through public-private verification methods&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security groups&lt;/strong&gt; work like firewalls deciding which users reach your system, by setting clear entry rules based on trusted sources&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>awschallenge</category>
    </item>
    <item>
      <title>AWS Identity and Access Management (IAM)</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Sun, 07 Dec 2025 15:03:21 +0000</pubDate>
      <link>https://forem.com/olymahmud/aws-identity-and-access-management-iam-2c0c</link>
      <guid>https://forem.com/olymahmud/aws-identity-and-access-management-iam-2c0c</guid>
      <description>&lt;p&gt;AWS IAM decides who gets into your account. So, it sets limits on the actions people can take. Also, it picks which tools they’re allowed to use. Get clear on users, groups, roles, and rules - one by one - and things start making sense fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;IAM Users&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A person needing AWS access is set up as an IAM user. They’re given a name, plus a sign-in password for the web interface. Access codes might also be added - these help when using command tools or software kits.&lt;/p&gt;

&lt;h3&gt;
  
  
  What someone adds
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Username&lt;/li&gt;
&lt;li&gt;Password (for console)&lt;/li&gt;
&lt;li&gt;Access keys (for CLI)&lt;/li&gt;
&lt;li&gt;MFA settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Beginner-friendly example
&lt;/h3&gt;

&lt;p&gt;You bring on a new person called Ali. Then you set up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: ali
Console login: yes
MFA: enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ali’s set up as a user, yet lacks access rights. Rather than assigning each permission separately, toss him into a group instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;IAM Groups&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Groups help give access to multiple people together. Put rules on a group - everyone inside gains that access straight away.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common group examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;developers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read-only&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admins&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example inside this topic
&lt;/h3&gt;

&lt;p&gt;If you’ve got five coders, here’s what could happen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Group: developers
Policy: Read-only access to EC2 and S3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, bring Ali into the team. Right away, he’s given access to develop - no extra actions needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;IAM Roles&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A role acts like a short-term ID for AWS services - or even users - when they need access. It doesn't come with passwords or permanent keys. Instead, AWS hands out time-limited credentials once it's activated.&lt;/p&gt;

&lt;p&gt;Roles are best for giving AWS services permission to talk to other AWS services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where roles get applied
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;EC2 → S3&lt;/li&gt;
&lt;li&gt;Lambda → CloudWatch&lt;/li&gt;
&lt;li&gt;Temporary access sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example: EC2 instance listing S3 buckets
&lt;/h3&gt;

&lt;p&gt;Let’s say your EC2 instance needs to run &lt;code&gt;aws s3 ls&lt;/code&gt; to see all S3 buckets.&lt;/p&gt;

&lt;p&gt;You do this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a role
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Role name: EC2S3ListRole
   Trusted entity: EC2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Attach a policy that allows listing S3 buckets:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListAllMyBuckets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Attach the role to your EC2 instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the instance can list S3 buckets safely without storing access keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;IAM Policies&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Policies come as JSON files showing which actions can be allowed or blocked. A user, group, or role only works once a policy is linked to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  A policy contains
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Effect&lt;/strong&gt;: Allow or Deny&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt;: What can be done&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource&lt;/strong&gt;: Where the action applies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Condition&lt;/strong&gt;: Optional extra rules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A basic case within this subject
&lt;/h3&gt;

&lt;p&gt;A policy to list all S3 buckets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:ListAllMyBuckets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A policy to read objects in one bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:GetObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::my-example-bucket/*"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We attach these policies to a group or a role depending on who needs the access.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Way to Master AWS IAM
&lt;/h2&gt;

&lt;p&gt;We go step by step through a full training run - create an IAM user, review permissions, attach a policy, assign an EC2 instance role, after that test everything using AWS CLI commands.&lt;/p&gt;

&lt;p&gt;The main goal is to understand how &lt;strong&gt;users&lt;/strong&gt;, &lt;strong&gt;groups&lt;/strong&gt;, &lt;strong&gt;roles&lt;/strong&gt;, and &lt;strong&gt;policies&lt;/strong&gt; work together.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start With IAM Users
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a new IAM user
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open the AWS Console and go to &lt;strong&gt;IAM&lt;/strong&gt;.&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%2Fbifjut2lks99popij8r1.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%2Fbifjut2lks99popij8r1.png" alt=" " width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Users&lt;/strong&gt; from the left menu.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create user&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Access to the AWS Management Console&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Pick &lt;strong&gt;Autogenerated password&lt;/strong&gt; and leave everything else as default.&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%2Ftky00m7o4huwf9euzuv8.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%2Ftky00m7o4huwf9euzuv8.png" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Continue to the next page.&lt;/li&gt;
&lt;li&gt;On the permissions page, keep the defaults and go next.&lt;/li&gt;
&lt;li&gt;Review everything and create the user.&lt;/li&gt;
&lt;li&gt;Download the credentials CSV file.&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%2Fyszvkadr2jv05azevhmc.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%2Fyszvkadr2jv05azevhmc.png" alt=" " width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Return to the user list.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test login
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Copy the sign-in URL shown on the user details page.&lt;/li&gt;
&lt;li&gt;Paste it into an incognito window.&lt;/li&gt;
&lt;li&gt;Log in with the autogenerated password.&lt;/li&gt;
&lt;li&gt;The console will ask you to reset the password.&lt;/li&gt;
&lt;li&gt;After logging in, you will see the default AWS console but with no permissions.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Test Lack of Permissions
&lt;/h2&gt;

&lt;p&gt;This is important because it shows how IAM actually blocks actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Try creating an S3 bucket
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Search for &lt;strong&gt;S3&lt;/strong&gt; in the AWS search bar.&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%2Fs7ovspa0gho9mid9yrx4.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%2Fs7ovspa0gho9mid9yrx4.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the S3 service.&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%2F653vppnrdbwrc74u1aqw.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%2F653vppnrdbwrc74u1aqw.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Create bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add a globally unique bucket name.&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%2Flqugfya91l95luh03go3.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%2Flqugfya91l95luh03go3.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep everything default and try to create it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You’ll get an error like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To create a bucket, the s3:CreateBucket permission is required.&lt;br&gt;
User is not authorized to perform: s3:CreateBucket …&lt;/p&gt;
&lt;/blockquote&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%2Fkhk18aytr8jn26fl2q0s.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%2Fkhk18aytr8jn26fl2q0s.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This confirms the user has &lt;strong&gt;zero&lt;/strong&gt; permission by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Add Permissions Using a User Group
&lt;/h2&gt;

&lt;p&gt;Go back to the &lt;strong&gt;root account&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an S3 access group
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;IAM &amp;gt; User groups&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create group&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name it &lt;strong&gt;s3-manager&lt;/strong&gt;.&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%2Fyx51fqof99jp0ngo29vz.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%2Fyx51fqof99jp0ngo29vz.png" alt=" " width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add your IAM user (for example, “random”).&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;AmazonS3FullAccess&lt;/strong&gt; and attach it.&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%2Fu6dwmb942doygle6zkxb.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%2Fu6dwmb942doygle6zkxb.png" alt=" " width="800" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the group.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test again as the IAM user
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in again as the IAM user.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;S3 &amp;gt; Create bucket&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Try creating the bucket again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This time the bucket should be created successfully.&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%2Ff0z2e2e7bwc3rznonzw0.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%2Ff0z2e2e7bwc3rznonzw0.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Add EC2 Permissions Through Another Group
&lt;/h2&gt;

&lt;p&gt;Back to the root account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create EC2 admin group
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;IAM &amp;gt; User groups&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Create a group named &lt;strong&gt;ec2-admin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Attach the &lt;strong&gt;AmazonEC2FullAccess&lt;/strong&gt; policy.&lt;/li&gt;
&lt;li&gt;Add your IAM user to this group.&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%2F7rm0jdgpuakpvft6wudf.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%2F7rm0jdgpuakpvft6wudf.png" alt=" " width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the user has both S3 full access and EC2 full access.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Launch an EC2 Instance
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;EC2&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Launch instance&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name it &lt;strong&gt;management-server&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Amazon Linux 2023&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Instance type: &lt;strong&gt;t2.micro&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use the default VPC and defaults for other settings.&lt;/li&gt;
&lt;li&gt;Create a key pair and download it.&lt;/li&gt;
&lt;li&gt;Allow SSH from anywhere.&lt;/li&gt;
&lt;li&gt;Launch the instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Connect
&lt;/h3&gt;

&lt;p&gt;Use SSH or the EC2 “Connect” button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test access
&lt;/h3&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Unable to locate credentials. You can configure credentials by running "aws configure".
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fzx58ryclqtexai7sz8an.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%2Fzx58ryclqtexai7sz8an.png" alt=" " width="714" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This shows that an EC2 instance does not inherit the logged-in user’s permissions.&lt;br&gt;
Instances need &lt;strong&gt;IAM roles&lt;/strong&gt;, not IAM users.&lt;/p&gt;
&lt;h2&gt;
  
  
  6. Create an IAM Role for EC2
&lt;/h2&gt;

&lt;p&gt;Back to the root account.&lt;/p&gt;
&lt;h3&gt;
  
  
  Create a role
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;IAM &amp;gt; Roles&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Create role&lt;/strong&gt;.&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%2Fapc73v2la30443akzsli.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%2Fapc73v2la30443akzsli.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;AWS service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Pick &lt;strong&gt;EC2&lt;/strong&gt; as the use case.&lt;/li&gt;
&lt;li&gt;Continue.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;AmazonS3FullAccess&lt;/strong&gt; and attach it.&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%2Fleikbcgafteygms48lnn.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%2Fleikbcgafteygms48lnn.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Name the role &lt;strong&gt;s3-manager&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create the role.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Attach the role to the instance
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;EC2 &amp;gt; Instances&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select your instance &lt;strong&gt;management-server&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Actions &amp;gt; Security &amp;gt; Modify IAM role.&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%2Fgl0blj6x2k2iw5hz9a7d.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%2Fgl0blj6x2k2iw5hz9a7d.png" alt=" " width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;s3-manager&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Update the role.&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%2F0yc4nzzwgsydyzlrtaze.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%2F0yc4nzzwgsydyzlrtaze.png" alt=" " width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  7. Test the Role on the EC2 Instance
&lt;/h2&gt;

&lt;p&gt;Connect again to the instance.&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws s3 ls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time it should list your buckets.&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%2Fh88xbjgcd7ku0h23dfug.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%2Fh88xbjgcd7ku0h23dfug.png" alt=" " width="719" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;)&lt;/p&gt;

&lt;p&gt;You’ve now validated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IAM user without permissions&lt;/li&gt;
&lt;li&gt;IAM group with permissions&lt;/li&gt;
&lt;li&gt;IAM policy attachment&lt;/li&gt;
&lt;li&gt;EC2 instance role&lt;/li&gt;
&lt;li&gt;Credential-less CLI access through instance role&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the exact workflow used in real AWS environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Clean Up
&lt;/h2&gt;

&lt;p&gt;Delete everything you created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket&lt;/li&gt;
&lt;li&gt;IAM user&lt;/li&gt;
&lt;li&gt;IAM groups&lt;/li&gt;
&lt;li&gt;IAM role&lt;/li&gt;
&lt;li&gt;EC2 instance&lt;/li&gt;
&lt;li&gt;Key pair&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;AWS IAM makes more sense when you picture how each piece connects. People get identified by users, while groups bundle up permissions neatly. Roles hand out short-term access to AWS tools instead of permanent keys. Policies lay down the rules on which actions actually work. Try logging in as someone with limited rights - it shows what restrictions feel like firsthand. Toss a user into a group and watch their powers change without touching individual settings. Hook a role to an EC2 machine, then see it talk to other services solo. These moves prove how IAM locks things down tight. Learn this core stuff and you’ll tweak access without second-guessing every click.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>iam</category>
      <category>awschallenge</category>
    </item>
    <item>
      <title>Unit Testing Using Spring Boot, JUnit and Mockito</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Fri, 31 Oct 2025 00:00:00 +0000</pubDate>
      <link>https://forem.com/olymahmud/unit-testing-using-spring-boot-junit-and-mockito-2l0b</link>
      <guid>https://forem.com/olymahmud/unit-testing-using-spring-boot-junit-and-mockito-2l0b</guid>
      <description>&lt;p&gt;Testing is very important to develop a good software. In this guide. We'll see how to perform unit testing in a Spring Boot app. I'll try to make it as simple as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. What is Unit Testing?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Unit testing&lt;/strong&gt; is the process of testing individual parts (units) of your application. In unit testing, we test the functions or methods, in isolation.&lt;br&gt;&lt;br&gt;
The goal is to make sure each unit works as expected.&lt;/p&gt;

&lt;p&gt;Examples of unit testing are,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing if a method correctly saves a todo item.
&lt;/li&gt;
&lt;li&gt;Testing if fetching by ID returns the correct item.
&lt;/li&gt;
&lt;li&gt;Testing if delete operation calls the repository properly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. Project Overview
&lt;/h2&gt;

&lt;p&gt;Here’s the structure of our Spring Boot project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/main/
├── java/com/example/unittesting
│   ├── controller/TodoController.java
│   ├── entity/Todo.java
│   ├── repository/TodoRepository.java
│   ├── service/TodoService.java
│   ├── service/impl/TodoServiceImpl.java
│   └── UnitTestingApplication.java
└── resources/
    └── application.properties

src/test/
└── java/com/example/unittesting
    └── service/TodoServiceImplTest.java
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll focus on the &lt;strong&gt;service layer tests&lt;/strong&gt; because they are perfect for unit testing with &lt;strong&gt;Mockito&lt;/strong&gt; (no need to connect to the real database).&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Entity Layer
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Todo&lt;/code&gt; entity represents a single task.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Data&lt;/span&gt;
&lt;span class="nd"&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class="nd"&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simple JPA entity with &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, and &lt;code&gt;completed&lt;/code&gt; fields.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Repository Layer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;TodoRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This interface extends &lt;code&gt;JpaRepository&lt;/code&gt;, giving you built-in CRUD operations.&lt;/p&gt;

&lt;p&gt;We won’t test this layer directly because Spring Data JPA already provides these methods. Instead, we’ll &lt;strong&gt;mock&lt;/strong&gt; it in our service tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Service Layer
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;TodoService&lt;/code&gt; defines our business operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;TodoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllTodos&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;getTodoById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;createTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;updateTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deleteTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoServiceImpl&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;TodoService&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;TodoRepository&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;TodoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TodoRepository&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;todoRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllTodos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;getTodoById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;createTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="nf"&gt;updateTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deleteTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This layer is perfect for unit testing because it calls the repository and contains logic we can verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Writing Unit Tests with Mockito and JUnit 5
&lt;/h2&gt;

&lt;p&gt;Our test class:&lt;br&gt;&lt;br&gt;
&lt;code&gt;src/test/java/com/example/unittesting/service/TodoServiceImplTest.java&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ExtendWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoExtension&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TodoServiceImplTest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Mock the repository to avoid using a real database&lt;/span&gt;
    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TodoRepository&lt;/span&gt; &lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Inject the mock into our service implementation&lt;/span&gt;
    &lt;span class="nd"&gt;@InjectMocks&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;TodoServiceImpl&lt;/span&gt; &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// ---------- Test 1 ----------&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;createTodo_shouldSaveAndReturnTodo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange: create a sample Todo and mock repository behavior&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Buy groceries"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act: call the method&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert: check if returned object is correct&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Buy groceries"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTitle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertFalse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCompleted&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// verify repository interaction&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ---------- Test 2 ----------&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;getAllTodos_shouldReturnAllTodos&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Buy groceries"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cook dinner"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todo2&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAllTodos&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;todos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ---------- Test 3 ----------&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;getTodoById_shouldReturnTodoIfExists&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Buy groceries"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTodoById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;findById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ---------- Test 4 ----------&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateTodo_shouldUpdateAndReturnUpdatedTodo&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Buy groceries"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Todo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Buy groceries and cook dinner"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="nc"&gt;Todo&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;updateTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;assertNotNull&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;assertEquals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Buy groceries and cook dinner"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTitle&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isCompleted&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ---------- Test 5 ----------&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deleteTodo_shouldCallRepositoryDeleteById&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
        &lt;span class="n"&gt;doNothing&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Act&lt;/span&gt;
        &lt;span class="n"&gt;todoServiceImpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deleteTodo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Assert&lt;/span&gt;
        &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;todoRepository&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;deleteById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1L&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Points:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt; integrates Mockito with JUnit 5.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@Mock&lt;/code&gt; creates a mock version of &lt;code&gt;TodoRepository&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@InjectMocks&lt;/code&gt; injects the mock into the service class.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;when(...).thenReturn(...)&lt;/code&gt; defines mock behavior.
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;verify(...)&lt;/code&gt; ensures the repository methods were called as expected.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Test Configuration
&lt;/h2&gt;

&lt;p&gt;We’re using an in-memory &lt;strong&gt;H2 database&lt;/strong&gt;, though we don’t really hit it during unit testing since we mock the repository.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;src/main/resources/application.properties&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;spring.application.name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;unit-testing&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;jdbc:h2:mem:testdb&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.driver-class-name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;org.h2.Driver&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;sa&lt;/span&gt;
&lt;span class="py"&gt;spring.datasource.password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;sa&lt;/span&gt;
&lt;span class="py"&gt;spring.jpa.hibernate.ddl-auto&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;create-drop&lt;/span&gt;
&lt;span class="py"&gt;spring.jpa.show-sql&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setup helps when you run integration tests later.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Running the Tests
&lt;/h2&gt;

&lt;p&gt;If you’re using IntelliJ or VS Code, you can simply right-click the test class and choose &lt;strong&gt;Run Tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Or run it from the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see all test cases executed successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BUILD SUCCESS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  9. Summary
&lt;/h2&gt;

&lt;p&gt;In this guide, we've seen how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structure a Spring Boot project for testing
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Mockito&lt;/strong&gt; to mock dependencies
&lt;/li&gt;
&lt;li&gt;Write unit tests for CRUD operations in the service layer
&lt;/li&gt;
&lt;li&gt;Verify repository interactions
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>testing</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>The Basics of Software Testing</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Wed, 29 Oct 2025 00:00:00 +0000</pubDate>
      <link>https://forem.com/olymahmud/the-basics-of-software-testing-29oe</link>
      <guid>https://forem.com/olymahmud/the-basics-of-software-testing-29oe</guid>
      <description>&lt;p&gt;Today, we'll explore one of the most annoying things for a Software Engineer. It's Software Testing!&lt;br&gt;
No, I'll not make it complex. My goal is to simplify software testing.&lt;/p&gt;

&lt;p&gt;Software testing means checking the software we have developed. It helps us catch mistakes before the users face those mistakes. Testing makes software more stable and safer to use.&lt;/p&gt;

&lt;p&gt;Think about a food delivery app. If a food delivery app crashes when you place an order, or a banking app sends money to the wrong account, people will lose trust in it. Testing helps prevent those problems in the production environment&lt;/p&gt;

&lt;h3&gt;
  
  
  But Why Should I Do This Annoying Testing
&lt;/h3&gt;

&lt;p&gt;Nobody writes perfect code the first time. You don't even know how many bugs you've developed. Testing finds bugs and errors early, before they turn into a bigger issue. It also saves time and effort later.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Unit Testing
&lt;/h3&gt;

&lt;p&gt;Unit testing is the process of testing small parts of your code. Suppose you have a single function, method, or class. In unit testing, you will test  those functions, classes are properly working or not&lt;/p&gt;

&lt;p&gt;For example, you have developed an e-commerce app. Now, you might test a function called &lt;code&gt;calculateDiscount(price, percent)&lt;/code&gt;. If the price is 100 and the discount is 10%, the result should be 90.&lt;/p&gt;

&lt;p&gt;If that test passes, your calculation works fine. Unit tests are quick to run and help catch bugs early before they spread.&lt;/p&gt;

&lt;p&gt;Common tools we use in unit testing are JUnit (Java), Testify (Go), PyTest (Python), Jest (JavaScript)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Integration Testing
&lt;/h3&gt;

&lt;p&gt;Integration testing is the tests that checks how different parts of your app work when they are connected. Even if each part works fine by itself, they can fail when connected. Don't get confused. It's very simple.&lt;/p&gt;

&lt;p&gt;If we take an example of a food delivery app. In a food delivery app, the order system talks to the payment system. Integration testing makes sure that when a user orders food, payment is processed and a confirmation is sent. So, our integration test checks that the order system and payment system work together.&lt;/p&gt;

&lt;p&gt;This kind of test finds problems with data exchange between parts of your app or the database connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common tools:&lt;/strong&gt;&lt;br&gt;
JUnit (Java), Go’s &lt;code&gt;httptest&lt;/code&gt; package, Postman, Spring Boot Test&lt;/p&gt;

&lt;h3&gt;
  
  
  3. End-to-End (E2E) Testing
&lt;/h3&gt;

&lt;p&gt;In End-to-End testing, we mimic the behavior of the software. In E2E, the tests are written like a user were using the software. &lt;/p&gt;

&lt;p&gt;Again, we'll see the example of an e-commerce. What type of feature do you expect to see in an e-commerce app? You’ll test signing in, adding an item to the cart, paying, and receiving confirmation. If all steps work perfectly, then the E2E test is passed.&lt;/p&gt;

&lt;p&gt;E2E testing makes sure the full system is perfect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common tools:&lt;/strong&gt;&lt;br&gt;
Cypress, Selenium, Playwright, Puppeteer&lt;/p&gt;

&lt;h3&gt;
  
  
  Difference Between Unit, Integration, and End-to-End Testing
&lt;/h3&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;What It Tests&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Scope&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unit Test&lt;/td&gt;
&lt;td&gt;One small part of code&lt;/td&gt;
&lt;td&gt;Checking if &lt;code&gt;calculateDiscount()&lt;/code&gt; returns the right value&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration Test&lt;/td&gt;
&lt;td&gt;How parts work together&lt;/td&gt;
&lt;td&gt;Order system and payment system working together&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-to-End Test&lt;/td&gt;
&lt;td&gt;The full user flow&lt;/td&gt;
&lt;td&gt;From login to checkout in an e-commerce app&lt;/td&gt;
&lt;td&gt;Large&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;You can think of it like building a car:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit testing&lt;/strong&gt; checks if each part (like the engine or brakes) works properly on its own.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration testing&lt;/strong&gt; checks if the engine connects correctly with the transmission.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end testing&lt;/strong&gt; takes the car for a drive to see if everything works together smoothly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Other Useful Types of Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Testing:&lt;/strong&gt; Checks how fast your app runs under load. For example, how your website performs when 10,000 users visit at once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Testing:&lt;/strong&gt; Looks for vulnerabilities that attackers might exploit. For example, checking if users can access data they shouldn’t.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usability Testing:&lt;/strong&gt; Ensures your app is easy to use. Real users try it and share feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regression Testing:&lt;/strong&gt; Makes sure new changes don’t break existing features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smoke Testing:&lt;/strong&gt; A quick check to see if basic features work after deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;A well-tested software is very important. If a software fails in production, it makes a negative impact on a company. So, software testing is a must.&lt;/p&gt;

</description>
      <category>software</category>
      <category>testing</category>
      <category>computerscience</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>Building A Real-Time Communication System Using Go and WebSocket</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Fri, 10 Oct 2025 16:30:20 +0000</pubDate>
      <link>https://forem.com/olymahmud/building-a-real-time-communication-system-using-go-and-websocket-19n5</link>
      <guid>https://forem.com/olymahmud/building-a-real-time-communication-system-using-go-and-websocket-19n5</guid>
      <description>&lt;p&gt;Real-time applications like chat systems, dashboards, or multiplayer games rely on persistent, low-latency communication between client and server. Traditional HTTP is request-response only, but it can’t push data to the client unless the client keeps polling. That’s where &lt;strong&gt;WebSockets&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore how WebSockets work, how connections are established and managed in Go using the &lt;strong&gt;Gorilla WebSocket&lt;/strong&gt; library, and how to safely handle multiple concurrent clients with &lt;strong&gt;Go’s concurrency primitives&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We’ll build on a simple Go project using only the standard &lt;code&gt;net/http&lt;/code&gt; router and Gorilla WebSocket.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a WebSocket?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;WebSocket&lt;/strong&gt; is a full-duplex communication channel over a single TCP connection. Once established, both client and server can send messages to each other anytime without re-establishing the connection.&lt;/p&gt;

&lt;p&gt;Unlike HTTP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSockets stay open until one side closes it.&lt;/li&gt;
&lt;li&gt;Communication happens through lightweight &lt;strong&gt;frames&lt;/strong&gt;, not HTTP requests.&lt;/li&gt;
&lt;li&gt;Data can flow in both directions independently.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How a WebSocket Connection is Formed
&lt;/h2&gt;

&lt;p&gt;The WebSocket handshake starts as a standard HTTP GET request with an &lt;code&gt;Upgrade&lt;/code&gt; header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /ws HTTP/1.1
Host: localhost:8080
Upgrade: websocket
Connection: Upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the server accepts it, it responds with a &lt;code&gt;101 Switching Protocols&lt;/code&gt; status, upgrading the connection to WebSocket. From that point, the connection is no longer HTTP, it’s a persistent socket.&lt;/p&gt;

&lt;p&gt;In Go, this upgrade is handled by Gorilla’s &lt;code&gt;Upgrader&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrader&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ReadBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;WriteBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CheckOrigin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;CheckOrigin&lt;/code&gt; function lets us control which clients can connect. Setting it to always return &lt;code&gt;true&lt;/code&gt; allows all origins, good for development, not for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connection Establishment and Storage
&lt;/h2&gt;

&lt;p&gt;When a client connects to &lt;code&gt;/ws&lt;/code&gt;, the handler upgrades the request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upgrade error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once upgraded, &lt;code&gt;conn&lt;/code&gt; is a &lt;code&gt;*websocket.Conn&lt;/code&gt;, which represents an open connection to a client.&lt;br&gt;
We store each connection in memory along with the client’s username (sent in the request header):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Connections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use a global slice of maps to keep track of all connected users.&lt;br&gt;
A &lt;code&gt;sync.Mutex&lt;/code&gt; ensures that concurrent reads and writes to the &lt;code&gt;Connections&lt;/code&gt; slice are thread-safe, since multiple clients can connect or disconnect at the same time.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reading and Writing Messages
&lt;/h2&gt;

&lt;p&gt;After establishing the connection, the server starts listening for messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;messageType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] read error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] says: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response to %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ReadMessage()&lt;/code&gt; blocks until a new message arrives. When it does, it returns the &lt;strong&gt;message type&lt;/strong&gt;, the &lt;strong&gt;payload&lt;/strong&gt;, and any &lt;strong&gt;error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;messageType&lt;/code&gt; is important because WebSockets can carry different kinds of messages.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSocket Message Types
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;TextMessage (1):&lt;/strong&gt; UTF-8 encoded text.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BinaryMessage (2):&lt;/strong&gt; Arbitrary binary data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PingMessage (9):&lt;/strong&gt; Sent by one peer to check if the connection is alive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PongMessage (10):&lt;/strong&gt; Sent automatically in response to a ping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloseMessage (8):&lt;/strong&gt; Sent when either side wants to terminate the connection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most applications only use text and binary frames, but ping/pong frames are crucial for keeping the connection healthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Detecting and Closing Idle Connections
&lt;/h2&gt;

&lt;p&gt;In a real-world system, we don’t want idle connections hanging around forever.&lt;br&gt;
We can use &lt;code&gt;SetReadDeadline()&lt;/code&gt; to close connections that haven’t received messages for a specific time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;idleTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idleTimeout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetPongHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idleTimeout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server expects a message or pong frame every 60 seconds.&lt;/li&gt;
&lt;li&gt;Each time one arrives, the deadline resets.&lt;/li&gt;
&lt;li&gt;If the timer expires without activity, &lt;code&gt;ReadMessage()&lt;/code&gt; returns a timeout error, and we close the connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is how we automatically disconnect idle clients while keeping active ones alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cleaning Up Disconnected Clients
&lt;/h2&gt;

&lt;p&gt;When a connection closes, we must remove it from our global store to prevent memory leaks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;removeConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that only active connections remain in memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Messages to Specific Clients
&lt;/h2&gt;

&lt;p&gt;Sometimes, you need to send data to a particular user. We can look up the connection by username and send directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SendMessageToSpecificUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;targetUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hi "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sent message to %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sent"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user not found"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can easily be extended to support broadcasting messages to all clients or to a subset (like chat rooms).&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrency and Multithreading in WebSocket Handling
&lt;/h2&gt;

&lt;p&gt;Each HTTP request in Go runs in its own goroutine.&lt;br&gt;
That means every WebSocket connection gets a &lt;strong&gt;dedicated goroutine&lt;/strong&gt; when the handler runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebsocketHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside that goroutine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;for&lt;/code&gt; loop reading messages is blocking, but isolated to that connection.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sync.Mutex&lt;/code&gt; ensures shared data structures (like &lt;code&gt;Connections&lt;/code&gt;) remain safe when multiple goroutines modify them simultaneously.&lt;/li&gt;
&lt;li&gt;The Go scheduler handles concurrency efficiently, thousands of WebSocket connections can run in parallel on a single server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This concurrency model is what makes Go such a great fit for real-time applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;Let’s walk through building and testing the complete WebSocket setup from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;

&lt;p&gt;Create your project:&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;mkdir &lt;/span&gt;websocket-chat-appp
&lt;span class="nb"&gt;cd &lt;/span&gt;websocket-chat-appp
go mod init websocket-chat-appp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Gorilla WebSocket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go get github.com/gorilla/websocket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Project structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;websocket-chat-app/
│── go.mod
├── main.go
└── handlers/
    └── websocket_handlers.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  main.go
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"websocket-chat-app/handlers"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/ws"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebsocketHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/show"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PrintConnections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST /send"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessageToSpecificUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server started on :8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  handlers/websocket_handlers.go
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;handlers&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/gorilla/websocket"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Global variables to store all active connections&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;          &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrader&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ReadBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;WriteBufferSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;CheckOrigin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// WebsocketHandler handles new WebSocket connections&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WebsocketHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"username query param required"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;upgrader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Upgrade error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Connections&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] connected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;handleConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// handleConnection reads messages and handles connection lifecycle&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;handleConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;removeConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] disconnected"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;idleTimeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idleTimeout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetPongHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;idleTimeout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;msgType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] read error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[%s] says: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Response to %s: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// removeConnection cleans up disconnected clients&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;removeConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// PrintConnections displays all connected usernames&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;PrintConnections&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Connected users:"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// SendMessageToSpecificUser sends a message to a specific user&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;SendMessageToSpecificUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;targetUser&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;Connections&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;targetUser&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hi "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sent message to %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sent"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user not found"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running the Server
&lt;/h3&gt;

&lt;p&gt;Start the Go server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2025/10/09 22:10:41 Server started on:8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing with Postman
&lt;/h3&gt;

&lt;p&gt;Now, let's see how our app works.&lt;br&gt;
Open Postman, then make a WebSocket connection to &lt;code&gt;localhost:8080/ws&lt;/code&gt;. Here I am using passing &lt;code&gt;mugdho&lt;/code&gt; as the username, in the header.&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%2Fy7aivm8rydj7c8ljvrro.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%2Fy7aivm8rydj7c8ljvrro.png" alt="WebSocket Request - Mugdho" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's make another WebSocket request. Here I am using "mila" as the username in the header.&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%2Ffm3he90ztnseh7wd1svp.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%2Ffm3he90ztnseh7wd1svp.png" alt="WebSocket Connection - Mila" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see the connected users using &lt;code&gt;HTTP REST API&lt;/code&gt;.&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%2Fhpws0bhiwo1z90tj2pji.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%2Fhpws0bhiwo1z90tj2pji.png" alt="Show All Connected Users - 2 users" width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now I am sending messages from the connection "Mugdho"&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%2Ffinhivskp8e2cpmqa3b1.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%2Ffinhivskp8e2cpmqa3b1.png" alt=" " width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But I'm not sending any messages from "Mila". So the connection is closed.&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%2Fl3xzkhs7wcupneeq454y.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%2Fl3xzkhs7wcupneeq454y.png" alt=" " width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, establish both connections again and send a message to a specific user. I am sending a message to "Mila".&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%2Fge607v2kl1hdfon8yjx5.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%2Fge607v2kl1hdfon8yjx5.png" alt=" " width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's see if Mila received the message or not.&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%2Fkwmlb4feoeuvmhntrbhd.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%2Fkwmlb4feoeuvmhntrbhd.png" alt=" " width="800" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, Mila received the message successfully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Here’s what we covered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How WebSockets work&lt;/strong&gt; and how they differ from HTTP&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to establish&lt;/strong&gt; and &lt;strong&gt;upgrade&lt;/strong&gt; a connection using Gorilla WebSocket&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message types&lt;/strong&gt; and how to read/write frames&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to detect idle clients&lt;/strong&gt; using &lt;code&gt;SetReadDeadline&lt;/code&gt; and close them cleanly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storing and managing connections&lt;/strong&gt; safely with &lt;code&gt;sync.Mutex&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency in Go&lt;/strong&gt; each WebSocket runs in its own goroutine&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>websocket</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>AWS Global Infrastructure | Amazon Web Services</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Fri, 10 Oct 2025 04:57:00 +0000</pubDate>
      <link>https://forem.com/olymahmud/part-2-aws-global-infrastructure-amazon-web-services-2n2f</link>
      <guid>https://forem.com/olymahmud/part-2-aws-global-infrastructure-amazon-web-services-2n2f</guid>
      <description>&lt;p&gt;In our last session, we saw how cloud computing allows app usage without handling real hardware. Today begins understanding AWS fundamentals.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS Global Infrastructure
&lt;/h2&gt;

&lt;p&gt;AWS runs on strong worldwide systems. That’s why apps work without issues. Wherever customers are located, speed stays high. From day one, delays stay low while uptime remains solid.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Regions and Availability Zones&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regions&lt;/strong&gt; are geographic areas such as &lt;strong&gt;US East (N. Virginia)&lt;/strong&gt; or &lt;strong&gt;Asia Pacific (Mumbai)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Each Region includes several &lt;strong&gt;Availability Zones (AZs)&lt;/strong&gt;, which are isolated data centers. Each data center has independent power, networking, and cooling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We could lower the risk by spreading things across different regions and zones.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Edge Locations, Local Zones, and Wavelength&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;AWS offers local spots to speed up apps for people - using nearby sites helps performance while cutting delays across regions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Edge Locations&lt;/strong&gt;: Cache content near users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Zones&lt;/strong&gt;: Bring some AWS services closer to big cities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wavelength Zones&lt;/strong&gt;: Connect to 5G networks for very low-latency apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AWS Outposts&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you want AWS tools locally, Outposts brings the network into your facility - offering combined cloud access. Rather than keeping systems separate, it links internal operations with external resources seamlessly - using consistent management layers across both environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Shared Responsibility Model&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Security on the cloud doesn't happen by itself. With the Shared Responsibility Model, AWS shows what parts each party must manage.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS handles "Security of the Cloud"&lt;/strong&gt;: Protects the physical data centers, servers, networking, and foundational services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You handle "Security in the Cloud"&lt;/strong&gt;: Responsible for applications, data, identity, access controls, encryption, and network configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's a joint effort: AWS supplies the safe foundation, while you develop atop it with care.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;AWS Well-Architected Framework&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;AWS offers a method known as the Well-Architected Framework. This approach supports creating stable, efficient systems. The model rests on six core areas. As stated in their public documentation, these elements include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Operational Excellence&lt;/strong&gt; – Monitor and improve systems continuously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; – Protect data, accounts, and workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability&lt;/strong&gt; – Recover quickly from failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Efficiency&lt;/strong&gt; – Use resources smartly and scale efficiently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Optimization&lt;/strong&gt; – Avoid waste and maximize value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sustainability&lt;/strong&gt; – Reduce environmental impact.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sticking to these principles enables the creation of safe, high-performing software that works consistently - using them streamlines your process while improving outcomes through better structure instead of guesswork.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here, we looked at AWS global infrastructure, its shared responsibility approach - also exploring the well-architected guidelines from AWS.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awschallenge</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Introduction to Cloud Computing and AWS</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Sat, 04 Oct 2025 06:17:58 +0000</pubDate>
      <link>https://forem.com/olymahmud/introduction-to-cloud-computing-and-aws-29li</link>
      <guid>https://forem.com/olymahmud/introduction-to-cloud-computing-and-aws-29li</guid>
      <description>&lt;p&gt;If you've ever thought about why Netflix plays smoothly, while new apps pop up fast from small teams, or how companies grow to serve tons of people without running giant server rooms, the reason is &lt;strong&gt;cloud computing&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Cloud Computing?
&lt;/h2&gt;

&lt;p&gt;Keep things basic - cloud computing means leasing tech stuff rather than owning it. Rather than managing hardware in-house, you access processing space, file room, and info systems online whenever needed.&lt;/p&gt;

&lt;p&gt;Take electricity, for example. Instead of running a personal generator, you connect to the network - then pay based on usage. Cloud computing follows this idea. Want a virtual machine? Space to keep documents? A database that operates smoothly in the background? It’s all available through the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Benefits of Cloud Computing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Scale up or down fast when your visitor count shifts - no hassle. Use more power if needed, less when it’s quiet. Adjust anytime without breaking a sweat.&lt;/li&gt;
&lt;li&gt;Save money by paying just for what you actually need - no huge costs at the start.&lt;/li&gt;
&lt;li&gt;Worldwide access: servers everywhere, which means faster service for people nearby.&lt;/li&gt;
&lt;li&gt;Running systems: folks take care of real-world parts - power, chillers, broken gear.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Service Models in the Cloud
&lt;/h2&gt;

&lt;p&gt;Cloud computing shows up in three big types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IaaS (Infrastructure as a Service):&lt;/strong&gt; IaaS means you lease computing resources - say, virtual servers or disk space - through cloud platforms such as AWS EC2; think of it like renting tech gear online instead of buying it outright.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PaaS (Platform as a Service):&lt;/strong&gt;  It’s a setup you can use right away to create and launch apps - take Google App Engine, for example.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SaaS (Software as a Service):&lt;/strong&gt; SaaS means software online - you sign in, start using it. Think Gmail or Dropbox - no install needed, just open your browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Deployment Models: Public, Private, and Hybrid Clouds
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Public Cloud:&lt;/strong&gt; This’s the go-to version of cloud tech. Services run on servers owned by big companies - these get split between lots of different people. Access? Open to anyone online, no restrictions. Think AWS, or Azure, maybe Google Cloud - they’re all in this group.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Private Cloud:&lt;/strong&gt; A private cloud? Just older tech. One business uses it alone - keeps it at their office or pays someone to run it. Used to rule before big online servers showed up. Gives tighter grip on safety and setup. Like a firm managing its gear inside, using tools like VMware or OpenStack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hybrid Cloud:&lt;/strong&gt; A mix of public plus private cloud setups makes a hybrid system. This setup lets data shift from one side to the other smoothly. It gives more room to adapt based on needs. Like when sensitive info stays in-house, yet high-traffic apps use external servers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Amazon Web Services (AWS)
&lt;/h2&gt;

&lt;p&gt;Amazon Web Services - also known as AWS - ranks as the top cloud platform globally. It kicked off in 2006 after Amazon chose to lease its huge tech setup. Right now, businesses big and small run on it, including major names such as Netflix alongside Airbnb.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core AWS Services
&lt;/h3&gt;

&lt;p&gt;Here’s what AWS actually does for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;💻 Compute (Running Apps):&lt;/strong&gt; Run websites or apps? Try EC2 - it’s like renting a virtual machine. Or go serverless with Lambda - just drop your code, it runs on its own. Both handle heavy lifting so you don’t have to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;🗂️ Storage (Saving Stuff):&lt;/strong&gt; Hold onto your files, pics, and info using tools such as S3 - solid for saving stuff - or EBS, which works like a virtual hard disk. While S3 handles buckets of data, EBS gives you block-level space that sticks around.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;📊 Databases:&lt;/strong&gt; Pick RDS when you’re working with structured data - say, MySQL. Or go for DynamoDB if speed matters more and you like room to adapt.&lt;br&gt;
Networking: set up safe connections using VPC, boost loading times through CloudFront.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;🌐 Networking:&lt;/strong&gt; Set up safe connections using VPC, boost loading times through CloudFront&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;🔐 Security &amp;amp; Access:&lt;/strong&gt; Keep things safe by picking who gets in using IAM, while encryption guards your info.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We’ve picked up what cloud computing’s about, along with AWS. It helps us grow without spending too much while connecting to people everywhere. Lots of groups use this tech because it gives them serious power.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awschallenge</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Day-8: Install Ansible | 100 Days of DevOps</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Fri, 03 Oct 2025 14:42:03 +0000</pubDate>
      <link>https://forem.com/olymahmud/day-8-install-ansible-100-days-of-devops-101c</link>
      <guid>https://forem.com/olymahmud/day-8-install-ansible-100-days-of-devops-101c</guid>
      <description>&lt;p&gt;In this guide, we’ll walk through the different ways to install Ansible and get it running on your system. By the end, you’ll be able to execute Ansible commands globally from your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Ansible?
&lt;/h2&gt;

&lt;p&gt;Ansible is an open-source automation engine that helps manage systems, deploy applications, and orchestrate workflows. Unlike many other configuration management tools, Ansible doesn’t require installing agents on managed nodes. It only needs SSH access and Python on the target machine, which keeps things lightweight and secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation Options
&lt;/h2&gt;

&lt;p&gt;There are several ways to install Ansible:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Package Manager&lt;/strong&gt; – Install via &lt;code&gt;apt&lt;/code&gt; (Debian/Ubuntu), &lt;code&gt;dnf&lt;/code&gt; or &lt;code&gt;yum&lt;/code&gt; (RHEL/CentOS/Fedora).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pip (Python package manager)&lt;/strong&gt; – Install via &lt;code&gt;pip3&lt;/code&gt;, which gives you more control over the version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From Source&lt;/strong&gt; – Clone the official Ansible GitHub repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article, we’ll focus on the &lt;strong&gt;pip3 installation method&lt;/strong&gt; since it allows us to install a specific version and ensures portability across environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Install Python and Pip
&lt;/h2&gt;

&lt;p&gt;Ansible requires Python 3. Most modern Linux distributions come with Python pre-installed. If not, install Python and pip3:&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;apt update &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3 python3-pip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the installation with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;
pip3 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Install Ansible via pip3
&lt;/h2&gt;

&lt;p&gt;To install the latest version of Ansible globally, run:&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;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;ansible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to install a specific version (for example, Ansible 4.9.0), use:&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;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;&lt;span class="nv"&gt;ansible&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;4.9.0 &lt;span class="nt"&gt;--prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--prefix=/usr/local&lt;/code&gt; flag ensures that the binary goes into &lt;code&gt;/usr/local/bin&lt;/code&gt;, which is accessible by all users on the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Verify Installation
&lt;/h2&gt;

&lt;p&gt;After installation, check whether Ansible is installed correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ansible [core 2.11.x]
  config file = None
  ansible python module location = /usr/local/lib/python3.9/dist-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.x.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Add Ansible to PATH (if needed)
&lt;/h2&gt;

&lt;p&gt;If the &lt;code&gt;ansible&lt;/code&gt; command isn’t found, add &lt;code&gt;/usr/local/bin&lt;/code&gt; to your PATH. Create a file under &lt;code&gt;/etc/profile.d/&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;echo&lt;/span&gt; &lt;span class="s1"&gt;'export PATH=$PATH:/usr/local/bin'&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/profile.d/ansible.sh
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x /etc/profile.d/ansible.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reload the environment:&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;source&lt;/span&gt; /etc/profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Ansible will be available to all users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Test Ansible with a Ping Command
&lt;/h2&gt;

&lt;p&gt;To make sure Ansible can talk to your servers, create an inventory file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[servers]&lt;/span&gt;
&lt;span class="err"&gt;192.168.1.10&lt;/span&gt;
&lt;span class="err"&gt;192.168.1.11&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ansible &lt;span class="nt"&gt;-i&lt;/span&gt; inventory servers &lt;span class="nt"&gt;-m&lt;/span&gt; ping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is set up correctly, you’ll see a “pong” response from each server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;So, we've successfully installed Ansible.&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>devchallenge</category>
      <category>devops</category>
      <category>100daysofdevops</category>
    </item>
    <item>
      <title>Day-7: Linux SSH Authentication | 100 Days of DevOps</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Sat, 27 Sep 2025 18:00:00 +0000</pubDate>
      <link>https://forem.com/olymahmud/day-7-linux-ssh-authentication-100-days-of-devops-5g68</link>
      <guid>https://forem.com/olymahmud/day-7-linux-ssh-authentication-100-days-of-devops-5g68</guid>
      <description>&lt;p&gt;When we work with remote servers, the most common way to connect is through &lt;strong&gt;SSH (Secure Shell)&lt;/strong&gt;. If you’ve ever managed Linux servers or deployed applications, chances are you’ve used it.&lt;br&gt;
In this article, we’ll walk through what SSH is, how to use it for login, and finally how to set up password-less login across multiple servers.&lt;/p&gt;
&lt;h2&gt;
  
  
  What is SSH?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;SSH (Secure Shell)&lt;/strong&gt; is a protocol that let us securely connect to another machine over an insecure network. It’s widely used by developers, system admins, and DevOps engineers to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to remote servers&lt;/li&gt;
&lt;li&gt;Run commands&lt;/li&gt;
&lt;li&gt;Transfer files&lt;/li&gt;
&lt;li&gt;Manage systems securely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike older methods like Telnet, SSH encrypts all communication. This means our credentials and data are safe from eavesdropping.&lt;/p&gt;
&lt;h2&gt;
  
  
  How to Log In Using SSH
&lt;/h2&gt;

&lt;p&gt;The basic syntax of an SSH login is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh username@hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;username&lt;/code&gt; → the user account on the remote server&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hostname&lt;/code&gt; → the server’s IP address or domain name&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;If we have a server at &lt;code&gt;172.16.238.10&lt;/code&gt; with a user &lt;code&gt;tony&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;ssh tony@172.16.238.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll be prompted to enter the password for that user. Once authenticated, you’ll get a shell on the remote machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Passwords
&lt;/h2&gt;

&lt;p&gt;Typing a password every single time quickly becomes annoying, especially when we need to log into multiple servers or run automation scripts. Passwords also pose security risks if they are weak or reused.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;SSH keys&lt;/strong&gt; come in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password-less SSH Login
&lt;/h2&gt;

&lt;p&gt;SSH keys allow us to authenticate without typing a password. The idea is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a pair of keys on our local machine (private + public).&lt;/li&gt;
&lt;li&gt;Copy the public key to the remote server.&lt;/li&gt;
&lt;li&gt;When we connect, the server verifies our private key against the stored public key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If they match, we can login without any password.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Generate SSH Keys
&lt;/h2&gt;

&lt;p&gt;On the client machine (in our case, the jump host with user &lt;code&gt;thor&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;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; rsa &lt;span class="nt"&gt;-b&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Press Enter to accept the defaults.&lt;/li&gt;
&lt;li&gt;Leave the passphrase empty (important for automation).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; → your private key (keep it safe!)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; → your public key (share this with servers)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Copy the Public Key to the Server
&lt;/h2&gt;

&lt;p&gt;To enable password-less login, copy the public key to the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub username@hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;For a server at &lt;code&gt;172.16.238.10&lt;/code&gt; with user &lt;code&gt;tony&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;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub tony@172.16.238.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll be asked for the password &lt;strong&gt;one last time&lt;/strong&gt;. After that, you’ll be able to log in without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Log In Without a Password
&lt;/h2&gt;

&lt;p&gt;Now test it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh tony@172.16.238.10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time we can connect directly, without any password prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Example: Multiple App Servers
&lt;/h2&gt;

&lt;p&gt;Here’s a real setup where we had to configure password-less login for a jump host user (&lt;code&gt;thor&lt;/code&gt;) to multiple application servers.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Server Name&lt;/th&gt;
&lt;th&gt;IP&lt;/th&gt;
&lt;th&gt;Hostname&lt;/th&gt;
&lt;th&gt;User&lt;/th&gt;
&lt;th&gt;Password&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;stapp01&lt;/td&gt;
&lt;td&gt;172.16.238.10&lt;/td&gt;
&lt;td&gt;stapp01.stratos.xfusioncorp.com&lt;/td&gt;
&lt;td&gt;tony&lt;/td&gt;
&lt;td&gt;Ir0nM@n&lt;/td&gt;
&lt;td&gt;Nautilus App 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stapp02&lt;/td&gt;
&lt;td&gt;172.16.238.11&lt;/td&gt;
&lt;td&gt;stapp02.stratos.xfusioncorp.com&lt;/td&gt;
&lt;td&gt;steve&lt;/td&gt;
&lt;td&gt;Am3ric@&lt;/td&gt;
&lt;td&gt;Nautilus App 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;stapp03&lt;/td&gt;
&lt;td&gt;172.16.238.12&lt;/td&gt;
&lt;td&gt;stapp03.stratos.xfusioncorp.com&lt;/td&gt;
&lt;td&gt;banner&lt;/td&gt;
&lt;td&gt;BigGr33n&lt;/td&gt;
&lt;td&gt;Nautilus App 3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub tony@172.16.238.10
ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub steve@172.16.238.11
ssh-copy-id &lt;span class="nt"&gt;-i&lt;/span&gt; ~/.ssh/id_rsa.pub banner@172.16.238.12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, the &lt;code&gt;thor&lt;/code&gt; user can log in to all app servers without typing passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password-less &lt;code&gt;sudo&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes, our scripts need &lt;code&gt;sudo&lt;/code&gt; privileges. By default, &lt;code&gt;sudo&lt;/code&gt; asks for a password. We can configure users for password-less &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On each app server, edit the sudoers file:&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;visudo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;username ALL=(ALL) NOPASSWD:ALL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;username&lt;/code&gt; with &lt;code&gt;tony&lt;/code&gt;, &lt;code&gt;steve&lt;/code&gt;, or &lt;code&gt;banner&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Automate scripts&lt;/li&gt;
&lt;li&gt;Manage multiple servers with ease&lt;/li&gt;
&lt;li&gt;Strengthen security with keys over passwords&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>devchallenge</category>
      <category>devops</category>
      <category>100daysofdevops</category>
    </item>
    <item>
      <title>Day-6: Cron Job | 100 Days of DevOps</title>
      <dc:creator>M. Oly Mahmud</dc:creator>
      <pubDate>Sat, 27 Sep 2025 14:27:39 +0000</pubDate>
      <link>https://forem.com/olymahmud/day-6-cron-job-100-days-of-devops-38ed</link>
      <guid>https://forem.com/olymahmud/day-6-cron-job-100-days-of-devops-38ed</guid>
      <description>&lt;p&gt;If you’ve ever wanted your Linux server to run tasks automatically, like cleaning logs, backing up databases, or sending reports, then &lt;strong&gt;cron jobs&lt;/strong&gt; are your best friend. Cron is a time-based job scheduler built into Unix-like operating systems, and it’s one of the most powerful automation tools for system admins and developers.&lt;/p&gt;

&lt;p&gt;In this article, we’ll walk through what cron jobs are, how the syntax works, real-world examples, and how we can set them up in our system.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Cron Job?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;cron job&lt;/strong&gt; is a command or script that is scheduled to run at a specific time or interval. The cron service (&lt;code&gt;crond&lt;/code&gt;) runs in the background and checks a special configuration file. This configuration file is called a &lt;strong&gt;crontab&lt;/strong&gt; (short for "cron table") to know what to execute.&lt;br&gt;
Each user on a system can have their own crontab file, and there’s also a system-wide crontab located at &lt;code&gt;/etc/crontab&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Cron Syntax Explained
&lt;/h2&gt;

&lt;p&gt;Cron syntax might be confusing. But it’s actually quite simple. Every cron job is defined with &lt;strong&gt;five time fields&lt;/strong&gt; followed by the command to run. Here’s a breakdown:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*    *    *    *    *   command_to_execute
-    -    -    -    -
|    |    |    |    |
|    |    |    |    +---- Day of week (0 - 6) (Sunday=0 or 7)
|    |    |    +--------- Month (1 - 12)
|    |    +-------------- Day of month (1 - 31)
|    +------------------- Hour (0 - 23)
+------------------------ Minute (0 - 59)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Special Characters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; → every value&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;,&lt;/code&gt; → list of values (e.g. &lt;code&gt;1,15&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&lt;/code&gt; → range (e.g. &lt;code&gt;1-5&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt; → step (e.g. &lt;code&gt;*/5&lt;/code&gt; means every 5 units)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cron Job Examples
&lt;/h2&gt;

&lt;p&gt;Let’s go through some practical examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;*/5 * * * * echo "Hello" &amp;gt;&amp;gt; /tmp/hello.log&lt;/code&gt;&lt;br&gt;
Run every 5 minutes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0 0 * * * /usr/bin/backup.sh&lt;/code&gt;&lt;br&gt;
Run a backup script every day at midnight.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;30 14 * * 1&lt;/code&gt;&lt;br&gt;
Run at 2:30 PM every Monday.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;0 */6 * * * /usr/bin/update.sh&lt;/code&gt;&lt;br&gt;
Run every 6 hours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;15 9-17 * * 1-5 /usr/bin/send_report.sh&lt;/code&gt;&lt;br&gt;
Run at 9:15, 10:15, …, 5:15 during working hours, Monday through Friday.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up a Cron Job
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install cron (if not already installed)&lt;/strong&gt;
On CentOS/RHEL:
&lt;/li&gt;
&lt;/ol&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;yum &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; cronie
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;crond
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start crond
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Ubuntu/Debian:&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;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; cron
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable &lt;/span&gt;cron
   &lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start cron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Edit the crontab&lt;/strong&gt;
To add a job for the user:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify cron jobs&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   crontab &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check if it’s working&lt;/strong&gt;
For example, add:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   */2 * * * * echo "Cron is working!" &amp;gt;&amp;gt; /tmp/test_cron.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then wait a few minutes and run:&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;cat&lt;/span&gt; /tmp/test_cron.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Automating backups&lt;/li&gt;
&lt;li&gt;Rotating or cleaning log files&lt;/li&gt;
&lt;li&gt;Sending periodic emails or reports&lt;/li&gt;
&lt;li&gt;Updating packages or databases&lt;/li&gt;
&lt;li&gt;Monitoring disk usage&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Cron jobs are simple yet powerful. With a few lines in crontab, we can automate tasks to run on time, every time. Whether managing servers or automating workflows, knowing cron is essential.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devchallenge</category>
      <category>devops</category>
      <category>100daysofdevops</category>
    </item>
  </channel>
</rss>
