Manage Cloudflare DNS — SKILL.md

Raw skill file that agents receive when using this skill

Download
---
name: "Manage Cloudflare DNS"
description: "Create, update, and delete DNS records on Cloudflare using the vault proxy API"
version: "1.0.0"
author: "skynet"
category: "infrastructure"
agents: ["claude-code", "codex", "gemini"]
tags: ["cloudflare", "dns", "networking", "vault"]
tools_required: ["shell"]
---

# Manage Cloudflare DNS

# Manage Cloudflare DNS

## When to use

Use this skill when you need to create, update, or delete DNS records for any domain managed on Cloudflare. The primary domain is `skynet.ceo`.

## Prerequisites

- Access to the vault proxy at `http://192.168.86.27:8020`
- `BOTS_VAULT_ADMIN_TOKEN` set in your environment (from `.env`)
- Know the zone ID for the target domain

## Key identifiers

| Item | Value |
|------|-------|
| Vault proxy URL | `http://192.168.86.27:8020` |
| Cloudflare Account ID | `7ee53b77377bfa08a66d323326a64b76` |
| skynet.ceo Zone ID | `a2ecd4cf8341dc3e8e105dc06c14d2fc` |
| realcontent.blog Zone ID | Look up via list zones endpoint |

## Instructions

### Step 1: Source credentials

```bash
source .env  # or source ~/dev/projects/bots/.env
# Uses $BOTS_VAULT_ADMIN_TOKEN
```

### Step 2: List existing DNS records

```bash
curl -s -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records" \
  | jq '.result[] | {id, type, name, content, proxied}'
```

Filter by name:
```bash
curl -s -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records?name=subdomain.skynet.ceo" \
  | jq '.result[]'
```

### Step 3: Create a DNS record

**CNAME record (for Vercel, tunnels, etc.):**
```bash
curl -s -X POST \
  -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records" \
  -d '{
    "type": "CNAME",
    "name": "myapp.skynet.ceo",
    "content": "cname.vercel-dns.com",
    "proxied": true,
    "ttl": 1
  }'
```

**A record (for direct IP):**
```bash
curl -s -X POST \
  -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records" \
  -d '{
    "type": "A",
    "name": "myapp.skynet.ceo",
    "content": "76.76.21.21",
    "proxied": true,
    "ttl": 1
  }'
```

**Tunnel CNAME (for Cloudflare Tunnel services):**
```bash
curl -s -X POST \
  -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records" \
  -d '{
    "type": "CNAME",
    "name": "worker-dev1.skynet.ceo",
    "content": "<tunnel-id>.cfargotunnel.com",
    "proxied": true,
    "ttl": 1
  }'
```

### Step 4: Update a DNS record

First get the record ID from Step 2, then:
```bash
curl -s -X PUT \
  -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records/<record-id>" \
  -d '{
    "type": "CNAME",
    "name": "myapp.skynet.ceo",
    "content": "new-target.example.com",
    "proxied": true,
    "ttl": 1
  }'
```

### Step 5: Delete a DNS record

```bash
curl -s -X DELETE \
  -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones/a2ecd4cf8341dc3e8e105dc06c14d2fc/dns_records/<record-id>"
```

### Common patterns

**Point subdomain to Vercel (for Next.js apps):**
- Type: CNAME, Content: `cname.vercel-dns.com`, Proxied: true
- Or Type: A, Content: `76.76.21.21`, Proxied: true

**Point subdomain to a Cloudflare Tunnel:**
- Type: CNAME, Content: `<tunnel-id>.cfargotunnel.com`, Proxied: true

**Point subdomain to Railway:**
- Get the Railway domain from `railway domain`
- Type: CNAME, Content: the Railway-provided CNAME target, Proxied: false (Railway needs unproxied for TLS)

**List all zones in the account:**
```bash
curl -s -H "Authorization: Bearer $BOTS_VAULT_ADMIN_TOKEN" \
  "http://192.168.86.27:8020/v1/proxy/cloudflare/zones" \
  | jq '.result[] | {id, name}'
```

## Troubleshooting

- **Wildcard certs**: Cloudflare Universal SSL only covers `*.skynet.ceo`, NOT multi-level like `*.sub.skynet.ceo`. Don't create multi-level subdomain records.
- **Proxied vs unproxied**: Set `proxied: true` for most services (enables CF CDN + SSL). Set `proxied: false` only when the target needs direct TCP (e.g., SSH, custom TLS like Railway).
- **TTL**: When proxied is true, TTL is automatically set to "Auto" regardless of the value you pass.
- **wrangler OAuth**: The wrangler CLI OAuth scopes don't include DNS write. Use the vault proxy instead.
- **CLOUDFLARE_API_TOKEN in .env**: This token is stale/invalid. Always use the vault proxy.

## References

- Cloudflare API docs: https://developers.cloudflare.com/api
- Vault proxy: `http://192.168.86.27:8020/v1/proxy/cloudflare/...`

curl -s https://skills.skynet.ceo/api/skills/manage-cloudflare-dns/skill.md