<?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: Prajwol Shrestha</title>
    <description>The latest articles on DEV Community by Prajwol Shrestha (@prajwolshrestha).</description>
    <link>https://dev.to/prajwolshrestha</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%2F732418%2Fc3b5945a-4d0e-42a8-838a-ac4c73a279da.png</url>
      <title>DEV Community: Prajwol Shrestha</title>
      <link>https://dev.to/prajwolshrestha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prajwolshrestha"/>
    <language>en</language>
    <item>
      <title>Hosting a Dockerized Node.js App on Oracle Cloud Free Tier</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sun, 15 Feb 2026 14:06:10 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/hosting-a-dockerized-nodejs-app-on-oracle-cloud-free-tier-38ga</link>
      <guid>https://dev.to/prajwolshrestha/hosting-a-dockerized-nodejs-app-on-oracle-cloud-free-tier-38ga</guid>
      <description>&lt;p&gt;I recently decided to host one of my Dockerized Node.js apps on a VPS using Oracle Cloud Free Tier - not just to deploy it, but to understand what’s actually happening under the hood.&lt;/p&gt;

&lt;p&gt;I wanted to learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to create and configure a compute instance&lt;/li&gt;
&lt;li&gt;How Docker behaves on a VPS&lt;/li&gt;
&lt;li&gt;Why backend ports shouldn't be exposed directly&lt;/li&gt;
&lt;li&gt;How NGINX fits into the picture&lt;/li&gt;
&lt;li&gt;What restart policies actually do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's exactly how I set it up - and what I learned along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1 - Create a Compute Instance on Oracle Cloud
&lt;/h2&gt;

&lt;p&gt;Inside Oracle Cloud:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Compute -&amp;gt; Instances&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create Instance&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Ubuntu&lt;/strong&gt; (I used 22.04)&lt;/li&gt;
&lt;li&gt;Select an &lt;strong&gt;Always Free&lt;/strong&gt; eligible shape (1 vCPU, ~1GB RAM)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When creating the instance, upload your SSH public key or download the key Oracle provides.&lt;/p&gt;

&lt;p&gt;Once the instance is running:&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; your-key.pem ubuntu@YOUR_SERVER_IP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you're inside a real Linux server - not a managed environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 - Basic Setup &amp;amp; Firewall
&lt;/h2&gt;

&lt;p&gt;First, update the system:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Then enable UFW:&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;ufw &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow OpenSSH
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw &lt;span class="nb"&gt;enable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only SSH is allowed&lt;/li&gt;
&lt;li&gt;Everything else is blocked&lt;/li&gt;
&lt;/ul&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Oracle Cloud has its own &lt;strong&gt;Security List&lt;/strong&gt; (cloud firewall).&lt;br&gt;&lt;br&gt;
Ubuntu has &lt;strong&gt;UFW&lt;/strong&gt; (OS firewall).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If something doesn't work later, check both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 - Install Docker
&lt;/h2&gt;

&lt;p&gt;Install Docker&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://get.docker.com &lt;span class="nt"&gt;-o&lt;/span&gt; get-docker.sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;sh get-docker.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing Docker, I added my user to the docker group:&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;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reconnect and test:&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 hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker is now ready to run containers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4 - Create a Private Docker Network
&lt;/h2&gt;

&lt;p&gt;Before running anything, I created a custom Docker network:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was important.&lt;/p&gt;

&lt;p&gt;Instead of exposing my Node.js app like this:&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; 3000:3000 my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I wanted the app to stay internal and let NGINX handle public traffic.&lt;/p&gt;

&lt;p&gt;Containers attached to the same custom network:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can talk to each other using their names&lt;/li&gt;
&lt;li&gt;Are not exposed publicly unless you publish ports&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it as a &lt;strong&gt;private network inside your VPS&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5 - Install NGINX Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;At this point, the Node.js app is internal. But something still needs to handle incoming HTTP requests from the outside world. That’s where NGINX comes in.&lt;/p&gt;

&lt;p&gt;I used &lt;strong&gt;NGINX Proxy Manager&lt;/strong&gt; for simplicity.&lt;/p&gt;

&lt;p&gt;Create a directory for it in VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;nginx-proxy
&lt;span class="nb"&gt;cd &lt;/span&gt;nginx-proxy   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create docker-compose.yml&lt;/p&gt;

&lt;p&gt;Here's the simplified &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&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;npm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jc21/nginx-proxy-manager:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-proxy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&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;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;81:81"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./data:/data&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./letsencrypt:/etc/letsencrypt&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;networks: web&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This attaches NGINX to the same private network as the app.&lt;br&gt;&lt;br&gt;
So it can forward traffic internally.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;volumes&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This ensures configuration and SSL certificates survive container restarts.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;restart: unless-stopped&lt;/code&gt;
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;If the VPS reboots -&amp;gt; the container starts automatically&lt;/li&gt;
&lt;li&gt;If Docker restarts -&amp;gt; container comes back&lt;/li&gt;
&lt;li&gt;If it crashes -&amp;gt; it restarts&lt;/li&gt;
&lt;li&gt;If you manually stop it -&amp;gt; it stays stopped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then start it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now NGINX is running.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6 - Open Ports in Oracle Cloud
&lt;/h2&gt;

&lt;p&gt;Open ports in OS level&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
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 443
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even after configuring UFW, I couldn't access the server from the browser.&lt;/p&gt;

&lt;p&gt;That's because Oracle Cloud blocks traffic by default.&lt;/p&gt;

&lt;p&gt;I had to allow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Port 80&lt;/li&gt;
&lt;li&gt;Port 443&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Networking - VCN -&amp;gt; Security List&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This reinforced something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cloud firewall and OS firewall are separate layers.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Step 7 - Deploy the Dockerized Node.js App
&lt;/h2&gt;

&lt;p&gt;I pushed my Node.js image to a container registry (I used Docker Hub).&lt;/p&gt;

&lt;p&gt;On the VPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker login
docker pull myusername/my-node-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then created a folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;app
&lt;span class="nb"&gt;cd &lt;/span&gt;app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Created &lt;code&gt;.env&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NODE_ENV=production
PORT=3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&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;node-app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myusername/my-node-app:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;env_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.env&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;web&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something important:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;-p 3000:3000&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Node.js app is running - but only inside the Docker network.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;not publicly accessible&lt;/strong&gt;.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 8 - Connect NGINX to the Node.js App
&lt;/h2&gt;

&lt;p&gt;Inside NGINX Proxy Manager:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;strong&gt;Proxy Host&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward Hostname&lt;/strong&gt;: &lt;code&gt;node-app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward Port&lt;/strong&gt;: &lt;code&gt;3000&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enable SSL (if using a domain)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now traffic flows like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Browser -&amp;gt; NGINX -&amp;gt; Node.js container&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Port 3000 remains internal.&lt;/p&gt;

&lt;p&gt;This separation reduces your public attack surface. Only NGINX is exposed. Your application server stays internal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free Tier Reality
&lt;/h2&gt;

&lt;p&gt;Oracle Free Tier gives ~1GB RAM.&lt;/p&gt;

&lt;p&gt;You can monitor usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;htop
docker stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This comfortably runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NGINX&lt;/li&gt;
&lt;li&gt;One or two small Node.js apps&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Learned From This
&lt;/h2&gt;

&lt;p&gt;Setting this up myself helped me understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What a compute instance actually is&lt;/li&gt;
&lt;li&gt;Why reverse proxies are important&lt;/li&gt;
&lt;li&gt;How Docker networking isolates services&lt;/li&gt;
&lt;li&gt;Why backend ports shouldn't be exposed&lt;/li&gt;
&lt;li&gt;How restart policies affect uptime&lt;/li&gt;
&lt;li&gt;How cloud and OS firewalls interact&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's very different from just deploying code.&lt;/p&gt;

&lt;p&gt;You start understanding the system your app runs on.&lt;/p&gt;

&lt;p&gt;And that's what made this exercise worth it.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>cloud</category>
      <category>nginx</category>
      <category>vps</category>
    </item>
    <item>
      <title>Building a Chrome Extension: From Idea to Automated Release</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sun, 11 Jan 2026 06:27:22 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/building-a-chrome-extension-from-idea-to-automated-release-2a85</link>
      <guid>https://dev.to/prajwolshrestha/building-a-chrome-extension-from-idea-to-automated-release-2a85</guid>
      <description>&lt;p&gt;Chrome extensions are one of the fastest ways to ship useful software.&lt;br&gt;
They’re lightweight, powerful, and force you to think in clear boundaries.&lt;/p&gt;

&lt;p&gt;This article walks through how to build a Chrome extension using modern tooling, and how to automate versioning and releases using GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We’re Building
&lt;/h2&gt;

&lt;p&gt;We’ll build a simple Chrome extension with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A content script that interacts with web pages&lt;/li&gt;
&lt;li&gt;A background script that handles logic and coordination&lt;/li&gt;
&lt;li&gt;A popup UI for user interaction&lt;/li&gt;
&lt;li&gt;Automated build, versioning, and GitHub releases&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Components
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Manifest
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Defines metadata, permissions, and entry points.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Content Script
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Runs in the context of a web page.&lt;/li&gt;
&lt;li&gt;Can read and manipulate the DOM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background Script
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Runs independently of pages.&lt;/li&gt;
&lt;li&gt;Handles state, messaging, and lifecycle events.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Popup UI
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;A short-lived interface shown when the extension icon is clicked.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Messaging Model
&lt;/h2&gt;

&lt;p&gt;Chrome extensions are event-driven.&lt;br&gt;
Components never directly access each other.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Popup -&amp;gt; sends user intent&lt;/li&gt;
&lt;li&gt;Background -&amp;gt; coordinates logic&lt;/li&gt;
&lt;li&gt;Content Script -&amp;gt; affects the page&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  Distribution Strategies
&lt;/h2&gt;

&lt;p&gt;Chrome extensions are commonly distributed using one of the following approaches, depending on the stage of the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chrome Web Store (Public &amp;amp; Auto-Updating)
&lt;/h3&gt;

&lt;p&gt;For public distribution, Chrome extensions can be published to the Chrome Web Store.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires a one-time $5 USD developer registration fee&lt;/li&gt;
&lt;li&gt;Enables automatic updates&lt;/li&gt;
&lt;li&gt;Makes the extension discoverable to non-technical users&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub Releases (Free &amp;amp; Flexible)
&lt;/h3&gt;

&lt;p&gt;Users install the extension by downloading the release archive and loading it manually in Chrome.&lt;br&gt;
Using GitHub Actions, releases can be fully automated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Versioned ZIP artifacts&lt;/li&gt;
&lt;li&gt;Consistent builds&lt;/li&gt;
&lt;li&gt;No review or approval process&lt;/li&gt;
&lt;li&gt;No cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Auto Scroll Extension
&lt;/h2&gt;

&lt;p&gt;As a practical example, I built a Chrome auto-scroller extension and set it up with a fully automated release pipeline using GitHub Actions.&lt;br&gt;
The project includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A content script that controls page scrolling&lt;/li&gt;
&lt;li&gt;A popup UI for user interaction&lt;/li&gt;
&lt;li&gt;A background script for coordination&lt;/li&gt;
&lt;li&gt;Automated versioned releases on every Git tag&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Source code
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://github.com/Prajwol-Shrestha/auto-scroll-browser-extenstion" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/auto-scroll-browser-extenstion&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Release Automation Overview
&lt;/h2&gt;

&lt;p&gt;In this project, releases are automated as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Git tag (e.g. v1.0.1) is pushed&lt;/li&gt;
&lt;li&gt;GitHub Actions builds the extension&lt;/li&gt;
&lt;li&gt;The build output is packaged into a ZIP&lt;/li&gt;
&lt;li&gt;A GitHub Release is created automatically&lt;/li&gt;
&lt;li&gt;The ZIP is attached as a release asset&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>extensions</category>
      <category>automation</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>Automatically Post Incoming Emails with attachments to Facebook Using n8n</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sun, 28 Dec 2025 05:33:03 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/automatically-post-incoming-emails-with-attachments-to-facebook-using-n8n-5hgd</link>
      <guid>https://dev.to/prajwolshrestha/automatically-post-incoming-emails-with-attachments-to-facebook-using-n8n-5hgd</guid>
      <description>&lt;p&gt;I kept doing the same thing over and over:&lt;br&gt;&lt;br&gt;
an email arrives → copy the subject → download attachments → convert attachments to images → post to Facebook.&lt;/p&gt;

&lt;p&gt;After the third or fourth time, I stopped and automated it with &lt;strong&gt;n8n&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, whenever a new email lands in a specific mailbox, it automatically becomes a Facebook post — attachments included.&lt;/p&gt;

&lt;p&gt;This post is a quick breakdown of &lt;strong&gt;what I built&lt;/strong&gt;, &lt;strong&gt;why I made certain choices&lt;/strong&gt;, and &lt;strong&gt;what actually worked for me&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What This Automation Does
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Watches an email inbox
&lt;/li&gt;
&lt;li&gt;Uses the email subject as the Facebook caption
&lt;/li&gt;
&lt;li&gt;Converts and uploads image attachments
&lt;/li&gt;
&lt;li&gt;Publishes the post automatically
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Workflow Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8xxho8z1xbby77a47ws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo8xxho8z1xbby77a47ws.png" alt="High-level view of the email → Facebook automation workflow" width="630" height="1904"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;High-level view of the email → Facebook automation workflow&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why IMAP (and Not the Gmail Trigger)
&lt;/h2&gt;

&lt;p&gt;I initially tried using n8n’s &lt;strong&gt;Gmail Trigger&lt;/strong&gt; because it felt like the more “native” option.&lt;/p&gt;

&lt;p&gt;In practice, it wasn’t reliable enough for my use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New emails didn’t always trigger the workflow&lt;/li&gt;
&lt;li&gt;Occasionally, nothing fired at all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For an automation that posts publicly, missing even one email isn’t acceptable.&lt;/p&gt;

&lt;p&gt;I switched to &lt;strong&gt;IMAP&lt;/strong&gt; for a few practical reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent execution&lt;/strong&gt; — new emails were picked up every time &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works with any email provider&lt;/strong&gt; — not locked into Gmail's API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s simple, reliable, and kept the workflow firing every time — exactly what I needed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling Facebook Image Posts
&lt;/h2&gt;

&lt;p&gt;Facebook doesn’t let you upload multiple images directly in a single post.&lt;/p&gt;

&lt;p&gt;Instead, you have to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload each image as &lt;strong&gt;unpublished&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Collect the returned &lt;code&gt;media_fbid&lt;/code&gt;s
&lt;/li&gt;
&lt;li&gt;Attach those IDs when creating the final post
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Here's what that looks like in n8n:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Loop through attachments&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use a &lt;strong&gt;Loop Over Items&lt;/strong&gt; node to process each attachment individually&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Upload as unpublished&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;code&gt;/{page-id}/photos&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Method: &lt;code&gt;POST&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;published: false&lt;/code&gt; and pass the attachment URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each upload returns a &lt;code&gt;media_fbid&lt;/code&gt; — save these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Create the final post&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Endpoint: &lt;code&gt;/{page-id}/feed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use the email subject as the message&lt;/li&gt;
&lt;li&gt;Attach all the &lt;code&gt;media_fbid&lt;/code&gt;s you collected&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I understood this flow, the rest was straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas I Ran Into
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Attachment format matters
&lt;/h3&gt;

&lt;p&gt;n8n treats email attachments as binary data. I had to use the Convert to File node before uploading to Facebook, otherwise the API rejected them&lt;/p&gt;

&lt;h3&gt;
  
  
  Facebook permissions
&lt;/h3&gt;

&lt;p&gt;Make sure your app has pages_manage_posts and pages_read_engagement permissions, or uploads will fail.&lt;/p&gt;




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

&lt;p&gt;This isn’t a flashy automation — but it quietly saves time and removes friction.&lt;/p&gt;

&lt;p&gt;If you’re already using n8n and dealing with repetitive posting, this kind of workflow is absolutely worth building.&lt;/p&gt;

&lt;p&gt;Sometimes the best automations are the ones you don’t even notice anymore.&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>automation</category>
      <category>email</category>
      <category>workflow</category>
    </item>
    <item>
      <title>How to Dockerize and Deploy a NestJS App on Render for Free</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sat, 13 Sep 2025 15:29:11 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/how-to-dockerize-and-deploy-a-nestjs-app-on-render-for-free-180j</link>
      <guid>https://dev.to/prajwolshrestha/how-to-dockerize-and-deploy-a-nestjs-app-on-render-for-free-180j</guid>
      <description>&lt;p&gt;So, you’ve built your NestJS app and now want to deploy it online, without spending any money or adding a credit card. In this blog, we’ll walk through a clear, step-by-step process to Dockerize your app and deploy it on Render for free.&lt;/p&gt;

&lt;p&gt;Render’s free tier makes it easy to deploy Dockerized apps, while Docker ensures your project runs consistently everywhere. In this guide, we’ll:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🐳 &lt;strong&gt;Dockerize&lt;/strong&gt; a NestJS app using &lt;code&gt;pnpm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;Deploy&lt;/strong&gt; it to Render in &lt;strong&gt;two different ways&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;🔁 &lt;strong&gt;Add CI/CD&lt;/strong&gt; for automatic deployments on every push to &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;🎁 &lt;strong&gt;Bonus&lt;/strong&gt;: Keep your free Render app alive &lt;strong&gt;24/7&lt;/strong&gt; using a Cloudflare Worker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive in! 🐳&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Docker for NestJS?
&lt;/h2&gt;

&lt;p&gt;Docker helps package your NestJS app with all its dependencies so it runs exactly the same in all environments.&lt;/p&gt;

&lt;p&gt;Render supports two ways of deploying Docker apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;From a Dockerfile&lt;/strong&gt; → Render builds the image itself
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From a prebuilt Docker image&lt;/strong&gt; → You push your image to Docker Hub (or any registry), and Render pulls it
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll cover both options.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Dockerizing the NestJS App
&lt;/h2&gt;

&lt;p&gt;First, we need to containerize our application. If you don’t have Docker installed, &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;grab it here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the &lt;code&gt;Dockerfile&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Create a file named &lt;code&gt;Dockerfile&lt;/code&gt; in your project's root directory:&lt;/p&gt;

&lt;p&gt;Here’s a example Dockerfile using pnpm:&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 a lightweight Node.js base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-slim &lt;/span&gt;

&lt;span class="c"&gt;# Set working directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# Copy dependency files first (better cache usage)&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package.json pnpm-lock.yaml* ./&lt;/span&gt;

&lt;span class="c"&gt;# Install 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="nt"&gt;-g&lt;/span&gt; pnpm &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pnpm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--frozen-lockfile&lt;/span&gt;

&lt;span class="c"&gt;# Copy the rest of the source code&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;# Build the NestJS project&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pnpm run build

&lt;span class="c"&gt;# Expose the app’s port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="c"&gt;# Start the app&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["pnpm", "run", "start:prod"]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Don't Forget the &lt;code&gt;.dockerignore&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Create a .dockerignore file to keep your image lean and mean by excluding unnecessary files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node_modules
dist
.git
Dockerfile
.dockerignore
.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Test It Locally First
&lt;/h3&gt;

&lt;p&gt;Before we deploy, let's build and run the container locally to make sure everything works.&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; nest-backend &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 nest-backend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Head over to &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; to verify your app is running. If it works, you're ready for deployment! ✅&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Deploying to Render
&lt;/h2&gt;

&lt;p&gt;Now that your NestJS app is Dockerized, let's get it deployed on Render. We have two options:&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A: The Simple Way (Let Render Build the Image)
&lt;/h3&gt;

&lt;p&gt;This is the &lt;strong&gt;easiest way&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push your code to GitHub/GitLab&lt;/li&gt;
&lt;li&gt;In Render Dashboard → &lt;strong&gt;New → Web Service&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Connect your repository&lt;/li&gt;
&lt;li&gt;Render will detect the &lt;code&gt;Dockerfile&lt;/code&gt; and build the image automatically&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;That's it!&lt;/strong&gt; Render will now build your Docker image from the &lt;code&gt;Dockerfile&lt;/code&gt; and deploy your app. Easy. 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: The CI/CD Way (Prebuilt Images with GitHub Actions)
&lt;/h3&gt;

&lt;p&gt;This method gives you more control and enables automatic deployments.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the Docker image locally&lt;/li&gt;
&lt;li&gt;Push it to Docker Hub&lt;/li&gt;
&lt;li&gt;Trigger Render to pull the new image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This also enables &lt;strong&gt;automatic CI/CD deployments&lt;/strong&gt; on every push.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Push to Docker Hub
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Build image&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; nest-backend &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# Tag with Docker Hub username&lt;/span&gt;
docker tag nest-backend your-username/nest-backend:latest

&lt;span class="c"&gt;# Push to Docker Hub&lt;/span&gt;
docker push your-username/nest-backend:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Render, choose Deploy an existing Docker image and use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker.io/your-username/nest-backend:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Render will fetch the latest image whenever you trigger a redeploy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📝 &lt;strong&gt;Notes on tags:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render redeploys based on the tag you specify (&lt;code&gt;latest&lt;/code&gt;, &lt;code&gt;v1.0.0&lt;/code&gt;, etc.).
&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;latest&lt;/code&gt; is simple, but versioned tags (e.g., &lt;code&gt;v1.0.0&lt;/code&gt;) are safer for production since they make rollbacks easier.
&lt;/li&gt;
&lt;li&gt;Render only fetches a new image from Docker Hub when you &lt;strong&gt;trigger a redeploy&lt;/strong&gt; (manually or via CI/CD).
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 2: Automate with GitHub Actions
&lt;/h4&gt;

&lt;p&gt;Create .github/workflows/docker-build.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;name: Build &amp;amp; Push Docker Image
on:
  push:
    branches: &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="nb"&gt;jobs&lt;/span&gt;:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Log &lt;span class="k"&gt;in &lt;/span&gt;to Docker Hub
        uses: docker/login-action@v2
        with:
          username: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.DOCKER_USERNAME &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
          password: &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.DOCKER_PASSWORD &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: &lt;span class="nb"&gt;.&lt;/span&gt;
          push: &lt;span class="nb"&gt;true
          &lt;/span&gt;tags: your-username/nest-backend:latest

      - name: Trigger Render Deploy
        run: |
          curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;{ secrets.RENDER_DEPLOY_HOOK &lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your GitHub repo → &lt;strong&gt;Settings → Secrets&lt;/strong&gt; → add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DOCKER_USERNAME&lt;/code&gt; → your Docker Hub username
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DOCKER_PASSWORD&lt;/code&gt; → your Docker Hub access token
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RENDER_DEPLOY_HOOK&lt;/code&gt; → from Render dashboard (service → settings → deploy hook URL)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now every push to &lt;code&gt;main&lt;/code&gt; will:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build the Docker image
&lt;/li&gt;
&lt;li&gt;Push it to Docker Hub
&lt;/li&gt;
&lt;li&gt;Trigger a new Render deployment
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎁 Bonus: Keep Your Render App Alive 24/7
&lt;/h2&gt;

&lt;p&gt;On Render’s free tier, your service &lt;strong&gt;goes to sleep after 15 minutes of inactivity&lt;/strong&gt; to save resources. When that happens, the next request can feel slow because the app has to “cold start.” &lt;/p&gt;

&lt;p&gt;To prevent this, you can set up a simple &lt;strong&gt;heartbeat&lt;/strong&gt; that pings your app every few minutes.  &lt;/p&gt;

&lt;p&gt;You don’t have to use Cloudflare Workers — you could also use:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://n8n.io" rel="noopener noreferrer"&gt;n8n&lt;/a&gt; (self-hosted or cloud)
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/apps-script" rel="noopener noreferrer"&gt;Google Apps Script&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Any external &lt;strong&gt;cron job service&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this tutorial, we’ll go with with &lt;strong&gt;Cloudflare Workers&lt;/strong&gt; (free tier).  &lt;/p&gt;

&lt;h3&gt;
  
  
  Create a Worker
&lt;/h3&gt;

&lt;p&gt;Install &lt;a href="https://developers.cloudflare.com/workers/wrangler/install-and-update/" rel="noopener noreferrer"&gt;Wrangler&lt;/a&gt;, Cloudflare’s CLI.&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; &lt;span class="nt"&gt;-g&lt;/span&gt; wrangler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate a new worker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wrangler init keep-alive-worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure the Worker
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;wrangler.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"keep-alive-worker"&lt;/span&gt;
&lt;span class="py"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"src/index.ts"&lt;/span&gt;
&lt;span class="py"&gt;compatibility_date&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2025-09-13"&lt;/span&gt;

&lt;span class="c"&gt;# Add this&lt;/span&gt;
&lt;span class="nn"&gt;[triggers]&lt;/span&gt;
&lt;span class="py"&gt;crons&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"*/15 * * * *"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c"&gt;# (Optional) to enable logs for worker&lt;/span&gt;
&lt;span class="nn"&gt;[observability.logs]&lt;/span&gt;
&lt;span class="py"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Worker Code
&lt;/h3&gt;

&lt;p&gt;In &lt;code&gt;src/index.ts&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;const SERVICES &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="s1"&gt;'https://your-app-name.onrender.com'&lt;/span&gt;, // Your app&lt;span class="s1"&gt;'s URL
  // Add more services here if needed!
];

export default {
  async scheduled(event, env, ctx) {
    for (const url of SERVICES) {
      try {
        const res = await fetch(url);
        console.log(`✅ Pinged ${url} → ${res.status}`);
      } catch (err) {
        console.error(`❌ Failed to ping ${url}`, err);
      }
    }
  },
};
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy the Worker
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wrangler deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! 🎉 Your Cloudflare Worker will automatically ping your Render app(s) every 15 minutes, keeping them awake and responsive.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>nestjs</category>
      <category>docker</category>
      <category>render</category>
    </item>
    <item>
      <title>Deploying Next.js App to Cloudflare Workers with OpenNext</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sun, 31 Aug 2025 16:57:44 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/deploying-nextjs-app-to-cloudflare-workers-with-opennext-hi0</link>
      <guid>https://dev.to/prajwolshrestha/deploying-nextjs-app-to-cloudflare-workers-with-opennext-hi0</guid>
      <description>&lt;p&gt;If you’ve ever tried deploying a Next.js app to Cloudflare Workers, you’ve probably noticed a gap: Next.js expects Node.js APIs, while Workers traditionally run in a restricted edge runtime.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://opennext.js.org/" rel="noopener noreferrer"&gt;OpenNext&lt;/a&gt;. With the &lt;code&gt;@opennextjs/cloudflare&lt;/code&gt; adapter, you can run your Next.js app on Workers using the &lt;strong&gt;Node.js runtime&lt;/strong&gt;, giving you access to many familiar Node APIs — something &lt;code&gt;@cloudflare/next-on-pages&lt;/code&gt; can’t provide.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll walk through deploying a Next.js app to Cloudflare Workers using OpenNext, step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚖️ Edge Runtime vs Node.js Runtime
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Edge Runtime&lt;/strong&gt; (&lt;code&gt;@cloudflare/next-on-pages&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Node.js Runtime&lt;/strong&gt; (&lt;code&gt;@opennextjs/cloudflare&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed / Weight&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Super fast, lightweight&lt;/td&gt;
&lt;td&gt;Fast, slightly heavier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Next.js Features&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited; some features won’t work&lt;/td&gt;
&lt;td&gt;Most features supported (SSR, ISR, middleware, streaming)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js APIs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Very restricted&lt;/td&gt;
&lt;td&gt;Many supported via Workers’ Node.js compatibility&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Use Node.js runtime if you need full Next.js features and Node API support; Edge runtime is great for ultra-lightweight functions.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Let’s Dive In: Creating or Using a Next.js App
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Start a new Next.js app preconfigured for Workers
&lt;/h3&gt;

&lt;p&gt;If you’re creating a new project, OpenNext can scaffold everything for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create cloudflare@latest &lt;span class="nt"&gt;--&lt;/span&gt; my-next-app &lt;span class="nt"&gt;--framework&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;next &lt;span class="nt"&gt;--platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;workers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Use with an Existing Next.js App
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Install the Cloudflare Adapter
&lt;/h4&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; &lt;span class="nt"&gt;-D&lt;/span&gt; @opennextjs/cloudflare wrangler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2: Create &lt;code&gt;wrangler.jsonc&lt;/code&gt; (optional)
&lt;/h4&gt;

&lt;p&gt;This file will be auto-generated if not present during build. The nodejs_compat flag enables Node.js APIs in Cloudflare Workers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node_modules/wrangler/config-schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".open-next/worker.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"demo-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compatibility_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-08-31"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compatibility_flags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"nodejs_compat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"global_fetch_strictly_public"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;".open-next/assets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"binding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ASSETS"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"binding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WORKER_SELF_REFERENCE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"demo-app"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Create &lt;code&gt;open-next.config.ts&lt;/code&gt; (optional)
&lt;/h4&gt;

&lt;p&gt;This file will also be auto-generated if not present during build. The R2 incremental cache is optional and requires R2 enabled on your Cloudflare account.&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;defineCloudflareConfig&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="s2"&gt;@opennextjs/cloudflare&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="nx"&gt;r2IncrementalCache&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache&lt;/span&gt;&lt;span class="dl"&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="nf"&gt;defineCloudflareConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;incrementalCache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;r2IncrementalCache&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;
  
  
  Step 4: Update &lt;code&gt;package.json&lt;/code&gt; Scripts
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dev"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next dev"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preview"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"opennextjs-cloudflare build &amp;amp;&amp;amp; opennextjs-cloudflare preview"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"opennextjs-cloudflare build &amp;amp;&amp;amp; opennextjs-cloudflare deploy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"opennextjs-cloudflare build &amp;amp;&amp;amp; opennextjs-cloudflare upload"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cf-typegen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 5: Remove &lt;code&gt;export const runtime = "edge";&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Edge runtime is &lt;strong&gt;not supported&lt;/strong&gt; with &lt;code&gt;@opennextjs/cloudflare&lt;/code&gt;. Make sure to remove this line from any of your source files before deploying.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This ensures your app runs in the Node.js runtime, which is fully compatible with OpenNext and Cloudflare Workers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 6: Update &lt;code&gt;.gitignore&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Add &lt;code&gt;.open-next&lt;/code&gt; to your &lt;code&gt;.gitignore&lt;/code&gt; file to prevent the build output from being committed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 7: Add Static Asset Caching
&lt;/h4&gt;

&lt;p&gt;Create a &lt;code&gt;public/_headers&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/_next/static/*
 Cache-Control: public,max-age=31536000,immutable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This ensures that your static assets (JS, CSS) are cached for one year, improving performance for repeat visitors.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 8: Preview and Deploy
&lt;/h4&gt;

&lt;p&gt;Preview your app locally first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run preview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then deploy to Cloudflare Workers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  ⚠️ Next.js Version &amp;amp; Known Issues
&lt;/h3&gt;

&lt;p&gt;If you run into errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NextJS request failed. Error: An error occurred while loading the instrumentation hook
at NextNodeServer.loadInstrumentationModule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This is a known issue (&lt;a href="https://github.com/opennextjs/opennextjs-cloudflare/issues/667" rel="noopener noreferrer"&gt;GitHub #667&lt;/a&gt;).&lt;br&gt;
The workaround is to &lt;strong&gt;downgrade your Next.js version to 15.3&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Other known issues and limitations with OpenNext on Cloudflare Workers can be found here:&lt;br&gt;
&lt;a href="https://opennext.js.org/cloudflare/known-issues" rel="noopener noreferrer"&gt;OpenNext Cloudflare Known Issues&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>nextjs</category>
      <category>cloudfare</category>
    </item>
    <item>
      <title>Enhancing Your Development Workflow with Husky, Commitlint, Prettier, and Lint-Staged</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Tue, 29 Oct 2024 10:21:34 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/enhancing-your-development-workflow-with-husky-commitlint-prettier-and-lint-staged-n81</link>
      <guid>https://dev.to/prajwolshrestha/enhancing-your-development-workflow-with-husky-commitlint-prettier-and-lint-staged-n81</guid>
      <description>&lt;p&gt;Setting up an automated workflow can greatly enhance code quality and consistency in your projects. In this guide, we’ll walk through setting up Husky, Commitlint, Prettier, and Lint-Staged to ensure your codebase is consistently formatted, follows commit message conventions, and has up-to-date dependencies after each merge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Husky
&lt;/h2&gt;

&lt;p&gt;Husky helps you manage Git hooks effortlessly, allowing for automated tasks like code quality checks to run before every commit.&lt;/p&gt;

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

&lt;p&gt;Install Husky as a dev dependency using npm (we will be using npm in this article):&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; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; husky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Initialization
&lt;/h3&gt;

&lt;p&gt;To create a .husky directory where Git hooks will be stored, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, add the following script in your package.json to set up Husky when installing dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prepare"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"husky install"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuring Commitlint
&lt;/h2&gt;

&lt;p&gt;Commitlint ensures that all commit messages follow a consistent format, maintaining a clean commit history.&lt;/p&gt;

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

&lt;p&gt;Install Commitlint along with a conventional config:&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; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; @commitlint/config-conventional @commitlint/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ol&gt;
&lt;li&gt;Create a commit-msg hook in .husky:
Now create a new file in .husky directory named commit-msg and add this line:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky add .husky/commit-msg &lt;span class="s2"&gt;"npx --no-install commitlint --edit &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Add a commitlint.config.js file to the root of your project with the following content:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;module.exports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;extends:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'@commitlint/config-conventional'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;rules:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;TODO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Scope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Here&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'scope-enum':&lt;/span&gt;&lt;span class="w"&gt; &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="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'always'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;'yourscope'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'yourscope'&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;'type-enum':&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;'always'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'feat'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'fix'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'docs'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'chore'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'style'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'refactor'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'ci'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'test'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'revert'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'perf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;'vercel'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding Lint-Staged and Prettier
&lt;/h2&gt;

&lt;p&gt;Lint-Staged allows you to run scripts on staged files, and Prettier enforces a consistent style in your codebase.&lt;/p&gt;

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

&lt;p&gt;Install both as dev dependencies:&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; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; lint-staged prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Prettier Configuration
&lt;/h3&gt;

&lt;p&gt;Create a .prettierrc.json file in your project root with your preferred configuration. Here’s an example:&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="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"plugins"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"prettier-plugin-tailwindcss"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;,
  &lt;span class="s2"&gt;"printWidth"&lt;/span&gt;: 120,
  &lt;span class="s2"&gt;"useTabs"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
  &lt;span class="s2"&gt;"tabWidth"&lt;/span&gt;: 2,
  &lt;span class="s2"&gt;"trailingComma"&lt;/span&gt;: &lt;span class="s2"&gt;"es5"&lt;/span&gt;, 
  &lt;span class="s2"&gt;"semi"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;, 
  &lt;span class="s2"&gt;"singleQuote"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;,
  &lt;span class="s2"&gt;"bracketSpacing"&lt;/span&gt;: &lt;span class="nb"&gt;true&lt;/span&gt;, 
  &lt;span class="s2"&gt;"arrowParens"&lt;/span&gt;: &lt;span class="s2"&gt;"always"&lt;/span&gt;,
  &lt;span class="s2"&gt;"jsxSingleQuote"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;, 
  &lt;span class="s2"&gt;"bracketSameLine"&lt;/span&gt;: &lt;span class="nb"&gt;false&lt;/span&gt;,
  &lt;span class="s2"&gt;"endOfLine"&lt;/span&gt;: &lt;span class="s2"&gt;"lf"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lint-Staged Configuration
&lt;/h3&gt;

&lt;p&gt;Add the following configuration to your package.json under lint-staged:&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="s2"&gt;"lint-staged"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"**/*.{js,jsx,ts,tsx}"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"eslint --max-warnings=0"&lt;/span&gt;,
      &lt;span class="s2"&gt;"prettier --write"&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;,
    &lt;span class="s2"&gt;"**/*.{html,json,css,scss,md,mdx}"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
      &lt;span class="s2"&gt;"prettier -w"&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a pre-commit hook to run Lint-Staged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky add .husky/pre-commit &lt;span class="s2"&gt;"npx lint-staged"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding a Post-Merge Hook for Dependencies
&lt;/h2&gt;

&lt;p&gt;A post-merge hook ensures that your dependencies are updated after each merge by running npm install or any package manager.&lt;/p&gt;

&lt;p&gt;Create a post-merge hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky add .husky/post-merge &lt;span class="s2"&gt;"npm install"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;With this setup, your project will maintain a standardized commit message format, automatically format code, and keep dependencies up-to-date post-merge. This robust workflow will streamline collaboration and improve code quality, helping you focus on building great features.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>husky</category>
      <category>git</category>
      <category>javascript</category>
    </item>
    <item>
      <title>8 Most Common Type Of Cyber Attacks</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sat, 13 Nov 2021 14:43:43 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/8-most-common-type-of-cyber-attacks-2be5</link>
      <guid>https://dev.to/prajwolshrestha/8-most-common-type-of-cyber-attacks-2be5</guid>
      <description>&lt;p&gt;Before learning about types of cyber attacks, you must know what a cyber attack is. Basically, it is an attack performed by a group or an individual to gain unauthorized access to a system with the intent to harm the victim.&lt;/p&gt;

&lt;p&gt;In this article, we will briefly learn about some of the most common types of cyber attacks  and how to protect yourself from them.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Phishing:
&lt;/h3&gt;

&lt;p&gt;Phishing involves sending emails that appear to be from trusted sources. The goal is to make the victim click on the link and trick them into giving their login credentials or spreading malware.&lt;/p&gt;

&lt;p&gt;Spear phishing is carried out in the same way, except it is more focused on particular people. The attacker has to do some research on the victim before sending them the malicious link. For example, with a little research an attacker can find your friend’s email and send you the malicious link which might appear to be a legitimate email from your friend. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Protect yourself:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Think before you click.&lt;/li&gt;
&lt;li&gt;Verify a site’s security.&lt;/li&gt;
&lt;li&gt;Never give out personal information.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Password Attack &amp;amp; Credential Reuse:
&lt;/h3&gt;

&lt;p&gt;The attacker will use an array of password hacking techniques. The attacker might use a list of common ‘weak’ passwords, to sophisticated ‘Rainbow table’ attacks using previously hacked/cracked passwords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to protect yourself:&lt;/strong&gt;&lt;br&gt;
*Use a strong password.&lt;br&gt;
*Don’t use the same password on different platforms.&lt;br&gt;
*Use two-factor authentication (2FA).&lt;/p&gt;

&lt;h3&gt;
  
  
  3. DOS and DDOS:
&lt;/h3&gt;

&lt;p&gt;It stands for Denial Of Service and Distributed Denial Of Service respectively. The difference between them is that DOS is an attack mode between a single machine and a single machine, whereas a DDOS attack is a large-scale attack mode based on DOS. DDOS uses a group of controlled computers (Botnets) to attack a host. &lt;br&gt;
The idea of both these attacks is to send a high volume of data or traffic through a network that is making a lot of connection requests until the server becomes overloaded and can no longer function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to prevent DDOS attacks:&lt;/strong&gt;&lt;br&gt;
*Protect your DNS Servers.&lt;br&gt;
*Configure your network hardware against DDOS attacks.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Drive-By Downloads:
&lt;/h3&gt;

&lt;p&gt;Unlike other cyber attacks, you don’t have to open an email attachment or download anything. You will get infected simply by viewing an email or by visiting a website that will automatically download malware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to protect yourself:&lt;/strong&gt;&lt;br&gt;
*Keep your OS and browsers updated.&lt;br&gt;
*Only keep the programs you need, the more plug-ins you have, the more vulnerable you are.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Man In The Middle(MitM):
&lt;/h3&gt;

&lt;p&gt;The hacker places himself between two communicating hosts and listens to their information. &lt;br&gt;
This attack is similar to the Eavesdropping attack but is much more dangerous. The attacker can not only listen to their information but can also impersonate one of them or change the context of the information being sent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Protect Yourself:&lt;/strong&gt;&lt;br&gt;
*Make sure you use SSL certificates (HTTPS, not just HTTP) to enhance security.&lt;br&gt;
*Use VPN to enhance security when using untrusted networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Malvertising:
&lt;/h3&gt;

&lt;p&gt;This attack will compromise your system with malicious code that is automatically downloaded to your system when you click on an infected advertisement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to protect yourself:&lt;/strong&gt;&lt;br&gt;
*Don’t click on advertisements just because they look appealing.&lt;br&gt;
*Keep your OS, browsers, and plug-in updated.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. SQL Injection:
&lt;/h3&gt;

&lt;p&gt;It stands for Structured Query Language Injection. The attacker inserts malicious SQL code into the website’s search box or input box. Once the code has been deployed, it might delete or modify data on the database and even copy the whole database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to protect yourself:&lt;/strong&gt;&lt;br&gt;
*Use input validation on input fields.&lt;br&gt;
*Update and patch your software and database.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Zero-Day Exploit:
&lt;/h3&gt;

&lt;p&gt;A Zero-Day exploit is an attack that occurs on the same day a weakness is discovered on software. This type of attack is usually hard to defend against since the precise nature of the attack is only known after it has happened. When a person discovers a vulnerability on software instead of directly reporting to the creators of the software, he decides to share this vulnerability on the internet. The hackers then exploit this vulnerability before the creators of the software could patch the vulnerability. &lt;br&gt;
&lt;strong&gt;How to protect yourself:&lt;/strong&gt;&lt;br&gt;
*Keep your OS and software up-to-date.&lt;br&gt;
*Only use SSL certified websites.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>beginners</category>
      <category>security</category>
      <category>todayilearned</category>
    </item>
    <item>
      <title>How cookies track you around the Internet</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Sat, 06 Nov 2021 12:31:34 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/how-cookies-track-you-around-the-internet-11nj</link>
      <guid>https://dev.to/prajwolshrestha/how-cookies-track-you-around-the-internet-11nj</guid>
      <description>&lt;h2&gt;
  
  
  What are cookies?
&lt;/h2&gt;

&lt;p&gt;Cookies are small text files that a website stores in your browser. Cookies are utilized to recall things about sites: your login data, what you have in your shopping basket, what language you prefer. They are generated by websites and remain in your browser until they expire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Different Types of Cookies
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Cookies are classified based on their different characteristics:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Based on their function,&lt;/strong&gt; cookies are divided as necessary and unnecessary. The necessary cookies are crucial for the functioning of a website, and the unnecessary cookies are the ones that are added additionally by the website and are not so crucial for the functioning of the website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Based on their source,&lt;/strong&gt; cookies are divided into first-party and third-party cookies. First-party cookies are set by the site that the user is visiting presently, say, to check whether or not the user is logged in. Whereas third-party cookies are set by other websites that track the user for showing related advertisements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Based on their span,&lt;/strong&gt; cookies are classified as persistent and session cookies. Session cookies are set when the user begins a session and are temporary cookies. They terminate once the browser is closed and the session ends. Whereas Persistent cookies stay on the user’s browser for a long period and expire when they reach their expiration period.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Can cookies track you around the internet?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Yes, cookies can be used to invade your privacy and track you around the internet.&lt;/strong&gt; Most browsers only allow websites to store a maximum of 300 cookies and they cannot store a lot of data. Cookies set by one website cannot be accessed by that other site. And that raises a question, How can cookies be used to track us around the internet, especially if cookies from one website cannot be accessed by another? For instance, How can Facebook track what website we visit?&lt;/p&gt;

&lt;p&gt;The whole process starts when you log into Facebook, to remember that you are logged in Facebook, it stores a cookie on your browser, many other websites do the same thing. This cookie is bound to the Facebook domain name, meaning that nobody else besides facebook.com can read what’s inside the cookie. Let’s now assume, you are visiting another website, this website cannot access Facebook cookies and vice versa. But let’s assume that the owner of another website places a Facebook like button on his website, to show this like button your browser has to download some content from the Facebook servers. And when it’s talking to Facebook.com, it sends along with the cookie that Facebook had stored in your browser. Facebook now knows who you are and that you visited this site.&lt;/p&gt;

&lt;p&gt;Many other companies also use this technique to track you around the internet. The trick is easy, convince as many as websites to place some of your code in their websites.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can you do to prevent cookies from tracking you?
&lt;/h2&gt;

&lt;p&gt;You can prevent cookies from tracking you by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using browser extensions like Privacy Badger, Ghostery, etc.&lt;/li&gt;
&lt;li&gt;Switching to a browser that has built-in privacy protection tools like Brave or safari.&lt;/li&gt;
&lt;li&gt;Enable Do Not Track (DNT) on browsers. Even though not all websites respect the DNT setting, it is one feature that users can use.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>todayilearned</category>
      <category>beginners</category>
      <category>information</category>
    </item>
    <item>
      <title>Python Projects For Beginners</title>
      <dc:creator>Prajwol Shrestha</dc:creator>
      <pubDate>Fri, 05 Nov 2021 05:34:56 +0000</pubDate>
      <link>https://dev.to/prajwolshrestha/python-projects-for-beginners-34nc</link>
      <guid>https://dev.to/prajwolshrestha/python-projects-for-beginners-34nc</guid>
      <description>&lt;p&gt;So, You have just finished learning Python and looking to get your hands on some easy yet interesting projects.  Then this article is for you.  In this article, I have listed some interesting projects that you might want to try.  If you are confused about how to create the program you can refer to my GitHub profile and get some ideas given below each respective projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Mad Libs:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This program is actually quite easy to create. It is a program based on the traditional Mad Libs game. The user is asked by the program to input some words. The program then takes those words and inserts them into paragraphs that are predefined in the program. When the execution is finished, the program displays the recreated paragraph with some words replaced by the user-given phrases at random places. &lt;br&gt;
You can make this more interesting by importing a CSV file that contains a number of paragraphs and code the program to select a random paragraph each time the program executes. OR you can even code your program to replace the word in random places by making use of the random module and string indexing.&lt;br&gt;
GitHub: &lt;a href="https://github.com/Prajwol-Shrestha/Mad_libs" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/Mad_libs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Number Guessing:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As the name suggests, this program is quite easy to code. Let me explain this program structure simple way. Generate a random number, ask the user for a number, check if the number matches, and finally display the result. &lt;br&gt;
But creating a program to do only this much seems quite boring, right? So to make this more interesting you can make this program a point and attempt-based program. Simply put,  You are giving the user a certain amount of attempts to try and guess the number, If the user guesses the correct number he/she gets a point, and if the user guesses the incorrect number he/she gets a point deducted. You can also give the user hints like mathematical equations but adding this feature seems quite complicated for a beginner's program.&lt;br&gt;
GitHub: &lt;a href="https://github.com/Prajwol-Shrestha/Number_guessing" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/Number_guessing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Email Slicer:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As the name states, this program slices the email address. Simply put, This program actually separates the part of the email address. For This program, we will ask the user to input an email address. Then we will take that email address and separate it at the '@' symbol. That's it! and we have successfully separated the email address and extracted the hostname and username from the given email address.&lt;br&gt;
For example, say we have a dummy email address (&lt;a href="mailto:ABC@gmail.com"&gt;ABC@gmail.com&lt;/a&gt;) when we feed this email address into the program, the program will slice the email address at the ‘@’ symbol and display the Username as ABC and the domain name or hostname as gmail.com. &lt;br&gt;
GitHub:&lt;a href="https://github.com/Prajwol-Shrestha/Email_slicer" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/Email_slicer&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Rock, paper, and scissor:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We all are familiar with traditional rock, paper, and scissor game.&lt;br&gt;
Simply put, You have to code your program to display one of these options when you input your option, Check who wins or if it is a draw and display the result.  You can make this game more interesting by making it the best out of three or giving the user a prompt to have a rematch after the game ends. &lt;br&gt;
You can make use of the random module to randomly generate a number and assign them to a single choice(rock, paper, or scissor). Then, Each time the program executes the computer will throw up a different choice. You will have to compare the choice given by the user and the computer to determine the results. &lt;br&gt;
GitHub:&lt;a href="https://github.com/Prajwol-Shrestha/rock_paper_scissor" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/rock_paper_scissor&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Dice rolling simulator:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This program is actually the easiest one among all the programs listed here. simulates the rolling of a dice. You just have to generate a random number between 1 to 6 (as on a standard dice) each time the program executes. With each execution, a random number is generated and displayed to the user. You can also ask if the user wants to roll the dice again without terminating the program.&lt;br&gt;
GitHub: &lt;a href="https://github.com/Prajwol-Shrestha/dice_rolling_simulator" rel="noopener noreferrer"&gt;https://github.com/Prajwol-Shrestha/dice_rolling_simulator&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Hangman:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is probably the hardest one among the above 5 programs. It is quite similar to guessing the number program except for the user having to guess the letters. The user has to guess the letter in a word for the given number of blank spaces. Give the users a certain number of attempts, if the user guesses the correct letter then the user gets a point and vice-versa. Also when the guess is correct the program should print the result and ask for the next letter in the word. You can create your own wordlist and select a random word each time the program executes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. YouTube Video downloader:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is one of the best projects for beginners to develop his/her skills in python programming. Everybody uses YouTube, there are many cases where we want to download some of those videos on our device permanently, but YouTube doesn’t provide those options to us. So, All you have to do is create your own YouTube video downloader. It may sound tedious, but with python, it is fairly easy to do so. To build this program you will need to install a third-party module named pytube which allows us to download YouTube videos. By implementing this module we can easily build our own YouTube video downloader. &lt;br&gt;
GitHub:&lt;a href="https://github.com/PrajwolShrestha/Youtube_video_downloader" rel="noopener noreferrer"&gt;https://github.com/PrajwolShrestha/Youtube_video_downloader&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>python</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
