LinhGo Labs
LinhGo Labs
Host Your Telegram Bot Proxy on Cloudflare Workers (Free!)

Host Your Telegram Bot Proxy on Cloudflare Workers (Free!)

How to set up a free Telegram bot proxy using Cloudflare Workers - no server costs, no maintenance headaches.

Running a Telegram bot? You might run into some issues:

  • Telegram API blocked in your region? This fixes it.
  • Want to use a custom domain for your webhook? Done.
  • Worried about rate limits or reliability? Cloudflare’s got you covered.
  • Don’t want to pay for a VPS just to proxy requests? This is completely free.

Cloudflare Workers gives you a serverless solution that handles millions of requests without breaking a sweat. Best part? It’s free for most use cases (up to 100,000 requests per day on the free plan).

We’ll use the excellent telegram-bot-proxy script and hook it up to your domain.

Before we start, make sure you have:

  • Cloudflare account - Sign up free
  • A domain - Doesn’t need to be on Cloudflare yet, we’ll transfer it
  • Telegram bot token - Get one from @BotFather

That’s it. No credit card required for Cloudflare Workers free tier.


Let’s get your proxy up and running:

  1. Head to your Cloudflare dashboard

  2. Click Workers & Pages in the sidebar

  3. Hit Create Application → select the Workers tab

  4. Click Create Worker

  5. Give it a memorable name like telegram-proxy (you’ll see this in logs)

  1. In the code editor that appears, delete everything and paste this proxy script:

    Credit to tuanpb99 for this excellent implementation:

    const TELEGRAM_API_BASE = "https://api.telegram.org";
    async function handleRequest(request) {
      const url = new URL(request.url);
    
      if (url.pathname === "/" || url.pathname === "") {
        return new Response(DOC_HTML, {
          headers: {
            "Content-Type": "text/html;charset=UTF-8",
            "Cache-Control": "public, max-age=3600",
          },
        });
      }
    
      // Extract the bot token and method from the URL path
      const pathParts = url.pathname.split("/").filter(Boolean);
      if (pathParts.length < 2 || !pathParts[0].startsWith("bot")) {
        return new Response("Invalid bot request format", { status: 400 });
      }
    
      // Reconstruct the Telegram API URL
      const telegramUrl = `${TELEGRAM_API_BASE}${url.pathname}${url.search}`;
    
      let body = undefined;
      if (request.method !== "GET" && request.method !== "HEAD") {
        try {
          body = await request.arrayBuffer();
        } catch (err) {
          return new Response(`Failed to read request body: ${err.message}`, {
            status: 400,
          });
        }
      }
    
      const proxyReq = new Request(telegramUrl, {
        method: request.method,
        headers: request.headers,
        body,
        redirect: "follow",
      });
    
      try {
        const tgRes = await fetch(proxyReq);
        const res = new Response(tgRes.body, tgRes); // Clone Telegram response
        res.headers.set("Access-Control-Allow-Origin", "*");
        res.headers.set(
          "Access-Control-Allow-Methods",
          "GET, POST, PUT, DELETE, OPTIONS"
        );
        res.headers.set("Access-Control-Allow-Headers", "Content-Type");
        return res;
      } catch (err) {
        return new Response(`Error proxying request: ${err.message}`, {
          status: 500,
        });
      }
    }
    
    // Handle OPTIONS requests for CORS
    function handleOptions(request) {
      const corsHeaders = {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
        "Access-Control-Allow-Headers": "Content-Type",
        "Access-Control-Max-Age": "86400",
      };
    
      return new Response(null, {
        status: 204,
        headers: corsHeaders,
      });
    }
    
    // Main event listener for the worker
    addEventListener("fetch", (event) => {
      const request = event.request;
    
      if (request.method === "OPTIONS") {
        event.respondWith(handleOptions(request));
      } else {
        event.respondWith(handleRequest(request));
      }
    });

What this does: The script intercepts requests to your domain, forwards them to Telegram’s API, and returns the response. It handles CORS, proper HTTP methods, and even shows a nice landing page when someone visits your domain directly.

  1. Click Save and Deploy

Your worker is now live! But it’s using an ugly *.workers.dev URL. Let’s fix that with a custom domain.


If your domain is already on Cloudflare, skip to step 3. Otherwise:

  1. In Cloudflare Dashboard → WebsitesAdd a Site

  2. Enter your domain (e.g., yourdomain.com) and click Add site

  3. Choose the Free plan (unless you want extra features)

  4. Cloudflare will scan your existing DNS records

  5. Important: Update your domain’s nameservers at your registrar (GoDaddy, Namecheap, etc.) to point to Cloudflare’s nameservers

    • Cloudflare shows you exactly which nameservers to use
    • This usually takes 5-30 minutes to propagate
  6. Once your domain is active on Cloudflare, add these DNS records:

    Go to DNSRecordsAdd record:

    First record (root domain):

    • Type: A
    • Name: @
    • IPv4 address: 192.0.2.1 (placeholder IP - doesn’t matter since we’re proxying through Workers)
    • Proxy status: ☁️ Proxied (orange cloud - this is important!)

    Second record (wildcard for subdomains):

    • Type: A
    • Name: *
    • IPv4 address: 192.0.2.1
    • Proxy status: ☁️ Proxied

    Click Save for each record.

The IP address doesn’t matter here because Cloudflare’s proxy intercepts the requests before they reach that IP.


Now we connect your domain to the Worker:

  1. Go back to Workers & Pages → select your telegram-proxy worker

  2. Click the Triggers tab (or SettingsTriggers)

  3. Scroll down to Routes section

  4. Click Add route and add these two routes:

    Route 1: yourdomain.com/*
    (Replace yourdomain.com with your actual domain)

    Route 2: *.yourdomain.com/*
    (This handles any subdomain like api.yourdomain.com)

  5. Click Save

Now any request to your domain or its subdomains will be handled by your Worker!


Let’s make sure everything works:

Open your browser and visit https://yourdomain.com/

You should see a simple page saying the worker is active. If you get an error, double-check:

  • DNS records are saved and proxied (orange cloud)
  • Worker routes are configured correctly
  • Domain nameservers point to Cloudflare

Now connect your bot to the proxy. Replace the placeholders:

curl "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook?url=https://yourdomain.com/bot<YOUR_BOT_TOKEN>/<SECRET_PATH>"

Replace:

  • <YOUR_BOT_TOKEN> - Your bot token from @BotFather
  • <SECRET_PATH> - Any random string for security (like webhook_abc123)

Example:

curl "https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/setWebhook?url=https://yourdomain.com/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/my_secret_webhook"

You should get a response:

{"ok":true,"result":true,"description":"Webhook was set"}

Send a message to your bot on Telegram. If your bot code is running correctly and pointed at your domain, it should respond!

Troubleshooting:

  • Bot not responding? Check your bot’s code is running and using the correct webhook URL
  • Getting errors? Check the Worker logs: Workers & Pages → your worker → Logs tab
  • SSL errors? Cloudflare automatically handles SSL - make sure you’re using https://

Congrats! You now have:

✅ A production-ready Telegram bot proxy running on Cloudflare’s global network
✅ Free SSL/HTTPS automatically handled
✅ No server costs (100k requests/day on free tier)
✅ Lightning-fast response times from 300+ edge locations worldwide
✅ Built-in DDoS protection from Cloudflare
✅ Your own custom domain for webhooks

Pro tips:

  • Monitor usage: Check Workers dashboard to see request counts
  • Multiple bots: You can run multiple bots through the same proxy - each just needs its own webhook URL
  • Debugging: Use the Logs tab in Workers to see what’s happening in real-time
  • Security: Keep your bot token and secret path private

Cost: Unless you’re getting millions of requests per day, this stays free forever. Even if you exceed the free tier, Cloudflare’s paid Workers plan is $5/month for 10 million requests.


Running into issues? Drop a comment below. If this helped you, share it with other bot developers!