Don’t want to read all this?
Just drop a link to https://xedant.com/agents/telegram/install.md or to https://xedant.com/llms.txt into any AI chat (Claude, ChatGPT, etc.) and ask it to generate the config files and commands. It will read the docs, ask you a few questions about your setup, and hand you a ready-to-use configuration. Save time — let the model do the reading for you.
You can also reach me on Telegram — I’m always glad to help. And that’s not just politeness — I genuinely enjoy talking to like-minded people, especially if you love coding as much as I do.
Telegram Agent is a program for managing your Telegram marketing that you run on your own server. It deploys as a single Docker container and keeps everything in two permanent volumes: /apps/telegram — the database, media, account sessions and the access keys to them, /project/apps/telegram — settings as plain readable files. No separate database server is needed: the built-in SQLite works out of the box, and PostgreSQL connects optionally.
The application is economical with the server’s resources. When idle, the CPU is not loaded: the publishing scheduler and the statistics upload do not poll the database on a timer — they wake up when there is work. After 15 minutes without activity the memory in use is released — the search index and service data; everything comes back by itself on the next task. That is why Telegram Agent sits comfortably next to other services on the same server.
Minimum requirements
Any Linux host with Docker is enough (an inexpensive VPS, for example). Everything else is already built into the image:
- the application web server (ASP.NET Core 9 runtime);
- an SQLite database — works without any setup;
- for the chat with the agent you will need the address and API key of your Xedant Agent — but that is optional: without them everything works except the agent chat.
Docker Compose
Create a compose.yml file and run docker compose up -d:
services:
telegram-agent:
image: xedant/telegram-agent:latest
container_name: telegram-agent
ports:
- "3997:80"
volumes:
- telegram-agent-data:/apps/telegram
- telegram-agent-config:/project/apps/telegram
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://+:80
- TELEGRAM_APP_DATA=/apps/telegram
- TELEGRAM_APP_CONFIG_FOLDER=/project/apps/telegram
# Optional "Call Agent" integration (leave unset to hide all Agent chat surfaces):
# - AGENT_API_URL=https://your-agent-host
# - AGENT_API_KEY=your-agent-API-key
# Serve from a first-level subfolder (see ../subfolder-hosting.md):
# - TELEGRAM_APP_BASE_PATH=/telegram
restart: unless-stopped
sysctls:
fs.inotify.max_user_watches: "524288"
fs.inotify.max_user_instances: "512"
volumes:
telegram-agent-data:
telegram-agent-config:
After startup the interface is available on port 3997: http://localhost:3997.
The two sysctls lines raise the system file-watching limits — they are needed so new messages from sources and new posts are picked up instantly, in real time. Without them, some updates may not reach the interface when the flow is large.
The second volume is the settings folder /project/apps/telegram. The application keeps what you configure yourself — channels, sources, templates, the schedule — there, as plain readable files (details in the Data storage section below).
Environment variables
Application settings are passed through environment variables — a convenient way to set them once in compose.yml and change them without touching the code:
| Variable | Purpose | Default |
TELEGRAM_APP_BRAND | brand and interface language: xedant (English) or pastukhov (Russian) | xedant |
TELEGRAM_APP_DATA | application data folder (inside the container — /apps/telegram) | /apps/telegram |
TELEGRAM_APP_CONFIG_FOLDER | settings folder — readable YAML files (inside the container — /project/apps/telegram) | /project/apps/telegram |
TELEGRAM_APP_LOGIN | login of the first user (the password is a SHA-256 hash in TELEGRAM_APP_PASSWORD) | — (self-registration) |
TELEGRAM_APP_PASSWORD | SHA-256 hash of the password, not the password itself: echo -n "your-password" | sha256sum | — |
AGENT_LICENSE | license key (or a path to a file with it) — the same variable Xedant Agent reads | — (no agent chat) |
AGENT_API_URL | address of Xedant Agent for the agent chat | — (Call Agent buttons hidden) |
AGENT_API_KEY | API key of Xedant Agent | — |
TELEGRAM_APP_HASH | SHA-256 hash of the machine key: with it the MultiAgent control server gets administrator access to the external API | — |
TELEGRAM_APP_BASE_PATH | serve from a first-level subfolder (for example, /telegram) | — |
TELEGRAM_APP_DATABASE | PostgreSQL connection string; empty value — the built-in SQLite | SQLite (/apps/telegram/data.db) |
TELEGRAM_APP_CLICKHOUSE_URL | ClickHouse address — a separate database for long-term channel statistics storage; empty — upload disabled | — |
TELEGRAM_APP_SSL | self-signed HTTPS: auto — enable (for a direct address like telegram.your-domain); alongside TELEGRAM_APP_SSL_PORT and TELEGRAM_APP_SSL_DOMAINS | — (HTTP only) |
TELEGRAM_APP_DOCS_FOLDER | project documents folder — files pasted into the agent chat land there | /project/docs (in the container — /apps/telegram/docs) |
TELEGRAM_APP_SEARCH_INDEX_FOLDER | search index folder for channels, posts, authors and comments | /apps/telegram/search-index |
TELEGRAM_APP_ERROR_REPORTING | 0 — disable sending automatic error reports | reports are enabled |
Note: TELEGRAM_APP_PASSWORD contains not the password but its SHA-256 hash — a “fingerprint” from which the password cannot be recovered. The hash is computed with echo -n "your-password" | sha256sum. On sign-in the application hashes the entered password and compares it with the configured value.
First-time setup happens right in the interface: self-registration is open while no user exists — the first person to register becomes the administrator. If there are no users yet and the login and password are not set with variables, the application creates a one-time password itself (login agents) and prints it to the container console. A sign-in session lasts 90 days.
Data storage
All permanent data lives in two volumes and survives container recreation. Application data — in the /apps/telegram volume:
/apps/telegram/data.db— the SQLite database (when PostgreSQL is not used);/apps/telegram/sessions/— sessions of the connected Telegram accounts;/apps/telegram/account-secrets.yml— access keys to the Telegram accounts (api_idandapi_hash): created automatically when an account is first connected;/apps/telegram/media/— uploaded media files;/apps/telegram/keys/— the sign-in signing key (JWT);/apps/telegram/auth/— data protection keys;/apps/telegram/docs/— files pasted into the agent chat;/apps/telegram/search-index/— the full-text search index for channels, posts, authors and comments: it sits on disk and is reused between runs, so search works right after a restart;/apps/telegram/.xedant/license.txt— the activated license key (for the pastukhov brand — the.pastukhovfolder).
Settings live separately — in the /project/apps/telegram volume, as plain readable files: settings.yml (application settings), bots.yml and accounts.yml (bots and Telegram accounts), one file per source and channel in the sources/ and channels/ folders (together with schedule slots and post templates), categories.yml, tags.yml, routers.yml, routing-rules.yml, taggers.yml, commenting-projects.yml, commenting-targets.yml, comment-templates.yml. This is convenient: the settings folder can be copied to another server or put into git, and a manual edit of a file is picked up on the fly. If a file is corrupted, the application keeps working with the last good version of the settings. Access keys to personal Telegram accounts (api_id and api_hash) are no longer kept in accounts.yml — they live separately, in the data volume, in the account-secrets.yml file. That is why a migration or a backup now needs both volumes: the settings folder alone is no longer enough.
Both volumes are mandatory: without them you lose the database, account sessions, the access keys to them, media and settings on the very first docker compose down. Make a backup and move to another server with both volumes at once.
First sign-in
Open the interface in a browser and register the first user — you become the administrator. Or sign in with the login set through environment variables (the variable holds the hash; at sign-in you enter the password itself) or the one printed to the container console. Right after signing in you can change the interface language and theme.
Setup after launch
Connect the bots first — tokens are created in @BotFather in a minute and verified automatically — and (optionally) personal Telegram accounts by phone number and code. Then connect channels: through a bot, a name and a token are enough; through an account, pick from the list of your channels. Details in the Channels section.
The agent chat is enabled with the AGENT_API_URL and AGENT_API_KEY variables: the Call Agent buttons appear on the channel page and in the queue, plus the chat panel. Details in the Agent section.
License
The license key is activated in the license dialog (the footer of the main screen) or passed with the AGENT_LICENSE variable at startup — the same variable Xedant Agent reads, so one key can license several products of this family at once. No ready license ships in the image: a fresh container starts without one. The important advantage: everything works without a license — channels, publishing, the schedule, the queue, sources, comments and analytics. The license is needed only for sending messages to the agent chat. Details on the Licensing page.
Docker CLI with a .env file
You can run Telegram Agent without compose too — with a docker run command, keeping the environment variables in a .env file:
# .env
ASPNETCORE_ENVIRONMENT=Production
ASPNETCORE_URLS=http://+:80
TELEGRAM_APP_DATA=/apps/telegram
TELEGRAM_APP_CONFIG_FOLDER=/project/apps/telegram
TELEGRAM_APP_LOGIN=admin
TELEGRAM_APP_PASSWORD=sha256-password-hash
# optional: agent chat through Xedant Agent
# AGENT_API_URL=
# AGENT_API_KEY=
# optional: license key (no license ships in the image)
# AGENT_LICENSE=
docker run -d \
--name telegram-agent \
--env-file .env \
-p 3997:80 \
-v telegram-agent-data:/apps/telegram \
-v telegram-agent-config:/project/apps/telegram \
--sysctl fs.inotify.max_user_watches=524288 \
--sysctl fs.inotify.max_user_instances=512 \
--restart unless-stopped \
xedant/telegram-agent:latest
The --env-file flag reads all the variables from the file. Individual values can be overridden with additional -e flags after it, for example -e TELEGRAM_APP_BRAND=pastukhov.