<?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: Garseta Yusuf</title>
    <description>The latest articles on DEV Community by Garseta Yusuf (@garsetayusuf).</description>
    <link>https://dev.to/garsetayusuf</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%2F4092844%2F3343ffe1-443a-47f4-9ca0-35db989ccb02.jpg</url>
      <title>DEV Community: Garseta Yusuf</title>
      <link>https://dev.to/garsetayusuf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/garsetayusuf"/>
    <language>en</language>
    <item>
      <title>Automating Oracle's Always-Free ARM Instance (So You Don't Have To Babysit It)</title>
      <dc:creator>Garseta Yusuf</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:19:51 +0000</pubDate>
      <link>https://dev.to/garsetayusuf/automating-oracles-always-free-arm-instance-so-you-dont-have-to-babysit-it-76</link>
      <guid>https://dev.to/garsetayusuf/automating-oracles-always-free-arm-instance-so-you-dont-have-to-babysit-it-76</guid>
      <description>&lt;p&gt;As a developer who likes free compute, I frequently found myself caught in a tedious cycle: trying to provision an Always-Free ARM instance on Oracle Cloud Infrastructure (OCI), watching it fail, and then trying again. And again. And again.&lt;/p&gt;

&lt;p&gt;Capacity for the &lt;code&gt;VM.Standard.A1.Flex&lt;/code&gt; shape is rarely available, the API throws rate-limit errors when you retry too fast, and sometimes the launch fails halfway through because the subnet you picked silently refuses a public IP. That's why I created &lt;strong&gt;oracle-instance&lt;/strong&gt;, a small bash retry loop to automate this process and make provisioning seamless.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: The Manual Retry Loop
&lt;/h2&gt;

&lt;p&gt;If you've ever tried to spin up an ARM instance on OCI's free tier, you might be familiar with this workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log into the OCI Console or fire up the CLI&lt;/li&gt;
&lt;li&gt;Request a &lt;code&gt;VM.Standard.A1.Flex&lt;/code&gt; instance&lt;/li&gt;
&lt;li&gt;Get rejected because the availability domain is out of capacity&lt;/li&gt;
&lt;li&gt;Wait, then try again&lt;/li&gt;
&lt;li&gt;Get throttled by the API for retrying too quickly&lt;/li&gt;
&lt;li&gt;Finally succeed, only for the launch to fail at the primary VNIC step because your subnet doesn't allow public IPs&lt;/li&gt;
&lt;li&gt;Repeat this process every single time capacity flickers back online&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This manual loop becomes increasingly painful the more you need a fresh instance. With each attempt, you're forced to spend valuable time fighting the console instead of actually building things.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: oracle-instance
&lt;/h2&gt;

&lt;p&gt;To address this challenge, I developed &lt;a href="https://github.com/garsetayusuf/oracle-instance" rel="noopener noreferrer"&gt;oracle-instance&lt;/a&gt;, a dependency-free bash script that automatically retries instance creation until it succeeds, and fixes the two most common OCI pitfalls on its own. Here's what it does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically retries instance creation with polite backoff (no more API throttling)&lt;/li&gt;
&lt;li&gt;Picks a valid public subnet instead of blindly guessing the first one&lt;/li&gt;
&lt;li&gt;Enforces the Always-Free cap (2 OCPUs / 12 GB) so a typo can't cost you money&lt;/li&gt;
&lt;li&gt;Grabs the latest Ubuntu 22.04 ARM image automatically&lt;/li&gt;
&lt;li&gt;Exits cleanly on &lt;code&gt;Ctrl+C&lt;/code&gt; without leaving half-built instances behind&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The script integrates seamlessly with the OCI CLI. Here's a quick setup guide:&lt;/p&gt;

&lt;p&gt;Install the OCI CLI (macOS with Homebrew):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew update
brew &lt;span class="nb"&gt;install &lt;/span&gt;oci-cli
oci &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or via Oracle's installer (Linux / macOS):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SHELL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure it with your tenancy, user, region, and API key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;oci setup config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the retry loop:&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;chmod&lt;/span&gt; +x retry.sh
&lt;span class="nv"&gt;DRY_RUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; ./retry.sh
./retry.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Hard Resource Cap
&lt;/h3&gt;

&lt;p&gt;The script refuses to request more than the free-tier allowance, even via environment override. A typo can't blow past Always-Free:&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="nv"&gt;MAX_OCPUS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2
&lt;span class="nv"&gt;MAX_MEMORY_GB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;12
&lt;span class="nv"&gt;OCPUS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OCPUS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;MEMORY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MEMORY&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;12&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Self-Correcting Subnet Selection
&lt;/h3&gt;

&lt;p&gt;Instead of taking the first subnet (which might be private), it queries for one that can actually receive a public IP:&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="nv"&gt;SUBNET_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;oci_cli network subnet list &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--compartment-id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COMPARTMENT_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'data[?prohibit-public-ip-on-vnic==false]|[0].id'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--raw-output&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you force a public IP on a private subnet, it fails fast with a clear message instead of dying mid-launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Polite Retries
&lt;/h3&gt;

&lt;p&gt;The loop sleeps between attempts and backs off longer after a rate-limit hit:&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="nv"&gt;SLEEP_SECONDS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SLEEP_SECONDS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;120&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;RATE_LIMIT_SLEEP_SECONDS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RATE_LIMIT_SLEEP_SECONDS&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;300&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Real-World Impact
&lt;/h3&gt;

&lt;p&gt;Since implementing this solution in my own workflow, I've noticed significant improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Saved hours previously spent manually clicking and retrying in the console&lt;/li&gt;
&lt;li&gt;Eliminated the subnet/VNIC launch failures that used to waste attempts&lt;/li&gt;
&lt;li&gt;Got a working ARM box the moment capacity opened up, without watching the screen&lt;/li&gt;
&lt;li&gt;Reduced friction for spinning up fresh test environments on demand&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Looking Forward
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;oracle-instance&lt;/strong&gt; script is just the beginning. I'm actively working on additional features based on community feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multi-availability-domain round-robin (try ADs in sequence instead of just the first)&lt;/li&gt;
&lt;li&gt;Slack or Telegram notify on success&lt;/li&gt;
&lt;li&gt;Optional automatic post-provision setup (Docker, Tailscale, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've fought the same OCI capacity battle, give it a try, and pull requests are very welcome.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/garsetayusuf/oracle-instance" rel="noopener noreferrer"&gt;https://github.com/garsetayusuf/oracle-instance&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>oraclecloud</category>
      <category>bash</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
