Oracle Cloud's Always Free tier is, quietly, one of the best deals in cloud
computing: 4 Arm OCPUs and 24 GB of RAM, free forever, no trial clock. That's
enough for a real homelab node, a Docker stack, a small k3s cluster, a VPN, or a
game server β running 24/7 without paying a cent or buying hardware.
There's just one problem standing between you and that box, and if you've tried
you already know its name:
ServiceError:
code: InternalError
message: Out of host capacity.
Those Arm hosts are in such heavy demand that creating an instance usually
fails. US regions can be dry for hours or days. Even busy EU/APAC regions dip in
and out. Capacity frees up in small, random windows β and whoever happens to be
retrying at that exact second gets it.
I spent the better part of a week refreshing the OCI console like it was a
concert ticket drop. Then I did the obvious thing: I wrote a script to play the
lottery for me, on a timer, and walked away. It worked β it caught me a 4 OCPU /
24 GB A1 instance. So I cleaned it up and open-sourced it.
π github.com/alexpua/oci-arm-catcher (MIT)
[GIF: terminal showing "Out of host capacity⦠retrying" a few times, then "SUCCESS! Instance created"]
The idea is dumb on purpose
There's no clever exploit here. The tool just calls the official OCI CLI
command β the exact same oci compute instance launch you'd run by hand β in a
polite loop, and reacts to the result:
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
The only part that actually matters is the last two branches. A naive
while true; do launch; sleep; done loop is worse than useless: when your config
has a typo β wrong subnet OCID, an x86 image, an auth problem β it will cheerfully
retry that broken request forever and you'll never notice.
So the catcher splits errors into two buckets:
-
Transient / capacity (
Out of host capacity,InternalError,TooManyRequests, timeouts) β keep trying, this is the whole point. -
Everything else (
NotAuthorizedOrNotFound,LimitExceeded, bad image) β stop immediately and tell the human.
That single distinction is the difference between "I left it running overnight and
woke up to a server" and "I left it running overnight and woke up to 4,000 copies
of the same error."
Things I added once it was more than a personal hack
Readable error output. The OCI CLI prints errors as a JSON blob to stderr.
My first version grepped for "message" and frequently printed ?: ? when the
shape didn't match. Now a tiny Python helper parses the JSON properly and always
falls back to something human-readable:
-> InternalError: Out of host capacity.
Multi-AD rotation. Regions like Ashburn, Phoenix and Frankfurt have three
Availability Domains, and capacity can appear in any one of them. Give the catcher
all three and it cycles through on each retry, multiplying your chances:
AVAILABILITY_DOMAINS="Abcd:US-ASHBURN-1-AD-1,Abcd:US-ASHBURN-1-AD-2,Abcd:US-ASHBURN-1-AD-3"
A config-discovery helper. The genuinely annoying part of OCI isn't the API,
it's finding all the OCIDs (compartment, subnet, image, availability domain). So
there's a read-only get-config script that prints them, formatted to paste
straight into your .env. It launches nothing β just reads metadata.
Cross-platform. Bash for macOS/Linux, plus a native PowerShell port for
Windows (with toast notifications). Or run the bash version under WSL2 β your call.
Desktop notifications. Because the whole pitch is "start it and forget it,"
it pings you the moment it lands β osascript on macOS, notify-send on Linux,
a toast on Windows.
Tests. It mocks the oci CLI and asserts the important behaviors: retries on
capacity errors, stops on auth errors, parses the OCID on success, never prints
?: ?. bats for bash, Pester for PowerShell, ShellCheck β all in CI. For a 200-line
shell script that's arguably overkill, but I wanted the "stop on real errors"
guarantee to be actually guaranteed.
Using it
git clone https://github.com/alexpua/oci-arm-catcher.git
cd oci-arm-catcher
cp .env.example .env
./scripts/get-config.sh # prints your OCIDs β paste into .env
# edit .env
nohup ./oci-arm-catcher.sh > catcher.log 2>&1 &
tail -f catcher.log
Then go do something else. When capacity opens up, you get a notification and a
running instance.
A note on being a good citizen
This isn't a way to "beat" Oracle or bypass anything. It does exactly what you'd
do by hand, just patiently and on an interval (default: every 5 minutes β not a
hammer). You still have to stay inside your free-tier allowance. It's automation
of a tedious manual task, nothing more.
Try it / break it
If you've been losing the capacity lottery, give it a run:
github.com/alexpua/oci-arm-catcher
Issues and PRs welcome β I'd especially love more notification backends
(Telegram, Discord, Slack), smarter backoff, and region/AD presets.
And if it caught you a free server: a β on the repo helps the next person find
it, and if you feel like it, you can buy me a coffee β.
Both totally optional β the tool's free either way.
Top comments (0)