<?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>Forem: Ashab Hussan</title>
    <description>The latest articles on Forem by Ashab Hussan (@ashabhussan).</description>
    <link>https://forem.com/ashabhussan</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%2F3804594%2F2585803e-e910-4f6a-8831-4286d0812751.png</url>
      <title>Forem: Ashab Hussan</title>
      <link>https://forem.com/ashabhussan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ashabhussan"/>
    <language>en</language>
    <item>
      <title>How I Use Cloudflare Tunnel for Local Webhooks</title>
      <dc:creator>Ashab Hussan</dc:creator>
      <pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate>
      <link>https://forem.com/ashabhussan/how-i-use-cloudflare-tunnel-for-local-webhooks-3c45</link>
      <guid>https://forem.com/ashabhussan/how-i-use-cloudflare-tunnel-for-local-webhooks-3c45</guid>
      <description>&lt;p&gt;While working with third-party services like Stripe, Paddle, or Qstash, I constantly deal with webhooks hitting my local machine during development.&lt;/p&gt;

&lt;p&gt;For a long time, I used tools like ngrok. They work — but the problem is always the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Restart the tunnel → get a new URL → update webhook configs in every service dashboard again.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That gets old fast, especially when multiple services depend on the same endpoint.&lt;/p&gt;

&lt;p&gt;I switched to &lt;a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/" rel="noopener noreferrer"&gt;Cloudflare Tunnel&lt;/a&gt;, and it completely solved this problem. Now I have stable, HTTPS webhook URLs pointing to my local machine — no restarts, no reconfiguration, no URL rotation.&lt;/p&gt;

&lt;p&gt;This post explains exactly how I set it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cloudflare Tunnel Over ngrok?
&lt;/h2&gt;

&lt;p&gt;Both tools create a tunnel from the internet to your local machine. The difference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ngrok (free tier)&lt;/th&gt;
&lt;th&gt;Cloudflare Tunnel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stable URLs&lt;/td&gt;
&lt;td&gt;No — new URL on every restart&lt;/td&gt;
&lt;td&gt;Yes — permanent subdomains&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom domains&lt;/td&gt;
&lt;td&gt;Paid plans only&lt;/td&gt;
&lt;td&gt;Free (if domain is on Cloudflare)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (auto-provisioned)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple services&lt;/td&gt;
&lt;td&gt;One tunnel per agent&lt;/td&gt;
&lt;td&gt;Multiple hostnames in one tunnel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free tier is limited&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The killer feature for me: &lt;strong&gt;stable URLs&lt;/strong&gt;. I set &lt;code&gt;stripe-webhook.example.com&lt;/code&gt; once in the Stripe dashboard, and it works forever. No matter how many times I restart the tunnel or reboot my machine, the URL stays the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You have a &lt;a href="https://dash.cloudflare.com/sign-up" rel="noopener noreferrer"&gt;Cloudflare account&lt;/a&gt; (free)&lt;/li&gt;
&lt;li&gt;You own a domain with its DNS managed by Cloudflare&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your domain isn't on Cloudflare yet, you can &lt;a href="https://developers.cloudflare.com/fundamentals/setup/manage-domains/add-site/" rel="noopener noreferrer"&gt;add it for free&lt;/a&gt; — Cloudflare's free plan includes DNS management and tunnel support.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing cloudflared
&lt;/h2&gt;

&lt;p&gt;Install the &lt;code&gt;cloudflared&lt;/code&gt; CLI for your platform:&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install cloudflared

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux (Debian/Ubuntu)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -LO https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;winget install --id Cloudflare.cloudflared

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

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared --version
# cloudflared version 2024.12.x (I'm using whatever Homebrew installs)

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Authenticating with Cloudflare
&lt;/h2&gt;

&lt;p&gt;Link &lt;code&gt;cloudflared&lt;/code&gt; to your Cloudflare account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel login

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

&lt;/div&gt;



&lt;p&gt;This opens a browser where you log in and select the domain you want to use. After success, credentials are saved under:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS/Linux: &lt;code&gt;~/.cloudflared/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;%USERPROFILE%\.cloudflared\&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Creating a Named Tunnel
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel create webhook-dev

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

&lt;/div&gt;



&lt;p&gt;This creates a persistent tunnel and outputs a &lt;strong&gt;tunnel ID&lt;/strong&gt; (a UUID). You'll need this ID for the config file.&lt;/p&gt;

&lt;p&gt;A named tunnel is the key to stable URLs — the tunnel ID stays the same across restarts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Ingress Rules
&lt;/h2&gt;

&lt;p&gt;Create the config file at &lt;code&gt;~/.cloudflared/config.yml&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;tunnel: webhook-dev
credentials-file: /Users/you/.cloudflared/&amp;lt;tunnel-id&amp;gt;.json

ingress:
  - hostname: stripe-webhook.example.com
    service: http://127.0.0.1:3000
    originRequest:
      httpHostHeader: localhost

  - hostname: qstash-webhook.example.com
    service: http://127.0.0.1:8080

  - service: http_status:404

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

&lt;/div&gt;



&lt;p&gt;This setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routes &lt;code&gt;stripe-webhook.example.com&lt;/code&gt; to your local app on port 3000&lt;/li&gt;
&lt;li&gt;Routes &lt;code&gt;qstash-webhook.example.com&lt;/code&gt; to a different local service on port 8080&lt;/li&gt;
&lt;li&gt;Returns 404 for any other hostname (safety catch-all)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;originRequest.httpHostHeader&lt;/code&gt; setting is only needed if your local app checks the &lt;code&gt;Host&lt;/code&gt; header for routing (common with Express virtual hosts or Nginx). If you're not sure, include it — it doesn't hurt.&lt;/p&gt;

&lt;p&gt;You can add as many hostname entries as you need. I have 3-4 running at any time during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routing DNS to the Tunnel
&lt;/h2&gt;

&lt;p&gt;Tell Cloudflare to point your subdomains to the tunnel:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel route dns webhook-dev stripe-webhook.example.com
cloudflared tunnel route dns webhook-dev qstash-webhook.example.com

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

&lt;/div&gt;



&lt;p&gt;Cloudflare automatically creates CNAME DNS records for these subdomains. No manual DNS editing needed. HTTPS certificates are provisioned automatically too.&lt;/p&gt;

&lt;p&gt;You only need to run these commands once per hostname. After that, the DNS records persist even if the tunnel is stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Tunnel
&lt;/h2&gt;

&lt;p&gt;Start the tunnel for local development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel run webhook-dev

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

&lt;/div&gt;



&lt;p&gt;At this point, &lt;code&gt;https://stripe-webhook.example.com&lt;/code&gt; forwards traffic directly to &lt;code&gt;http://127.0.0.1:3000&lt;/code&gt; on your machine. Configure this URL once in your Stripe (or any other service) webhook settings, and never touch it again.&lt;/p&gt;

&lt;p&gt;To stop: &lt;code&gt;Ctrl+C&lt;/code&gt;. Your webhook URLs will return errors while the tunnel is down, but the DNS records stay in place. Next time you run the tunnel, everything reconnects instantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Daily Workflow
&lt;/h2&gt;

&lt;p&gt;My typical development session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Terminal 1: Start the tunnel
cloudflared tunnel run webhook-dev

# Terminal 2: Start my app
npm run dev

# Terminal 3: Trigger webhooks from service dashboards or CLI tools
# Stripe: stripe trigger payment_intent.succeeded
# Everything hits my local machine through the stable URL

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

&lt;/div&gt;



&lt;p&gt;When I'm done for the day, I stop the tunnel and my app. Next morning, I start them again — same URLs, no reconfiguration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Issues I Ran Into
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;502 or 523 errors:&lt;/strong&gt; Your tunnel is running but the local app isn't, or it's running on a different port. Double-check the port in &lt;code&gt;config.yml&lt;/code&gt; matches your actual app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DNS not resolving:&lt;/strong&gt; You created the tunnel but forgot to route the hostname. Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel route dns webhook-dev your-hostname.example.com

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Host header mismatch:&lt;/strong&gt; Some frameworks (Express with virtual hosts, Nginx) reject requests where the &lt;code&gt;Host&lt;/code&gt; header doesn't match expectations. Fix with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;originRequest:
  httpHostHeader: localhost

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Permission errors on Linux:&lt;/strong&gt; If running as a non-root user, make sure the credentials file is readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 600 ~/.cloudflared/&amp;lt;tunnel-id&amp;gt;.json

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Debugging tunnel issues:&lt;/strong&gt; Run with verbose logging to see exactly what's happening:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel run webhook-dev --loglevel debug

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

&lt;/div&gt;



&lt;p&gt;Other useful commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cloudflared tunnel list # see all your tunnels
cloudflared tunnel info webhook-dev # details about a specific tunnel

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

&lt;/div&gt;



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

&lt;p&gt;Cloudflare Tunnel gave me stable, secure webhook URLs without the constant URL rotation of ngrok's free tier. Once it's set up, it just works — and it's completely free if your domain is already on Cloudflare.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/" rel="noopener noreferrer"&gt;official Cloudflare Tunnel docs&lt;/a&gt; cover advanced setups like running the tunnel as a system service, load balancing, and access policies if you need to go further.&lt;/p&gt;

&lt;p&gt;I use this alongside Colima for a lightweight Docker setup — if you're still on Docker Desktop, here's &lt;a href="https://ashab.dev/blog/docker-desktop-colima" rel="noopener noreferrer"&gt;my experience switching to Colima on macOS&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks for reading — and stay tuned.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>cloudflare</category>
      <category>webhooks</category>
      <category>development</category>
      <category>devops</category>
    </item>
    <item>
      <title>Switching from Docker Desktop to Colima on macOS</title>
      <dc:creator>Ashab Hussan</dc:creator>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      <link>https://forem.com/ashabhussan/switching-from-docker-desktop-to-colima-on-macos-1dm8</link>
      <guid>https://forem.com/ashabhussan/switching-from-docker-desktop-to-colima-on-macos-1dm8</guid>
      <description>&lt;p&gt;I recently switched to Colima as my Docker Desktop alternative on macOS — and I'm not going back. It's lightweight, starts in seconds, and plugs straight into the existing Docker CLI and docker-compose. If you want a faster local container setup with no new learning curve, Colima is worth trying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Switched from Docker Desktop to Colima
&lt;/h2&gt;

&lt;p&gt;Docker Desktop worked fine for a long time, but a few things started bothering me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource usage&lt;/strong&gt; — Docker Desktop was eating 2-4GB of RAM even when idle. On a 16GB MacBook, that's noticeable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow startup&lt;/strong&gt; — launching Docker Desktop and waiting for the engine to be "ready" took 20-30 seconds. Colima starts in under 5 seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The UI I never use&lt;/strong&gt; — I do everything from the terminal. The Docker Desktop dashboard was just sitting there consuming resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License concerns&lt;/strong&gt; — Docker Desktop requires a paid subscription for companies with 250+ employees or $10M+ revenue. Colima is free and open source.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted something that runs containers, works with my existing &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt; commands, and stays out of the way. That's exactly what Colima does.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Colima?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/abiosoft/colima" rel="noopener noreferrer"&gt;Colima&lt;/a&gt; is a container runtime for macOS (and Linux). It creates a lightweight Linux VM using &lt;a href="https://github.com/lima-vm/lima" rel="noopener noreferrer"&gt;Lima&lt;/a&gt;, and runs Docker (or containerd) inside it. The key point: it exposes the standard Docker socket, so all your existing Docker commands, Compose files, and workflows work unchanged.&lt;/p&gt;

&lt;p&gt;It's not a Docker replacement — it's a Docker Desktop replacement. The &lt;code&gt;docker&lt;/code&gt; CLI stays the same. Only the engine running behind it changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Colima on macOS
&lt;/h2&gt;

&lt;p&gt;Here's the full setup:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install Colima and Docker CLI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install colima docker docker-compose

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

&lt;/div&gt;



&lt;p&gt;This installs Colima (the VM manager), the Docker CLI (the commands), and the Docker Compose plugin. You don't need Docker Desktop installed at all — if it's still installed, you can remove it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Start Colima
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colima start --cpu 4 --memory 4 --disk 60

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

&lt;/div&gt;



&lt;p&gt;This creates a VM with 4 CPU cores, 4GB RAM, and 60GB disk. Adjust based on your machine. On my M1, this starts in about 3-5 seconds.&lt;/p&gt;

&lt;p&gt;If you need to change these later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colima stop
colima start --cpu 2 --memory 8 --disk 100

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Verify everything works
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colima status
docker info
docker run hello-world

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

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;docker run hello-world&lt;/code&gt; prints the success message, you're good. Every Docker command you already know works from this point.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Use Docker like before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker-compose up -d
docker build -t myapp .
docker ps

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

&lt;/div&gt;



&lt;p&gt;Nothing changes in your day-to-day commands. That's the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker Commands Quick Reference
&lt;/h2&gt;

&lt;p&gt;Colima doesn't replace Docker commands — it just replaces the engine running behind them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;View all containers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop all containers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker stop $(docker ps -aq)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove all containers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rm $(docker ps -aq)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove all images&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker rmi $(docker images -aq)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clean everything&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker system prune -a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell into a container&lt;/td&gt;
&lt;td&gt;&lt;code&gt;docker exec -it &amp;lt;container&amp;gt; sh&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Colima-Specific Commands
&lt;/h2&gt;

&lt;p&gt;These are the only new commands you need to learn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colima start # start the VM
colima stop # stop the VM (containers pause)
colima delete # delete the VM entirely (careful — you lose containers)
colima status # check if VM is running
colima list # list all VMs
colima start --kubernetes # start with K8s enabled

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

&lt;/div&gt;



&lt;p&gt;My daily workflow: &lt;code&gt;colima start&lt;/code&gt; when I begin work, &lt;code&gt;colima stop&lt;/code&gt; when I'm done. That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resource Comparison
&lt;/h2&gt;

&lt;p&gt;Here's the rough difference I noticed on my M1 MacBook Pro with 16GB RAM:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Docker Desktop&lt;/th&gt;
&lt;th&gt;Colima&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Idle RAM usage&lt;/td&gt;
&lt;td&gt;2-4 GB&lt;/td&gt;
&lt;td&gt;~600 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Startup time&lt;/td&gt;
&lt;td&gt;20-30 seconds&lt;/td&gt;
&lt;td&gt;3-5 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background processes&lt;/td&gt;
&lt;td&gt;Multiple (Docker Desktop, Docker Engine, etc.)&lt;/td&gt;
&lt;td&gt;Single &lt;code&gt;colima&lt;/code&gt; process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GUI&lt;/td&gt;
&lt;td&gt;Full dashboard app&lt;/td&gt;
&lt;td&gt;None (CLI only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Free for personal, paid for business&lt;/td&gt;
&lt;td&gt;Free and open source&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These aren't scientific benchmarks — just what I observed on my machine during normal development. The RAM difference alone made the switch worth it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Issues and Gotchas
&lt;/h2&gt;

&lt;p&gt;A few things I ran into during the switch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Colima VM not starting after macOS update:&lt;/strong&gt; After a macOS system update, Colima occasionally fails to start with a cryptic error. The fix is usually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;colima delete
colima start --cpu 4 --memory 4 --disk 60

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

&lt;/div&gt;



&lt;p&gt;You lose running containers, but your images rebuild from Dockerfiles and Compose files anyway. It's a minor inconvenience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Volume mounts only cover your home directory:&lt;/strong&gt; By default, Colima mounts &lt;code&gt;~&lt;/code&gt; into the VM. If your project lives outside your home directory, containers can't access the files. I keep everything under &lt;code&gt;~/projects&lt;/code&gt; so this wasn't an issue, but it's worth knowing. You can configure additional mounts in &lt;code&gt;~/.colima/default/colima.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker socket path:&lt;/strong&gt; Some tools expect the Docker socket at &lt;code&gt;/var/run/docker.sock&lt;/code&gt;. Colima creates it at &lt;code&gt;~/.colima/default/docker.sock&lt;/code&gt;. If a tool complains it can't find Docker, add this to your shell profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Port conflicts with AirPlay on macOS:&lt;/strong&gt; macOS Sonoma uses port 5000 and 7000 for AirPlay Receiver. If you're mapping containers to these ports, you'll get a "port already in use" error. Either change the port mapping or disable AirPlay Receiver in System Settings → General → AirDrop &amp;amp; Handoff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker Compose v1 vs v2:&lt;/strong&gt; If you install &lt;code&gt;docker-compose&lt;/code&gt; via Homebrew, you get v2 (invoked as &lt;code&gt;docker compose&lt;/code&gt; with a space). If your scripts use &lt;code&gt;docker-compose&lt;/code&gt; with a hyphen, either update them or create an alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias docker-compose='docker compose'

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

&lt;/div&gt;



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

&lt;p&gt;Switching to Colima took about 5 minutes and I haven't opened Docker Desktop since. My machine runs cooler, containers start just as fast, and I didn't change a single Dockerfile or Compose file.&lt;/p&gt;

&lt;p&gt;If you're a CLI-first developer who doesn't need Docker Desktop's GUI, give &lt;a href="https://github.com/abiosoft/colima" rel="noopener noreferrer"&gt;Colima&lt;/a&gt; a try. The &lt;a href="https://github.com/abiosoft/colima#readme" rel="noopener noreferrer"&gt;official README&lt;/a&gt; covers advanced configuration like Kubernetes, custom VM profiles, and containerd mode.&lt;/p&gt;

&lt;p&gt;If you're also streamlining your local dev setup, check out &lt;a href="https://ashab.dev/blog/how-i-use-cloudflare-tunnel-for-local-webhooks" rel="noopener noreferrer"&gt;how I use Cloudflare Tunnel for stable local webhook URLs&lt;/a&gt; — another tool that removed a lot of friction from my workflow.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks for reading — and stay tuned.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>docker</category>
      <category>colima</category>
      <category>macos</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
