Deploy A Nearly Free AI Personal Assistant: Clawdbot on Oracle

In my last post I briefly discussed Clawdbot, the virtual assistant from Peter Steinberger that has taken off as an open source alternative to something like Poke.

I wanted to host this 24/7 as cheap as possible, not on my laptop. Oracle Cloud's free-tier compute: 4 core & 24gb RAM VPS offering is more than sufficient to achieve this at no hosting cost.

I've published a repository to spin this up on Oracle Cloud, via Pulumi (infra-as-code) and GitHub Actions.

What you'll need to do is:

Task List

The rest of the article walks you through the above tasks.

Task List

What are we deploying

Infra

I'm detailing the infra using the Oracle terms and the AWS equivalent for familiarity:

  • a 'VCN' (VPC): a virtual cloud network.
  • internet gateway & route table to provide the compute instance with internet access
  • a Ubuntu server with up to 4 cores, 24gb RAM; you could choose to tune this down as this is overkill for clawdbot alone, but perhaps not if you want it to control harness sessions, or browsers too.
  • 'security list' (security group) defining allowed inbound/outbound port connectivity
  • the compute is going into a public subnet to avoid the expense of a NAT gateway & load balancer.

Networking:

We allow inbound:

  • TCP port 22 (SSH) but only with a public key, no password or root login, and the stack won't deploy without public/private key (encrypted) specified.
  • UDP 41641 is open for Tailscale to avoid falling back to DERP relays adding latency if you want to use your devices as clients.

Fail2ban is configured in cloud-init to ban IPs making too many failed login attempts.

All outbound traffic is allowed.

For receiving data from third party services, Tailscale Funnel is natively integrated into Clawdbot, you will need to configure Clawdbot to use it (post-deploy).

What 'Funnel' will achieve: you'll be given a Tailscale URL which acts as your unique tunnel to Clawdbot's HTTP listener, with our Tailscale client on the VPS terminating TLS and passing data to Clawdbot. The Tailscale client maintains a persistent outbound connection to its DERP home region, which Funnel relay servers use to reach your node when requests arrive: meaning we don't need to expose inbound ports for Clawdbot.

A Word on Security

This article is aimed at an audience who want to experiment with a personal AI assistant, as cheaply as possible. You are responsible for what data you expose via your configuration of Clawdbot, especially in relation to your choice of LLM model provider.

If you put an absolute premium on information security, the approach in this article is not the correct one for you. I might write up a self-hosted LLM equivalent article if there's sufficient demand (subscribe and drop a note: author@abrown.blog).

My goal is to give you a secure infrastructure setup, from there you need to carefully consider what you choose to do.

Limitations

Genuine question:
Why are people buying expensive Mac minis to run an agent that rips on a $25/mo VPS you can access from anywhere?
I must be missing something. Please let me be missing something.

People are buying mac minis because of discrimination of cloud IPs versus residential IPs and more shenanigans that services are pulling. For now, coming out on your own computer and IP lets you access way more services than doing it from the cloud.

Regarding the IP limitations, as noted in the thread, a Tailscale exit node is a fairly easy solution here. This might compromise the goal of not running your own compute 24/7, but personally my GL.iNet GL-MT3000 router happily does this and is on 24/7 anyway.

There are possibly some further limitations if you actually need to access Apple ecosystem tools (as Armin pointed out later), but these can be solved by having your macbook function as a Node, though it would need to be on.

Before you deploy

You'll need accounts with a few services before we can deploy. All of these have free tiers that are sufficient for our purposes.

Oracle Cloud Account

Head to Oracle Cloud and sign up for a free account.

The compute resources we're deploying are within the always-free tier, however there is a small catch regarding provisioning the instance.

When I tried to provision the instance without signing up to pay-as-you-go, it would regularly fail (over 50 attempts). Once my plan was upgraded, again bearing in mind we're still operating in the always-free tier, the deployment succeeded on the first attempt.

You probably need to sign up to pay-as-you-go in order to acquire a free instance, but this deployment won't cost you anything as-is.

Now to the data you'll need from Oracle once signed up:

VariableHow to Retrieve
OCI_TENANCY_OCIDProfile (top-right corner) > Tenancy > OCID
OCI_USER_OCIDProfile > your email > OCID
OCI_FINGERPRINTProfile > User Settings > Tokens and Keys > Create an API Key. Afterwards, the fingerprint will be visible. Make sure to download the private key if you have Oracle generate it.
OCI_PRIVATE_KEY_FILEDownload it from the previous step, for simplicity, .gitignore a top-level folder and place it here. If deploying in CI/CD, we'll cover what to do in the Deploy chapter.
OCI_REGIONLook this up as appropriate for you
OCI_COMPARTMENT_IDJust the tenancy OCID above.

Tailscale

Sign up for a free Tailscale account. We'll use Tailscale to create secure networking for your VPS and enable Funnel for external webhooks.

VariableHow to Retrieve
TAILSCALE_CLIENT_IDAdmin Console > Settings > Settings > Trust Credentials. Add the Auth Keys write scope when creating it.
TAILSCALE_CLIENT_SECRETGenerated alongside the Client ID in the previous step. Save it immediately as you won't be able to view it again.
TAILSCALE_TAGAdmin Console > Access Controls > Tags tab > Create a tag (e.g., tag:clawdbot) with owner set to autogroup:admin. Then assign this tag to your OAuth client.
TAILSCALE_TAILNETAdmin Console > DNS tab > Your tailnet DNS name

Pulumi Cloud

Pulumi is an infrastructure-as-code tool that lets us define our cloud resources in TypeScript. Create a free account and generate an access token. The free tier includes 200 resources which is plenty for this deployment.

The reason we're troubling with this is that it lets us store our state file without needing paid cloud storage or keeping it in the repo and awkwardly re-committing it after deployment.

VariableHow to Retrieve
PULUMI_ACCESS_TOKENProfile (top-right) > Personal access tokens > Create new access token
PULUMI_ORGYour Pulumi organization name (visible in the URL after logging in)

LLM Model

Clawdbot needs an LLM to function. I strongly recommend against any provider's API key pricing, better to obtain a subscription and cap your expenditure.

The most popular low-cost option among the Clawdbot community seems to be Minimax (starts $10 USD/month), this is a referral link for 10% off.

If you're planning to do a lot of coding via Clawdbot or even on your own machine, possibly a better option is z.ai's GLM 4.7, starting at a mere $3 USD/month (first month) and $6 thereafter. Here's a referral, but bear in mind Z.AI seems to emphasise use with coding agents only, they may crack down on this at some point.

Note: we don't configure the subscription key as an env variable, we provide it to Clawdbot after we SSH in.

Fork or Clone Repo

Simple option: If you just want to deploy locally, clone the repo and set your environment variables in a gitignore'd .env file.

Slightly more involved: If you want to run all of your changes to the infra through CI/CD (more involved), fork it, make it private and setup the appropriate secrets / variables in GitHub Actions.

Configure Repository Actions

Skip this if you opted to clone.

If you have a coding agent setup with access to your github account, I highly recommend having it set these up for you (reading from your .env file) instead of manually setting them up.

To do this manually, go to your forked repository in GitHub -> Settings -> Secrets and Variables -> Actions.

Set the below as Secrets (not variables):

Secret Name
OCI_TENANCY_OCID
OCI_USER_OCID
OCI_FINGERPRINT
OCI_COMPARTMENT_ID
OCI_PRIVATE_KEY
PULUMI_ACCESS_TOKEN
TAILSCALE_CLIENT_ID
TAILSCALE_CLIENT_SECRET
SSH_PUBLIC_KEY

Set the below as Variables (not secrets):

Variable Name
TAILSCALE_HOSTNAME
TAILSCALE_TAG
TAILSCALE_TAILNET
PULUMI_ORG
PULUMI_STACK
PULUMI_PROJECT
OCI_REGION

Note: PULUMI_PROJECT and PULUMI_STACK are the names you want these to have, it's not extremely important what these are.

I set project to 'clawdbot' and stack to 'oracle-vps'.

Deployment

Via CI/CD

Go to your Repo -> Actions and find the Pulumi Deploy workflow on the left hand side.

Click it, then 'Run Workflow' from the main branch, near the right hand side of the page.

Reminder: If you didn't set up pay-as-you-go in Oracle Cloud, there's a good chance you'll see a 'no instances available' error. Other errors are likely to do with your actions secrets/variables, check these closely and consider feeding the error to OpenCode with a free model to check the configuration for you.

If it was succesful, to test SSH:

Copied
$ssh -i ./your-key-folder/path-to-your-private-key.pem ubuntu@<your-public-ip>

Local Deployment

If you've chosen the local deployment, ensure your .env file contains the following variables:

VariableDescription
OCI_TENANCY_OCIDYour Oracle tenancy OCID
OCI_USER_OCIDYour Oracle user OCID
OCI_FINGERPRINTYour API key fingerprint
OCI_COMPARTMENT_IDYour compartment ID (usually the tenancy OCID)
OCI_PRIVATE_KEY_FILEPath to your OCI private key file
OCI_REGIONYour Oracle region (e.g., uk-london-1)
PULUMI_ACCESS_TOKENYour Pulumi access token
PULUMI_ORGYour Pulumi organization name
PULUMI_PROJECTYour Pulumi project name (e.g., clawdbot)
PULUMI_STACKYour Pulumi stack name (e.g., oracle-vps)
TAILSCALE_CLIENT_IDYour Tailscale OAuth client ID
TAILSCALE_CLIENT_SECRETYour Tailscale OAuth client secret
TAILSCALE_HOSTNAMEHostname for your VPS in Tailscale (you can specify any arbitrary name for this)
TAILSCALE_TAGTailscale tag (e.g., tag:clawdbot)
TAILSCALE_TAILNETYour Tailscale tailnet name
SSH_PUBLIC_KEYYour SSH public key for VPS access

Then run $npm start up:localcopied. You should see it spit out your instanceId, public IP and tailscaleFqdn.

Reminder: If you didn't set up pay-as-you-go in Oracle Cloud, there's a good chance you'll see a 'no instances available' error. Other errors are likely to do with your .env, check these closely and consider feeding the error to OpenCode with a free model to check the configuration for you.

If it was succesful, to test SSH:

Copied
$ssh -i ./your-key-folder/path-to-your-private-key.pem ubuntu@<your-public-ip>

Post-Deployment

The first thing you'll want to do is tail the cloud-init output: $tail -f /var/log/cloud-init-output.logcopied Note that this will likely be in progress if you SSH straight after deployment, give it time if it appears stuck.

If everything went to plan, you should see a URL under some text reading:

"Funnel is enabled, but the list of allowed nodes in the tailnet policy file does not include the one you are using. To give access to this node you can edit the tailnet policy file, or visit:"

Click the link and approve your instance to use Funnel.

Once this is done, your cloud-init should complete and you can run $clawdbot onboardcopied to get started with Clawdbot.