title: "Setting up a Reverse Proxy for Telegram Bot API"
slug: "nginx_tgapi_proxy"
date: 2023-09-19T22:28:07+08:00
type: posts
draft: false
categories: ["Using Software","Nginx"]
tags: ["Technical Sharing","nginx","proxy","telegram"]
description: ""#
Due to certain reasons, configuring epusdt requires the use of a reverse proxy address for tg!
#telegram proxy url (for mainland servers, a foreign server can be used as a reverse proxy for tg), if running on a foreign server, no need to fill in
tg_proxy=
Two implementation options, choose and use according to personal preference
Nginx Reverse Proxy for Telegram Api#
Install nginx#
sudo apt update && sudo apt install -y nginx
Create configuration file#
nano tgapi.conf
Enter the following content and save
server {
listen 80;
server_name tgapi.domain;
location / {
return 444;
}
location ~* ^/bot {
resolver 8.8.8.8;
proxy_buffering off;
proxy_pass https://api.telegram.org$request_uri;
}
}
Load configuration#
sudo systemctl reload nginx
#or
sudo nginx -s reload
Test access#
Enter the following command line, replacing BOT_TOKEN with your own bot token.
curl https://tgapi.domain/bot<BOT_TOKEN>/getMe
If you see the bot information, it means it is working.
Configure epusdt telegram proxy url#
epusdt configuration (.env) reference
#telegram proxy url (for mainland servers, a foreign server can be used as a reverse proxy for tg), if running on a foreign server, no need to fill in
tg_proxy=https://tgapi.domain
Docker configuration nginx reference docker-compose.yaml content#
version: "3"
services:
nginx:
container_name: "nginx"
restart: always
ports:
- "80:80"
image: nginx:bookworm
volumes:
- ./conf.d:/etc/nginx/conf.d
- ./log:/var/log/nginx
extra_hosts:
- "host.docker.internal:host-gateway"
Use Cloudflare Worker to Proxy Telegram Bot Api#
Prerequisites
- A domain hosted on Cloudflare
- Enable Cloudflare's free worker service
First, log in to Cloudflare and click Workers and Pages on the left side#
Click Create Application
-Create Worker
Fill in a Name
, click Deploy
After creation, click on the newly created Worker, then click Quick Edit
Delete the existing code on the left side and enter the code provided below
/**
* Helper functions to check if the request uses
* corresponding method.
*
*/
const Method = (method) => (req) => req.method.toLowerCase() === method.toLowerCase();
const Get = Method('get');
const Post = Method('post');
const Path = (regExp) => (req) => {
const url = new URL(req.url);
const path = url.pathname;
return path.match(regExp) && path.match(regExp)[0] === path;
};
/*
* The regex to get the bot_token and api_method from request URL
* as the first and second backreference respectively.
*/
const URL_PATH_REGEX = /^\/bot(?<bot_token>[^/]+)\/(?<api_method>[a-z]+)/i;
/**
* Router handles the logic of what handler is matched given conditions
* for each request
*/
class Router {
constructor() {
this.routes = [];
}
handle(conditions, handler) {
this.routes.push({
conditions,
handler,
});
return this;
}
get(url, handler) {
return this.handle([Get, Path(url)], handler);
}
post(url, handler) {
return this.handle([Post, Path(url)], handler);
}
all(handler) {
return this.handler([], handler);
}
route(req) {
const route = this.resolve(req);
if (route) {
return route.handler(req);
}
const description = 'No matching route found';
const error_code = 404;
return new Response(
JSON.stringify({
ok: false,
error_code,
description,
}),
{
status: error_code,
statusText: description,
headers: {
'content-type': 'application/json',
},
}
);
}
/**
* It returns the matching route that returns true
* for all the conditions if any.
*/
resolve(req) {
return this.routes.find((r) => {
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) {
return true;
}
if (typeof r.conditions === 'function') {
return r.conditions(req);
}
return r.conditions.every((c) => c(req));
});
}
}
/**
* Sends a POST request with JSON data to Telegram Bot API
* and reads in the response body.
* @param {Request} request the incoming request
*/
async function handler(request) {
// Extract the URl method from the request.
const { url, ..._request } = request;
const { pathname: path, search } = new URL(url);
// Leave the first match as we are interested only in backreferences.
const { bot_token, api_method } = path.match(URL_PATH_REGEX).groups;
// Build the URL
const api_url = 'https://api.telegram.org/bot' + bot_token + '/' + api_method + search;
// Get the response from API.
const response = await fetch(api_url, _request);
const result = await response.text();
const res = new Response(result, _request);
res.headers.set('Content-Type', 'application/json');
return res;
}
/**
* Handles the incoming request.
* @param {Request} request the incoming request.
*/
async function handleRequest(request) {
const r = new Router();
r.get(URL_PATH_REGEX, (req) => handler(req));
r.post(URL_PATH_REGEX, (req) => handler(req));
const resp = await r.route(request);
return resp;
}
/**
* Hook into the fetch event.
*/
addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
Save and Deploy
Go back to the management dashboard homepage, click Website
on the left side, and click Your domain hosted on Cloudflare
on the right side
Select Workers Routes
for the domain
Select Add Route
Fill in Route
with the subdomain you want to use, for example: tgapi.domain/*
Note that it must end with /*
, select the Worker service you just created, and click Save
.