<?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: Alexander Pervushen</title>
    <description>The latest articles on DEV Community by Alexander Pervushen (@alexpua).</description>
    <link>https://dev.to/alexpua</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%2F3972866%2Fa2183283-3ad1-4a3d-9cb2-bcec1a7bcc0e.png</url>
      <title>DEV Community: Alexander Pervushen</title>
      <link>https://dev.to/alexpua</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexpua"/>
    <language>en</language>
    <item>
      <title>How I stopped fighting Oracle's "Out of host capacity" and let a script catch a free ARM server for me</title>
      <dc:creator>Alexander Pervushen</dc:creator>
      <pubDate>Sun, 07 Jun 2026 19:58:49 +0000</pubDate>
      <link>https://dev.to/alexpua/how-i-stopped-fighting-oracles-out-of-host-capacity-and-let-a-script-catch-a-free-arm-server-for-41a6</link>
      <guid>https://dev.to/alexpua/how-i-stopped-fighting-oracles-out-of-host-capacity-and-let-a-script-catch-a-free-arm-server-for-41a6</guid>
      <description>&lt;p&gt;Oracle Cloud's Always Free tier is, quietly, one of the best deals in cloud&lt;br&gt;
computing: &lt;strong&gt;4 Arm OCPUs and 24 GB of RAM, free forever&lt;/strong&gt;, no trial clock. That's&lt;br&gt;
enough for a real homelab node, a Docker stack, a small k3s cluster, a VPN, or a&lt;br&gt;
game server — running 24/7 without paying a cent or buying hardware.&lt;/p&gt;

&lt;p&gt;There's just one problem standing between you and that box, and if you've tried&lt;br&gt;
you already know its name:&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;ServiceError&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;InternalError&lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Out of host capacity.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those Arm hosts are in such heavy demand that creating an instance usually&lt;br&gt;
fails. US regions can be dry for hours or days. Even busy EU/APAC regions dip in&lt;br&gt;
and out. Capacity frees up in small, random windows — and whoever happens to be&lt;br&gt;
retrying at that exact second gets it.&lt;/p&gt;

&lt;p&gt;I spent the better part of a week refreshing the OCI console like it was a&lt;br&gt;
concert ticket drop. Then I did the obvious thing: I wrote a script to play the&lt;br&gt;
lottery for me, on a timer, and walked away. It worked — it caught me a 4 OCPU /&lt;br&gt;
24 GB A1 instance. So I cleaned it up and open-sourced it.&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://github.com/alexpua/oci-arm-catcher" rel="noopener noreferrer"&gt;github.com/alexpua/oci-arm-catcher&lt;/a&gt;&lt;/strong&gt; (MIT)&lt;/p&gt;

&lt;p&gt;[GIF: terminal showing "Out of host capacity… retrying" a few times, then "SUCCESS! Instance created"]&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea is dumb on purpose
&lt;/h2&gt;

&lt;p&gt;There's no clever exploit here. The tool just calls the &lt;strong&gt;official&lt;/strong&gt; OCI CLI&lt;br&gt;
command — the exact same &lt;code&gt;oci compute instance launch&lt;/code&gt; you'd run by hand — in a&lt;br&gt;
polite loop, and reacts to the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loop:
  oci compute instance launch  --shape VM.Standard.A1.Flex ...
  ├─ success            → parse the instance OCID, desktop notification, exit
  ├─ "out of capacity"  → wait, (optionally rotate AD), retry
  │   InternalError / LimitExceeded / TooManyRequests / timeout
  └─ any other error    → print it, notify, STOP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only part that actually matters is the last two branches. A naive&lt;br&gt;
&lt;code&gt;while true; do launch; sleep; done&lt;/code&gt; loop is worse than useless: when your config&lt;br&gt;
has a typo — wrong subnet OCID, an x86 image, an auth problem — it will cheerfully&lt;br&gt;
retry that broken request forever and you'll never notice.&lt;/p&gt;

&lt;p&gt;So the catcher splits errors into two buckets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transient / capacity&lt;/strong&gt; (&lt;code&gt;Out of host capacity&lt;/code&gt;, &lt;code&gt;InternalError&lt;/code&gt;,
&lt;code&gt;TooManyRequests&lt;/code&gt;, timeouts) → &lt;em&gt;keep trying, this is the whole point.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything else&lt;/strong&gt; (&lt;code&gt;NotAuthorizedOrNotFound&lt;/code&gt;, &lt;code&gt;LimitExceeded&lt;/code&gt;, bad image) →
&lt;em&gt;stop immediately and tell the human.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That single distinction is the difference between "I left it running overnight and&lt;br&gt;
woke up to a server" and "I left it running overnight and woke up to 4,000 copies&lt;br&gt;
of the same error."&lt;/p&gt;
&lt;h2&gt;
  
  
  Things I added once it was more than a personal hack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Readable error output.&lt;/strong&gt; The OCI CLI prints errors as a JSON blob to stderr.&lt;br&gt;
My first version grepped for &lt;code&gt;"message"&lt;/code&gt; and frequently printed &lt;code&gt;?: ?&lt;/code&gt; when the&lt;br&gt;
shape didn't match. Now a tiny Python helper parses the JSON properly and always&lt;br&gt;
falls back to &lt;em&gt;something&lt;/em&gt; human-readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  -&amp;gt; InternalError: Out of host capacity.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Multi-AD rotation.&lt;/strong&gt; Regions like Ashburn, Phoenix and Frankfurt have three&lt;br&gt;
Availability Domains, and capacity can appear in any one of them. Give the catcher&lt;br&gt;
all three and it cycles through on each retry, multiplying your chances:&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;AVAILABILITY_DOMAINS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Abcd:US-ASHBURN-1-AD-1,Abcd:US-ASHBURN-1-AD-2,Abcd:US-ASHBURN-1-AD-3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;A config-discovery helper.&lt;/strong&gt; The genuinely annoying part of OCI isn't the API,&lt;br&gt;
it's finding all the OCIDs (compartment, subnet, image, availability domain). So&lt;br&gt;
there's a read-only &lt;code&gt;get-config&lt;/code&gt; script that prints them, formatted to paste&lt;br&gt;
straight into your &lt;code&gt;.env&lt;/code&gt;. It launches nothing — just reads metadata.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-platform.&lt;/strong&gt; Bash for macOS/Linux, plus a native PowerShell port for&lt;br&gt;
Windows (with toast notifications). Or run the bash version under WSL2 — your call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desktop notifications.&lt;/strong&gt; Because the whole pitch is "start it and forget it,"&lt;br&gt;
it pings you the moment it lands — &lt;code&gt;osascript&lt;/code&gt; on macOS, &lt;code&gt;notify-send&lt;/code&gt; on Linux,&lt;br&gt;
a toast on Windows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tests.&lt;/strong&gt; It mocks the &lt;code&gt;oci&lt;/code&gt; CLI and asserts the important behaviors: retries on&lt;br&gt;
capacity errors, stops on auth errors, parses the OCID on success, never prints&lt;br&gt;
&lt;code&gt;?: ?&lt;/code&gt;. bats for bash, Pester for PowerShell, ShellCheck — all in CI. For a 200-line&lt;br&gt;
shell script that's arguably overkill, but I wanted the "stop on real errors"&lt;br&gt;
guarantee to be actually guaranteed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using it
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/alexpua/oci-arm-catcher.git
&lt;span class="nb"&gt;cd &lt;/span&gt;oci-arm-catcher

&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
./scripts/get-config.sh     &lt;span class="c"&gt;# prints your OCIDs → paste into .env&lt;/span&gt;
&lt;span class="c"&gt;# edit .env&lt;/span&gt;

&lt;span class="nb"&gt;nohup&lt;/span&gt; ./oci-arm-catcher.sh &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; catcher.log 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; catcher.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then go do something else. When capacity opens up, you get a notification and a&lt;br&gt;
running instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on being a good citizen
&lt;/h2&gt;

&lt;p&gt;This isn't a way to "beat" Oracle or bypass anything. It does exactly what you'd&lt;br&gt;
do by hand, just patiently and on an interval (default: every 5 minutes — not a&lt;br&gt;
hammer). You still have to stay inside your free-tier allowance. It's automation&lt;br&gt;
of a tedious manual task, nothing more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it / break it
&lt;/h2&gt;

&lt;p&gt;If you've been losing the capacity lottery, give it a run:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://github.com/alexpua/oci-arm-catcher" rel="noopener noreferrer"&gt;github.com/alexpua/oci-arm-catcher&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Issues and PRs welcome — I'd especially love more notification backends&lt;br&gt;
(Telegram, Discord, Slack), smarter backoff, and region/AD presets.&lt;/p&gt;

&lt;p&gt;And if it caught you a free server: a ⭐ on the repo helps the next person find&lt;br&gt;
it, and if you feel like it, you can &lt;a href="https://send.monobank.ua/jar/4Hq7auheaa" rel="noopener noreferrer"&gt;buy me a coffee&lt;/a&gt; ☕.&lt;br&gt;
Both totally optional — the tool's free either way.&lt;/p&gt;

</description>
      <category>oraclecloud</category>
      <category>devops</category>
      <category>opensource</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
