Automationintermediate

Oracle ARM Always-Free in 2026: What I Learned Running 15 Services on One Free Box

I run a dozen-plus production services on a single Always Free Oracle A1 instance in Mumbai. Here is the real allocation, the gotchas the marketing page hides, and the one networking trap that costs everyone a weekend.

By··8 min read·Reviewed
Oracle ARM Always-Free Tier 2026 - Real Limits, Real Gotchas

I run more than a dozen small production services on a single Oracle Always Free ARM instance. One box, four OCPUs, 24GB of RAM, in the Mumbai region, hosting a Coolify control plane, several PocketBase backends, a Cloudflare Tunnel, and the cron workers behind a handful of sites. The monthly bill is zero rupees. It has been zero rupees for months.

Almost every Oracle free-tier guide gets that headline right. What they get wrong is everything after it: the capacity game that decides whether you can even launch the box, the storage math that quietly fills up, the idle-reclaim rule that deletes instances people forget about, and one Docker networking trap that breaks Cloudflare Tunnels in a way that takes a full evening to debug. This is the version written by someone who actually lives on the tier, not someone summarising the pricing page.

What you actually get

The ARM Always Free allocation is pooled across your whole tenancy, not granted per instance:

  • 3,000 OCPU hours per month on VM.Standard.A1.Flex
  • 18,000 GB memory hours per month
  • Practical steady-state equivalent: 4 OCPUs and 24 GB RAM running 24x7
  • Up to four A1 instances, if you split the pool into smaller shapes
  • 200 GB total Always Free Block Volume storage, shared across every boot and data volume
  • 10 TB per month outbound transfer
  • Arm64 Linux images, Oracle Linux or Ubuntu

The word that matters is pooled. You can run one fat 4-OCPU / 24GB VM, or four thin 1-OCPU / 6GB VMs, or any split in between. I run the single fat box on purpose, because Coolify plus a real database layer wants RAM headroom more than it wants four tiny nodes. The processor is Ampere Altra, one OCPU maps to one physical core, and it is ARM64. Every binary, base image, and language runtime you deploy must have an ARM64 build. That single constraint causes more day-one failures than any billing limit.

The capacity game nobody warns you about

The hardest part of the free tier is not billing. It is getting the instance to launch at all. Out of host capacity for VM.Standard.A1.Flex is the single most common wall, and it has nothing to do with your quota. Oracle simply does not guarantee spare A1 hardware in the availability domain you picked, and the popular regions stay starved because everyone wants free ARM.

What works in practice:

  • Pick your home region deliberately, because some Always Free resources bind to it permanently and you cannot move them later. Mumbai is the obvious India choice for latency, but it is also one of the most capacity-starved. Hyderabad, Singapore, and Tokyo are realistic alternatives if Mumbai keeps refusing you.
  • When you hit Out of host capacity, do not sit and click Launch by hand. The capacity frees in bursts when other tenancies release hardware, often at odd hours. A small retry loop that re-issues the launch every few minutes will catch a free slot you would never get manually.
  • Ask for less first. A 2-OCPU / 12GB launch succeeds far more often than a 4-OCPU / 24GB launch, because the scheduler needs a smaller contiguous block. Grab a smaller A1, then resize up later once you own a foothold in that availability domain.

This is the step that filters out most people. They try twice, see the capacity error, assume the free tier is a lie, and leave. It is not a lie. It is a queue.

Block storage is the real ceiling

Oracle gives 200 GB of Always Free block storage shared across boot and data volumes combined. The default boot volume is commonly 50 GB. That math bites quickly: four small instances at a 50 GB boot each consume the entire 200 GB before you attach a single data disk. My single-box layout uses one 50 GB boot volume and leaves roughly 150 GB for an attached data volume, which is plenty for SQLite-backed PocketBase databases and a Coolify image cache.

Watch the boot-volume default when you launch, never create a paid block volume on a free tenancy without a budget alert set first, and prune Docker images aggressively because Coolify accumulates build layers fast. A docker system prune on a cron is not optional on a 50 GB boot disk.

Idle reclaim is real, and fake load does not fix it

Oracle reclaims idle Always Free compute. The documented trigger is a 7-day window where 95th-percentile CPU, network, and memory utilisation all sit below 20 percent for an A1 shape. People panic and install crypto miners or busy loops to fake activity. Do not. It wastes the box and it is against the terms.

If the instance is doing real work, you will never trip the threshold. A Coolify host running even a few live services, health checks, backups, and package updates stays comfortably above 20 percent on at least one axis. The instances that get reclaimed are the ones someone spun up, never deployed anything to, and forgot. The fix is to actually use the box, and to keep a restorable image plus off-instance provisioning notes so a reclaim is an annoyance, not a disaster.

The networking trap that costs everyone a weekend

This is the gotcha I have not seen documented anywhere, and it is the reason this article exists.

The clean way to expose services on a free A1 box is a Cloudflare Tunnel. No open ingress ports, no public IP exposed, DDoS protection for free. You run cloudflared, point a hostname at a local service, and Cloudflare routes traffic in through an outbound-only connection. On the free tier with no SLA and a public IP you do not want probed, this is the correct architecture.

Here is where it breaks. If you run Coolify, your cloudflared very likely runs as a container inside Coolify's Docker network. Inside that container, localhost and 127.0.0.1 mean the container itself, not the host. So when you point a tunnel ingress rule at http://localhost:8090 expecting to reach a PocketBase instance running on the bare-metal host, you get a connection refused and a tunnel that returns 502s while every local curl on the host works perfectly. You will burn an evening before you suspect the network namespace.

The fix is to address the host from inside the container using the Docker bridge gateway:

# cloudflared tunnel config, ingress rule
# WRONG when cloudflared runs inside the Coolify docker network:
#   service: http://localhost:8090
# RIGHT, reach the host service via the bridge gateway:
ingress:
  - hostname: pb.example.com
    service: http://10.0.2.1:8090
  - service: http_status:404

10.0.2.1 is the gateway address of Coolify's Docker bridge network, which routes to the host. A service that lives inside the same Coolify network is reachable by its container name instead. The rule of thumb: a containerised tunnel reaches a bare-metal host service through the bridge gateway, and a co-networked container through its service name, never through localhost. Get that one line right and the whole zero-open-ports design just works.

My actual layout

The setup I run, which has held up for months:

  • One A1 instance, 4 OCPUs and 24 GB RAM, Mumbai, 50 GB boot plus an attached data volume
  • Coolify as the self-hosted PaaS control plane, deploying every app from a Git push
  • Several PocketBase instances as backends, one per project, each on its own subdomain
  • A single Cloudflare Tunnel fronting everything, so zero ingress ports are open on the VM
  • Litestream streaming each PocketBase SQLite file to Cloudflare R2, so a dead instance is a restore, not a loss
  • Caddy or the Coolify-managed proxy for internal TLS where a service is not behind the tunnel

That stack carries 15 to 20 small services comfortably. The constraint I hit first is never CPU, it is RAM when too many Node build steps run at once, which is why the single fat box beats four thin ones for this workload.

When to use it, and when not

Use an A1 Always Free box for personal APIs and internal tools, PocketBase or SQLite-backed apps, background workers and bots, uptime monitors and status pages, ARM64 compatibility staging, and exactly the kind of bootstrapped multi-app PaaS I described above. It is an excellent free lab and an honest early production server. The same idle headroom makes it a clean home for a self-hosted GitHub Actions runner on Oracle ARM, which moves your CI off GitHub's free-minutes meter for zero rupees.

Do not use it for revenue-critical databases without off-instance backups, sustained heavy-CPU jobs where paid capacity is simply simpler, x86-only software stacks, public file mirrors or high-bandwidth media, or anything that needs a contractual uptime SLA. Free compute has no SLA, and the moment a project earns money, the right move is to pay for infrastructure and demote the A1 box to staging or a utility node.

Quick takeaways

  • The free pool is 3,000 OCPU hours and 18,000 GB memory hours per month, equivalent to 4 OCPUs and 24 GB RAM run continuously.
  • The real wall is Out of host capacity, not billing. Choose your region deliberately, ask for a smaller shape first, and retry on a loop.
  • 200 GB block storage is shared across all boot and data volumes. Prune Docker images or the 50 GB boot disk fills.
  • Idle reclaim is real at 7-day p95 below 20 percent. Real workload clears it. Fake load is a waste and a violation.
  • A containerised Cloudflare Tunnel reaches a host service via the Docker bridge gateway, not localhost. This is the single most expensive gotcha on the tier.
  • Stream your databases off-instance with Litestream to R2, because a free VM is a box you should be able to lose without flinching.

Related