# The env template and the compose file name the API key differently

> A Telegram bot that answers questions through any API speaking the OpenAI format, with web search plugins, file handling, per-topic isolation in groups, and one-click deployment on three free platforms. The code is straightforward; the packaging around it is where the surprises are. The env template and the compose file disagree on the name of the required key, the Dockerfile builds nothing, and the default access policy is open to every user on the platform.

**yym68686/ChatGPT-Telegram-Bot** — TeleChat: 🤖️ an AI chat Telegram bot can Web Search Powered by GPT-5, DALL·E , Groq, Gemini 2.5 Pro/Flash and the official Claude4.1 API using Python on Zeabur, fly.io and Replit.

- Repository: https://github.com/yym68686/ChatGPT-Telegram-Bot
- Stars: 1,290 · Forks: 407
- Language: Python
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/yym68686-chatgpt-telegram-bot

## The env template and the compose file disagree on the required key

Two of the only three environment blocks in the repository name the API credential differently. The documentation table calls it one thing and marks it required, and the compose file passes that same name with an empty value.

```yaml
    environment:
      - BOT_TOKEN=
      - BASE_URL=
      - API_KEY=
```

The shipped env template sets the base URL to the full first-party chat completions endpoint, sets the model, and then writes the credential under a different name with nothing after the equals sign.

```
BOT_TOKEN=
BASE_URL=https://api.openai.com/v1/chat/completions
API=
MODEL=gpt-5
```

So a deployment assembled from the template will not populate the variable the compose file and the documentation expect. That is the kind of mismatch that produces a bot which starts, accepts messages, and then answers every one of them with an authentication error, which is a slow way to discover a single letter. It is also worth noticing that the compose block does not interpolate from a file at all: the values are literal empty strings in the file, so adding a local env file will not change what the container sees.

## The Dockerfile builds nothing, it pulls the project's own published image

The Dockerfile in the root of the repository is a single instruction and it names the project's own image on a public registry as its base.

```dockerfile
FROM yym68686/chatgpt:latest
```

That is the whole file. So running a build against it produces an image containing the published image, which means it cannot be used to verify a change, cannot be used to pin a version, and silently gives you whatever was pushed most recently. There is a second build file beside it with the real work in it, and the multi-stage compose file for the translation sibling is also present, so the tooling is not missing. The single-line file appears to exist so that a hosting platform's automatic build button has something to call, which is a reasonable convenience and a poor debugging story. If you want to know what you are running, read the other build file.

## Port 80, empty credentials, and an access policy that defaults to open

The compose file maps host port 80 to container port 8080 with no interface restriction, so the service is reachable from the network the host sits on. Its environment block is the three empty strings above. The access control is the third piece, and it defaults the wrong way for a public deployment. The documentation is explicit that the allow list's default value means the bot is open to everyone, and the deny list's default is likewise unset. So the shipped compose configuration is a bot on port 80 that any user who finds it can talk to, backed by whatever credentials happen to be present. Add an allow list or a deny list before you expose it, and if you do need to expose it, remember that every message is forwarded to a third-party API endpoint.

## A group entry overrides the allow list for everyone in that group

The access model has three lists and the interaction between two of them is worth reading carefully. The allow list controls which user identifiers may use the bot. The group list controls which group identifiers may use it, and the documentation states that even if the members of a listed group are not on the allow list, every member of that group may use the bot. That is the intended design, since per-group onboarding is the point, but it means the allow list is not a complete description of who has access. Two consequences follow. Adding a group is a broader grant than adding its members individually, because membership changes without your involvement. And if a group identifier is set wrongly, or a group identifier is reused after a group is dissolved and its identifier reassigned, the grant follows the identifier rather than the people. The admin list is separate and narrower: only admins may use the configuration command.

## An empty nick means the bot answers every message in every group it joins

One optional variable controls whether the bot speaks at all, and it defaults to empty. The documentation describes the two states plainly: when a nick is set, the bot replies only when a message starts with it; when it is empty, the bot replies to any message. It then singles out group chats, where an empty nick means the bot will reply to all messages in the room. Put a bot with an empty nick and an empty allow list into a busy group and you have built a machine for spending someone else's model budget on every message in the channel, with no filter on who asked. The nick is the single most important setting to set before the bot goes anywhere near a group, and it is marked optional in the table.

## CUSTOM_MODELS is a configuration language packed into one string

One optional variable carries model selection, removal and grouping in a single value, and the documentation gives the whole grammar in one cell. Commas separate entries. A hyphen before a name removes a default model, and a hyphen before a literal token removes all defaults. Semicolons separate groups, and a colon separates a group name from the models inside it, so a value can both delete defaults and define named groups in the same string. Models that end up in no named group are placed into a fallback group automatically. It is compact enough to fit in a platform's environment editor and dense enough that a typo changes behaviour rather than erroring. The fallback group is a small mercy: a malformed grouping string degrades into an ungrouped list instead of an empty model picker.

## Two dependencies are vendored as submodules, so a plain clone will not run

The repository carries a submodule configuration file and two directories at the top level that correspond to separate projects by the same author. One is the hand-written HTTP client the bot uses to reach the backend, and the README says explicitly that it does not rely on the official OpenAI client. The other is the Markdown-to-Telegram renderer behind the message formatting feature. Both are linked from the README as distinct projects in their own right. That is a reasonable way to share one HTTP layer and one renderer across several bots, and it means the dependency graph extends past this repository. Anyone who clones without initialising submodules gets a tree that imports modules which are not present, so the setup instructions that do not mention submodules will cost you an afternoon.

## The description advertises providers the page defers to a sibling project

The repository summary names a first-party model, an image generator, a fast inference provider, two Google model tiers and an Anthropic model as powering the bot. The page underneath says something narrower and explains it. The bot speaks the OpenAI-compatible format, and for every other provider, a list that includes Anthropic, Google, Vertex AI, Azure, AWS, a social-network-owned lab, Cohere, Groq, Cloudflare and OpenRouter, you are pointed at a separate translation project the same author maintains, with the reason given: it reduces maintenance cost. Two other gateway projects are named as also supported. So the summary describes the stack available to a user of the pair of projects, while the page describes the scope of this one. Not a contradiction, but if you are sizing the work, this repository is the Telegram surface and the sibling is the provider surface.

## Conclusion

ChatGPT-Telegram-Bot is a capable bot for a group or a small team, and the decision to speak only the OpenAI format rather than integrate a dozen providers is a defensible one that halves the surface area. Three things to check before you deploy it. Two of its required environment variables are named inconsistently between the template and the compose file, so copy from one and not the other and you will get a bot with no key. The access list is empty by default, meaning anyone who finds the bot can use it, and the group list overrides the allow list for every member of a listed group. And the repository's Dockerfile pulls its own published image, so building from it tells you nothing about the code you cloned.

## FAQ

### Which environment variables are required for ChatGPT-Telegram-Bot?

Two: the Telegram bot token and an API key. Everything else in the table is optional, including the default model, the endpoint, the web hook, the search keys and all four access lists. The base URL defaults to the first-party chat completions endpoint.

### Can I restrict who can use the ChatGPT-Telegram-Bot?

Yes, with four lists: an allow list, a deny list, a group list and an admin list. The allow list's default means the bot is open to everyone, and a group in the group list lets every member of that group use the bot even if they are not on the allow list.

### Does the ChatGPT-Telegram-Bot support Anthropic and Gemini directly?

Not through this repository. It speaks the OpenAI-compatible format, and the page directs every other provider, naming Anthropic, Google, Vertex AI, Azure, AWS and several gateways, to a separate translation project by the same author so that maintenance cost stays down. Two other gateway projects are also named as supported.

### What does the CUSTOM_MODELS variable do in ChatGPT-Telegram-Bot?

It carries three things in one string: a comma-separated model list, a hyphen prefix that removes a default model or all of them, and semicolon-separated groups with colon-separated names and members. Models that land in no named group are placed in a fallback group automatically.

### How does ChatGPT-Telegram-Bot search the web?

Through a plugin with two backends. Without a Google key it falls back to DuckDuckGo search; with a Google API key and a matching search engine identifier it uses Google instead. The same plugin set also does URL summarisation, paper summarisation and code execution.

## Sources

- [Issues](https://github.com/yym68686/ChatGPT-Telegram-Bot/issues)
- [License: GPL-3.0](https://github.com/yym68686/ChatGPT-Telegram-Bot/blob/main/LICENSE)
- [README](https://github.com/yym68686/ChatGPT-Telegram-Bot/blob/main/README.md)
- [yym68686/ChatGPT-Telegram-Bot on GitHub](https://github.com/yym68686/ChatGPT-Telegram-Bot)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yym68686-chatgpt-telegram-bot
