<?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: IkemHood</title>
    <description>The latest articles on DEV Community by IkemHood (@ikemhood).</description>
    <link>https://dev.to/ikemhood</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%2F1055750%2F64ea2674-17de-4ba5-ae95-dda6c611ad80.jpeg</url>
      <title>DEV Community: IkemHood</title>
      <link>https://dev.to/ikemhood</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ikemhood"/>
    <language>en</language>
    <item>
      <title>The Fake Job Listings That Was Just a Front for Pushing Malware - My Story</title>
      <dc:creator>IkemHood</dc:creator>
      <pubDate>Thu, 28 Sep 2023 11:47:11 +0000</pubDate>
      <link>https://dev.to/ikemhood/the-fake-job-listings-that-was-just-a-front-for-pushing-malware-my-story-38f6</link>
      <guid>https://dev.to/ikemhood/the-fake-job-listings-that-was-just-a-front-for-pushing-malware-my-story-38f6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a freelance developer, I'm always keeping an eye out for potential new projects to take on. So when a friend reached out about an interesting blockchain gig they had seen, I was definitely interested.&lt;/p&gt;

&lt;p&gt;The role involved building web apps with React and some blockchain integreation - right up my alley! Little did I know that would lead me down a rabbit hole of red flags and questionable technical “screening”. &lt;/p&gt;

&lt;p&gt;Devs have to be selective about the clients we take on. But we don't expect trouble from potential employers themselves. This bizarre scheme I uncovered taught me that job seekers need to be vigilant too. &lt;/p&gt;

&lt;p&gt;I wanted to share my story as a cautionary tale about keeping your guard up. Especially when asked to run unknown code for an interview “test”. With so many unethical actors out there, we have to watch each other’s backs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Job Listing That Wasn’t What It Seemed
&lt;/h2&gt;

&lt;p&gt;This whole shady situation started with a blockchain developer job listing a friend shared with me. It seemed pretty normal at first - they were looking for someone with React and blockchain development experience to work on web apps.&lt;/p&gt;

&lt;p&gt;But the suspicious part was their instructions for “assessing candidates.” The listing included a Google Drive link and asked applicants to download the code, get it running locally, and send a screenshot of the app as proof before moving to the next interview stage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8cjsu6n8u8wf31pwxorh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8cjsu6n8u8wf31pwxorh.jpg" alt="screenshot of job request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In hindsight, this was clearly a ruse to get unsuspecting developers to run malware. But at the time, I didn't immediately think twice about it. I figured it was just a small technical challenge to evaluate skills before an in-depth interview.&lt;/p&gt;

&lt;p&gt;So I downloaded the linked codebase and started reviewing it carefully, knowing anything from an unknown source should be vetted first. That's when the red flags popped up...&lt;/p&gt;

&lt;h2&gt;
  
  
  Red Flags Raised My Suspicions
&lt;/h2&gt;

&lt;p&gt;Once I extracted the files, at first glance nothing seemed too out of the ordinary. Just a typical React project skeleton with dependencies in package.json. But having heard horror stories of malicious technical tests, I knew better than to just npm install and start building.&lt;/p&gt;

&lt;p&gt;That’s when the first red flag popped up. I noticed this config.js file that was called from the package.json scripts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9ezm7jvrq1xialh5kd0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9ezm7jvrq1xialh5kd0.png" alt="Package.json file with malicious code trigger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Very odd place for configuration code. And sure enough when I opened it up, there was a mess of heavily obfuscated code full of encoding and encryption:&lt;/p&gt;

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

&lt;p&gt;My heartbeat quickened. Obfuscation like that is almost always a giveaway of malicious intent. Legitimate config has no reason to hide itself that way. It immediately became clear what was going on - this was malware disguised as an interview “test”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Malware Designed to Compromise My System
&lt;/h2&gt;

&lt;p&gt;My stomach turned as it set in how unethical this was. A potential employer looking to compromise my personal info and system security under the guise of screening me. Who knows what kind of data their malware aimed to extract had I naively installed and ran their code. Absolute violation of trust.&lt;/p&gt;

&lt;p&gt;I took a deep breath and went into damage control mode. First step – to feed my curiosity, i copied the entire config.js code to chatgpt for analysis and possibly unwrapping it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho0okozaa3tclagm8jto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fho0okozaa3tclagm8jto.png" alt="Chatgpt remark on the malicious code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then i tried to ask chatgpt to see if it could show me what exactly the code was doing but it refused,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71fn5n0au2q6fju3seho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71fn5n0au2q6fju3seho.png" alt="chatgpt refusing to decompile code on legality"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then i tried claude which was a little lenient to allow me have an overview of what was happening, it was obviosly what I expected&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfmy214caegfgms4f6j3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqfmy214caegfgms4f6j3.png" alt="Claude's deconstruction of the malicoius code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lz9n3e27u5ol1ooyypo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lz9n3e27u5ol1ooyypo.png" alt="Claude's deconstruction of the malicoius code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1onhz4izquyt8oamvg69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1onhz4izquyt8oamvg69.png" alt="Claude's deconstruction of the malicoius code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having understood what the malicious code was meant for, i went ahead to completely wipe both the codebase itself and any system I had unpacked it on. No point trying to debug such clearly malicious code. I wasn’t about to let my machine become their playground.&lt;/p&gt;

&lt;p&gt;Next I considered reporting this behavior for such a blatantly unethical practice. But I quickly realized there was probably no point. They clearly knew what they were doing was wrong. Reporting them would likely accomplish nothing. Better to share my experience and help other developers spot similar red flags.&lt;/p&gt;

&lt;p&gt;While an extremely unsettling experience, it was an important reminder to thoroughly vet technical screening tests during a job search. You have to be able to trust that employers have your best interests in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways for Job Seekers
&lt;/h2&gt;

&lt;p&gt;Since going through this sneaky malware scheme disguised as an interview test, I’m vigilant about technical assessments. Here are some key lessons I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Look out for unnecessary obfuscation of code or implementation details - huge red flag.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Don't feel rushed into running unknown code for a test. Ask for more details if anything seems unclear.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Review tests in an isolated environment first, not your main system. Check for any suspicious network activity.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Get a second opinion from other developers if something seems off about a test. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remember employers have no right to probe your personal data without consent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consider anonymously reporting unethical behavior to help protect others.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While most companies are ethical, it pays to be vigilant. You should feel empowered to question anything that doesn’t seem legitimate. Your skills speak for themselves - you don’t need to comply with shady tests. Prioritize your safety and code of ethics.&lt;/p&gt;

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

&lt;p&gt;This experience with a malware “technical screening” left me rattled but also better prepared to identify red flags going forward. However, it worries me that more naive developers may fall victim to traps like this. &lt;/p&gt;

&lt;p&gt;We all just want to build cool things with technology in an ethical way. Having to guard against potential employers is an unfortunate burden. My hope in sharing this story is that it will help shine a light on some deceptive practices that take place under the guise of job screening.&lt;/p&gt;

&lt;p&gt;Devs, watch each other's backs out there. We have so much to contribute when given the chance. Don't let schemes like this undermine your potential. Prioritize openness, ethics, and safety in your job search. The right opportunities are out there.&lt;/p&gt;

</description>
      <category>security</category>
      <category>career</category>
      <category>community</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>From Localhost to the Cloud: Deploying my First Node.js App with Docker</title>
      <dc:creator>IkemHood</dc:creator>
      <pubDate>Fri, 18 Aug 2023 10:12:33 +0000</pubDate>
      <link>https://dev.to/ikemhood/from-localhost-to-the-cloud-deploying-my-first-nodejs-app-with-docker-1nn3</link>
      <guid>https://dev.to/ikemhood/from-localhost-to-the-cloud-deploying-my-first-nodejs-app-with-docker-1nn3</guid>
      <description>&lt;p&gt;As a developer, one of the most satisfying moments is finally getting your web app live on the internet for the world to see! However, turning your locally running code into an accessible web app can be tricky sometimes. I learned this the hard way when I tried to deploy my first Node.js app.&lt;/p&gt;

&lt;p&gt;After weeks of late nights and endless debugging, I had a web app that ran flawlessly on my own machine, for once i felt like a genius 😁. But this happiness was short lived. When it came time to launch it on a cloud server, things started breaking left and right! After banging my head on the desk troubleshooting deployment issues, I knew there had to be a better way. That's when I discovered Docker, and it ended up being the magical solution I needed to easily deploy my Node app and many more after! &lt;/p&gt;

&lt;p&gt;In this post, I'll walk through how taking the time to Dockerize my application gave me the keys to rapidly deploying it to the cloud with minimal fuss. I hope my experience will convince you to embrace Docker for your next Node.js project! Let's get started on this journey from localhost to the cloud!&lt;/p&gt;

&lt;h2&gt;
  
  
  My Application Architecture
&lt;/h2&gt;

&lt;p&gt;First, let me tell you a bit about the simple web application I had built. It was called CatsGram, and it allowed users to post pictures of their cats and leave comments for other fuzzy felines. The app had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A frontend written in React that let users upload cat photos + comments&lt;/li&gt;
&lt;li&gt;A backend REST API written in Node.js and Express that handled the data and storage&lt;/li&gt;
&lt;li&gt;A MongoDB database to store the cat profiles and comments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is what the React frontend looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Frontend in React&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&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&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;App&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSubmit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="c1"&gt;// Call API to submit form data&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;CatsGram&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleSubmit&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"file"&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Add Photo&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is part of the Express backend that handled the API calls from the frontend:&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;// Backend API in Express&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&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;mongoose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongoose&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;cors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cors&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Connect to MongoDB&lt;/span&gt;
&lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mongodb://localhost/catsgram&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;useNewUrlParser&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="c1"&gt;// Cat profile model&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mongoose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;mongoose&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;picUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/cats&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&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="c1"&gt;// Create new cat profile&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newCat&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;Cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newCat&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app worked flawlessly on my local machine, but deploying it to an online server was another story...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deployment Headache
&lt;/h2&gt;

&lt;p&gt;I decided to deploy my app to a popular cloud provider and rented a Linux server. After SSH-ing in, I hit my first roadblock - the server was running an older version of Node than the one I used for development. My app crashed with an error about missing modules and so on! &lt;/p&gt;

&lt;p&gt;After fumbling with NVM to try and install the right Node version, I finally got the backend API running. But then the React frontend failed to build due to mismatching webpack versions with the create-react-app starter I used. &lt;/p&gt;

&lt;p&gt;Each error I fixed seemed to unveil yet another environmental issue between my local machine and the server. Path issues, missing dependencies, environment variables - you name it!&lt;/p&gt;

&lt;p&gt;I was tearing my hair out trying to get things working. I finally conceded defeat and turned to my savior... Docker!&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker to the Rescue!
&lt;/h2&gt;

&lt;p&gt;Docker is a tool that allows you to package applications into standardized units called containers. These containers bundle up the code, dependencies, system libraries, and settings into an isolated executable package.&lt;/p&gt;

&lt;p&gt;The key benefit is that this container will run the same way regardless of the underlying environment. No more worrying about compatibility issues across different machines!&lt;/p&gt;

&lt;p&gt;Some other awesome benefits of Docker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform portability&lt;/strong&gt; - Ship your containers to any Linux, Windows, cloud provider, etc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment consistency&lt;/strong&gt; - Containers include everything needed to run the app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation&lt;/strong&gt; - Apps run in isolated environments without conflicting with other apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Speed&lt;/strong&gt; - Containers start instantly compared to virtual machines
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Docker seemed like the perfect solution to my deployment woes. By Dockerizing my app, I could neatly package it up with all its needed dependencies and specs into a standardized container. This container could seamlessly run on my local machine for development, then be deployed to the cloud server without any environment mismatches!&lt;/p&gt;

&lt;p&gt;Let's look at how I Dockerized the CatsGram app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dockerizing the Backend API
&lt;/h2&gt;

&lt;p&gt;The first step was containerizing my Express backend API. Docker uses special Dockerfile configuration files to build container images. Here is the Dockerfile for my backend:&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;# Dockerfile&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:16-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&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="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]  &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Starts with a Node.js base image&lt;/li&gt;
&lt;li&gt;Sets the working directory to &lt;code&gt;/app&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Copies the backend code into the image&lt;/li&gt;
&lt;li&gt;Installs dependencies with &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Specifies the command to run the app - &lt;code&gt;node server.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this Dockerfile, I could build a container image for my backend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker build -t catsgram-api .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This built an image tagged &lt;code&gt;catsgram-api&lt;/code&gt; based on my Dockerfile. I could then run a container from that image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker run -p 4000:3000 catsgram-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This started a container on port 4000 and mounted the internal port 3000 to be accessible externally. My backend API was now running in an isolated Docker container!&lt;/p&gt;

&lt;h2&gt;
  
  
  Containerizing the Frontend
&lt;/h2&gt;

&lt;p&gt;For my React frontend, I used a multi-stage Docker build:&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;# Stage 1 - Build&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app &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="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
npm run build 

&lt;span class="c"&gt;# Stage 2 - Run &lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:alpine &lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/build /usr/share/nginx/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This first installs Node to build the React app, then copies the built artifacts to an Nginx image for the runtime. This gave me a lean production image!&lt;/p&gt;

&lt;p&gt;Again I could &lt;code&gt;docker build&lt;/code&gt; this and run a container to serve my frontend on port 3000. &lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Services with Docker Compose
&lt;/h2&gt;

&lt;p&gt;At this point, I had two containers - one for the backend API and one for the frontend. To link them together, I used Docker Compose to define the app services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.yml&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

  &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;4000:3000"&lt;/span&gt;

  &lt;span class="na"&gt;frontend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&lt;/span&gt; 
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;docker-compose up&lt;/code&gt; would now start both containers and wire them together!&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to the Cloud
&lt;/h2&gt;

&lt;p&gt;With Docker, deploying these containers to the cloud was a breeze! I pushed my images up to a registry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker push catsgram-api
$ docker push catsgram-frontend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then on the server I just had to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker pull catsgram-api
$ docker pull catsgram-frontend
$ docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The containers started up just as they did locally and my app was live on the internet! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker is Deployment Magic
&lt;/h2&gt;

&lt;p&gt;No more fussing with dependencies, runtimes, builds, etc across different environments. Docker let me develop my app locally as I normally would, then package everything needed up into portable containers ready for deployment anywhere.&lt;/p&gt;

&lt;p&gt;Some of the key benefits I saw:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent environments&lt;/strong&gt; - Containers included the exact dependencies and Node runtime needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform&lt;/strong&gt; - I could develop on OSX but deploy the same containers to Linux servers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightweight&lt;/strong&gt; - Containers are much more efficient than VMs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular&lt;/strong&gt; - Services like frontend and backend were compartmentalized into separate containers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Docker really is a game-changer when it comes to deploying applications. I can now develop apps faster without worrying about environment differences between my machine and servers. &lt;/p&gt;

&lt;p&gt;If you're struggling to deploy Node apps, I highly recommend exploring Docker! It will save you those late night "works on my machine" debugging sessions when you'd rather be sleeping.&lt;/p&gt;

&lt;p&gt;Let me know if you have any questions! I'm happy to chat more about my experience Dockerizing my first Node app. Wishing you happy coding and smooth deploying!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
