<?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: Biswadeep Mazumder</title>
    <description>The latest articles on DEV Community by Biswadeep Mazumder (@biswadeep_mazumder).</description>
    <link>https://dev.to/biswadeep_mazumder</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4028914%2F6ec266bf-7687-4948-a8a3-ec5eb18a7f94.png</url>
      <title>DEV Community: Biswadeep Mazumder</title>
      <link>https://dev.to/biswadeep_mazumder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/biswadeep_mazumder"/>
    <language>en</language>
    <item>
      <title>I self-hosted n8n for basically free (like, $1.54 total)</title>
      <dc:creator>Biswadeep Mazumder</dc:creator>
      <pubDate>Wed, 15 Jul 2026 03:40:03 +0000</pubDate>
      <link>https://dev.to/biswadeep_mazumder/i-self-hosted-n8n-for-basically-free-like-154-total-1h66</link>
      <guid>https://dev.to/biswadeep_mazumder/i-self-hosted-n8n-for-basically-free-like-154-total-1h66</guid>
      <description>&lt;p&gt;If you've been paying for n8n Cloud every month, or you've been avoiding automation because hosting sounded complicated or expensive, this might save you some money.&lt;/p&gt;

&lt;p&gt;You can run your own fully functional n8n instance with a real public HTTPS domain for just &lt;strong&gt;$1.54&lt;/strong&gt; a year.&lt;/p&gt;

&lt;p&gt;Yep, a year—not per month. The only thing you need to pay for is the domain. Everything else is completely free. No subscriptions, no hidden costs.&lt;/p&gt;

&lt;p&gt;One &lt;strong&gt;honest downside&lt;/strong&gt; though — this isn't a cloud server, it's literally running off my laptop. So if my laptop's off, n8n's off too. If you need 24/7 uptime this probably isn't for you.&lt;/p&gt;

&lt;p&gt;Anyway here's how I did it, in three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get n8n running locally with Docker (free)&lt;/li&gt;
&lt;li&gt;Grab a cheap domain and hook it up to Cloudflare&lt;/li&gt;
&lt;li&gt;Expose the local n8n instance to the internet with a Cloudflare Tunnel so webhooks (Telegram, WhatsApp, Google, whatever) can actually reach it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Running it locally with Docker
&lt;/h2&gt;

&lt;p&gt;Whole point of this step is just to get n8n working on your own machine first, no money involved yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Docker Desktop
&lt;/h3&gt;

&lt;p&gt;Grab it from docker.com, whatever OS you're on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy the n8n Self-Hosted AI Starter Kit
&lt;/h3&gt;

&lt;p&gt;Rather than installing n8n on its own, I just used the official n8n-io/self-hosted-ai-starter-kit repo on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhr24jua9kk2qp2l6ajzj.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhr24jua9kk2qp2l6ajzj.png" alt="example Commands for For Nvidia GPU users" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the command matching your setup (CPU only vs Nvidia GPU etc, it's in the README) and copy the command.&lt;/li&gt;
&lt;li&gt;Open the terminal &lt;strong&gt;as Administrator&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste the first 3 command copied from there.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then you would need to edit the .env file before running the last command.&lt;/p&gt;

&lt;p&gt;I'm in Windows so i did "code .env" to open the file, for Linux/MacOS maybe try nano or vim.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After opening replace the default values for &lt;strong&gt;N8N_ENCRYPTION_KEY&lt;/strong&gt; and &lt;strong&gt;N8N_USER_MANAGEMENT_JWT_SECRET&lt;/strong&gt; to any random long string. Doesn't matter much.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then finally paste the last command (i.e, docker compose --profile gpu-nvidia up -&amp;gt; for Nvidia GPU people)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That one command pulls 4 containers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Container&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;n8n&lt;/td&gt;
&lt;td&gt;the actual workflow builder / UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ollama&lt;/td&gt;
&lt;td&gt;runs LLMs locally, uses your CPU/GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Qdrant&lt;/td&gt;
&lt;td&gt;vector db, basically memory for AI agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;the database storing all your workflows/data&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Open it up
&lt;/h3&gt;

&lt;p&gt;Once it's running, open the app docker and turn on the self-hosted-ai-starter-kit and when you see green light go to the URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:5678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you should see the n8n editor pop up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9bqridgme040krkk55b.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fe9bqridgme040krkk55b.png" alt="screenshot: n8n running locally" width="799" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The problem
&lt;/h3&gt;

&lt;p&gt;Ok so here's where it gets annoying. Everything works great as long as you're on your own machine. But try hooking up a webhook trigger — Telegram, WhatsApp, whatever — and it just doesn't work. Because the webhook URL is still &lt;code&gt;localhost:5678&lt;/code&gt;, which is a private address only your PC can see. Telegram's servers have literally no way to reach that.&lt;/p&gt;

&lt;p&gt;That's what part 2 and 3 are for.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Getting a domain + Cloudflare
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Buy a cheap domain
&lt;/h3&gt;

&lt;p&gt;You really don't need to spend much here. I used Porkbun — cheapest first-year pricing I could find. Got &lt;code&gt;biswadeep.lol&lt;/code&gt; for $1.54.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzzag1rsqawf2ttr3sbrv.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzzag1rsqawf2ttr3sbrv.png" alt="screenshot: porkbun orders" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick heads up
&lt;/h3&gt;

&lt;p&gt;Before you fully connect things — in Porkbun and set up your basic DNS records (A record, CNAME etc) if you haven't already, and do it BEFORE switching the nameservers over. Makes the whole transition way less painful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add it to Cloudflare
&lt;/h3&gt;

&lt;p&gt;Log into your Cloudflare dashboard.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Domains overview page&lt;/li&gt;
&lt;li&gt;Add a domain&lt;/li&gt;
&lt;li&gt;Connect your domain, type it in, leave defaults as it is and press Continue&lt;/li&gt;
&lt;li&gt;Pick the Free plan&lt;/li&gt;
&lt;li&gt;Continue to Activation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cloudflare scans for any existing DNS records automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Point your nameservers to Cloudflare
&lt;/h3&gt;

&lt;p&gt;Cloudflare gives you two nameservers, unique to your domain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkc5ezuqoxzrejhg8bkpo.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkc5ezuqoxzrejhg8bkpo.png" alt="cloudflare two nameservers" width="799" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Back in Porkbun, go to NS settings&lt;/li&gt;
&lt;li&gt;Delete the default Porkbun nameservers&lt;/li&gt;
&lt;li&gt;Paste in the two from Cloudflare&lt;/li&gt;
&lt;li&gt;Save&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then Return back to Cloudflare and hit "I updated my nameserves".&lt;/p&gt;

&lt;p&gt;Propagation takes anywhere from a few mins to a couple hours (mine took like 10 min). Once it's done, check Domains → Overview in Cloudflare, should say "Active."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmnbzky0fv51rutf54675.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmnbzky0fv51rutf54675.png" alt="screenshot: cloudflare showing active status" width="800" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Don't move on to part 3 until you see that Active status, otherwise you're just gonna confuse yourself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: The Cloudflare Tunnel (this is the part that actually makes it work)
&lt;/h2&gt;

&lt;p&gt;This is the bit that lets outside services actually talk to your local n8n, without you having to open sketchy ports on your router.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the tunnel
&lt;/h3&gt;

&lt;p&gt;In Cloudflare: Networking → Tunnels → Create a tunnel. Name it whatever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install the connector
&lt;/h3&gt;

&lt;p&gt;Cloudflare gives you an installer command based on your OS. Run it, follow whatever it says. Once it connects you'll see the tunnel status go "Healthy."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxx7j730esgdv9ninribp.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxx7j730esgdv9ninribp.png" alt="screenshot: healthy tunnel status" width="799" height="239"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set the public hostname
&lt;/h3&gt;

&lt;p&gt;Inside the tunnel settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Routes → Add Route&lt;/li&gt;
&lt;li&gt;Published application&lt;/li&gt;
&lt;li&gt;Set your subdomain, like &lt;code&gt;n8n.yourdomain.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Service URL = &lt;code&gt;http://localhost:5678&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5972uuvyg1su84zfqng.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5972uuvyg1su84zfqng.png" alt="screenshot: route config screen" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's basically it — n8n.yourdomain.com now points straight at your localhost:5678 behind the scenes. Same app, just two doors into it.&lt;/p&gt;

&lt;p&gt;One thing to remember: your n8n container actually has to be running for the domain to load. Obvious in hindsight but I forgot this like twice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix the webhook URLs (important, don't skip)
&lt;/h3&gt;

&lt;p&gt;Here's the annoying part — even though you can now reach n8n from your phone or wherever, if you open a Webhook Trigger node it STILL shows a broken &lt;code&gt;localhost:5678&lt;/code&gt; url. Google OAuth, Telegram, none of them can do anything with that.&lt;/p&gt;

&lt;p&gt;Fix: open the docker-compose.yml in your project folder (self-hosted-ai-starter-kit) and add these two lines to the n8n service:&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="s"&gt;WEBHOOK_URL=https://n8n.yourdomain.com/&lt;/span&gt;
&lt;span class="s"&gt;N8N_PROTOCOL=https&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example (My Setup):&lt;br&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmlgldsy36v5o6tj1tys1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmlgldsy36v5o6tj1tys1.png" alt="screenshot: docker-compose.yml with the env vars added" width="507" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Restart everything
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;self-hosted-ai-starter-kit
docker compose down
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b743ru37afa05mucs16.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7b743ru37afa05mucs16.png" alt="screenshot: terminal running down/up" width="800" height="188"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: when you run &lt;code&gt;docker compose down&lt;/code&gt; you might get a warning that some resource is still in use — don't panic, just run &lt;code&gt;up -d&lt;/code&gt; right after and it sorts itself out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check it worked
&lt;/h3&gt;

&lt;p&gt;Open the &lt;code&gt;https://n8n.yourdomain.com/&lt;/code&gt;, click into any webhook node, and you should now see your actual domain instead of localhost.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgnrpxb5e5ys8oq1f16i.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcgnrpxb5e5ys8oq1f16i.jpg" alt="screenshot: webhook node showing public url" width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you're here — Google OAuth redirects, Telegram bots, WhatsApp triggers, all of it just works, because there's finally a real HTTPS address for the outside world to hit.&lt;/p&gt;




&lt;h2&gt;
  
  
  What it actually cost me
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Thing&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Docker Desktop&lt;/td&gt;
&lt;td&gt;free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;n8n / Ollama / Qdrant / Postgres&lt;/td&gt;
&lt;td&gt;free, open source&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloudflare (tunnel + proxy)&lt;/td&gt;
&lt;td&gt;free tier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain (porkbun, yr 1)&lt;/td&gt;
&lt;td&gt;$1.54&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$1.54&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  That's pretty much it
&lt;/h2&gt;

&lt;p&gt;Private, fully self-hosted n8n, local AI models, a vector db, a real database, and an actual public HTTPS domain that webhooks can hit — all for the price of a domain name. Only catch is it's tied to my laptop being on, which I'm fine with for now.&lt;/p&gt;

&lt;p&gt;If you run into issues setting this up, drop a comment and I'll try to help sort it out.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>docker</category>
      <category>tutorial</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
