DEV Community

Cover image for I Run My AI Assistant 24/7 on a $0 Server. Here's Every Detail.
thestack_ai
thestack_ai

Posted on

I Run My AI Assistant 24/7 on a $0 Server. Here's Every Detail.

My AI assistant doesn't sleep.

It checks my calendar every 3 hours, summarizes my day at 9 PM, reviews my GitHub repos every 2 hours, and syncs notes to Notion at 10 PM. All on its own.

The server costs me $0/month. Not "$0 for the first year." Not "$0 with credits." Actually zero, forever.

Here's the full setup — including the mistakes I made so you won't have to.

TL;DR: You can run a Claude-powered Telegram bot with 9 scheduled jobs 24/7 on Oracle Cloud's Always Free tier — $0/month, no expiration. The hardware: 1 OCPU + 1 GB RAM + 4 GB swap. After 2 weeks of operation: 99.7% uptime, 3 auto-recovered OOM events, ~15 scheduled job executions per day. Key tricks: aggressive swap, flock-based concurrency control, systemd auto-restart, and 5-minute health monitoring via cron.

The Problem: AI Assistants Die When You Close Your Laptop

I built a Telegram bot powered by Claude. It worked great — when my MacBook was open. Close the lid? Silent. Morning briefings? Missed. Calendar reminders? Gone.

The "personal AI assistant" was really a "personal AI assistant that only works during business hours when I'm already at my desk."

I needed a server. But I also needed it to cost nothing, because this is a side project, not a startup.

The $0 Solution: Oracle Cloud Always Free

Oracle Cloud offers an Always Free tier that never expires. Unlike AWS's 12-month free tier or GCP's $300 credit, OCI Always Free resources do not expire. Here's what you get:

Resource Always Free Allocation
AMD Compute 1 OCPU, 1 GB RAM
Boot Volume 47 GB
Outbound Data 10 TB/month
Object Storage 20 GB

What you'll pay in total:

  • OCI server: $0/month (Always Free, no credit card charges after verification)
  • Claude API: $0/month (using Claude Code with an existing subscription — not per-API-call billing)
  • Telegram Bot API: $0/month (free forever)
  • Domain/DNS: Not needed (Telegram handles routing)
  • Total: $0.00/month

One OCPU and 1 GB of RAM sounds terrible. And honestly? It is terrible. But it's enough.

Step 1: Provision and SSH In

After creating your OCI account (you'll need a credit card for verification — it won't be charged), spin up an "Always Free eligible" AMD instance with Ubuntu.

ssh -i ~/.ssh/your_key ubuntu@YOUR_SERVER_IP
Enter fullscreen mode Exit fullscreen mode

First thing: check your RAM situation.

free -h
#               total   used   free
# Mem:          981Mi   612Mi  102Mi
Enter fullscreen mode Exit fullscreen mode

Yeah. 981 MB total. My Telegram bot alone eats 300-400 MB during Claude API calls. We need swap.

Step 2: The Swap Trick (This Saved Everything)

With 1 GB RAM, you'll hit OOM kills within hours. Don't skip this step.

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Make it permanent
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Tune swappiness — use swap aggressively
sudo sysctl vm.swappiness=60
echo 'vm.swappiness=60' | sudo tee -a /etc/sysctl.conf
Enter fullscreen mode Exit fullscreen mode

After this:

# Mem:   981Mi total, ~350Mi free
# Swap:  4.0Gi total, ~3.8Gi free
Enter fullscreen mode Exit fullscreen mode

Why 4 GB and not 2 GB? During peak scheduled job execution, swap usage hits 2.1 GB. With 2 GB swap, you'd still OOM. 4 GB gives comfortable headroom on an SSD-backed boot volume. Response times go from ~2s to ~5s under memory pressure, but the bot never crashes.

Step 3: Prevent Concurrent Execution

Claude API calls are expensive (in time and memory). Two simultaneous requests on 1 GB RAM = instant OOM. I wrote a wrapper using flock:

#!/bin/bash
# claude-single.sh — ensures only one Claude process runs at a time
LOCKFILE="/tmp/claude-telegram.lock"

exec 200>"$LOCKFILE"
if ! flock -n 200; then
    echo "Another instance is running. Queuing..."
    flock 200  # Wait for lock
fi

# Your actual command here
claude --message "$1" --output-format json
Enter fullscreen mode Exit fullscreen mode

Crude? Yes. Effective? Absolutely. Request #2 waits in line instead of competing for RAM.

Step 4: systemd for Auto-Recovery

The bot needs to survive crashes, OOM kills, and server reboots:

# /etc/systemd/system/claude-telegram.service
[Unit]
Description=Claude Telegram Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/claude-telegram
ExecStart=/home/ubuntu/claude-telegram/start.sh
Restart=always
RestartSec=10
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
Enter fullscreen mode Exit fullscreen mode
sudo systemctl enable claude-telegram
sudo systemctl start claude-telegram
Enter fullscreen mode Exit fullscreen mode

Restart=always is the key line. OOM kill at 3 AM? Back up in 10 seconds. No human intervention needed.

Step 5: Health Monitoring

"It's probably running" is not a monitoring strategy. I verify:

# monitor.sh — runs every 5 minutes via cron
#!/bin/bash

SERVICE="claude-telegram"
LOG="/home/ubuntu/claude-telegram/logs/monitor.log"

if ! systemctl is-active --quiet "$SERVICE"; then
    echo "$(date): $SERVICE is down. Restarting..." >> "$LOG"
    sudo systemctl restart "$SERVICE"

    # Alert via Telegram (using a separate, lightweight curl call)
    curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
        -d "chat_id=${ADMIN_CHAT_ID}" \
        -d "text=Bot was down. Auto-restarted at $(date)."
fi
Enter fullscreen mode Exit fullscreen mode
# Cron: check every 5 minutes
*/5 * * * * /home/ubuntu/claude-telegram/monitor.sh
Enter fullscreen mode Exit fullscreen mode

In 2 weeks of operation, the monitor has caught and recovered from 3 OOM kills. Each time, the bot was back within 15 seconds. Without monitoring, I wouldn't have even known it went down.

Step 6: Scheduled Jobs (The Real Value)

A bot that only responds to messages is a chatbot. A bot that proactively works for you is an assistant. This distinction matters.

The 9 Jobs I Run Daily

Job Schedule What It Does
Morning Briefing Weekdays 8:00 AM Calendar + tasks + news summary
Calendar Check 4x daily (9/12/15/18) Upcoming meeting alerts
Evening Summary Daily 9:00 PM Day recap + memory save
GitHub Check Every 2 hours PR reviews, issue notifications
Memory Sync Every 3 hours Sync context across devices
Notion Sync Daily 10:00 PM Save important conversations
Weekly Review Friday 6:00 PM Week summary + planning
Token Check Daily 10:00 AM Verify API credentials
Threads Notify 2x daily Social updates digest

Why Morning Briefing Is the Killer Feature

The morning briefing alone justifies the entire setup. Every weekday at 8 AM, before I even open my laptop, my phone buzzes. One Telegram message with my schedule, pending tasks, and relevant news — generated by Claude using my calendar data via MCP (Model Context Protocol) integration.

It pulls from Google Calendar and Notion, cross-references deadlines, and delivers a single digest. No app switching. No manual checks. One message. That's it.

Step 7: Authentication That Doesn't Expire Every Hour

Default OAuth tokens expire quickly. For a 24/7 server, you need a long-lived token:

# Store in .env
CLAUDE_CODE_OAUTH_TOKEN=your_long_lived_token_here
Enter fullscreen mode Exit fullscreen mode

I configured a token with 1-year validity. Without this, the bot silently fails every few hours when the token expires — and you wake up to 8 hours of missed messages with no error in sight.

I also run a daily token health check that alerts me 30 days before expiry.

What I'd Do Differently

1. Start with swap from minute one. I spent 2 days debugging random crashes before realizing it was OOM kills. One command would have told me immediately:

dmesg | grep -i oom
Enter fullscreen mode Exit fullscreen mode

2. Don't underestimate 1 OCPU. The CPU is fine. It's not fast, but Claude API calls are I/O-bound (waiting for API responses), not CPU-bound. One OCPU handles my workload without breaking a sweat.

3. Log everything from day one. I added proper logging after a week of "it probably works." Future me was grateful. The monitor log has caught issues I never would have noticed otherwise.

The Numbers: $0 vs Paid Servers

After 2 weeks of 24/7 operation, here's how the free tier actually compares to paid alternatives:

Metric OCI Always Free ($0/mo) Typical VPS ($5-20/mo) Dedicated ($200+/mo)
Uptime 99.7% (auto-recovered) ~99.9% 99.99%
Response time 40-50s 40-50s 40-50s
Monthly cost $0.00 $5-20 $200+
RAM 1 GB + 4 GB swap 2-4 GB 16+ GB
Concurrent requests 1 (flock-limited) 3-5 Unlimited

The response time row is the key insight: it's identical across all tiers. The bottleneck is Claude's API latency (40-50 seconds of thinking time), not server hardware. You'd be paying $200/month for faster concurrent handling — which you probably don't need for a personal assistant that handles 30-40 messages a day.

Full Metrics Breakdown

Metric Value
Uptime 99.7% (3 auto-recovered OOM events)
Monthly cost $0.00
Average response time 40-50 seconds (Claude API latency)
Daily messages handled ~30-40
Scheduled jobs/day ~15 executions
RAM usage (steady state) ~600 MB + swap
Swap usage (peak) ~2.1 GB

Total Stack

+-----------------------------------+
|  Oracle Cloud (Always Free)       |
|  Ubuntu 22.04 / 1 OCPU / 1 GB    |
|  + 4 GB Swap                      |
|                                   |
|  +-----------------------------+  |
|  | systemd (auto-restart)      |  |
|  |  +- Telegram Bot (Python)   |  |
|  |      +-- Claude API         |  |
|  |      +-- MCP: Calendar      |  |
|  |      +-- MCP: Notion        |  |
|  |      +-- 9 Scheduled Jobs   |  |
|  +-----------------------------+  |
|                                   |
|  +-----------------------------+  |
|  | Cron                        |  |
|  |  +-- monitor.sh (5 min)     |  |
|  |  +-- memory-sync (3 hr)     |  |
|  |  +-- token-check (daily)    |  |
|  +-----------------------------+  |
+-----------------------------------+
Enter fullscreen mode Exit fullscreen mode

FAQ

Will Oracle actually keep this free forever?

Oracle's Always Free tier has been available since 2019 with no expiration date. Unlike AWS's 12-month free tier or GCP's $300 credit that runs out, OCI Always Free resources genuinely persist indefinitely. I've been running for over 2 weeks with zero charges on my account. That said — Oracle can change terms, so don't build a business-critical production service on it. For a personal AI assistant? It's perfect.

Can I run GPT-based bots instead of Claude?

Yes. The server architecture is completely API-agnostic. Swap the Claude API call for OpenAI's API and everything else stays the same. The memory constraints, swap tricks, flock concurrency, and systemd setup apply identically — the bottleneck is always API latency, not local compute.

What happens when the server runs out of swap?

The Linux OOM killer activates and terminates the heaviest process — which is your bot. With Restart=always in the systemd unit file, the bot comes back in approximately 10 seconds. In my 2 weeks of operation, this happened 3 times — all during overlapping scheduled job executions. The 5-minute monitor catches anything systemd misses.

Is 1 GB RAM enough for multiple bots?

Probably not. One bot with flock-serialized requests uses approximately 600 MB at steady state. A second bot would push you into constant heavy swapping with degraded performance. For running multiple bots, look at OCI's Ampere A1 Always Free tier — 4 OCPUs and 24 GB RAM — though availability varies by region and is often limited.

How do I set up the MCP integrations (Calendar, Notion)?

MCP (Model Context Protocol) lets Claude connect to external services through standardized tool interfaces. I use two MCP servers: one for Google Calendar (HTTP-based with OAuth) and one for Notion (stdio-based with API key). The Claude documentation covers MCP setup in detail — the server-side configuration is identical whether you're running locally or on OCI.

Try It Yourself

  1. Get an OCI account: Sign up at Oracle Cloud. Select "Always Free" resources only.
  2. Set up swap immediately: 4 GB minimum. Don't skip this.
  3. Use systemd + monitoring: Your bot will crash. Make sure it comes back automatically.
  4. Start with one scheduled job: Morning briefing is the most impactful. Add more as you validate each one works.

The whole setup took me a weekend. The hardest part wasn't the code — it was accepting that 1 GB of RAM is actually enough when you manage it properly. Then it just... runs.

Your AI assistant shouldn't need your laptop to be open. Give it a home that runs while you sleep.


What's your always-on setup? Running AI tools on a VPS, a Raspberry Pi, or something weirder? Drop it in the comments — I genuinely want to see what others have built.

If this saved you some Googling, bookmark this post for when you're ready to deploy. And if you're into AI tools that actually run in production — not just in demos — follow me for more.


I build AI-powered automation that runs 24/7 on minimal infrastructure — no drama, no cloud bills. This bot handles 30-40 messages daily plus 15 scheduled jobs without me touching it. If that's the kind of AI engineering you care about, follow along.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.