<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tonny Kirwa</title>
    <description>The latest articles on DEV Community by Tonny Kirwa (@tkirwa).</description>
    <link>https://dev.to/tkirwa</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%2F1109472%2Fd2b64555-d98c-4d0c-885a-577b6ca2eef1.jpeg</url>
      <title>DEV Community: Tonny Kirwa</title>
      <link>https://dev.to/tkirwa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tkirwa"/>
    <language>en</language>
    <item>
      <title>The Graveyard of Repos: 100 Projects - Zero Shipped</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Fri, 26 Dec 2025 07:08:32 +0000</pubDate>
      <link>https://dev.to/tkirwa/the-graveyard-of-repos-100-projects-zero-shipped-46g1</link>
      <guid>https://dev.to/tkirwa/the-graveyard-of-repos-100-projects-zero-shipped-46g1</guid>
      <description>&lt;p&gt;Every software engineer knows the feeling. You're browsing GitHub, your own local machine, or even just your mental list of "things I'm working on," and there it is: a sprawling digital graveyard of half-finished projects. Directories brimming with package.json files and node_modules folders, each one a testament to initial enthusiasm that slowly, quietly, faded into abandonment.&lt;/p&gt;

&lt;p&gt;You started with a spark - a brilliant idea, a new technology to learn, a problem to solve. You coded furiously, built out the core features, marvelled at your progress, and then... nothing. The last 20%-the polish, the edge cases, the deployment, the marketing-became an insurmountable wall. The allure of the next shiny idea pulled you away, and another project joined the ranks of the dearly departed.&lt;/p&gt;

&lt;p&gt;If you're nodding along, you're not alone. The transition from "starter" to "shipper" is one of the most significant hurdles in a software engineer's journey. It's not about a lack of skill or intelligence; it's about shifting your relationship with "done."&lt;/p&gt;

&lt;p&gt;It's time to stop collecting projects and start collecting wins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Projects Die: The Unseen Killers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before we revive the living, let's understand why so many projects end up in the digital afterlife:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "Creation High"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The initial phase of building something from scratch is exhilarating. It's pure problem-solving and immediate gratification. The tedious work of bug fixing, UI polish, and deployment simply can't compete with the thrill of a fresh canvas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lack of a Clear "Definition of Done"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you don't know what the finish line looks like, you'll never cross it. "Done" becomes a perpetually moving target, leading to feature creep and endless tinkering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Allure of the Next Shiny Thing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tech landscape evolves at light speed. A new framework, a new language, or just a cooler idea can easily derail an almost-finished project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Perfectionism&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The enemy of "good enough." The desire for a flawless product often prevents any product from ever seeing the light of day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fear of Judgment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Putting your work out there can be intimidating. What if it's not good enough? What if people criticize it? This fear often manifests as endless "just one more feature" syndrome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;From Graveyard to Greenhouse: A Framework to Finally Ship&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's time to move beyond motivation and implement concrete systems that prioritize completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redefine "Done" with the Minimum Viable Ship (MVS)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the single most critical shift. Stop aiming for v1.0; aim for v0.1.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Single Core Feature&lt;/strong&gt;: What is the absolute, non-negotiable, singular most important thing your project must do? If it's a note-taking app, it's "create and view a note." Forget search, tags, or rich text for the MVS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The "One-User" Rule&lt;/strong&gt;: A project is truly "shipped" when one person (even if it's just you, a trusted friend, or a stranger from a niche forum) can use it via a URL or a downloadable artifact. No user, no ship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Public URL First&lt;/strong&gt;: As early as possible, deploy a "Hello World" or a basic skeleton of your app to a public URL (Vercel, Netlify, Fly.io, etc.). This makes the project feel real and creates a psychological commitment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Leverage Powerful Mental Models&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parkinson's Law in Action&lt;/strong&gt;: "Work expands to fill the time available for its completion." Instead of "I'll finish this project this weekend," try, "I will get this deployed in the next 4 hours." This forces aggressive prioritization and efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The 15-Minute Rule&lt;/strong&gt;: When you hit a frustrating bug or feel the urge to start something new, commit to working on the current project for just 15 minutes. Often, the inertia of starting is the biggest hurdle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type 1 vs. Type 2 Decisions&lt;/strong&gt;: Don't get stuck in analysis paralysis over framework choices (React vs. Vue), database options (SQL vs. NoSQL), or styling libraries. These are almost always "Type 2" (reversible) decisions. Pick one quickly and move on. Only "Type 1" (irreversible, high impact) decisions warrant significant thought.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The "Finish One" Protocol: A Digital Declutter&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have multiple active projects, you're fragmenting your focus.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inventory &amp;amp; Excise&lt;/strong&gt;: List every single open project you have. Be honest. Then, ruthlessly archive or delete anything you haven't touched in 3-6 months. Let them go. They served their purpose as learning tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Your Champion&lt;/strong&gt;: From your remaining list, select one project. Your goal is to get this one across the finish line. Choose the one closest to completion, or the one you're most excited about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salami Slice the Remaining Work&lt;/strong&gt;: Break down the remaining tasks for your chosen champion into incredibly small, actionable steps. "Build Authentication" is too big. "Create Login Form UI" or "Implement Email/Password Sign-up" are tasks. Aim for tasks that take 30-90 minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Systems Over Motivation: Build Pipelines, Not Dreams&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embrace Boilerplates&lt;/strong&gt;: If your goal is to ship a product, not to learn every intricate detail of Webpack configuration, use a solid boilerplate (e.g., Create React App, T3 Stack, Next.js templates, Phoenix generators). Speed to deployment is key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate Everything Possible&lt;/strong&gt;: CI/CD pipelines, automated testing (even minimal), and simple deployment scripts reduce the friction of getting updates out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Unfinished Project as Tuition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's crucial to acknowledge this: Your graveyard of repos is not a monument to failure; it's a testament to your learning and experimentation. Each abandoned project likely taught you a new library, a better coding pattern, a different language, or a deeper understanding of software architecture. You haven't wasted time; you've been acquiring skills.&lt;/p&gt;

&lt;p&gt;Now, it's time to leverage those skills to create something tangible. Choose one project. Define its MVS. Break it down. And ship it. The first one is the hardest, but it breaks the cycle.&lt;/p&gt;

&lt;p&gt;You have the skills. You have the ideas. It's time to move from aspiring developer to a developer who ships. What will be the first project you pull from the graveyard and bring to life?&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>motivation</category>
      <category>softwareengineering</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Zod, A Population Schema Validation Library, Next.js</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sat, 07 Jun 2025 08:59:52 +0000</pubDate>
      <link>https://dev.to/tkirwa/zod-a-population-schema-validation-library-nextjs-2gek</link>
      <guid>https://dev.to/tkirwa/zod-a-population-schema-validation-library-nextjs-2gek</guid>
      <description>&lt;p&gt;In Next.js, &lt;strong&gt;Zod&lt;/strong&gt; is commonly used as a &lt;strong&gt;schema validation library&lt;/strong&gt; to ensure data integrity and type safety for runtime data, such as form inputs, API responses, or environment variables. It is not a built-in part of Next.js but is often integrated into Next.js projects to handle validation and type inference in a robust, TypeScript-friendly way.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Schema Validation&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Zod allows you to define schemas to validate data structures, ensuring they conform to expected formats before processing them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Cases&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Form Validation&lt;/strong&gt;: Validate user inputs in forms (e.g., ensuring an email is valid or a password meets complexity requirements).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Route Validation&lt;/strong&gt;: Validate incoming request data in Next.js API routes or server actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Variables&lt;/strong&gt;: Validate environment variables to ensure they are present and correctly formatted before the app runs.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example (Form Validation)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// Define a schema for a user form&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Name must be at least 2 characters&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Must be at least 18&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="c1"&gt;// In a Next.js API route or server action&lt;/span&gt;
   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validatedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Throws error if invalid&lt;/span&gt;
       &lt;span class="c1"&gt;// Process validated data&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validatedData&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&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;h4&gt;
  
  
  &lt;strong&gt;Type Safety with TypeScript&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Zod integrates seamlessly with TypeScript by automatically inferring TypeScript types from schemas using &lt;code&gt;z.infer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This ensures that validated data is type-safe, reducing runtime errors and improving developer experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example (Type Inference)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
     &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
     &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="c1"&gt;// Infer TypeScript type from schema&lt;/span&gt;
   &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="c1"&gt;// Use the inferred type&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;john@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Environment Variable Validation&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;In Next.js, environment variables are often defined in &lt;code&gt;.env&lt;/code&gt; files. Zod can validate these variables to ensure they exist and have the correct format, especially in &lt;code&gt;next.config.js&lt;/code&gt; or server-side code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example (Environment Variables)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envSchema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
     &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;envSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="na"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="c1"&gt;// Use validated environment variables&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATABASE_URL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Safe access&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;strong&gt;Integration with Next.js Features&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Components and Server Actions&lt;/strong&gt;: Zod can validate data in React Server Components or server actions, ensuring safe data handling on the server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Routes&lt;/strong&gt;: Validate incoming JSON payloads in Next.js API routes to prevent invalid data from reaching your business logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form Libraries&lt;/strong&gt;: Zod is often used with libraries like &lt;code&gt;react-hook-form&lt;/code&gt; or &lt;code&gt;formik&lt;/code&gt; for client-side form validation in Next.js apps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example (with &lt;code&gt;react-hook-form&lt;/code&gt;)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;zodResolver&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hookform/resolvers/zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Password too short&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;LoginForm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;formState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;zodResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;

     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;infer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Validated data:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;handleSubmit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&lt;/span&gt;&lt;span class="err"&gt;&amp;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;h4&gt;
  
  
  &lt;strong&gt;Error Handling&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Zod provides detailed error messages when validation fails, which can be used to return meaningful feedback to users or log issues for debugging.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;userSchema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;not-a-number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ZodError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Detailed validation errors&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;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Use Zod in Next.js?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;: Combines runtime validation with TypeScript type inference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Experience&lt;/strong&gt;: Clear, declarative schema definitions and detailed error messages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility&lt;/strong&gt;: Works across client, server, and API contexts in Next.js.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecosystem Compatibility&lt;/strong&gt;: Integrates well with popular Next.js tools like &lt;code&gt;react-hook-form&lt;/code&gt;, &lt;code&gt;tRPC&lt;/code&gt;, or &lt;code&gt;NextAuth&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;To use Zod in a Next.js project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;zod
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add zod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Zod’s role in Next.js is to provide robust data validation and type safety, making it easier to handle form inputs, API requests, and environment variables in a secure and maintainable way. It’s particularly valuable in TypeScript projects for ensuring consistency between runtime and compile-time types.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Managing Secure Boot Keys for Software on Ubuntu 24.04 LTS</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Fri, 09 May 2025 06:51:34 +0000</pubDate>
      <link>https://dev.to/tkirwa/managing-secure-boot-keys-for-software-on-ubuntu-2404-lts-5f7k</link>
      <guid>https://dev.to/tkirwa/managing-secure-boot-keys-for-software-on-ubuntu-2404-lts-5f7k</guid>
      <description>&lt;p&gt;Secure Boot is a security feature that ensures your computer only boots with software trusted by the Original Equipment Manufacturer (OEM). It verifies the digital signatures of bootloaders and firmware, preventing unauthorized or malicious software from loading before the operating system. This helps protect against rootkits and other malware that could compromise the system early in the boot sequence. &lt;/p&gt;

&lt;p&gt;When using Secure Boot on Ubuntu 24.04 LTS, your system ensures that only trusted software is loaded during the boot process. Ubuntu's core components are signed by Canonical's key, which is recognized through a chain of trust established with the UEFI firmware. However, for third-party software, particularly drivers (like NVIDIA proprietary graphics drivers) or custom-compiled kernel modules, an additional step is often required: enrolling a Machine Owner Key (MOK).&lt;/p&gt;

&lt;p&gt;There isn't a single command to "add all keys pending for all software" in a batch operation for distinct keys. Instead, the system typically handles MOK enrollment on a per-need basis when software requiring a new signature is installed or updated.&lt;/p&gt;

&lt;p&gt;Here's how the process generally works and how you can manage these keys:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Understanding MOKs and the Enrollment Process:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Triggering Enrollment:&lt;/strong&gt; When you install software that includes kernel modules not signed by Canonical's key (e.g., via &lt;code&gt;dkms&lt;/code&gt; for NVIDIA drivers, VirtualBox modules, etc.), the installation process should automatically initiate the MOK enrollment procedure.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Password Prompt:&lt;/strong&gt; You will typically be prompted to create a temporary password (usually between 8 and 16 characters). This password is specifically for the MOK enrollment process that will occur on the next reboot. Remember this password.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Reboot and MOKManager:&lt;/strong&gt; Upon rebooting your system, before Ubuntu fully loads, a blue screen interface called MOKManager (or Shim UEFI key management) will appear.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Enrolling the Key:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Select &lt;strong&gt;"Enroll MOK"&lt;/strong&gt; (or a similar option like "Enroll key from disk").&lt;/li&gt;
&lt;li&gt;You might be asked to confirm the key you want to enroll.&lt;/li&gt;
&lt;li&gt;You will then be prompted to enter the password you created in step 2.&lt;/li&gt;
&lt;li&gt;Confirm the enrollment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;System Reboots Again:&lt;/strong&gt; After successful enrollment, the system will reboot once more, and the newly enrolled key will allow the signed third-party modules to be loaded.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Checking Secure Boot and MOK Status:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;mokutil&lt;/code&gt; command in the terminal to check the status:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check Secure Boot status:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mokutil &lt;span class="nt"&gt;--sb-state&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This will tell you if Secure Boot is enabled.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;List enrolled MOKs:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mokutil &lt;span class="nt"&gt;--list-enrolled&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This will show any MOKs that have already been enrolled in your system's firmware.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What if Enrollment was Skipped or Failed?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you accidentally skipped the MOKManager screen (e.g., by selecting "Continue boot") or if an enrollment seems to have failed, you can often re-initiate the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Re-initiating MOK Enrollment:&lt;/strong&gt;&lt;br&gt;
For keys managed by &lt;code&gt;shim-signed&lt;/code&gt; (which is common for DKMS modules like NVIDIA drivers), you can try to force the re-enrollment prompt for an existing key that hasn't been enrolled yet:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;update-secureboot-policy &lt;span class="nt"&gt;--enroll-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This command will check for a pending MOK and, if found, prompt you to set a password for enrollment on the next reboot. If it says a key is already enrolled, or no new key is pending, then there's nothing immediate for this command to do.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reinstalling the Software:&lt;/strong&gt;&lt;br&gt;
In some cases, reinstalling the specific software package (e.g., the DKMS version of a driver) might re-trigger the MOK enrollment prompts:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt reinstall &amp;lt;package-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Replace &lt;code&gt;&amp;lt;package-name&amp;gt;&lt;/code&gt; with the actual name of the driver package (e.g., &lt;code&gt;nvidia-dkms-550&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generating and Importing a New MOK (Advanced):&lt;/strong&gt;&lt;br&gt;
If a MOK wasn't generated or if you need to manage keys manually (less common for typical software installs):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A MOK is often automatically generated by packages like &lt;code&gt;shim-signed&lt;/code&gt; and placed in &lt;code&gt;/var/lib/shim-signed/mok/&lt;/code&gt; or by DKMS in &lt;code&gt;/var/lib/dkms/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can generate a new MOK pair if needed:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;update-secureboot-policy &lt;span class="nt"&gt;--new-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll be prompted to create and verify a password for this new key. Then, use &lt;code&gt;sudo update-secureboot-policy --enroll-key&lt;/code&gt; to enroll it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To manually import a specific key file (e.g., &lt;code&gt;MOK.der&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;mokutil &lt;span class="nt"&gt;--import&lt;/span&gt; /path/to/your/MOK.der
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll be prompted to set a password for enrollment on reboot.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Important Considerations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"All Software":&lt;/strong&gt; Secure Boot key enrollment is decentralized. Each piece of software that installs unsigned kernel modules will typically trigger its own MOK enrollment request if its signing key isn't already trusted. If multiple drivers are built using DKMS, they might all be signed by a single DKMS-generated MOK once it's enrolled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third-Party Repositories:&lt;/strong&gt; Software from third-party repositories might also require MOK enrollment if it includes kernel modules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TPM and Full Disk Encryption (FDE):&lt;/strong&gt; While generally compatible, some users have reported complexities with MOK enrollment when TPM-backed FDE is also in use. Ensure your system firmware is up to date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;BIOS/UEFI Settings:&lt;/strong&gt; Ensure Secure Boot is enabled in your system's UEFI/BIOS settings. Some firmware interfaces also offer options to manage Secure Boot keys directly (e.g., to enroll keys from a USB drive), though using Ubuntu's &lt;code&gt;mokutil&lt;/code&gt; is usually the standard procedure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By understanding the MOK enrollment process and using the &lt;code&gt;mokutil&lt;/code&gt; and &lt;code&gt;update-secureboot-policy&lt;/code&gt; commands, you can effectively manage the keys required for your software to run under Secure Boot on Ubuntu 24.04 LTS. Remember to follow the on-screen prompts carefully during driver or module installation and the subsequent reboot.&lt;/p&gt;

</description>
      <category>secureboot</category>
      <category>ubuntu</category>
      <category>linux</category>
      <category>bootkeys</category>
    </item>
    <item>
      <title>Gatsby and Next.js</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Fri, 09 Feb 2024 09:26:09 +0000</pubDate>
      <link>https://dev.to/tkirwa/gatsby-and-nextjs-4bj7</link>
      <guid>https://dev.to/tkirwa/gatsby-and-nextjs-4bj7</guid>
      <description>&lt;p&gt;Let’s delve into a comparison between  &lt;strong&gt;Gatsby&lt;/strong&gt;  and  &lt;strong&gt;Next.js&lt;/strong&gt;, two popular frameworks in the React ecosystem. Each of these tools serves distinct purposes and excels in different scenarios. Here’s an overview of both, along with their ideal use cases:&lt;br&gt;
&lt;strong&gt;Gatsby&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static Site Generator (SSG)&lt;/strong&gt;: Gatsby is primarily a static site generator. It builds static HTML/CSS/JS files during the build process, which can be deployed without a server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance and SEO&lt;/strong&gt;: Gatsby focuses on fast page load times, excellent SEO optimization, and progressive image loading.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Content Sources&lt;/strong&gt;: It integrates well with various data sources (e.g., Markdown files, APIs, headless CMS) to create content-rich websites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ideal Use Cases&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building static websites (blogs, portfolios, marketing sites).&lt;/li&gt;
&lt;li&gt;Content-driven sites with rich data sources.&lt;/li&gt;
&lt;li&gt;Projects where SEO and performance are critical.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next.js&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Framework&lt;/strong&gt;: Next.js combines server-side rendering (SSR) and static site generation. It generates HTML/CSS/JS at runtime when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side Rendering&lt;/strong&gt;: Next.js excels in server-side rendering, making it suitable for dynamic content and personalized experiences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Handling&lt;/strong&gt;: Next.js leaves data handling decisions to the developer, allowing flexibility in fetching data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ideal Use Cases&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Server-rendered pages (e-commerce, dashboards, user-specific content).&lt;/li&gt;
&lt;li&gt;Projects where developer experience and scalability matter.&lt;/li&gt;
&lt;li&gt;Applications requiring offline access (Progressive Web Apps).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When to Choose Each&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gatsby&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Choose Gatsby for static sites, blogs, and content-heavy projects.&lt;/li&gt;
&lt;li&gt;If you prioritize SEO, image optimization, and fast initial page loads.&lt;/li&gt;
&lt;li&gt;When you want to leverage GraphQL for data sourcing.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Choose Next.js for dynamic pages, e-commerce, and personalized content.&lt;/li&gt;
&lt;li&gt;If you need server-side rendering (SSR) for better SEO and user experience.&lt;/li&gt;
&lt;li&gt;When you value developer experience and scalability.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remember that both frameworks have their strengths, and the choice depends on your specific project requirements.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Formatting Phone Number in JavaScript - Country Code + Leading Zero (0)</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sun, 07 Jan 2024 07:33:53 +0000</pubDate>
      <link>https://dev.to/tkirwa/formatting-phone-number-javascript-country-code-leading-zero-0-3hd9</link>
      <guid>https://dev.to/tkirwa/formatting-phone-number-javascript-country-code-leading-zero-0-3hd9</guid>
      <description>&lt;p&gt;To ensure that &lt;code&gt;smsPhone&lt;/code&gt; is in the format &lt;code&gt;'+2547XXXXXXXX'&lt;/code&gt;, you can modify the code as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Assuming smsPhone is a variable holding the phone number&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formattedPhone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`+&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;smsPhone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^0/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;254&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sms&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;formattedPhone&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;smsMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code uses the &lt;code&gt;replace&lt;/code&gt; function to replace the leading '0' in the phone number with '254' and then adds a '+' to the beginning. This ensures that the phone number is in the international format. Ensure that &lt;code&gt;smsPhone&lt;/code&gt; is a string representing the phone number without the country code. The modified &lt;code&gt;formattedPhone&lt;/code&gt; variable should then be used in the &lt;code&gt;to&lt;/code&gt; field of the &lt;code&gt;sms.send&lt;/code&gt; method.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Disappoint Hackers - Add SSL Certificates to your Website</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sat, 06 Jan 2024 12:18:41 +0000</pubDate>
      <link>https://dev.to/tkirwa/disappoint-hackers-add-ssl-certificates-to-your-website-1a3</link>
      <guid>https://dev.to/tkirwa/disappoint-hackers-add-ssl-certificates-to-your-website-1a3</guid>
      <description>&lt;p&gt;To obtain SSL certificates for &lt;code&gt;www.realmigo.tech&lt;/code&gt; and &lt;code&gt;realmigo.tech&lt;/code&gt; using Let's Encrypt, you can use Certbot. Certbot simplifies the process of obtaining and renewing SSL certificates. Here's a step-by-step guide:&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Ensure that your domain's DNS records point to the correct IP address.&lt;/li&gt;
&lt;li&gt;Make sure that your server is reachable on ports 80 and 443.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Certbot:&lt;/strong&gt;
Install Certbot on your server. The commands might vary depending on your operating system. For example, on Ubuntu, you can use:
&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;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;certbot
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3-certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Obtain SSL Certificates:&lt;/strong&gt;
Run Certbot to obtain SSL certificates for both &lt;code&gt;www.realmigo.tech&lt;/code&gt; and &lt;code&gt;realmigo.tech&lt;/code&gt;:
&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;certbot certonly &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; realmigo.tech &lt;span class="nt"&gt;-d&lt;/span&gt; www.realmigo.tech
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will use Certbot in standalone mode and perform the necessary steps to prove domain ownership.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configure Nginx to Redirect HTTP to HTTPS (Optional but recommended):&lt;/strong&gt;
Create an Nginx configuration file for your application, specifying the SSL certificate paths. Create a new file, for example, &lt;code&gt;/etc/nginx/sites-available/your-app&lt;/code&gt;, and add the following content:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;   &lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;realmigo.tech&lt;/span&gt; &lt;span class="s"&gt;www.realmigo.tech&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;realmigo.tech&lt;/span&gt; &lt;span class="s"&gt;www.realmigo.tech&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/realmigo.tech/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/realmigo.tech/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="c1"&gt;# Additional SSL configurations go here&lt;/span&gt;

       &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://localhost:your_app_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_http_version&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="s"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Upgrade&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Connection&lt;/span&gt; &lt;span class="s"&gt;'upgrade'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="kn"&gt;proxy_cache_bypass&lt;/span&gt; &lt;span class="nv"&gt;$http_upgrade&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;Replace &lt;code&gt;your_app_port&lt;/code&gt; with the actual port where your application is running.&lt;br&gt;
&lt;strong&gt;Create a Symbolic Link:&lt;/strong&gt;&lt;br&gt;
   Create a symbolic link to enable the Nginx site:&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 ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /etc/nginx/sites-available/your-app /etc/nginx/sites-enabled/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test Nginx Configuration and Restart Nginx:&lt;/strong&gt;
Check the Nginx configuration for syntax errors:
&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;nginx &lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are no errors, restart Nginx:&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;service nginx restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Renewal:&lt;/strong&gt;
Set up a cron job to automatically renew the Let's Encrypt certificates:
&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;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following line to run the renewal process twice daily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   0 */12 * * * certbot renew --quiet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and exit the editor.&lt;/p&gt;

&lt;p&gt;Now, your site should be accessible over HTTPS at &lt;code&gt;https://www.realmigo.tech&lt;/code&gt; and &lt;code&gt;https://realmigo.tech&lt;/code&gt;. Make sure to customize the Nginx configuration according to your application's needs.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>SSH: "Connection refused" Fix - Ubuntu Server</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sat, 06 Jan 2024 11:28:52 +0000</pubDate>
      <link>https://dev.to/tkirwa/ssh-connection-refused-fix-ubuntu-server-3m75</link>
      <guid>https://dev.to/tkirwa/ssh-connection-refused-fix-ubuntu-server-3m75</guid>
      <description>&lt;p&gt;The "Connection refused" error typically indicates that the SSH service is not running on the specified host, or a firewall is blocking the connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error below&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;root@00bc17d6e6f8:/# ssh -v &lt;a href="mailto:ubuntu@100.24.238.153"&gt;ubuntu@100.24.238.153&lt;/a&gt;&lt;br&gt;
OpenSSH_6.6.1, OpenSSL 1.0.1f 6 Jan 2014&lt;br&gt;&lt;br&gt;
debug1: Reading configuration data&lt;br&gt;
/etc/ssh/ssh_config  debug1: /etc/ssh/ssh_config line 19: Applying&lt;br&gt;
options for *  debug1: Connecting to 100.24.238.153 [100.24.238.153]&lt;br&gt;
port 22.  debug1: connect to address 100.24.238.153 port 22: &lt;br&gt;
Connection refused ssh: connect to host 100.24.238.153 port 22:&lt;br&gt;
Connection refused root@00bc17d6e6f8:/#&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here are a few steps to troubleshoot the issue:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check SSH Service:&lt;/strong&gt;
Ensure that the SSH service is running on the remote server. If you have access to the server, you can check and restart the SSH service using the following commands:
&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;service ssh status
   &lt;span class="nb"&gt;sudo &lt;/span&gt;service ssh restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Firewall Configuration:&lt;/strong&gt;&lt;br&gt;
Make sure that the firewall on the remote server is not blocking incoming connections on port 22 (the default SSH port). You can temporarily disable the firewall or allow SSH traffic through it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security Group / Network ACLs (for AWS):&lt;/strong&gt;&lt;br&gt;
If you are using Amazon Web Services (AWS), check the security group and network ACL settings for the instance. Ensure that incoming traffic on port 22 is allowed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check if SSH is Listening:&lt;/strong&gt;&lt;br&gt;
On the remote server, check if SSH is listening on the specified port (22 by default). You can use the following command:&lt;br&gt;
&lt;/p&gt;&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;netstat &lt;span class="nt"&gt;-tulpn&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should show an entry for the SSH daemon (&lt;code&gt;sshd&lt;/code&gt;) listening on port 22.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Restart SSH Service on the Remote Server:&lt;/strong&gt;
If the SSH service is running, try restarting it on the remote server:
&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;service ssh restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Check Server Logs:&lt;/strong&gt;&lt;br&gt;
Examine the logs on the remote server for any SSH-related issues. The location of the logs may vary depending on your server's operating system. Common locations include &lt;code&gt;/var/log/auth.log&lt;/code&gt;, &lt;code&gt;/var/log/secure&lt;/code&gt;, or &lt;code&gt;/var/log/messages&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confirm IP Address:&lt;/strong&gt;&lt;br&gt;
Double-check that the IP address (100.24.238.153 in this case) is correct and corresponds to the intended server.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After performing these steps, try connecting again:&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;-v&lt;/span&gt; ubuntu@100.24.238.153
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-v&lt;/code&gt; option provides verbose output and might give more details about the connection issue. If the problem persists, inspect the logs and error messages for further troubleshooting.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Senior Backend Engineer, Markets (Kenya) - TALA - Job</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sun, 31 Dec 2023 13:03:17 +0000</pubDate>
      <link>https://dev.to/tkirwa/senior-backend-engineer-markets-kenya-tala-job-291f</link>
      <guid>https://dev.to/tkirwa/senior-backend-engineer-markets-kenya-tala-job-291f</guid>
      <description>&lt;h6&gt;
  
  
  &lt;a href="https://www.linkedin.com/company/talamobile/life" rel="noopener noreferrer"&gt;Tala&lt;/a&gt;  · Nairobi, Nairobi County, Kenya
&lt;/h6&gt;

&lt;p&gt;The Senior Backend Engineer builds and extends Tala’s backend architecture to support new country launches, new features, and a fast-growing user base. As a technologist and a leader, the Senior Backend Engineer pushes the team towards building a highly available, scalable, reliable, fault-tolerant, and performant microservices platform. The Senior Backend Engineer follows and improves upon Tala’s engineering processes and standards while advancing Tala’s mission and business objectives. This is a technical leadership role within Tala’s technical track. You will report to the Backend Engineering Manager and collaborate cross-functionally with all Tala teams across the globe.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Responsibilities&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Design and implement features as defined in the Product roadmap&lt;/li&gt;
&lt;li&gt;  Review design documents, perform code reviews, and weigh in on implementation choices from other technical teams&lt;/li&gt;
&lt;li&gt;  Collaborate and support with cross-functional teams (Product, Data, Credit, and Business Development) to ship scalable software solutions&lt;/li&gt;
&lt;li&gt;  Continually improve our codebase with clean and efficient code as well as solve problems using the most appropriate technology&lt;/li&gt;
&lt;li&gt;  Contribute to the complete migration of the legacy codebase to the microservices architecture&lt;/li&gt;
&lt;li&gt;  Contribute to the testing infrastructure to increase code coverage for backend modules&lt;/li&gt;
&lt;li&gt;  Advance monitoring and alerting capabilities of backend modules to allow proactive improvements to availability and response times&lt;/li&gt;
&lt;li&gt;  Technically lead and mentor a team of Backend Engineers to build/extend complex modules
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Requirements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  4+ years of backend software engineering experience&lt;/li&gt;
&lt;li&gt;  4+ years coding in one or more of the following languages: Java, Scala, Kotlin&lt;/li&gt;
&lt;li&gt;  Developed and launched large-scale consumer applications with the backend on Cloud infrastructure (AWS, Google Cloud, or Azure) using a microservices architecture paradigm&lt;/li&gt;
&lt;li&gt;  Expert knowledge in REST API design and development for mobile/web use&lt;/li&gt;
&lt;li&gt;  Expert proficiency in the Agile development process&lt;/li&gt;
&lt;li&gt;  Excellent ability to prioritize and communicate in a fast-paced environment&lt;/li&gt;
&lt;li&gt;  Strong relational database experience (MySQL, PostgreSQL, Oracle, or MS SQL)&lt;/li&gt;
&lt;li&gt;  Strong non-relational database experience (Cassandra, Redshift, DynamoDB, HDFS)&lt;/li&gt;
&lt;li&gt;  BS degree in Computer Science or related fields is a plus&lt;/li&gt;
&lt;li&gt;  Demonstrated ability to interview candidates and evaluate technical skills
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our vision is to build a new financial ecosystem where everyone can participate on equal footing and access the tools they need to be financially healthy. We strongly believe that inclusion fosters innovation and we’re proud to have a diverse global team that represents a multitude of backgrounds, cultures, and experiences. We hire talented people regardless of race, religion, colour, national origin, gender, gender expression, sexual orientation, age, marital status, veteran status, or disability status.&lt;/p&gt;

&lt;p&gt;Apply Here&lt;br&gt;
&lt;a href="https://www.linkedin.com/jobs/view/3707531360/" rel="noopener noreferrer"&gt;https://www.linkedin.com/jobs/view/3707531360/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>job</category>
    </item>
    <item>
      <title>Setting up Express Backend API to use Docker</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Mon, 18 Dec 2023 15:31:56 +0000</pubDate>
      <link>https://dev.to/tkirwa/setting-up-express-backend-api-to-use-docker-4b2e</link>
      <guid>https://dev.to/tkirwa/setting-up-express-backend-api-to-use-docker-4b2e</guid>
      <description>&lt;p&gt;To set up a Dockerfile for your Clarek CRM backend using Express.js with port 8000, follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Create a Dockerfile:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create a file named &lt;code&gt;Dockerfile&lt;/code&gt; in the root directory of your Clarek CRM backend project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use an official Node.js runtime as a base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory in the container&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Copy package.json and package-lock.json to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install app dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy the rest of the application code to the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Expose port 8000&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;

&lt;span class="c"&gt;# Define the command to run your application&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Noted that &lt;code&gt;WORKDIR /usr/src/app&lt;/code&gt;  becomes &lt;code&gt;WORKDIR /clarek-crm-backend&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Build the Docker Image:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open a terminal and navigate to the directory containing your Dockerfile and application code. Run the following command to build the Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; clarek-crm-backend &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will build the Docker image using the instructions in the Dockerfile and tag it with the name &lt;code&gt;clarek-crm-backend&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Run the Docker Container:&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After building the image, you can run the Docker container using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 &lt;span class="nt"&gt;-d&lt;/span&gt; clarek-crm-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command maps port 8000 on your host machine to port 8000 in the Docker container and runs the container in detached mode (&lt;code&gt;-d&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, your Clarek CRM backend should be accessible at &lt;code&gt;http://localhost:8000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Note: Make sure your Express.js application is configured to listen on port 8000. You can set the port in your Express.js application code or through a configuration file.&lt;/p&gt;

&lt;p&gt;Remember to replace any placeholder names or values with your actual project details. Adjust the Node.js version in the &lt;code&gt;FROM&lt;/code&gt; statement based on your project's compatibility.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>express</category>
      <category>api</category>
    </item>
    <item>
      <title>Generate a Random JWT Secret Key</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Sat, 16 Dec 2023 12:06:41 +0000</pubDate>
      <link>https://dev.to/tkirwa/generate-a-random-jwt-secret-key-39j4</link>
      <guid>https://dev.to/tkirwa/generate-a-random-jwt-secret-key-39j4</guid>
      <description>&lt;p&gt;To generate a random JWT secret key, you can use a tool like Node.js to create a random string. Here's a simple example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal or command prompt.&lt;/li&gt;
&lt;li&gt;Run the following Node.js script to generate a random string:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"console.log(require('crypto').randomBytes(32).toString('hex'))"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command uses the &lt;code&gt;crypto&lt;/code&gt; module in Node.js to generate a random sequence of 32 bytes and then converts it to a hexadecimal string.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Copy the generated string.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open your &lt;code&gt;.env&lt;/code&gt; file and set the JWT secret key:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JWT_SECRET=paste-the-generated-string-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;paste-the-generated-string-here&lt;/code&gt; with the string you copied.&lt;/p&gt;

&lt;p&gt;Save the changes to your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Now, you have a securely generated JWT secret key. Remember to keep this key confidential and don't share it publicly. If needed, you can regenerate the key and update it in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

</description>
      <category>jwt</category>
      <category>env</category>
      <category>express</category>
      <category>node</category>
    </item>
    <item>
      <title>PostgreSQL and Nginx through the firewall using Ports</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Tue, 10 Oct 2023 10:39:46 +0000</pubDate>
      <link>https://dev.to/tkirwa/postgresql-and-nginx-through-the-firewall-using-ports-2hi3</link>
      <guid>https://dev.to/tkirwa/postgresql-and-nginx-through-the-firewall-using-ports-2hi3</guid>
      <description>&lt;p&gt;To allow PostgreSQL and Nginx through the firewall by specifying the ports they use, you can use the &lt;code&gt;ufw&lt;/code&gt; (Uncomplicated Firewall) utility on Ubuntu. Here's how you can do it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allow PostgreSQL (Postgres) Port&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;By default, PostgreSQL uses port 5432. To allow PostgreSQL through the firewall, you can use the following 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;ufw allow 5432/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command allows incoming TCP traffic on port 5432, which is the default PostgreSQL port.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allow Nginx Port&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;Nginx uses port 80 (HTTP) and/or port 443 (HTTPS) to serve web traffic. You can allow these ports using the following commands:&lt;/p&gt;

&lt;p&gt;For HTTP (port 80):&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;ufw allow 80/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For HTTPS (port 443):&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;ufw allow 443/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands allow incoming TCP traffic on ports 80 and 443, which are the default ports for HTTP and HTTPS traffic served by Nginx.&lt;/p&gt;

&lt;p&gt;After running these commands, make sure to check the status of the firewall rules to ensure that they are correctly configured:&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;ufw status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the rules you've added, and they should be marked as "ALLOW." If everything looks correct, you can reload the firewall to apply the changes:&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;ufw reload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your PostgreSQL and Nginx services should now be accessible through their respective ports, and they are allowed through the firewall.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploying Django Project on an Ubuntu Server</title>
      <dc:creator>Tonny Kirwa</dc:creator>
      <pubDate>Tue, 10 Oct 2023 10:35:37 +0000</pubDate>
      <link>https://dev.to/tkirwa/deploying-django-project-on-an-ubuntu-server-32jb</link>
      <guid>https://dev.to/tkirwa/deploying-django-project-on-an-ubuntu-server-32jb</guid>
      <description>&lt;p&gt;Setting up a Django project on an Ubuntu server involves several steps. Here's a step-by-step guide to help you get started:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connect to the Remote Server&lt;/strong&gt;&lt;br&gt;
   Open your terminal and use the &lt;code&gt;ssh&lt;/code&gt; command to connect to your remote server using the provided IP address and your SSH key. Replace &lt;code&gt;~/.ssh/id_rsa&lt;/code&gt; with the path to your private SSH key:&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; ~/.ssh/id_rsa ubuntu@ip_address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be logged into your Ubuntu server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update Package List&lt;/strong&gt;&lt;br&gt;
   It's always a good practice to update the package list on your server before installing new software. Run the following command to update the package list:&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Install Nginx&lt;/strong&gt;&lt;br&gt;
   Nginx is a popular web server that can serve as a reverse proxy for your Django application. Install Nginx using the following 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 &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the installation is complete, start the Nginx service and enable it to start at boot:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;By default, Nginx should be allowed through the firewall, but you can verify that it's enabled by running:&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;ufw allow &lt;span class="s1"&gt;'Nginx Full'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Install PostgreSQL &amp;amp; Allow it via Firewall&lt;/strong&gt;&lt;br&gt;
   If you intend to use PostgreSQL as your database, you can install it using the following 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 &lt;span class="nb"&gt;install &lt;/span&gt;postgresql postgresql-contrib
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PostgreSQL should also be allowed through the firewall, but you can explicitly enable it:&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;ufw allow &lt;span class="s1"&gt;'PostgreSQL'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To create a PostgreSQL database, assign a user to it, and grant all privileges, you can follow these steps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log in as the PostgreSQL Superuser&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First, switch to the PostgreSQL user and open the PostgreSQL command line utility:&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; &lt;span class="nt"&gt;-u&lt;/span&gt; postgres psql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create the Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Once you are in the PostgreSQL shell, you can create a new database. Replace &lt;code&gt;your_db_name&lt;/code&gt; with your desired database name and &lt;code&gt;your_db_user&lt;/code&gt; with your desired username:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;   &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;your_db_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a User and Assign to the Database&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create a user and set a password for it. Replace &lt;code&gt;your_db_user&lt;/code&gt; and &lt;code&gt;your_password&lt;/code&gt; with your desired username and password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;   &lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;your_db_user&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PASSWORD&lt;/span&gt; &lt;span class="s1"&gt;'your_password'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, grant the user privileges on the database. Replace &lt;code&gt;your_db_name&lt;/code&gt; and &lt;code&gt;your_db_user&lt;/code&gt; with your database name and username:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;   &lt;span class="k"&gt;GRANT&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;PRIVILEGES&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;your_db_name&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;your_db_user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will grant the user full access to the specified database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit the PostgreSQL Shell&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To exit the PostgreSQL shell and return to the regular command line, type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;   &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now have created a PostgreSQL database, assigned a user to it, and granted that user all privileges on the database. Make sure to update your Django project's settings to use the correct database name, username, and password as configured in these steps.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Install Python and Virtual Environment&lt;/strong&gt;&lt;br&gt;
   You'll need Python and a virtual environment for your Django project. Install Python and &lt;code&gt;venv&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3 python3-venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clone Your Django Project&lt;/strong&gt;&lt;br&gt;
   You can clone your Django project repository from a Git repository or transfer it to the server using another method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Set Up Your Django Project&lt;/strong&gt;&lt;br&gt;
   Navigate to your Django project directory and create a virtual 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;cd&lt;/span&gt; /path/to/your/django/project
   python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the virtual 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;venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install project dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configure Django Settings&lt;/strong&gt;&lt;br&gt;
   Configure your Django settings to use the PostgreSQL database and other necessary configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collect Static Files&lt;/strong&gt;&lt;br&gt;
    If your project serves static files using Django, collect them using the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    python manage.py collectstatic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Migrate Database&lt;/strong&gt;&lt;br&gt;
    Apply initial database migrations&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    python manage.py migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Test Your Application&lt;/strong&gt;&lt;br&gt;
    Start your Django development server to test your application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    python manage.py runserver 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Configure Nginx for Django&lt;/strong&gt;&lt;br&gt;
    Configure Nginx to serve your Django application. Create an Nginx server block (virtual host) configuration file for your site. You can create a new configuration file in &lt;code&gt;/etc/nginx/sites-available/&lt;/code&gt;, or modify the default configuration. Make sure to configure Nginx to proxy requests to your Django application using the Gunicorn or uWSGI server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test Your Website&lt;/strong&gt;&lt;br&gt;
    Test your website by accessing it through your domain or the server's IP address in a web browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secure Your Site with SSL&lt;/strong&gt; (Optional)&lt;br&gt;
    Consider securing your site with SSL using Let's Encrypt or another SSL certificate provider.&lt;/p&gt;

&lt;p&gt;That's a general overview of the steps required to set up a Django project on an Ubuntu server. The specific details may vary depending on your project's requirements and configurations.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>django</category>
      <category>deploy</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
