<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ali Shaikh on Medium]]></title>
        <description><![CDATA[Stories by Ali Shaikh on Medium]]></description>
        <link>https://medium.com/@ali-shaikh?source=rss-7a312b7c3373------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*rxPMahPLiUqlgn_-C3Iv_w.jpeg</url>
            <title>Stories by Ali Shaikh on Medium</title>
            <link>https://medium.com/@ali-shaikh?source=rss-7a312b7c3373------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 08 Jun 2026 09:48:21 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ali-shaikh/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Creating Simple AI Agents: A Beginner’s Guide]]></title>
            <link>https://ali-shaikh.medium.com/creating-simple-ai-agents-a-beginners-guide-095be6552ba0?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/095be6552ba0</guid>
            <category><![CDATA[ai-agent]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ollama]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Tue, 04 Mar 2025 08:33:18 GMT</pubDate>
            <atom:updated>2025-03-04T09:20:03.308Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TMgLJORdjczhnAC7" /></figure><p>In today’s rapidly evolving tech landscape, AI agents are becoming increasingly accessible to developers of all skill levels. This article introduces the concept of AI agents and walks through creating a simple yet practical example: a landing page generator powered by language models running locally on your system using Ollama.</p><h3>What Are AI Agents?</h3><p>AI agents are software programs that can perform tasks with varying degrees of autonomy using artificial intelligence techniques. They typically:</p><ol><li><strong>Take input</strong> from users or environment</li><li><strong>Process information</strong> using AI models</li><li><strong>Perform actions</strong> based on this processing</li><li><strong>Provide output or feedback</strong> to users</li></ol><p>The complexity of AI agents ranges from simple task-specific tools to sophisticated systems with complex reasoning capabilities.</p><h3>Prerequisites: Running Local LLMs with Ollama</h3><p>Before diving into our AI agent, make sure you have Ollama set up on your system. If you haven’t installed it yet, I’ve written a comprehensive guide on <a href="https://alishaikh.me/how-to-run-local-llms-with-ollama-quick-setup-guide/">how to run local LLMs with Ollama</a>. This will walk you through the installation process and get you ready to build your first AI agent.</p><h3>Anatomy of a Simple AI Agent</h3><p>The landing page generator we’re examining represents a basic AI agent with these key components:</p><h3>1. User Interface</h3><p>A command-line interface collecting user requirements and displaying results.</p><h3>2. AI Integration Layer</h3><p>Code that formats prompts and communicates with the AI model (Ollama’s DeepSeek in this case).</p><h3>3. Processing Logic</h3><p>Functions for extracting relevant content from AI responses and saving the output.</p><h3>4. Action Execution</h3><p>Code that opens the generated landing page and handles user workflow.</p><h3>How This Landing Page Generator Works</h3><p>This agent follows a straightforward workflow:</p><ol><li><strong>User Input</strong>: Collects a description of the desired landing page</li><li><strong>AI Instruction</strong>: Sends carefully crafted prompts to the language model</li><li><strong>Response Processing</strong>: Extracts HTML/CSS code from the model’s response</li><li><strong>Output Generation</strong>: Saves the code as an HTML file</li><li><strong>Result Delivery</strong>: Opens the file in a browser and offers to create another</li></ol><h3>Key Design Principles</h3><p>Looking at the code, we can identify several principles for effective AI agent design:</p><h3>Clear, Specific Prompts</h3><p>The system prompt defines the agent’s role as a “skilled web developer” and provides specific constraints (using Tailwind CSS, delivering ready-to-use code).</p><h3>Error Handling</h3><p>The code gracefully handles potential failures in AI generation, extraction, and file operations.</p><h3>User Experience Focus</h3><p>The interface includes progress updates, confirmation prompts, and clear navigation options.</p><h3>The Landing Page Generator Code</h3><pre>import ollama<br>import os<br>import re<br>from pathlib import Path<br>from datetime import datetime<br><br><br>def generate_landing_page(description):<br>    &quot;&quot;&quot;Use Ollama to generate HTML/CSS for a landing page based on description.&quot;&quot;&quot;<br>    messages = [<br>        {&quot;role&quot;: &quot;system&quot;,<br>         &quot;content&quot;: &quot;You are a skilled web developer who creates clean, responsive landing pages using HTML, CSS, and minimal JavaScript. Your code should be complete, valid, and ready to use without external dependencies.&quot;},<br>        {&quot;role&quot;: &quot;user&quot;,<br>         &quot;content&quot;: f&quot;Create a complete landing page based on this description: {description}. Provide only the HTML code with internal CSS and JavaScript. The code should be complete and ready to be saved as an index.html file.&quot;}<br>    ]<br><br>    try:<br>        print(&quot;Generating landing page... This may take a minute or two...&quot;)<br>        response = ollama.chat(<br>            model=&#39;deepseek-r1:8b&#39;,<br>            messages=messages<br>        )<br><br>        # Extract HTML code from response<br>        html_content = response[&#39;message&#39;][&#39;content&#39;]<br><br>        # Extract code between ```html and ``` if present<br>        code_pattern = re.compile(r&#39;```(?:html)?\s*([\s\S]*?)\s*```&#39;)<br>        match = code_pattern.search(html_content)<br><br>        if match:<br>            return match.group(1).strip()<br>        else:<br>            # If no code blocks found, try to extract just the HTML<br>            if &quot;&lt;html&quot; in html_content and &quot;&lt;/html&gt;&quot; in html_content:<br>                start = html_content.find(&quot;&lt;html&quot;)<br>                end = html_content.find(&quot;&lt;/html&gt;&quot;) + 7<br>                return html_content[start:end]<br>            return html_content<br><br>    except Exception as e:<br>        return f&quot;Error generating landing page: {str(e)}&quot;<br><br><br>def save_landing_page(html_content, output_dir=&quot;landing_pages&quot;):<br>    &quot;&quot;&quot;Save the generated HTML to a file.&quot;&quot;&quot;<br>    # Ensure the output directory exists<br>    Path(output_dir).mkdir(exist_ok=True)<br><br>    # Create a filename with timestamp<br>    timestamp = datetime.now().strftime(&quot;%Y%m%d_%H%M%S&quot;)<br>    filename = f&quot;{output_dir}/landing_page_{timestamp}.html&quot;<br><br>    # Save the HTML content<br>    with open(filename, &quot;w&quot;, encoding=&quot;utf-8&quot;) as f:<br>        f.write(html_content)<br><br>    return filename<br><br><br>def main():<br>    &quot;&quot;&quot;Run the dedicated landing page generator.&quot;&quot;&quot;<br>    print(&quot;==========================================&quot;)<br>    print(&quot;  LANDING PAGE GENERATOR (OLLAMA)  &quot;)<br>    print(&quot;==========================================&quot;)<br><br>    # Get description for the landing page<br>    print(&quot;\nDescribe the landing page you want (be specific about colors, layout, features):&quot;)<br>    description = input(&quot;&gt; &quot;)<br><br>    if not description:<br>        print(&quot;Error: You must provide a description for the landing page.&quot;)<br>        return<br><br>    # Generate the landing page HTML<br>    html_content = generate_landing_page(description)<br><br>    # Save the landing page<br>    filename = save_landing_page(html_content)<br><br>    print(f&quot;\nSuccess! Landing page created and saved to: {filename}&quot;)<br><br>    # Ask if user wants to open the file<br>    open_file = input(&quot;Would you like to open the landing page now? (y/n): &quot;)<br>    if open_file.lower() in [&#39;y&#39;, &#39;yes&#39;]:<br>        # Try to open the file in the default browser<br>        try:<br>            import webbrowser<br>            file_path = os.path.abspath(filename)<br>            webbrowser.open(&#39;file://&#39; + file_path)<br>            print(f&quot;Opened {filename} in your default browser.&quot;)<br>        except Exception as e:<br>            print(f&quot;Couldn&#39;t open the file automatically: {e}&quot;)<br>            print(f&quot;Please open {filename} manually in your browser.&quot;)<br><br>    # Ask if user wants to create another landing page<br>    another = input(&quot;\nWould you like to create another landing page? (y/n): &quot;)<br>    if another.lower() in [&#39;y&#39;, &#39;yes&#39;]:<br>        main()  # Recursive call<br>    else:<br>        print(&quot;Thank you for using the Landing Page Generator. Goodbye!&quot;)<br><br><br>if __name__ == &quot;__main__&quot;:<br>    main()</pre><p>I am using <strong>deepseek-r1:8b</strong> and I have also tried <strong>qwen2.5-coder:14b </strong>which gave me a better result. Feel free to tweak the script to match your setup.</p><p>You can visit my GitHub Repo where I will be adding more examples as I continue my journey in this exciting field of AI.</p><p><a href="https://github.com/Ali-Shaikh">https://github.com/Ali-Shaikh</a></p><h3>Going Beyond: Enhancing Your AI Agents</h3><p>Again, this is a simple example to help you get up and running with creating an AI Agent. To create more sophisticated AI agents, consider:</p><ul><li><strong>Multiple Model Integration</strong>: Combine specialised models for different aspects of a task</li><li><strong>Memory and Context</strong>: Maintain conversation history for more coherent interactions</li><li><strong>User Preference Learning</strong>: Store and apply user preferences over time</li><li><strong>Feedback Loops</strong>: Collect user feedback to improve future outputs</li><li><strong>Validation Layers</strong>: Add code to validate AI outputs before presenting them</li></ul><h3>Conclusion</h3><p>The landing page generator demonstrates how even simple AI agents can provide significant value. By combining clear prompts, effective processing, and thoughtful user experience design, developers can create tools that leverage AI to solve specific problems.</p><p>As you build your own AI agents, remember that the quality of your prompts, the robustness of your error handling, and the thoughtfulness of your user experience will largely determine your success.</p><p>In a nutshell, an AI agent is basically like calling an API with parameters, processing the result, manipulating it to your requirements and displaying the output. Anyone can get started with building an AI agent using Ollama or <a href="https://alishaikh.me/run-a-local-llm-with-lm-studio-easy-2025-tutorial/">LM Studio</a>. If you have a modest system, try using any of the smaller models such as <strong>qwen2.5-coder:3b</strong> or even a smaller model such as <strong>qwen2.5-coder:1.5b.</strong></p><p>Smaller models are a great starting point, and while they may not offer the same quality as larger models, they are perfect for building your skills. As you get more comfortable with creating AI agents, you’ll be ready to work with larger models to unlock even more powerful capabilities!</p><p>Keep creating and innovating, and I would love to hear and see what you create. please feel free to share any comments, questions and examples of what you got done in the comments. If you need any help, feel free to reach out through my <a href="https://www.linkedin.com/in/alishaikh1/?ref=alishaikh.me">LinkedIn</a>.</p><p><em>Originally published at </em><a href="https://alishaikh.me/creating-simple-ai-agents-a-beginners-guide/"><em>https://alishaikh.me</em></a><em> on March 4, 2025.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=095be6552ba0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How AI Models Process Text: Understanding Tokens in AI and LLMs with TikTokenizer]]></title>
            <link>https://ali-shaikh.medium.com/how-ai-models-process-text-understanding-tokens-in-ai-and-llms-with-tiktokenizer-4a7ac90c8002?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/4a7ac90c8002</guid>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Sat, 01 Mar 2025 07:22:15 GMT</pubDate>
            <atom:updated>2025-03-03T05:02:40.969Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3da6SIDqOWQfiuom.png" /></figure><p>In the world of artificial intelligence (AI) and large language models (LLMs), <strong>tokens</strong> are the essential building blocks that allow these systems to process and understand text. But what exactly are tokens, and how can a tool like <a href="https://tiktokenizer.vercel.app/?ref=alishaikh.me">TikTokenizer</a> help us explore them? Let’s dive in.</p><h3>What Are Tokens?</h3><p>Tokens are the smallest units of text that an AI language model works with. Depending on the tokenization method, a token could be:</p><ul><li>A <strong>word</strong> (e.g., “love” or “AI”),</li><li>A <strong>subword</strong> (e.g., “play” and “##ing” for “playing”),</li><li>Or even an <strong>individual character</strong> (e.g., “A” or “!”).</li></ul><p>For instance, the sentence “I love AI” might be tokenized as [“I”, “love”, “AI”]. Tokenization is the process of breaking down raw text into these units, transforming it into a format that a model can interpret. This step is critical because it determines how the model “sees” the text, influencing its ability to generate responses or understand meaning.</p><h3>Why Tokenization Matters</h3><p>Tokenization isn’t just a technical detail — it directly affects a model’s performance. The way text is split into tokens impacts:</p><ul><li><strong>Efficiency:</strong> Smaller tokens might mean more processing steps, while larger ones could simplify things.</li><li><strong>Accuracy:</strong> Misaligned token boundaries might confuse the model’s interpretation.</li></ul><p>Understanding tokenization is key for anyone working with LLMs, whether you’re crafting prompts, debugging outputs, or optimizing text inputs.</p><h3>Enter TikTokenizer</h3><p>The <a href="https://tiktokenizer.vercel.app/?ref=alishaikh.me">TikTokenizer tool</a> is a fantastic resource for visualizing and experimenting with tokenization. It’s interactive and user-friendly: simply type in any text, and the tool breaks it down into tokens, showing each one alongside its unique <strong>token ID</strong> — a numerical value that models use internally. For example, input “I love AI!” and you’ll see how it’s split and numbered.</p><h3>How to Use It</h3><ol><li>Visit <a href="https://tiktokenizer.vercel.app/?ref=alishaikh.me">TikTokenizer</a>.</li><li>Enter a sentence-like “Hello, world!”-into the text box.</li><li>Watch as it displays the tokens (e.g., [“Hello”, “,”, “world”, “!”]) and their IDs.</li></ol><p>You can play around with it by:</p><ul><li>Adding punctuation (e.g., “Hello,world” vs. “Hello, world”),</li><li>Changing capitalization (e.g., “hello” vs. “HELLO”),</li><li>Or trying complex phrases to see how the tokenization adapts.</li></ul><p>This hands-on approach makes it easy to see how different choices affect the process.</p><h3>Why It’s Useful</h3><p>TikTokenizer isn’t just a fun toy — it’s a practical tool for anyone interested in AI and LLMs. Here’s why it’s worth exploring:</p><ul><li><strong>Prompt Engineering:</strong> Learn to craft prompts that fit within token limits for better results.</li><li><strong>Debugging:</strong> Spot why a model might misread your input by checking how it’s tokenized.</li><li><strong>Learning:</strong> Gain a clearer grasp of NLP concepts if you’re new to the field.</li><li><strong>Optimization:</strong> Tweak your text preprocessing to improve model performance.</li></ul><h3>Wrap-Up</h3><p>Alright, let’s wrap this up! Tokens are the core of how AI language models make sense of text, and <strong>TikTokenizer</strong> lets you peek under the hood. Type something in, and it breaks it down into tokens with their IDs--super straightforward and honestly kinda cool. It’s perfect whether you’re new to AI or a seasoned pro. Want to see how your words get “read” by a machine? Check out <a href="https://tiktokenizer.vercel.app/?ref=alishaikh.me">TikTokenizer</a> and give it a spin!</p><p><em>Originally published at </em><a href="https://alishaikh.me/how-ai-models-process-text-understanding-tokens-in-ai-and-llms-with-tiktokenizer/"><em>https://alishaikh.me</em></a><em> on March 1, 2025.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4a7ac90c8002" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Access a Remote Linux Machine Using SSH Keys]]></title>
            <link>https://ali-shaikh.medium.com/how-to-log-in-to-a-remote-linux-machine-using-ssh-keys-f29a81af20c1?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/f29a81af20c1</guid>
            <category><![CDATA[servers]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[ssh]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Sat, 22 Feb 2025 07:02:50 GMT</pubDate>
            <atom:updated>2025-02-22T14:14:34.208Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*w8VRw3mBtP5Y8ieY" /><figcaption>Photo by <a href="https://unsplash.com/@jouwdan?utm_source=medium&amp;utm_medium=referral">Jordan Harrison</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>SSH (Secure Shell) is a common way to securely connect to remote Linux machines. Instead of using passwords, SSH keys make logging in safer and easier. This guide will show you how to install an SSH server, create SSH keys, add your public key to the remote server and then connect using your SSH keys.</p><h3>1. Installing the SSH Server</h3><p>To enable SSH access, the remote Linux machine must have an SSH server installed.</p><h4>For Debian-based Systems (e.g., Ubuntu)</h4><pre>sudo apt update<br>sudo apt install openssh-server -y<br>sudo systemctl enable ssh<br>sudo systemctl start ssh</pre><h4>For Red Hat-based Systems (e.g., CentOS, Rocky Linux)</h4><pre>sudo yum update -y<br>sudo yum install -y openssh-server<br>sudo systemctl enable sshd<br>sudo systemctl start sshd</pre><h4>Verify SSH Server is Running</h4><pre>sudo systemctl status ssh  # For Ubuntu/Debian<br>sudo systemctl status sshd # For CentOS/RHEL</pre><p>If the server is running you should see active (running) as shown below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/669/1*wm3wDO_awW7klzGwnalc-Q.png" /></figure><h3>2. Generating SSH Keys on your Local Machine</h3><p>SSH keys consist of a <strong>private key</strong> (kept secure on your local machine) and a <strong>public key</strong> (placed on the remote server). If you haven’t generated SSH keys before, check out this detailed guide:</p><p>🔗 <a href="https://ali-shaikh.medium.com/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a"><strong>Generating SSH Keys on Windows, Linux, and macOS</strong></a></p><p>Once you’ve generated your SSH keys, proceed to the next step to configure the server for SSH key-based authentication by adding your public key to the remote server.</p><h3>3. Adding your Public Key to the Remote Machine</h3><p>Now, we need to copy the public key to the remote server so it can allow your key to be used to log in.</p><h4>Copy your Public Key from the Local Machine</h4><p>On your local machine, display the public key by running cat ~/.ssh/id_rsa.pub or opening the .pub file in Notepad, and copy the contents.</p><h4>Prepare the Remote Server</h4><p>On the remote machine, create the .ssh directory and authorized_keys file if they do not already exist.</p><pre>mkdir -p ~/.ssh<br>touch ~/.ssh/authorized_keys</pre><h4>Add the Public Key to Authorized Keys</h4><p>Paste the copied key into the ~/.ssh/authorized_keys file on the remote machine. If there&#39;s already another key in the file, make sure to add your key <strong>on a new line</strong>.</p><p>Alternatively, you can use echo command on the remote machine and append it directly:</p><pre>echo &quot;PASTE_PUBLIC_KEY_HERE&quot; &gt;&gt; ~/.ssh/authorized_keys</pre><h4><strong>Set the correct permissions</strong> to ensure security:</h4><p>Some systems will now allow you to use your SSH keys if the permissions are too open or incorrect. Run the following commands to set the recommended permissions.</p><pre>chmod 700 ~/.ssh<br>chmod 600 ~/.ssh/authorized_keys</pre><h3>4. Connecting to the Remote Machine Using SSH Keys</h3><p>Now that the remote machine is ready for SSH-based authentication and your public key has successfully been added, you can connect from your local machine:</p><pre>ssh username@remote_host</pre><p>If your private key exists in a non-default location, then provide the path to the private key by using the following command:</p><pre>ssh -i /path/to/private_key username@remote_host</pre><h3>Conclusion</h3><p>You have now set up your remote server for SSH access and learned how to log in securely using SSH keys, eliminating the need to enter a password each time. This method enhances security and convenience, making remote access more efficient. With SSH keys in place, you can now connect to your server seamlessly and focus on what matters most.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f29a81af20c1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cloning GitHub Repositories with SSH: A Step-by-Step Guide]]></title>
            <link>https://ali-shaikh.medium.com/cloning-github-repositories-with-ssh-a-step-by-step-guide-6e3eb651dc01?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/6e3eb651dc01</guid>
            <category><![CDATA[git]]></category>
            <category><![CDATA[github]]></category>
            <category><![CDATA[engineering]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[ssh]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Tue, 18 Feb 2025 04:01:41 GMT</pubDate>
            <atom:updated>2025-02-18T04:01:41.224Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*k_-DccTGq476Pwx4" /><figcaption>Photo by <a href="https://unsplash.com/@synkevych?utm_source=medium&amp;utm_medium=referral">Roman Synkevych</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In the previous guide, we learnt how to generate SSH Keys on Windows, Linux, and macOS, read <a href="https://ali-shaikh.medium.com/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a">here</a>.</p><p>In this guide, we’ll explain how to use your SSH keys to clone GitHub repositories — a common task for developers working on projects locally. And remember, these SSH keys aren’t just for cloning; they also secure your push and pull operations.</p><h3>Prerequisites</h3><p>Before you begin, make sure:</p><ul><li><strong>SSH Key Pair:</strong> You have generated an SSH key pair, to learn how click <a href="https://ali-shaikh.medium.com/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a">here</a>.</li><li><strong>Git Installed:</strong> Git is installed on your system.</li><li><strong>Internet Access:</strong> You can access GitHub.</li></ul><h3>Adding Your SSH Key to GitHub</h3><h4>Step 1: Copy Your Public Key</h4><p>Your public key is typically stored in a file like ~/.ssh/id_ed25519.pub (or id_rsa.pub if you’re using RSA). You can simply display the key and copy it.</p><pre>cat ~/.ssh/id_rsa.pub<br><br>OR<br><br>cat ~/.ssh/id_ed25519.pub</pre><h4>Step 2: Log in to Your GitHub Account</h4><p>Open your web browser and navigate to <a href="https://github.com">GitHub.com</a>. Log in with your credentials.</p><h4>Step 3: Navigate to SSH Keys Settings</h4><p><strong>Click your profile icon</strong> in the top right corner and select ‘<strong>Settings.’</strong></p><p>In the left sidebar, click ‘<strong>SSH and GPG keys.’</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*r4TtrNWWOLQWp8ft1LghmA.png" /></figure><h4>Step 4: Add a New SSH Key</h4><p>Click on the <strong>“New SSH key”</strong> button.</p><p><strong>Title:</strong> Enter a descriptive title (e.g., ‘My Laptop Key’).</p><p><strong>Key:</strong> Paste the copied public key into the key field.</p><p>Click <strong>“Add SSH key.”</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/968/1*kJkceUSd2KuYRcAkBC3RxQ.png" /></figure><h3>Cloning a Repository Using SSH</h3><p>Now you are ready to enter the realm of passwordless authentication!</p><h4>Step 1: Verify Your SSH Connection</h4><p>Before cloning, verify that your SSH configuration is working:</p><pre>ssh -T git@github.com</pre><p>If it’s your first time connecting, you might be asked to confirm the authenticity of GitHub’s host. Type ‘<strong>yes’</strong> to continue.</p><p>If all goes well then you will see the following success message.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/835/1*Av53vg8zc3NHeI7Q1cY_5w.png" /></figure><p>This means you are now good to go and use SSH to Clone GitHub repositories.</p><h4>Step 2: Obtain the Repository’s SSH URL</h4><ol><li>Navigate to your repository on GitHub.</li><li>Click the ‘<strong>Code’</strong> button.</li><li>Select the ‘<strong>SSH’</strong> tab and copy the URL</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/910/1*GUAcPwqgOOlb4K8wb3sT1g.png" /></figure><h4>Step 3: Clone the Repository</h4><p>In your terminal, change to the directory where you want the repository and type<strong> ‘git clone’</strong> followed by the ‘<strong>SSH repository URL’</strong> you copied earlier and hit enter.</p><p>Aaaand that&#39;s it! You have successfully learnt how to clone GitHub repositories without having to enter your username and password.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/718/1*Hr2K92pw7tI20Bv9xXsmsQ.png" /></figure><h3>Conclusion</h3><p>By following these steps, you’ve not only added your SSH key to GitHub but also learned how to clone repositories securely over SSH.</p><p>This method works seamlessly for all Git operations, including pushing new commits and pulling updates from remote repositories. You can follow the same steps to add your SSH keys in GitLab, BitBucket, and more.</p><p>This is a very convenient way of accessing Git repositories and will make your development workflows more efficient.</p><p>Happy coding!</p><p>In a future tutorial, we will learn how to SSH into a remote server.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6e3eb651dc01" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mastering Proxmox Automation: Build an Ubuntu 24.04 Cloud‑Init Template for Rapid VM Deployment]]></title>
            <link>https://ali-shaikh.medium.com/mastering-proxmox-automation-build-an-ubuntu-24-04-cloud-init-template-for-rapid-vm-deployment-95bc8e7b2230?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/95bc8e7b2230</guid>
            <category><![CDATA[virtualization]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[ubuntu]]></category>
            <category><![CDATA[cloud]]></category>
            <category><![CDATA[proxmox]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Mon, 17 Feb 2025 04:01:44 GMT</pubDate>
            <atom:updated>2025-02-17T04:01:44.528Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*D4YBoZeeCgIQ16P4" /><figcaption>Photo by <a href="https://unsplash.com/@6heinz3r?utm_source=medium&amp;utm_medium=referral">Gabriel Heinzer</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Recently I embarked on a journey to set up Kubernetes Cluster on my home lab running Proxmox. From my experience designing K8s architectures on AWS EKS and Azure AKS, I knew I would need to create multiple VMs so instead of having to create them 1 by 1 and repeating the same steps I decided to leverage automation and Cloud‑Init enabled VM templates to streamline the process.</p><h3>How Cloud‑Init and Proxmox Automation Help</h3><p>Cloud‑Init is a powerful tool designed for early initialisation of cloud instances. By leveraging Cloud‑Init with Proxmox, you can automate the initial configuration of your VMs, installing necessary packages, setting up SSH keys, and even pre-configuring network settings. Once the VM template is created, deploying new VMs becomes a matter of minutes rather than hours, ensuring that each instance is consistently configured and ready to run immediately.</p><h3>More Automation Queue in Bash — Scripting 😍</h3><p>Below is the Bash script that automates the entire process, streamlining the configuration and setup of your VM template. Why Type When You Can Script, Eh? 😏</p><pre>#!/bin/bash<br><br># VM and storage identifiers<br>VMID=10002<br>STORAGE=local-lvm<br><br># Define the VM name and Ubuntu image parameters<br>VM_NAME=&quot;ubuntu-2404-cloudinit-template&quot;<br>STORAGE=&quot;local-lvm&quot;  # Adjust if using a different storage backend<br>IMAGE_URL=&quot;https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img&quot;<br>IMAGE_PATH=&quot;/var/lib/vz/template/iso/$(basename ${IMAGE_URL})&quot;<br><br># Cloud‑Init credentials (consider stronger hashing for production)<br>CI_USER=&quot;ubuntu&quot;<br>CI_PASSWORD=&quot;$(openssl passwd -6 ubuntu)&quot;<br><br># Create an SSH public key file for injecting into the VM<br>echo &quot;ssh-rsa PASTE YOUR PUBLIC KEY HERE&quot; &gt; ssh.pub<br><br># 1. Download the Ubuntu 24.04 Cloud Image if not already present<br>if [ ! -f &quot;${IMAGE_PATH}&quot; ]; then<br>  echo &quot;Downloading Ubuntu 24.04 Cloud Image...&quot;<br>  wget -P /var/lib/vz/template/iso/ &quot;${IMAGE_URL}&quot;<br>else<br>  echo &quot;Image already exists at ${IMAGE_PATH}&quot;<br>fi<br><br>set -x  # Enable command echoing for debugging<br><br># Destroy any existing VM with the same VMID to avoid conflicts<br>qm destroy $VMID 2&gt;/dev/null || true<br><br># Create a new VM with UEFI support and custom hardware configurations<br>echo &quot;Creating VM ${VM_NAME} with VMID ${VMID}...&quot;<br>qm create ${VMID} \<br>  --name &quot;${VM_NAME}&quot; \<br>  --ostype l26 \<br>  --memory 2048 \<br>  --cores 2 \<br>  --agent 1 \<br>  --bios ovmf --machine q35 --efidisk0 ${STORAGE}:0,pre-enrolled-keys=0 \<br>  --cpu host --socket 1 --cores 2 \<br>  --vga serial0 --serial0 socket \<br>  --net0 virtio,bridge=vmbr0<br><br># Import the downloaded disk image into Proxmox storage<br>echo &quot;Importing disk image...&quot;<br>qm importdisk ${VMID} &quot;${IMAGE_PATH}&quot; ${STORAGE}<br><br># Attach the imported disk as a VirtIO disk using the SCSI controller<br>qm set $VMID --scsihw virtio-scsi-pci --virtio0 $STORAGE:vm-${VMID}-disk-1,discard=on<br><br># Resize the disk by adding an additional 8G<br>qm resize ${VMID} virtio0 +8G<br><br># Configure the VM to boot from the VirtIO disk<br>qm set $VMID --boot order=virtio0<br><br># Attach a Cloud‑Init drive (recommended on UEFI systems using SCSI)<br>qm set $VMID --scsi1 $STORAGE:cloudinit<br><br># Create a custom Cloud‑Init configuration snippet<br>cat &lt;&lt; EOF | tee /var/lib/vz/snippets/ubuntu.yaml<br>#cloud-config<br>runcmd:<br>    - apt-get update<br>    - apt-get install -y qemu-guest-agent htop<br>    - systemctl enable ssh<br>    - reboot<br>EOF<br><br># Apply Cloud‑Init customizations and additional VM settings<br>qm set $VMID --cicustom &quot;vendor=local:snippets/ubuntu.yaml&quot;<br>qm set $VMID --tags ubuntu-template,noble,cloudinit<br>qm set ${VMID} --ciuser ${CI_USER} --cipassword &quot;${CI_PASSWORD}&quot;<br>qm set $VMID --sshkeys ~/ssh.pub<br>qm set $VMID --ipconfig0 ip=dhcp<br><br># Finally, convert the configured VM into a template for rapid future deployment<br>echo &quot;Converting VM to template...&quot;<br>qm template ${VMID}<br><br>echo &quot;Template ${VM_NAME} (VMID: ${VMID}) created successfully.&quot;</pre><h3>Make It Your Own</h3><p>Before you run the script there are some things you would need to modify to tailor it to your environment. Here’s a quick rundown of the main components you might consider editing:</p><pre># VM and storage identifiers<br>VMID=10002<br>STORAGE=local-lvm<br><br># Define the VM name and Ubuntu image parameters<br>VM_NAME=&quot;ubuntu-2404-cloudinit-template&quot;<br>STORAGE=&quot;local-lvm&quot;  # Adjust if using a different storage backend<br>IMAGE_URL=&quot;https://cloud-images.ubuntu.com/daily/server/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img&quot;<br>IMAGE_PATH=&quot;/var/lib/vz/template/iso/$(basename ${IMAGE_URL})&quot;<br><br># Cloud‑Init credentials (consider stronger hashing for production)<br>CI_USER=&quot;ubuntu&quot;<br>CI_PASSWORD=&quot;$(openssl passwd -6 ubuntu)&quot;<br><br># Create an SSH public key file for injecting into the VM<br>echo &quot;ssh-rsa PASTE YOUR PUBLIC KEY HERE&quot; &gt; ssh.pub</pre><ul><li><strong>VM Identification &amp; Naming:</strong><br>Customize the VMID and VM_NAME to assign a unique identifier and a descriptive name for your template.</li><li><strong>Storage Settings:</strong><br>The STORAGE variable lets you define the backend storage (e.g., local-lvm, local-zfs). Adjust this parameter based on your storage setup.</li><li><strong>Image Source &amp; Path:</strong><br>The IMAGE_URL points to the cloud image you wish to use, while IMAGE_PATH determines where the image will be stored locally.</li><li><strong>Cloud‑Init Credentials:</strong><br>Parameters like CI_USER and CI_PASSWORD are set to pre-configure the default login credentials. Please modify these as per your requirements.</li><li><strong>SSH Key Injection:</strong><br>The script injects an <a href="https://medium.com/@ali-shaikh/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a">SSH</a> public key file for secure access to your VM, saving you the hassle of manually copying SSH keys after deployment. Please add your SSH key here echo &quot;ssh-rsa PASTE YOUR PUBLIC KEY HERE&quot; &gt; ssh.pub. If you need to create a new SSH Key click <a href="https://medium.com/@ali-shaikh/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a">here</a> to learn how.</li></ul><h3>How to Use This Script</h3><p>It’s really simple — just SSH into your Proxmox server, create a new file (e.g., create-ubuntu-2404-template.sh), paste the script into it, make it executable, and run it. The script handles everything for you, from downloading the Ubuntu image to converting the VM into a reusable template.</p><p>Here’s a step-by-step guide:</p><ol><li><strong>SSH into Your Proxmox Server:<br></strong>ssh your_user@proxmox-server-ip</li><li><strong>Create the Script File:<br></strong>Use your preferred text editor to create a new file. For example, using Nano: nano create-ubuntu-2404-template.sh</li><li>Paste the script into this file, then save and exit the editor.<br><em>In Nano, press </em><em>Ctrl+O to save, then </em><em>Ctrl+X to exit.</em></li><li><strong>Make the Script Executable:<br></strong>Change the file permissions to make it executable:<br>chmod +x create-ubuntu-2404-template.sh</li><li><strong>Run the Script:<br></strong>Execute the script with:<br>./create</li></ol><p>That’s it! With these commands, your Proxmox server will automatically handle downloading the Ubuntu image, setting up the VM, integrating Cloud‑Init, and converting the VM into a reusable template.</p><h3>Profit!</h3><p>Awesome! So now you have a shiny template ready to be used. You can use this template to create as many VMs as you want and you will have a brand new VM up and running in minutes. Now let&#39;s see how to use this template to create a new VM.</p><p>Login to Proxmox and locate the template that you just created</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/391/1*dErYXu7m-LKHZkNtS1y2Jw.png" /></figure><p>In this example, I will use the ‘ubuntu-2404-cloudinit-k8s-template’. Right-click on the template and click Clone. Fill in the VM ID and Name and click Clone.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/604/1*Qk8IStqprN37v1d6eIZjVg.png" /></figure><p>Once the cloning is complete, the new VM will appear in your list. You can modify the hardware settings if required, then click <strong>Start</strong>. The VM will boot up, and Cloud‑Init will automatically perform the initial configuration tasks.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/748/1*lY6o_f8F1TWo6DeGJKBeDQ.png" /></figure><p>And voila, the VM is created.</p><p>In a future tutorial, we will look at how to configure the Cloud-Init configuration to set things like a new user, password, static IP etc. and also I will teach you how to create a Kubernetes-ready template so you can quickly set up as many nodes as you wish.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/674/1*s3VrhqR8XH3qiN7_yPSlAQ.png" /></figure><p>Feel free to leave any feedback, suggestions or your thoughts down in the comments.</p><p>Thank you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=95bc8e7b2230" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Generating SSH Keys on Windows, Linux, and macOS]]></title>
            <link>https://ali-shaikh.medium.com/generating-ssh-keys-on-windows-linux-and-macos-3bfd55e12d6a?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/3bfd55e12d6a</guid>
            <category><![CDATA[macos]]></category>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[ssh]]></category>
            <category><![CDATA[cloud]]></category>
            <category><![CDATA[security]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Sat, 15 Feb 2025 16:24:28 GMT</pubDate>
            <atom:updated>2025-02-15T16:33:22.489Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*RcL9hVVRvmKpo1fU" /><figcaption>Photo by <a href="https://unsplash.com/@jakubzerdzicki?utm_source=medium&amp;utm_medium=referral">Jakub Żerdzicki</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>SSH keys are a secure way to authenticate when connecting to remote servers and services such as GitHub Repositories. In this article, we’ll walk through the process of generating SSH keys on three popular operating systems: Windows, Linux, and macOS.</p><h3>Why Use SSH Keys?</h3><p>Using SSH keys enhances security by replacing less secure password authentication. Keys are generated as a pair: a public key (which you share with remote servers) and a private key (which you keep secret). Once set up, you can log into your servers or repositories with ease.</p><h3>Generating SSH Keys on Windows</h3><h4>Using Git Bash</h4><ol><li><strong>Install Git for Windows:</strong><br>Download and install <a href="https://gitforwindows.org/">Git for Windows</a>, which includes Git Bash — a command-line environment that supports SSH.</li><li><strong>Open Git Bash:</strong><br>Launch Git Bash from the Start menu.</li><li><strong>Generate the Key Pair:</strong><br>Run the following command, replacing &#39;email@cool-domain.com&#39; with your email address:<br>ssh-keygen -t rsa -b 4096 -C &#39;email@cool-domain.com&#39; <br>-t rsa: Specifies the type of key to create.<br>-b 4096: Sets the key size to 4096 bits for enhanced security.<br>-C &#39;email@cool-domain.com&#39;: Adds a comment to help identify the key. This can be your email address, computer or device name or anything that lets you know what this key is for</li><li><strong>Follow the Prompts:</strong><br>Press Enter to accept the default file location (typically C:\Users\{USERNAME}\.ssh\id_rsa). Choose a secure passphrase when prompted or press enter again to continue without a passphrase.</li><li><strong>Complete the Process:</strong><br>After confirmation, your SSH key pair is created and stored in your user’s .ssh directory. Your public key will have a .pub extension. You can view the public key by running cat ~/.ssh/id_rsa.pub.</li></ol><h3>Generating SSH Keys on Linux</h3><h4>Using the Terminal</h4><ol><li><strong>Open a Terminal Window:</strong><br>Most Linux distributions include a built-in terminal.</li><li><strong>Generate the Key Pair:</strong><br>Enter the following command:<br>ssh-keygen -t rsa -b 4096 -C &#39;email@cool-domain.com&#39;<br>command options are identical to those used in Windows.</li><li><strong>Respond to Prompts:</strong><br>Press Enter to accept the default file location (typically ~/.ssh/id_rsa). Choose a secure passphrase when prompted or press enter again to continue without a passphrase.</li><li><strong>Locate Your Keys:</strong><br>Your new SSH key pair will be stored in the ~/.ssh/ directory. You can view the public key using:<br>cat ~/.ssh/id_rsa.pub</li></ol><h3>Generating SSH Keys on macOS</h3><h4>Using the Terminal</h4><ol><li><strong>Open Terminal:</strong><br>Find Terminal in your Applications &gt; Utilities folder, or use Spotlight to search for it.</li><li><strong>Generate the Key Pair:</strong><br>Run the following command in the terminal:<br>ssh-keygen -t rsa -b 4096 -C &#39;email@cool-domain.com&#39;</li><li><strong>Follow the Prompts:</strong><br>Press Enter to accept the default file location (typically ~/.ssh/id_rsa). Choose a secure passphrase when prompted or press enter again to continue without a passphrase.</li><li><strong>Verify Your SSH Keys:</strong><br>To display your public key, type: cat ~/.ssh/id_rsa.pub.</li></ol><h3>Conclusion</h3><p>Congratulations you have successfully learnt how to generate SSH key pairs. This is a fundamental skill for your IT Toolbox. Remember to keep your private key safe and secure. In a later tutorial, we will learn different ways we can use these keys to enhance your IT workflows.</p><p>I encourage you to share your thoughts and ask questions in the comments!</p><p>Thank you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3bfd55e12d6a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Upgrade AWS Elastic Beanstalk from PHP 7.4 to PHP 8.0]]></title>
            <link>https://ali-shaikh.medium.com/upgrade-aws-elastic-beanstalk-from-php-7-4-to-php-8-0-f622476d3076?source=rss-7a312b7c3373------2</link>
            <guid isPermaLink="false">https://medium.com/p/f622476d3076</guid>
            <category><![CDATA[elastic-beanstalk]]></category>
            <category><![CDATA[php-8]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[laravel]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[Ali Shaikh]]></dc:creator>
            <pubDate>Fri, 02 Apr 2021 12:12:00 GMT</pubDate>
            <atom:updated>2021-04-02T12:31:04.324Z</atom:updated>
            <content:encoded><![CDATA[<p>The <a href="https://console.aws.amazon.com/elasticbeanstalk/home">AWS Elastic Beanstalk Console</a> currently only permits you to change between minor platform versions (e.g. from 64bit Amazon Linux 2 <strong>v3.1.6</strong> running PHP 7.4 to 64bit Amazon Linux 2 <strong>v3.2.0</strong> running PHP 7.4), but does not allow changes between major versions (e.g. from 64bit Amazon Linux 2 <strong>v3.2.0</strong> running PHP 7.4 to 64bit Amazon Linux 2 <strong>v3.2.0</strong> running PHP 8.0).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/826/1*C2YZik2va_hI-hlm29cyHQ.png" /></figure><p><em>But, fret not!!! </em>It is possible to update to a major platform version using the <a href="https://aws.amazon.com/cli/">AWS Command Line Interface (CLI)</a>:</p><pre>aws elasticbeanstalk update-environment --solution-stack-name &quot;64bit Amazon Linux 2 v3.2.0 running PHP 8.0&quot; --environment-id &quot;x-xxxxxxxxxx&quot; --region &quot;us-west-1&quot;</pre><p>To find the newest PHP platform version AWS Elastic Beanstalk supports view the <a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/platforms/platforms-supported.html#platforms-supported.PHP">Elastic Beanstalk Supported Platforms</a>.</p><p>For previous versions see the <a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/platforms/platform-history-php.html">PHP Platform History</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f622476d3076" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>