OCI Free Tier ARM in practice · Always Free 2 vCPU / 12GB RAM (since 2026-06-15) · PAYG 4 OCPU / 24GB unaffected (see §15) · systemd running 24/7 Zero-cost cloud AI Agent, all pitfalls have been eliminated for you
⚡ This guide is continuously updated (latest measurement 2026-09). All resources must stay within the "Always Free" allowance or charges apply; PAYG tenancies are unaffected by the 2026-06-15 halving (see §15).
Hermes Agent is an open source AI Agent framework (MIT protocol) developed by Nous Research - it reads files, writes code, executes commands, and controls browsers on the terminal. It is not bound to any model manufacturer and has a built-in Telegram Gateway. Put it on Oracle's permanently free VM and it becomes a 24/7 uninterrupted cloud AI Agent.
systemd service management: auto-start at boot, auto-restart after crash, and disconnect SSH all run as usual.
💰
Free forever
ARM 2 vCPU + 12GB RAM + 200GB disk (Always Free, since 2026-06-15); PAYG keeps 4 OCPU / 24GB (see §15)
🔄
Model freedom
You can choose from DeepSeek / OpenAI / Anthropic / Google, just change the supplier and change the config.
💬
Telegram native
Built-in Gateway, a systemd service that automatically replies 24/7
🖥️
Zero operational anxiety
Automatic restart after crash + journald log + remote backup, you can’t even sleep.
1. Register
1Register for an Oracle Cloud Free Tier account
Go to registration page
https://signup.cloud.oracle.com/
Fill in your name, email, and country/region.
Pick Home Regionkey
Be sure to pickSupports Ampere ARM instancesRegion (Cannot be changed after Home Region): Osaka / Tokyo / Paris / Frankfurt / Ashburn / Phoenix are all supported.
If you choose the wrong Home Region, there will be no ARM instances - this will determine whether you will have 2 vCPU free machines later.
Credit card verification
A valid credit or debit card is required. Oracle will temporarily deduct the contract$1 USDVerify and return after a few days.Virtual or prepaid cards are not accepted.
Waiting for activation
Usually a few minutes to a few hours. Log in after receiving the activation emailcloud.oracle.com.
⚠️ Free does not mean unlimited:Resources exceeding the "Always Free" limit will incur fees. It is recommended to upgrade to Pay-As-You-Go (still $0, but it can be solved when the capacity is insufficient, and it is also an antidote to the lack of capacity with free ARM).
2. Create VM
2Create an OCI computing instance (VM)
Open the creation page
OCI Console →Compute → Instances → Create Instance. The area should display the "Always Free-eligible" label.
VM.Standard.A1.Flex— 2 OCPU + 12GB RAM (was 4/24 before 2026-06-15)
✅ Main force (largest within free allowance)
x86Micro
VM.Standard.E2.1.Micro— 1/8 OCPU + 1GB
❌ Too thin, only suitable for testing
Network + SSH key
Use the default VCN/subnet and check "Assign a public IPv4 address". SSH select "Paste public keys" and paste your public key (generate it if it is not available locally):
⚠️ Remember:Oracle has two layers of firewall— In addition to UFW/iptables inside the VM, there is also the Security List of OCI VCN (discussed in Section 10). Both floors must be opened first.
out to the version number (e.g.hermes 0.14.0) means success. The installation path is~/.local/bin/hermes, set in~/.hermes/.
⚠️ ARM actual test pit: HTTP/2 download failed.The installation script may report when downloading Node.jscurl: (92) HTTP/2 stream error. Solution:Ctrl+CTermination → Manually download Node.js for ARM using HTTP/1.1:
Enter "Hello" and receive the reply successfully.Ctrl+CExit.
⚠️ Pitfall: There are two types of DeepSeek Key!People who have used Claude Code + DeepSeek may be mistaken - one is used by Claude CodeANTHROPIC_AUTH_TOKEN, one is the DeepSeek platform native Key,Both have the same format but different values. Use the original Key of the platform; reporting 401 means Key error. Quick test:
On a Linux server, Gateway must run systemd to: auto-start at boot, auto-restart on crash, stay connected 24/7, and continue running after disconnecting SSH.
Install Gateway
hermes gateway install
Manually create systemd service filecore steps
⚠️The biggest pitfall: systemd cannot read .env files!Environment variables must be written directly to the service file, otherwise the Bot session will be "No messaging platforms enabled".
[Unit]
Description=Hermes Gateway Service
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu
ExecStart=/home/ubuntu/.local/bin/hermes gateway
Restart=always
RestartSec=10
Environment=PATH=/home/ubuntu/.local/bin:/usr/local/bin:/usr/bin:/bin
# Key: systemd does not read .env, environment variables must be written directly there!
Environment=DEEPSEEK_API_KEY=sk-your-deepseek-key
Environment=TELEGRAM_BOT_TOKEN=Your Bot Token
Environment=TELEGRAM_ALLOWED_USERS=Your Telegram digital ID
Environment=TELEGRAM_HOME_CHANNEL=Your Telegram digital ID
Environment=GATEWAY_ALLOW_ALL_USERS=true
[Install]
WantedBy=multi-user.target
Key points of modification:User/WorkingDirectory/ExecStartChange according to actual path; fiveEnvironment=All must be filled in with true values.
Lessons from actual testing (our machine):To modify the service file, you can write it locally and upload it first -sudo cpenter/etc/systemd/system/Againdaemon-reloadJust have to. In additionBefore using systemd on Bot, you must pkill the old polling process., otherwise Telegram will report 409 Conflict (two getUpdates compete for the same Bot at the same time). finallyhermes git pull --rebaseRemember to restart the service after updating.
8. Telegram
8Access Telegram Bot
Build a Bot with @BotFather
Telegram search@BotFather→/newbot→ Set name/username →Bot Token(Format123456:ABC-DEF1234ghiJKL). Store it properly and avoid leakage.
Get your Telegram digital ID
Search@userinfobot→/start→ Numeric ID (e.g.123456789).
log see✓ telegram connected, and then talk to your Bot on Telegram and get a reply.
Troubleshooting tips:Bot has no response → ①sudo systemctl status hermes-gatewaySystem running → ② logjournalctl -u hermes-gateway -f→ ③ seeNo messaging platforms enabled= Token has not been read → ④ Check the service file Environment → ⑤daemon-reload+restart→ ⑥ Verify again.
CRITICAL LANGUAGE RULE: You MUST reply in Chinese (繁体中文) at all times.
The user speaks Chinese. Never use English unless the user explicitly asks.
(Optional) Inject project knowledge
SOUL.md can write identity, skills, project structure, coding specifications, and commonly used commands - it becomes Hermes' "long-term memory" and is referenced in every conversation.
Restart takes effect
sudo systemctl restart hermes-gateway
After changing SOUL.md, you must restart Gateway for it to take effect.
10. Firewall
10Firewall and security rules (both layers must be turned on)
Oracle VM hasTwo-layer firewall: Security List of OCI VCN (cloud layer) + UFW (system layer) within the instance. Both floors will not be allowed to pass until they are cleared first.
If you install WebUI, you need to open the corresponding port (such as 8787).
▎10.2 Instance firewall (system layer)
sudo ufw status verbose
should see22 / 80 / 443 ALLOW IN. Oracle Linux users may need to change iptables directly if UFW does not respond.
⚠️ Lessons from actual testing: OCI’s “NSG ≠ iptables”.If you have opened the security list in the Console but still cannot connect, it is best to check iptables in the VM - first confirm whether the OCI layer (Security List / NSG) is allowed. The two floors are independent.Any layer that blocks it will fail.. Zhong You: Many times 443 has been occupied by other services (such as sing-box proxy). Before opening the port,ss -tlnpTake a look at the location below.
12A collection of pitfalls (all personally tested)
Q: Bot reports 409 Conflict after running systemd?
Reason:The old polling process is still competing with the Gateway for a Bot Token. Solution:Before starting servicepkill -f "hermes"or directlypkill -f polling, againsystemctl start hermes-gateway.
Q: Gateway is started but Bot is completely unresponsive?
Reason:9 Systemd does not read environment variables. Log appearsNo messaging platforms enabledThat is, the Token is not loaded. Solution:Confirm the service fileEnvironment=All five variables are filled in →daemon-reload+restart→ Read the log again.
Q: DeepSeek API reports 401 Authentication Fails?
Reason:The wrong Key (the Claude Code one) is used or the Key expires. Solution:Use curl to test the Key (see §6) → Rebuild the platform → Update the service fileDEEPSEEK_API_KEY→daemon-reload+restart.
Q: SSH connection failed/timed out?
Check order:① Is OCI Security List open? 22 → ② Public IP Yes → ③ Key permissionschmod 400 ~/.ssh/id_rsa→ ④ Username (for Ubuntuubuntu).
Q: Out of memory (OOM)?
Basically you will not encounter this with ARM 2 vCPU / 12GB instances. x86 micro needs to add Swap first: sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile Join again/etc/fstabEffective permanently.
Q: Will Oracle recycle my machine?
Oracle will recycle free instances with long periods of low activity. Gateway 24/7 operation itself is a continuous activity; if you want to be more stable, you can add keepalive: crontab -e→ Join*/30 * * * * echo "keepalive $(date)" >> ~/keepalive.log
Q: Do I need to restart after updating?
apt upgradeAfter updating the kernel, you need tosudo rebootEffective first;hermes git pull --rebaseAfter updating the source code, you need tosudo systemctl restart hermes-gateway.
13.WebUI
13Advanced: Hermes WebUI (optional)
Want to interact with the Agent using the browser interface without using SSH? Just install WebUI.
Clone + set password
cd ~
git clone https://github.com/nesquena/hermes-webui.git hermes-webui
cd hermes-webui
echo "HERMES_WEBUI_PASSWORD=Set a strong password" > .env
tar -czvf hermes-backup-$(date +%Y%m%d).tar.gz \
~/.hermes/config.yaml ~/.hermes/.env ~/.hermes/SOUL.md \
~/.hermes/logs/ /etc/systemd/system/hermes-gateway.service
# Pull back to local
scp ubuntu@<your public IP>:~/hermes-backup-*.tar.gz ./
config.yaml(setting),.env(key),SOUL.md(long-term memory), systemd service files - these four additions are the "soul" of the machine, without them they are the same as starting from scratch.
rotation API Key, check Drive/remote backup integrity
⚠️ Never assume an apt upgrade is "safe": upgrading docker-ce / containerd restarts the Docker daemon, which bounces every container. Measured 2026-09-16: during that restart Pi-hole could not rebind its host port and died silently, taking every proxy handshake with it — clients showed "port not open" while 443/853 were still listening. After any upgrade verify three things: docker ps lists every container, systemctl status sing-box is active, and actually connect through the proxy once (see §16 for the automated way).
▎14.3 Safety recommendations
Regularly update the system package; after kernel updatesudo reboot
It’s not easy to use root to run Hermes (use ubuntu user)
LimitTELEGRAM_ALLOWED_USERS, to prevent unauthorized use
Install fail2ban to prevent brute force cracking:sudo apt install fail2ban -y
Regularly check API usage to avoid unexpected overspending
Appendix
15 ⚠️ 2026-06-15: Oracle silently halved the free tier
On 2026-06-15 Oracle silently updated its Always Free docs with no announcement or email: the ARM allowance was halved from 4 OCPU / 24GB → 2 OCPU / 12GB (monthly cap 3,000 OCPU-hrs + 18,000 GB-hrs → 1,500 + 9,000). Network egress stays at 10TB/month (unchanged).
Config (always-on for a month)
Usage
New cap 1,500 + 9,000
4 OCPU / 24GB (old)
2,920 OCPU-hrs + 17,520 GB-hrs
❌ 2x over
2 OCPU / 12GB (new)
1,460 OCPU-hrs + 8,760 GB-hrs
✅ Fits exactly
▎15.1 Pure free vs PAYG — different fates
Pure free accounts: over the cap → risk of forced instance termination (shrink to 2/12 to be safe)
PAYG: ✅ Official written confirmation (2026-08-03) — not affected; keep your existing 4 OCPU/24GB, no resize, no billing, no deadline
⚠️ Only caveat (acknowledged by Oracle): a stopped instance can be started again normally; but if it is terminated, recreating the same configuration depends on ARM capacity in Osaka at that time. Insurance in place: OCI boot volume backup + Drive off-site backup.
"All tenancies get the first 1,500 OCPU hours and 9,000 GB hours per month for free for VM instances using the VM." "you can create one or two OCI Ampere A1 Compute instances, 2 OCPUs total."
▎15.3 Official support reply, verbatim (2026-08-03, PAYG inquiry)
"Thank you for providing the details. Since your tenancy is a Pay As You Go (PAYG) account, you do not need to worry about the recent Always Free Ampere A1 resource limit update. Your existing 4 OCPU / 24 GB A1 instance does not need to be resized as a result of this policy change. You will not be billed for your existing 4 OCPU / 24 GB A1 instance solely because of the Always Free limit update. The reduction to 2 OCPUs / 12 GB RAM applies only to Always Free tenancies, not to PAYG accounts. There is no deadline requiring PAYG customers to resize existing A1 instances because of this change. If your instance is stopped, you can start it again normally. However, if it is terminated, the ability to recreate an instance with the same configuration depends on current capacity availability in your selected region. The reduction in the Always Free Ampere A1 allocation applies only to Always Free tenancies. PAYG and other paid tenancy types are not affected by this specific policy change. Based on the information available, your existing 4 OCPU / 24 GB A1 instance on your PAYG tenancy will continue to operate under the terms applicable to your paid account and will not incur charges solely because of this Always Free policy update."
▎15.4 Community consensus (2026-07)
Reddit r/selfhosted PSA (1.5K upvotes): "Resize by June 15 to avoid charges"
Enforcement is inconsistent: many accounts still run 4/24 untouched; Oracle's price list still shows 3K/18K free
⚠️ Biggest risk: ARM capacity shortage (many "insufficient capacity" reports) — if your instance terminates, you may not even be able to recreate 2/12
▎15.5 Insurance (tested)
OCI Boot Volume Backup: Console → Compute → Instance → Boot volume → Create backup (cloud-level full restore, ~10 min to Available)
Drive off-site backup: config tar.gz (~/.hermes, nginx, systemd, crontab) auto-uploaded daily → Google Drive (see §14)
Don't stop the instance casually: once terminated during the grandfather period, you may never get it back
▎15.6 Alternatives (if Oracle falls apart)
Need
Option
Cost
Japan IP + cheapest
Keep Oracle 2/12
$0
Japan IP (paid)
Contabo Osaka 4vCPU/8GB | Vultr Tokyo 1-2GB
~€7/mo | $5-6/mo
No Japan IP needed
RackNerd 1GB | GCP e2-micro
~$1/mo | $0
GFW purposes
VLESS/REALITY (works on any VPS) + CF Worker backup
from $0
💡 GFW note: Oracle/Contabo datacenter IPs tend to get blocked over time; REALITY resists active probing; a CF Worker (edgetunnel) is a free backup channel.
Oracle will not tell you how much of your free allowance you have burned — you usually find out when a charge appears. This section pulls your real usage from the official Usage API every day, projects it to month-end, warns past 90%, and lets Hermes push it to Telegram. Every number is live from the API — nothing hand-typed.
▎16.1 Install the OCI CLI + API key
bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
~/bin/oci setup config # interactive: Tenancy OCID / User OCID / Region / generate keypair
Then in the Console: avatar (top right) → My profile → API keys → Add API key → paste the contents of ~/.oci/oci_api_key_public.pem. Note your Tenancy OCID — that is the --tenant-id below. Every query afterwards just reads ~/.oci/config; no login needed.
Docs vs reality: in this CLI version oci limits / oci iam limit*do not exist, so you cannot query free-tier quota from a quota API — derive it from the Usage API below instead.
▎16.2 The two commands that matter (verified; the docs are incomplete)
The real path is usage-api usage-summary request-summarized-usages. usage-api request-summarized-usages and usage-api query ... (saved queries only) both give Error: No such command.
When oci ... list finds nothing it returns rc=0 with completely empty stdout (not {"data": []}) → json.loads blows up. Handle it with if not out: return {"data": []}.
The keyword Standard - A1 also matches the memory row → OCPU hrs = qty("A1") − qty("A1 - Memory"), otherwise your compute figure is doubled.
▎16.3 Wire it into Hermes: push to Telegram daily at 08:00
# 1) The report script (whatever it prints on stdout IS the Telegram message)
nano /home/ubuntu/oci-billing/oci_billing_report.py
# 2) Hermes cron only accepts files under ~/.hermes/scripts/, so add a thin wrapper
echo '#!/bin/bash' > ~/.hermes/scripts/oci_billing_report.sh
echo 'exec python3 /home/ubuntu/oci-billing/oci_billing_report.py' >> ~/.hermes/scripts/oci_billing_report.sh
chmod +x ~/.hermes/scripts/oci_billing_report.sh
# 3) Create a no_agent job (zero tokens; stdout is delivered verbatim)
hermes cron create "0 8 * * *" --name "OCI daily billing report" \
--script oci_billing_report.sh --no-agent --deliver origin
# 4) Fire it once now (no need to wait for the morning)
hermes cron run <job_id>
--no-agent means no LLM is called — stdout goes out as-is, and empty stdout sends nothing (the classic watchdog shape). Change the schedule by editing the cron expression, e.g. "30 7 * * 1" = Mondays 07:30. Plain system crontab works too, but hermes cron adds run history and failure notices.