// DevOps

Self-Hosted Telegram Bot API: Run Your Own Server with Docker (2 GB Files, HTTP Webhooks)

Published on 2026-09-22

Local Telegram Bot API allows developers to run their own API server, providing significant advantages for handling large files, performance, and configuration flexibility. However, to understand the need for a local server, it’s important to consider the limitations of the standard Telegram Bot API that works via an HTTPS interface. In this article we’ll review the benefits of the Local Bot API, the limitations of the standard approach, and steps to set up a local server via Docker, including registering a bot to use with it.


🚀 Main advantages of the Local Bot API

1. Increased file handling limits

For developers whose bots actively work with media, a local API server opens new possibilities:

  • Upload files up to 2 GB:
    Unlike the standard Bot API, which limits uploaded file size to 50 MB, the local server allows working with files up to 2000 MB (2 GB). This is ideal for bots that process videos, audio, or other large media files.

  • Download files without restrictions:
    The local API allows downloading files from Telegram servers without size restrictions (up to 2000 MB), whereas the standard API limits downloads to 20 MB.

  • Use of local path for uploads:
    The local API server supports specifying a local path or the file:// URI scheme for uploads, which eliminates the need to transmit files via HTTP requests.


2. Reduced network latency

A local API server can significantly improve performance:

  • Latency reduction:
    Requests from your bot are first sent to your local API server and then forwarded to Telegram servers.
    If your bot and API server are in the same network or geographically close, this reduces network latency, enabling faster request handling.

3. Flexibility and increased limits for Webhooks

Using a local API server expands webhook configuration options:

  • Support for HTTP:
    Unlike the standard Bot API, which requires HTTPS, the local server allows using HTTP for webhooks, simplifying setup in some scenarios.

  • Any IP and port:
    You can configure webhooks on any local IP address and any port, providing flexibility in server configuration.

  • More concurrent connections:
    The max_webhook_connections parameter on the local server can be raised up to 100,000 (by default in --local mode — 100). The standard API accepts values from 1 to 100, default 40, and only accepts webhooks over HTTPS on ports 443, 80, 88, or 8443.


4. Faster access to files

In --local mode the getFile method returns the absolute local path to the file (file_path) and does not require a separate download. For the bot to read such a file, it must have access to the server’s data directory — for example, a shared Docker volume.

All advantages in this section only work when the server is started with the --local flag. Without it, the local server behaves like the cloud one: the same file limits and the same webhook requirements.


🛑 Limitations of the standard Telegram Bot API

ParameterLimitNote
Global limit (overall)≤ 30 messages per secondMaximum send rate from one bot to all chats.
Single chat (private)≤ 1 message per secondPer user.
Group/channel≤ 20 messages per minutePer chat.
Sending files≤ 50 MBVia the standard API.
Receiving files≤ 20 MBWhen downloading from Telegram servers.
Message length≤ 4096 characters—
Media caption≤ 1024 characters—
Inline buttons≤ 100—
Commands≤ 100Configured via @BotFather.
WebhooksOnly HTTPS and limited ports443, 80, 88, 8443

🛠 Setting up Local Bot API via Docker

1. Preparation for launch

Before starting, make sure you have Docker and Docker Compose installed, and you have your API ID and API Hash obtained at my.telegram.org.

Create a .env file:

env
TELEGRAM_API_ID=your_api_id
TELEGRAM_API_HASH=your_api_hash

2. Docker Compose configuration

File docker-compose.yml:

yaml
services:
  telegram-bot-api:
    build: ./telegram-bot-api-builder
    container_name: telegram-local-api
    restart: unless-stopped
    environment:
      TELEGRAM_API_ID: ${TELEGRAM_API_ID}
      TELEGRAM_API_HASH: ${TELEGRAM_API_HASH}
    ports:
      - "127.0.0.1:8081:8081"
    volumes:
      - tgdata:/var/lib/telegram-bot-api
    command:
      - --local
      - --http-port=8081
      - --dir=/var/lib/telegram-bot-api
      - --temp-dir=/tmp/telegram-bot-api

volumes:
  tgdata:

What matters in this configuration:

  • --local enables local mode: files up to 2000 MB, webhooks over HTTP on any port, local paths in getFile. Without this flag the server works with the same limits as the cloud.
  • TELEGRAM_API_ID and TELEGRAM_API_HASH are read by the server from environment variables, so you don’t need to also pass them as --api-id and --api-hash arguments.
  • The port is published only on 127.0.0.1. The server accepts requests using a single bot token without additional checks, so you should not expose it to the internet. If the bot runs in the same Compose project, it contacts the server by the service name, http://telegram-bot-api:8081, and you don’t need to publish the port at all.
  • The version: line at the top of the file is deprecated: modern Docker Compose ignores it and emits a warning.

3. Dockerfile

File telegram-bot-api-builder/Dockerfile:

dockerfile
# ---------- Stage 1: Build ----------
FROM ubuntu:24.04 AS builder

ARG DEBIAN_FRONTEND=noninteractive
# Branch or commit to build; for reproducibility specify the commit hash:
# --build-arg TELEGRAM_BOT_API_REF=<commit>
ARG TELEGRAM_BOT_API_REF=master

# Build dependencies from the official instructions (gperf is required)
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      make git zlib1g-dev libssl-dev gperf cmake g++ ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# Repository is cloned recursively: TDLib is included as a submodule
WORKDIR /src
RUN git clone --recursive https://github.com/tdlib/telegram-bot-api.git . && \
    git checkout "${TELEGRAM_BOT_API_REF}" && \
    git submodule update --init --recursive

# Build
RUN mkdir -p build && cd build && \
    cmake -DCMAKE_BUILD_TYPE=Release .. && \
    cmake --build . --target telegram-bot-api -j"$(nproc)"

# Strip the binary (reduce size)
RUN strip /src/build/telegram-bot-api || true


# ---------- Stage 2: Runtime ----------
FROM ubuntu:24.04

ARG DEBIAN_FRONTEND=noninteractive

# Minimal runtime dependencies:
# on Ubuntu 24.04 the OpenSSL library is called libssl3t64
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
      libssl3t64 zlib1g ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# Data directory + system user
RUN groupadd -r telegram-bot-api && \
    useradd  -r -g telegram-bot-api -d /var/lib/telegram-bot-api -s /sbin/nologin telegram-bot-api && \
    mkdir -p /var/lib/telegram-bot-api /tmp/telegram-bot-api && \
    chown -R telegram-bot-api:telegram-bot-api /var/lib/telegram-bot-api /tmp/telegram-bot-api

# Copy the binary
COPY --from=builder /src/build/telegram-bot-api /usr/local/bin/telegram-bot-api

# Default port (change in docker-compose with the --http-port command)
EXPOSE 8081

# Healthcheck: verify the server accepts TCP connections on the port
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD bash -c 'exec 3<>/dev/tcp/127.0.0.1/8081' || exit 1

USER telegram-bot-api
WORKDIR /var/lib/telegram-bot-api

# Arguments are passed via docker-compose (command), API keys — via environment variables
ENTRYPOINT ["/usr/local/bin/telegram-bot-api"]

Features of this version:

  • Dependencies and git clone --recursive — as in the official build instructions. Without gperf and without the TDLib submodule the build will fail.
  • Base — Ubuntu 24.04; at runtime the package libssl3t64 is required.
  • Parallel build and strip of the binary to reduce size.
  • HEALTHCHECK verifies that the port accepts connections. Checking with curl -f on the root address is not suitable here: the server responds to such a request with an error.
  • The server runs as an unprivileged user.
  • The TELEGRAM_BOT_API_REF argument allows pinning the build to a specific commit.

4. Starting the server

bash
docker compose up -d --build

After startup the server will be available at:

http://localhost:8081

5. Checking and registering the bot

If the bot was previously working through the cloud API, before switching to the local server it should be logged out from the cloud using the logOut method. Otherwise some updates may continue to go to Telegram servers:

bash
curl https://api.telegram.org/bot<YOUR_TOKEN>/logOut

After a successful call, returning the bot to the cloud is only possible after 10 minutes. To move the bot from one local server to another, call deleteWebhook and close on the old server.

Then check the local server:

bash
curl http://localhost:8081/bot<YOUR_TOKEN>/getMe

If you see a JSON response with the bot’s name — everything works.


6. Using in code

Python (python-telegram-bot 20 and newer)

python
from telegram.ext import ApplicationBuilder

application = (
    ApplicationBuilder()
    .token("YOUR_TOKEN")
    .base_url("http://localhost:8081/bot")
    .base_file_url("http://localhost:8081/file/bot")
    .local_mode(True)
    .build()
)

The address is specified with the /bot suffix: by default the library points to https://api.telegram.org/bot. The Updater(token, base_url=...) class from older examples belongs to version 13 and does not work this way in current versions. local_mode(True) is needed when the server is started with --local: then get_file() returns a local path and the library does not try to download the file.

Any other language or library

Bot API is a normal HTTP interface: just replace https://api.telegram.org with your server address in the client. The parameter name depends on the library; look for base URL or API URL in its documentation. You can test without a library:

bash
curl -X POST "http://localhost:8081/bot<YOUR_TOKEN>/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{"chat_id": 123456789, "text": "Local server check"}'

7. Setting up Webhook

bash
curl -X POST "http://localhost:8081/bot<YOUR_TOKEN>/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{"url": "http://bot:8443/telegram-webhook"}'

The url should point to your bot — the application that receives updates, not the Bot API server address. In the example the bot is run in the same Compose project as the bot service and listens on port 8443. In --local mode the webhook can be HTTP, on any port, and on a local address.

8. HTTPS and HTTP version error

The Bot API server accepts only HTTP requests. If you need to reach it from the outside via HTTPS, place a TLS proxy in front of it — nginx, Caddy, or HAProxy.

The server understands only HTTP/1.0 and HTTP/1.1. For requests using another protocol version it responds with 505 HTTP Version Not Supported, and client libraries turn that into messages like “self hosted bot api instances only support HTTP/1.1”. The reasons are usually two:

  • The client is configured to use HTTP/2. In python-telegram-bot this is the http_version="2" parameter on the request; by default "1.1" is used, and it’s enough to leave it unchanged. In other libraries disable HTTP/2 for the local server address.
  • The proxy connects to the server using HTTP/2. Between the proxy and the Bot API server there must be HTTP/1.1. In nginx set proxy_http_version 1.1; in the location block; you can keep HTTP/2 on the client side.

💡 Summary

Local Telegram Bot API is suitable for:

  • working with large files (up to 2 GB);
  • reducing latency;
  • flexible webhook configuration;
  • high-load systems.

The standard API is suitable for:

  • small projects;
  • working with files up to 50 MB;
  • typical HTTPS webhooks.

Building in Docker gives a reproducible image and easy updates. The main points when switching — run the server with --local, call logOut for the cloud API, and do not publish the server port to the internet.


Frequently Asked Questions

What is the local Telegram Bot API server?
The local Telegram Bot API server is a self-hosted version of Telegram’s Bot API that runs on your own infrastructure. Unlike the standard API at api.telegram.org, it removes file size limits (up to 2 GB), allows HTTP webhooks on any port, and supports up to 100,000 concurrent webhook connections.
What is the maximum file size supported by the local Telegram Bot API?
The local Telegram Bot API server supports uploading and downloading files up to 2 GB. The standard Telegram Bot API limits uploads to 50 MB and downloads to 20 MB.
Does the local Telegram Bot API require HTTPS?
No. The standard API requires HTTPS and only accepts webhooks on ports 443, 80, 88, and 8443. The local server supports plain HTTP and accepts webhooks on any IP address and any port.
How do I run the local Telegram Bot API server with Docker?
You need Docker and a Telegram API ID and API Hash from my.telegram.org. Create a docker-compose.yml and a Dockerfile that builds the official telegram-bot-api binary, then run docker-compose up -d. The server starts on http://localhost:8081 by default.
What is the difference between the standard and local Telegram Bot API?
The standard API is a shared Telegram service at api.telegram.org: 50 MB upload limit, 20 MB download limit, HTTPS-only webhooks, up to 30 messages per second globally. The local API runs on your own server: 2 GB file limits, HTTP webhooks on any port, up to 100,000 concurrent connections.
How many concurrent connections does the local Telegram Bot API support?
The local Telegram Bot API server supports up to 100,000 concurrent webhook connections, significantly exceeding the standard API which is limited to specific ports (443, 80, 88, 8443).

// Contact

Need help?

Get in touch with me and I'll help solve the problem

I reply within one business day (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirm that you are not a bot.

Write and get a quick reply