Cloudflare, CDN & Edge

Cloudflare Workers and R2 Storage for Domain India Apps

By Domain India Team · DomainIndia EngineeringPublished 8 min read
Knowledge base article
Contents (11 sections)

Cloudflare Workers and R2 sit in front of, or beside, the hosting your site already runs on. Workers run small pieces of JavaScript or TypeScript on Cloudflare's network, close to your visitors; R2 is S3-compatible object storage with no egress fees. This guide shows when they help, a working edge-auth Worker, R2 uploads, and how they fit with Domain India hosting.

Key takeaways

Cloudflare Workers run your code on Cloudflare's global network (Cloudflare says 330+ cities), and R2 stores files with no charge for downloads. Use them to take edge auth, cached API responses and image or upload traffic off your origin. Your main app, database and long-running jobs stay on your hosting or VPS.

1. When Workers make sense

Workers don't replace your hosting; they complement it. Good use cases:

  • Edge auth: validate a JWT at the edge and reject unauthenticated requests before they reach your origin.
  • A/B testing: route 10% of traffic to a different backend without touching your app.
  • Image resizing: serve correctly sized images on demand.
  • Geolocation redirects: send India traffic to one origin and EU traffic to another.
  • Cache tiering: cache expensive API responses at the edge.
  • Webhook receivers: accept third-party webhooks and forward compact data to your origin.

Poor fits: full apps with complex state, heavy CPU work and long-running jobs. Keep those on your own server.

2. Limits and pricing (Cloudflare's figures)

These are Cloudflare's published numbers at the time of writing. They change, so check Cloudflare's Workers and R2 pricing pages before you plan around them.

  • Workers Free: 100,000 requests a day, 10 ms CPU time per request, 128 MB memory.
  • Workers Paid: from USD 5 a month, with 10 million requests a month included and a much higher CPU-time allowance per request.
  • R2 free tier: 10 GB-month of storage, 1 million Class A (write) and 10 million Class B (read) operations a month. No egress fees, which is R2's main advantage over S3.

3. Install Wrangler and create a Worker

Wrangler is Cloudflare's CLI. Use it through the project template rather than a global install, so each project pins its own version:

bash
npm create cloudflare@latest edge-auth   # choose "Hello World" Worker, JavaScript or TypeScript
cd edge-auth
npx wrangler login                        # opens the browser to authorise your Cloudflare account

The older wrangler init --type=javascript form no longer works; npm create cloudflare replaced it.

4. An edge-auth Worker

src/index.js:

javascript
export default {
  async fetch(request, env, ctx) {
    // 1. Edge auth: check the JWT before the request reaches the origin
    const auth = request.headers.get('Authorization');
    if (!auth?.startsWith('Bearer ')) {
      return new Response('Unauthorized', { status: 401 });
    }
    const claims = await verifyJWT(auth.slice(7), env.JWT_SECRET);
    if (!claims) return new Response('Invalid token', { status: 401 });

    // 2. Forward to your origin (a hostname that is NOT proxied through this Worker)
    const url = new URL(request.url);
    url.hostname = 'origin.yourcompany.com';
    const response = await fetch(new Request(url, request));

    // 3. Add edge headers
    const modified = new Response(response.body, response);
    modified.headers.set('X-Auth-At-Edge', 'true');
    modified.headers.set('X-User-Id', String(claims.sub ?? ''));
    return modified;
  },
};

function b64urlToBytes(s) {
  const b64 = s.replace(/-/g, '+').replace(/_/g, '/').padEnd(Math.ceil(s.length / 4) * 4, '=');
  return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
}

async function verifyJWT(token, secret) {
  const [h, p, s] = token.split('.');
  if (!h || !p || !s) return null;

  const header = JSON.parse(new TextDecoder().decode(b64urlToBytes(h)));
  if (header.alg !== 'HS256') return null;            // never accept "none" or another alg

  const key = await crypto.subtle.importKey(
    'raw', new TextEncoder().encode(secret),
    { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']
  );
  const ok = await crypto.subtle.verify(
    'HMAC', key, b64urlToBytes(s), new TextEncoder().encode(`${h}.${p}`)
  );
  if (!ok) return null;

  const claims = JSON.parse(new TextDecoder().decode(b64urlToBytes(p)));
  if (claims.exp && claims.exp < Date.now() / 1000) return null;  // expired
  return claims;
}

For production, a maintained library such as jose handles key rotation and more algorithms; the hand-written version above shows what happens.

wrangler.toml (Wrangler also accepts wrangler.jsonc):

toml
name = "edge-auth"
main = "src/index.js"
compatibility_date = "2026-09-01"

routes = [
  { pattern = "api.yourcompany.com/*", zone_name = "yourcompany.com" }
]

[vars]
# non-secret config here

Set the secret and deploy:

bash
npx wrangler secret put JWT_SECRET   # paste the secret when prompted
npx wrangler deploy

The route needs yourcompany.com to be a zone in your Cloudflare account with the api record proxied (orange cloud). After the deploy, requests to api.yourcompany.com run through the Worker.

5. R2 object storage

R2 is S3-compatible, with no egress charge. It suits user uploads, backups and static assets.

bash
npx wrangler r2 bucket create uploads

Bind the bucket in wrangler.toml (top level, next to routes):

toml
r2_buckets = [
  { binding = "UPLOADS", bucket_name = "uploads" }
]

Use it from the Worker (put your auth check in front of the PUT branch in real code):

javascript
export default {
  async fetch(request, env) {
    const key = new URL(request.url).pathname.slice(1); // "user-123/photo.jpg"

    if (request.method === 'PUT') {
      await env.UPLOADS.put(key, request.body, {
        httpMetadata: { contentType: request.headers.get('Content-Type') ?? 'application/octet-stream' },
      });
      return new Response('Uploaded', { status: 201 });
    }

    if (request.method === 'GET') {
      const object = await env.UPLOADS.get(key);
      if (!object) return new Response('Not found', { status: 404 });
      const headers = new Headers();
      object.writeHttpMetadata(headers);
      headers.set('etag', object.httpEtag);
      return new Response(object.body, { headers });
    }

    return new Response('Method not allowed', { status: 405 });
  },
};

6. Uploading to R2 from your own app

Any S3 SDK can talk to R2. Create credentials under R2 → Manage R2 API Tokens in the Cloudflare dashboard, and scope the token to one bucket.

Node.js:

javascript
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  region: 'auto',
  endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
  },
});

await s3.send(new PutObjectCommand({
  Bucket: 'uploads',
  Key: 'photo.jpg',
  Body: fileBuffer,
  ContentType: 'image/jpeg',
}));

PHP apps can use the AWS SDK for PHP the same way (set endpoint, region to auto and use_path_style_endpoint to true). For large files, generate a presigned URL on your server and let the browser upload straight to R2, so the file never passes through your hosting.

7. Storage cost: R2 vs S3 vs B2

Providers' list prices change and depend on region and free tiers, so compare on their own pricing pages. As a rough guide at the time of writing (providers' figures, in USD):

StorageStorage priceDownload (egress) price
Cloudflare R2about 0.015 per GB-monthFree
AWS S3 Standardabout 0.023 per GB-month (varies by region)Charged per GB after AWS's free allowance
Backblaze B2about 0.006 per GB-monthFree up to about 3 times the data stored, then charged
Your hosting accountNo separate storage feeUses your plan's disk and bandwidth allowance

R2 suits public-facing files that are downloaded often. B2 suits backups that are rarely downloaded. Serving from your hosting account is fine for low-traffic sites and internal use.

8. Durable Objects: stateful edge (advanced)

For chat, live collaboration or per-user rate limiting, Durable Objects give you a single, serialised instance of state per key.

javascript
import { DurableObject } from 'cloudflare:workers';

export class RateLimiter extends DurableObject {
  async fetch(request) {
    const count = (await this.ctx.storage.get('count')) ?? 0;
    await this.ctx.storage.put('count', count + 1);
    return Response.json({ count });
  }
}

// In your Worker's fetch handler:
const stub = env.RATE_LIMITER.get(env.RATE_LIMITER.idFromName(userId));
return stub.fetch(request);

Each key (here, each user) gets its own object, created close to where it is first used. The class also needs a durable_objects binding and a migration entry in wrangler.toml; see Cloudflare's Durable Objects docs.

9. Running this with Domain India hosting

Workers and R2 are Cloudflare services with their own accounts and billing; Domain India does not sell or support them. They work alongside any Domain India plan:

  • Origin on shared hosting (cPanel or DirectAdmin): point your domain's DNS at Cloudflare and keep the website on your hosting. The Worker forwards to it like any other origin. For DNS changes, see how to change your domain's DNS settings.
  • Uploading to R2 from PHP: the S3 SDK makes HTTPS calls with cURL. On DirectAdmin, curl_exec is disabled on many sites, so test on your plan first. See PHP disabled functions on shared hosting.
  • Node.js on shared hosting: the Setup Node.js App tool on cPanel and DirectAdmin runs request/response apps; see deploying a Node.js app on shared hosting.
  • Database access: Workers can't reach a MySQL database on shared hosting, because port 3306 is closed from outside. Put a small API on your hosting and call it with fetch(). On a VPS you control the firewall, so you can use Cloudflare Hyperdrive or an API.
  • VPS: self-managed with full root access, so you run and secure the origin yourself.

10. Common pitfalls

"CPU time exceeded"
The Worker is doing too much computation. Move the heavy work to your origin and call it with a subrequest.
Secrets in wrangler.toml
Never. Use wrangler secret put; values in [vars] are visible in the dashboard and your repo.
Loop between Worker and origin
If the origin hostname also routes through the Worker, requests loop. Use a separate origin hostname that the Worker route does not match.
Public R2 bucket by mistake
A public bucket is readable by anyone. Keep private files in a private bucket and serve them through a Worker with auth.
Unverified JWTs
Check the algorithm and the expiry, not just the signature, or use a library such as jose.

FAQ

Do Cloudflare Workers replace my Domain India hosting?

No. Workers are for small, fast, stateless edge logic. Your website, database and long-running processes stay on your hosting or VPS, and the Worker sits in front of them.

Can a Worker connect to the MySQL database on my shared hosting?

Not directly. MySQL port 3306 is closed from outside on Domain India shared servers. Expose a small HTTPS API on your hosting and call it from the Worker with fetch(). On a VPS you control the firewall and can use Cloudflare Hyperdrive.

Is R2 reliable enough for production?

Cloudflare designs R2 for eleven nines of durability and publishes an availability SLA for paid use. Check Cloudflare's current terms, and keep an independent backup of anything you can't lose.

Can I serve a full website from Workers?

You can, especially static sites with Workers static assets or Cloudflare Pages. For a PHP, WordPress or database-backed site, keep the site on your hosting and use Workers as a thin edge layer.

How do I debug a Worker in production?

Run npx wrangler tail to stream live logs, and turn on Workers Logs or Logpush in the dashboard for longer retention.

Does Domain India support Cloudflare Workers?

Workers and R2 are Cloudflare products, so their setup and billing are between you and Cloudflare. Domain India support can help with the hosting side: your origin site, DNS records and SSL on your plan.

Ready to put an edge layer in front of your site? Host the origin on cPanel hosting or DirectAdmin hosting, or run your own stack on a VPS. Questions about your plan? Open a support ticket.

Host the origin behind your Worker

Keep your website and database on Domain India hosting and use Cloudflare Workers and R2 for the edge.

See hosting plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app
Cloudflare Workers & R2 Storage for DomainIndia Apps