Files
tg-ws-proxy/docs/EN/CfWorker.md
T

4.4 KiB

Cloudflare Worker

An alternative (completely free, no domain purchase required unlike CfProxy) method for proxying.

The proxy restores access to content that previously wouldn't load (reactions, certain stickers). If you are using a non-Premium account with this method and photos/videos still fail to load, leave only 4:149.154.167.220 in the DC → IP block.

  1. Add the following domains to zapret or any other DPI bypass software:
cloudflare.com
cloudflare.dev
workers.dev
  1. Create an account on Cloudflare (or log into an existing one)

    • After creating your account, verify your email using the link sent to your inbox
  2. Select ComputeWorkers & Pages from the left panel image

  3. Click the Create application button in the top right → Start with Hello World!Deploy image image image

  4. Click the Edit code button in the top right, then replace the code on the left with the one found at the bottom of this page

    • If the code section fails to load, it means you missed the first step image image
  5. Click the Deploy button in the top right image

  6. Copy the domain from the field on the right and specify it in your Cloudflare Worker settings (or via the --cfproxy-worker-domain argument)

    • Example domain: random-symbols-1234.username.workers.dev
    • You can specify multiple domains separated by commas (or by repeating the --cfproxy-worker-domain argument) image

Worker Code

import { connect } from "cloudflare:sockets";

function toBytes(data) {
	if (data instanceof ArrayBuffer) {
		return new Uint8Array(data);
	}
	if (typeof data === "string") {
		return new TextEncoder().encode(data);
	}
	if (data && typeof data.arrayBuffer === "function") {
		return data.arrayBuffer().then((ab) => new Uint8Array(ab));
	}
	return new Uint8Array();
}

export default {
	async fetch(request) {
		if ((request.headers.get("Upgrade") || "").toLowerCase() !== "websocket") {
			return new Response("Expected websocket", { status: 426 });
		}

		const url = new URL(request.url);
		if (url.pathname !== "/apiws") {
			return new Response("Not found", { status: 404 });
		}

		const dst = url.searchParams.get("dst");
		const pair = new WebSocketPair();
		const client = pair[0];
		const server = pair[1];
		server.accept();

		const socket = connect({ hostname: dst, port: 443 });
		const tcpReader = socket.readable.getReader();
		const tcpWriter = socket.writable.getWriter();

		server.addEventListener("message", async (event) => {
			try {
				await tcpWriter.write(await toBytes(event.data));
			} catch {
				try {
					server.close(1011, "tcp write failed");
				} catch {}
			}
		});

		server.addEventListener("close", async () => {
			try {
				await tcpWriter.close();
			} catch {}
			try {
				socket.close();
			} catch {}
		});

		(async () => {
			try {
				while (true) {
					const { value, done } = await tcpReader.read();
					if (done) {
						break;
					}
					if (value) {
						server.send(value);
					}
				}
			} catch {
			} finally {
				try {
					server.close();
				} catch {}
				try {
					tcpReader.releaseLock();
				} catch {}
				try {
					socket.close();
				} catch {}
			}
		})();

		return new Response(null, { status: 101, webSocket: client });
	},
};