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.
What You’ll Need
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.
Step 1: Create the Worker
Let’s get your proxy up and running:
Create a New Worker
Head to your Cloudflare dashboard
Click Workers & Pages in the sidebar
Hit Create Application → select the Workers tab
Click Create Worker
Give it a memorable name like
telegram-proxy(you’ll see this in logs)
Add the Proxy Code
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.
- 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.
Step 2: Add Your Domain to Cloudflare
If your domain is already on Cloudflare, skip to step 3. Otherwise:
In Cloudflare Dashboard → Websites → Add a Site
Enter your domain (e.g.,
yourdomain.com) and click Add siteChoose the Free plan (unless you want extra features)
Cloudflare will scan your existing DNS records
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
Once your domain is active on Cloudflare, add these DNS records:
Go to DNS → Records → Add 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.
- Type:
The IP address doesn’t matter here because Cloudflare’s proxy intercepts the requests before they reach that IP.
Step 3: Route Your Domain to the Worker
Now we connect your domain to the Worker:
Go back to Workers & Pages → select your
telegram-proxyworkerClick the Triggers tab (or Settings → Triggers)
Scroll down to Routes section
Click Add route and add these two routes:
Route 1:
yourdomain.com/*
(Replaceyourdomain.comwith your actual domain)Route 2:
*.yourdomain.com/*
(This handles any subdomain likeapi.yourdomain.com)Click Save
Now any request to your domain or its subdomains will be handled by your Worker!
Step 4: Test Your Proxy
Let’s make sure everything works:
Test 1: Check the Landing Page
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
Test 2: Set Your Telegram Webhook
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 (likewebhook_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"}Test 3: Send a Message
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://
What You Just Built
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!


