Documentation menu

Providers

Cloudflare

Uses the Ahena CLI (beta). Install it with npm install -g @ahena/cli, or prefix commands with npx @ahena/cli. See Installation. The dashboard covers projects, connections, Doctor, the Stack Graph, plans and approvals without it.

Overview

Ahena connects to your Cloudflare account to set up R2 object storage (buckets, CORS) and DNS records, and to check them. Your app talks to R2 directly through the generated src/ahena/storage code (S3-compatible API). Ahena is never in the request path.

Package: @ahena/provider-cloudflare · Category: storage Capabilities: r2, r2-cors, dns, zone-inspection

Connection

Field Secret Stored as
CLOUDFLARE_API_TOKEN yes envelope-encrypted, bound to the environment
CLOUDFLARE_ACCOUNT_ID (32 hex characters) no connection setting
CLOUDFLARE_API_TOKEN=… ahena connect cloudflare -e production   # lists your accounts to pick from

Both user tokens and account-owned tokens work.

Capabilities

Capability What Ahena does
r2 Creates buckets (BILLABLE, always approved explicitly); generates an S3-compatible storage adapter with presigned URLs.
r2-cors Manages one CORS rule (id ahena) and keeps rules you added.
dns Creates and updates records you declared, including email records from Resend. Never deletes records.
zone-inspection Checks zone status and nameservers.

Network: only api.cloudflare.com (enforced). ahena lock tracks bucket existence, CORS origins, declared DNS records and zone status for drift.

Permissions

Create a custom token with only what you use:

Permission Needed for
Account › Workers R2 Storage › Read Doctor, inspect
Account › Workers R2 Storage › Write creating buckets, setting CORS
Zone › Zone › Read DNS checks, zone status
Zone › DNS › Read / Edit checking / adding DNS records

Ahena probes what the token can do and reports it (r2:read, zone:read). A missing permission shows up as a named Doctor finding rather than a vague failure.

Configure

Declare intent in ahena.config.ts:

storage: {
  provider: "cloudflare-r2",
  bucket: { production: "leo-uploads", development: "leo-uploads-dev" },
  corsOrigins: { production: ["https://example.com"], development: ["http://localhost:3000"] },
},
dns: {
  provider: "cloudflare",
  zone: "example.com",
  records: { production: [{ type: "CNAME", name: "files", content: "uploads.example.net" }] },
},

Then ahena configure cloudflare -e production shows the diff and asks for approval. --desired file.json takes the same shape as the provider's desiredSchema.

Change Classification
Create an R2 bucket BILLABLE (R2 usage beyond the free tier is billed). Needs admin and an extra confirmation; --yes also needs --allow-billable.
Set CORS CONFIRMATION_REQUIRED. Ahena manages one rule (id: "ahena") and keeps every other rule.
Add a DNS record CONFIRMATION_REQUIRED
Change an existing DNS record (A/AAAA/CNAME content, or replace the SPF record) DESTRUCTIVE: it overwrites a live record, and the zone is shared by every environment. --yes also needs --allow-billable; through MCP it always asks the developer.

Refused outright: * or localhost origins in production, non-https production origins, CNAMEs that would collide with other records, records outside the zone.

DNS behavior: A/AAAA/CNAME are single-valued per name, so Ahena updates them in place (old → new shown in the diff). TXT/MX can have several values, so Ahena adds yours alongside the others. The exception is SPF: a name may have only one SPF record, so Ahena updates the existing one.

Generate

ahena generate cloudflare writes src/ahena/providers/cloudflare.ts (S3 client for R2), src/ahena/storage/index.ts (upload, download, remove, uploadUrl, downloadUrl, raw) and .env.example.cloudflare. It uses an R2 access key (R2 → Manage API tokens), never your Cloudflare API token. Install @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner.

Limitations

  • Ahena never deletes buckets, objects, CORS rules it didn't create, or DNS records.
  • It doesn't create R2 access keys for your app. Create them in the dashboard.
  • Zones must already be added to the account. Ahena doesn't add domains or change registrars.
  • Workers routes and custom domains aren't managed yet.

Manual steps

Situation What to do
Zone pending Turn off DNSSEC at the registrar, replace its nameservers with the two Cloudflare shows (Doctor prints them), wait for activation.
Token missing a permission Edit the token in the Cloudflare dashboard and add the permission Doctor names.
Token expiring Roll it, then ahena disconnect cloudflare and ahena connect cloudflare.

Doctor checks

Id Severity Meaning
cloudflare.token PASS / WARNING / FAIL Active, expiring within 14 days, or inactive.
cloudflare.r2.access PASS / INFO / FAIL Token can or can't list R2 buckets.
cloudflare.r2.bucket PASS / FAIL Configured bucket exists.
cloudflare.r2.cors_wildcard FAIL Production bucket allows every origin.
cloudflare.r2.cors_local WARNING localhost/private origins on a production bucket.
cloudflare.r2.cors_missing PASS / FAIL Your configured origins are allowed.
cloudflare.r2.cors / _unmanaged INFO No CORS policy, or rules Ahena didn't create.
cloudflare.dns.zone PASS / WARNING / FAIL Active, pending nameservers, missing, or no permission.
cloudflare.dns.record.<type>.<name> PASS / FAIL Configured record present, wrong, missing or conflicting.

Disconnect behavior

Removes the connection and the token Ahena stored. Ahena didn't create the token, so it doesn't revoke it. It links you to https://dash.cloudflare.com/profile/api-tokens. Buckets, objects and DNS records are untouched.