Oracle Cloud Grátis: Crie VM A1.Flex com Script Automático 2026
Leitura: ~14 min
TL;DR — Resumo Executivo
- A Oracle oferece 4 OCPUs ARM + 24 GB RAM eternamente gratuitos — mas o painel só deixa você clicar e torcer para ter vaga. O script neste post cria toda a infraestrutura e tenta automaticamente até a instância aparecer.
- "Out of host capacity" não é erro seu — é fila de hardware na Oracle. A solução é um loop que tenta AD-1, AD-2 e AD-3 a cada 10 minutos até conseguir a máquina.
- Zero pré-requisito além do Windows e Python 3.8+ — o tutorial cobre do zero: instalação da OCI CLI, geração de chave API, criação de VCN, subnet, internet gateway e VM com um único script PowerShell.
Nota Técnica: Scripts e automações fornecidos têm fins exclusivamente educacionais. Teste sempre em ambiente controlado. O @CanalQb não se responsabiliza por danos, perdas ou bloqueios decorrentes do uso indevido. A conta Oracle Always Free possui limites — nunca crie recursos além da cota gratuita.
A Oracle tem 4 OCPUs ARM e 24 GB de RAM esperando pelo seu nome — e ela não te avisa quando a fila abre.
Enquanto você clica no painel e recebe "Out of host capacity" pela décima vez, alguém em outro fuso já pegou a máquina usando um script que tentou de madrugada. Aqui no @CanalQb, testamos isso na prática: a instância só apareceu depois de um loop automático tentando AD-1, AD-2 e AD-3 a cada 10 minutos durante a madrugada.
Este guia cobre exatamente o que você precisa: instalar a OCI CLI no Windows, configurar autenticação com chave API, criar toda a infraestrutura de rede do zero via script e rodar uma rotina automática que não para até a VM subir.
O que é o Oracle Always Free e por que vale a pena?
O Oracle Always Free oferece recursos que não expiram — ao contrário dos trials de 30 dias de outras clouds. O destaque é o shape VM.Standard.A1.Flex: arquitetura ARM64 (Ampere), com até 4 OCPUs e 24 GB de RAM completamente gratuitos. Para contexto, um VPS com essa configuração custaria entre R$80 e R$180 por mês em qualquer provedor convencional.
Aqui no @CanalQb, usamos instâncias A1.Flex para rodar bots, APIs, scrapers e automações pesadas — tudo dentro da cota gratuita. O único obstáculo real é a escassez de capacidade nos datacenters Oracle. O hardware existe, mas está sempre concorrido.
| Recurso | Always Free | Equivalente pago |
|---|---|---|
| VM.Standard.A1.Flex (ARM) | 4 OCPU / 24 GB — grátis | ~R$120/mês |
| VM.Standard.E2.1.Micro (x86) | 2 VMs — grátis | ~R$30/mês cada |
| Object Storage | 20 GB — grátis | ~R$5/mês |
| Bandwidth de saída | 10 TB/mês — grátis | ~R$200/mês |
Como instalar a OCI CLI no Windows corretamente?
A OCI CLI (Oracle Cloud Infrastructure Command Line Interface) é o canal direto entre o PowerShell e a API da Oracle. A instalação mais confiável no Windows é via Winget, que gerencia atualizações automaticamente e evita conflitos de Python.
Verificar se o Winget está disponível
Abra o PowerShell e execute:
winget --version
Se retornar uma versão (ex: v1.28.240), está pronto. Caso contrário, atualize o Windows ou instale o Winget pela Microsoft Store.
Instalar a OCI CLI via Winget
winget install Oracle.OCI-CLI
O Winget baixa e instala automaticamente. O processo leva de 2 a 5 minutos dependendo da conexão. Ao final, feche e reabra o PowerShell.
Confirmar a instalação
oci --version
Resultado esperado: 3.88.0 ou superior. Se o comando não for reconhecido, feche e reabra o PowerShell — o PATH precisa ser atualizado.
Atenção: Evite instalar a OCI CLI via script Python manual se você também vai usar o Winget — os dois métodos podem criar ambientes virtuais conflitantes. Escolha um e siga com ele.
Como configurar autenticação da OCI CLI com chave API?
A OCI CLI não usa usuário/senha. Toda autenticação é feita por par de chaves RSA — a chave privada fica no seu PC, a pública é cadastrada no painel Oracle. Esse modelo é muito mais seguro e funciona perfeitamente para automação.
Ajustar a política de execução do PowerShell
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Esse comando libera scripts locais sem precisar de administrador. Confirme com Y quando solicitado.
Iniciar o assistente de configuração
oci setup config
O assistente vai pedir três informações que você encontra no painel Oracle Cloud:
| Campo | Onde encontrar |
|---|---|
| User OCID | Perfil (canto superior direito) → User Settings → copiar OCID |
| Tenancy OCID | Menu → Administration → Tenancy Details → copiar OCID |
| Region | Digitar 72 para us-ashburn-1 (Home Region) |
Gerar par de chaves (sem senha — essencial para automação)
Quando o assistente perguntar sobre gerar novo par de chaves, responda Y. Na etapa de passphrase, pressione Enter vazio ou digite N/A. Chave com senha bloqueia scripts automáticos.
Definir uma passphrase impede que loops de automação funcionem sem intervenção manual. Para scripts de retry de VM, passphrase é incompatível com execução autônoma.
Cadastrar a chave pública no painel Oracle
Após o setup, abra o arquivo gerado:
notepad C:\Users\SEU_USUARIO\.oci\oci_api_key_public.pem
Copie todo o conteúdo. No painel Oracle: User Settings → API Keys → Add API Key → Paste Public Key. O fingerprint gerado deve bater com o que está em C:\Users\SEU_USUARIO\.oci\config.
Testar a autenticação
oci os ns get --profile hermes
Resultado esperado:
{
"data": "seu_namespace_aqui"
}
Se aparecer esse JSON, a autenticação está 100% funcional.
Erro "NotAuthenticated" após geração da chave? Quase sempre significa que a chave pública não foi cadastrada no painel Oracle, ou que o fingerprint no arquivo config não bate com a chave registrada. Delete a chave antiga no painel, adicione a nova e teste de novo.
Como criar VCN, subnet, internet gateway e VM com um único script?
Aqui está o diferencial deste tutorial. Em vez de criar tudo pelo painel (clicando em 12 telas diferentes), o script abaixo faz tudo do zero: cria a rede, a subnet pública, o internet gateway, a rota padrão e depois entra no loop de criação de VM tentando os três Availability Domains até conseguir.
Crie a pasta de trabalho:
mkdir C:\oci-scripts
cd C:\oci-scripts
Crie o arquivo de configuração de shape:
notepad C:\oci-scripts\shape-config.json
Conteúdo do shape-config.json:
{
"ocpus": 4,
"memoryInGBs": 24
}
Agora crie o script principal:
notepad C:\oci-scripts\hermes-full-deploy.ps1
Cole o conteúdo completo abaixo:
# ================================================================
# @CanalQb — Script Completo: VCN + Subnet + IGW + VM A1.Flex
# Versão: 2026.06 | Perfil: hermes | Região: us-ashburn-1
# Documentação: https://canalqb.com.br
# ================================================================
# ---- CONFIGURAÇÕES — edite aqui ----
$PROFILE = "hermes"
$TENANCY_OCID = "COLE_SEU_TENANCY_OCID_AQUI"
$COMPARTMENT = "COLE_SEU_COMPARTMENT_OCID_AQUI"
$REGION = "us-ashburn-1"
$IMAGE_ID = "ocid1.image.oc1.iad.aaaaaaaas3q57pjdbmj46ykc5djtazakxanfvvadw43iuyguiue6ruvjd6yq"
$VCN_CIDR = "10.0.0.0/16"
$SUBNET_CIDR = "10.0.0.0/24"
$VCN_NAME = "vcn-hermes"
$SUBNET_NAME = "subnet-hermes-publica"
$IGW_NAME = "igw-hermes"
$VM_NAME = "hermes-vm"
$VNIC_NAME = "vnic-hermes"
$ADS = @(
"qRwa:US-ASHBURN-AD-1",
"qRwa:US-ASHBURN-AD-2",
"qRwa:US-ASHBURN-AD-3"
)
$INTERVAL_MINUTES = 10
$SHAPE_CONFIG = "file://C:\oci-scripts\shape-config.json"
$LOG_FILE = "C:\oci-scripts\hermes-deploy.log"
# ---- FUNÇÕES AUXILIARES ----
function Log($msg) {
$ts = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$line = "[$ts] $msg"
Write-Host $line
Add-Content $LOG_FILE $line
}
function OciJson($cmd) {
$output = Invoke-Expression "$cmd --profile $PROFILE 2>&1"
if ($LASTEXITCODE -ne 0) { return $null }
try { return $output | ConvertFrom-Json }
catch { return $null }
}
# ---- INÍCIO ----
Log "========================================"
Log "@CanalQb — Hermes Full Deploy Iniciado"
Log "========================================"
# ---- PASSO 1: Verificar se VCN já existe ----
Log "Verificando VCN existente..."
$vcnList = OciJson "oci network vcn list --compartment-id $COMPARTMENT --region $REGION"
$existingVcn = $vcnList.data | Where-Object { $_.'display-name' -eq $VCN_NAME }
if ($existingVcn) {
$VCN_ID = $existingVcn.id
Log "VCN encontrada: $VCN_ID"
} else {
Log "Criando VCN $VCN_NAME ..."
$vcnResult = OciJson "oci network vcn create --compartment-id $COMPARTMENT --cidr-block $VCN_CIDR --display-name $VCN_NAME --dns-label vcnhermes --region $REGION"
if (-not $vcnResult) {
Log "ERRO: Falha ao criar VCN. Verifique o compartment e a região."
exit 1
}
$VCN_ID = $vcnResult.data.id
Log "VCN criada: $VCN_ID"
Start-Sleep -Seconds 5
}
# ---- PASSO 2: Internet Gateway ----
Log "Verificando Internet Gateway..."
$igwList = OciJson "oci network internet-gateway list --compartment-id $COMPARTMENT --vcn-id $VCN_ID --region $REGION"
$existingIgw = $igwList.data | Where-Object { $_.'display-name' -eq $IGW_NAME }
if ($existingIgw) {
$IGW_ID = $existingIgw.id
Log "Internet Gateway encontrado: $IGW_ID"
} else {
Log "Criando Internet Gateway $IGW_NAME ..."
$igwResult = OciJson "oci network internet-gateway create --compartment-id $COMPARTMENT --vcn-id $VCN_ID --is-enabled true --display-name $IGW_NAME --region $REGION"
if (-not $igwResult) {
Log "ERRO: Falha ao criar Internet Gateway."
exit 1
}
$IGW_ID = $igwResult.data.id
Log "Internet Gateway criado: $IGW_ID"
Start-Sleep -Seconds 5
}
# ---- PASSO 3: Route Table padrão com rota 0.0.0.0/0 -> IGW ----
Log "Configurando rota padrão na Route Table..."
$rtList = OciJson "oci network route-table list --compartment-id $COMPARTMENT --vcn-id $VCN_ID --region $REGION"
$defaultRt = $rtList.data | Select-Object -First 1
$RT_ID = $defaultRt.id
$routeRules = "[{`"cidrBlock`": `"0.0.0.0/0`", `"networkEntityId`": `"$IGW_ID`"}]"
$routeFile = "C:\oci-scripts\route-rules.json"
$routeRules | Out-File $routeFile -Encoding utf8
oci network route-table update `
--rt-id $RT_ID `
--route-rules file://C:\oci-scripts\route-rules.json `
--region $REGION `
--profile $PROFILE `
--force | Out-Null
Log "Rota padrão configurada."
Start-Sleep -Seconds 3
# ---- PASSO 4: Security List — liberar SSH e saída ----
Log "Configurando regras de segurança (SSH porta 22)..."
$slList = OciJson "oci network security-list list --compartment-id $COMPARTMENT --vcn-id $VCN_ID --region $REGION"
$defaultSl = $slList.data | Select-Object -First 1
$SL_ID = $defaultSl.id
$ingressRules = '[{"protocol":"6","source":"0.0.0.0/0","tcpOptions":{"destinationPortRange":{"min":22,"max":22}}}]'
$egressRules = '[{"protocol":"all","destination":"0.0.0.0/0"}]'
$ingressFile = "C:\oci-scripts\ingress-rules.json"
$egressFile = "C:\oci-scripts\egress-rules.json"
$ingressRules | Out-File $ingressFile -Encoding utf8
$egressRules | Out-File $egressFile -Encoding utf8
oci network security-list update `
--security-list-id $SL_ID `
--ingress-security-rules file://C:\oci-scripts\ingress-rules.json `
--egress-security-rules file://C:\oci-scripts\egress-rules.json `
--region $REGION `
--profile $PROFILE `
--force | Out-Null
Log "Regras de segurança configuradas."
Start-Sleep -Seconds 3
# ---- PASSO 5: Subnet ----
Log "Verificando Subnet..."
$subnetList = OciJson "oci network subnet list --compartment-id $COMPARTMENT --vcn-id $VCN_ID --region $REGION"
$existingSubnet = $subnetList.data | Where-Object { $_.'display-name' -eq $SUBNET_NAME }
if ($existingSubnet) {
$SUBNET_ID = $existingSubnet.id
Log "Subnet encontrada: $SUBNET_ID"
} else {
Log "Criando Subnet $SUBNET_NAME ..."
$subnetResult = OciJson "oci network subnet create --compartment-id $COMPARTMENT --vcn-id $VCN_ID --cidr-block $SUBNET_CIDR --display-name $SUBNET_NAME --dns-label subnethermespub --prohibit-public-ip-on-vnic false --region $REGION"
if (-not $subnetResult) {
Log "ERRO: Falha ao criar Subnet."
exit 1
}
$SUBNET_ID = $subnetResult.data.id
Log "Subnet criada: $SUBNET_ID"
Start-Sleep -Seconds 8
}
# ---- PASSO 6: Verificar se VM já existe ----
Log "Verificando se VM já existe..."
$vmList = OciJson "oci compute instance list --compartment-id $COMPARTMENT --region $REGION"
$existingVm = $vmList.data | Where-Object { $_.'display-name' -eq $VM_NAME -and $_.'lifecycle-state' -notin @('TERMINATED','TERMINATING') }
if ($existingVm) {
Log "VM '$VM_NAME' já existe com status: $($existingVm.'lifecycle-state'). Nada a fazer."
exit 0
}
# ---- PASSO 7: Loop de criação da VM ----
Log "Iniciando loop de criação da VM A1.Flex..."
Log "Tentando AD-1 → AD-2 → AD-3 a cada $INTERVAL_MINUTES minutos"
$tentativa = 0
while ($true) {
foreach ($ad in $ADS) {
$tentativa++
Log "Tentativa $tentativa — AD: $ad"
$result = oci compute instance launch `
--compartment-id $COMPARTMENT `
--availability-domain $ad `
--shape "VM.Standard.A1.Flex" `
--shape-config $SHAPE_CONFIG `
--image-id $IMAGE_ID `
--subnet-id $SUBNET_ID `
--display-name $VM_NAME `
--assign-public-ip true `
--vnic-display-name $VNIC_NAME `
--region $REGION `
--profile $PROFILE `
2>&1
if ($LASTEXITCODE -eq 0) {
Log "============================================"
Log "VM CRIADA COM SUCESSO no $ad!"
Log "============================================"
$result | Out-String | Add-Content $LOG_FILE
Write-Host "`n✅ VM hermes criada! Verifique o painel Oracle." -ForegroundColor Green
exit 0
} else {
$errorMsg = $result | Out-String
if ($errorMsg -match "Out of host capacity") {
Log "Sem capacidade no $ad. Tentando próximo AD..."
} elseif ($errorMsg -match "LimitExceeded") {
Log "Limite de recursos atingido. Verifique sua cota no painel Oracle."
exit 1
} else {
Log "Erro inesperado no $ad:"
Log $errorMsg
}
Start-Sleep -Seconds 5
}
}
Log "Todos os ADs sem capacidade. Aguardando $INTERVAL_MINUTES minutos..."
Start-Sleep -Seconds ($INTERVAL_MINUTES * 60)
}
O que o script faz automaticamente: verifica se cada recurso já existe antes de criar (idempotente), cria VCN → Internet Gateway → Route Table → Security List → Subnet → e entra no loop de VM tentando AD-1, AD-2 e AD-3 até conseguir. Tudo com log em arquivo.
Como configurar e executar o script no PowerShell?
Antes de rodar, você precisa preencher dois valores no topo do script. São os OCIDs que identificam sua conta Oracle.
Pegar os OCIDs necessários via CLI
Tenancy OCID (você já tem no config) — e Compartment OCID:
oci iam compartment list --compartment-id-in-subtree true --all --profile hermes
Copie o campo "id" do compartment desejado. No script, substitua:
$TENANCY_OCID = "ocid1.tenancy.oc1..aaaaaaaaxxxxxxx"
$COMPARTMENT = "ocid1.compartment.oc1..aaaaaaaaxxxxxxx"
Verificar o Image OCID do Ubuntu 22.04 ARM
Para garantir que está usando a imagem mais recente compatível com A1.Flex (ARM64):
oci compute image list --compartment-id SEU_TENANCY_OCID --operating-system "Canonical Ubuntu" --operating-system-version "22.04" --all --profile hermes
Use a imagem com aarch64 no nome — essa é a única compatível com VM.Standard.A1.Flex. Copie o campo "id" mais recente e substitua no script.
Executar o script
cd C:\oci-scripts
powershell -ExecutionPolicy Bypass -File .\hermes-full-deploy.ps1
O script cria toda a infraestrutura de rede na primeira execução e começa a tentar criar a VM imediatamente. Se falhar por capacidade, aguarda 10 minutos e tenta de novo.
Monitorar o progresso
Para acompanhar o log em tempo real em outro PowerShell:
Get-Content C:\oci-scripts\hermes-deploy.log -Wait -Tail 20
Para verificar se a VM foi criada:
oci compute instance list --compartment-id SEU_COMPARTMENT_OCID --profile hermes
Regra do PowerShell no Windows: nunca use \ para continuar linha de comando — no Windows o caractere de continuação é a crase (`). Usar barra invertida gera erro imediato de parser.
Quais são os erros mais comuns no OCI CLI e como resolver?
Aqui no @CanalQb, passamos por cada um desses erros durante os testes reais desta configuração. Essa tabela é a síntese do que aprendemos:
| Erro | Causa real | Solução |
|---|---|---|
| NotAuthenticated | Chave pública não registrada na OCI ou fingerprint divergente | Remover chave antiga no painel, adicionar a nova oci_api_key_public.pem |
| Out of host capacity | Hardware A1.Flex lotado na região/AD | Loop automático tentando AD-1, AD-2, AD-3 — normalmente resolve em horas |
| CannotParseRequest | JSON de shape config mal formatado ou AD com typo | Usar file:// para o JSON e conferir o nome exato do AD |
| shape_config must be JSON | PowerShell quebrando JSON inline com aspas | Sempre usar arquivo externo com file://caminho\arquivo.json |
| MissingExpressionAfterOperator | Usando \ (barra Linux) para continuar linha no PowerShell |
Substituir por crase (`) ou colocar tudo em uma linha |
| LimitExceeded | Cota Always Free já atingida (recursos anteriores ainda existem) | Verificar e deletar instâncias/volumes antigos no painel Oracle |
Perguntas Frequentes
Quanto tempo leva para conseguir uma VM A1.Flex grátis na Oracle?
Posso usar a VM Oracle A1.Flex com Always Free sem pagar nada?
Por que o comando oci funciona sem o --profile mas retorna erro com ele?
O script de retry pode ser bloqueado por rate limit da Oracle?
Como conectar via SSH na VM Oracle Cloud após a criação?
O script funciona se a VCN e subnet já existirem?
Fontes e Referências
Gostou do tutorial? O @CanalQb publica scripts e guias práticos toda semana.
Ver mais no YouTube @CanalQbFeito com Master Rules Claude v8.4

Comentários
Comente só assim vamos crescer juntos!