Telegram Backup Downloader v5
Downloads text, photos, videos, and documents from configured Telegram channels. Message text is stored in messages.txt and JSONL metadata; media is sorted into per-channel folders. SQLite tracks completed work, failed downloads, and sync progress.
Platform support: Docker images are built for
linux/amd64andlinux/arm64only. Legacy 32-bit ARM (arm/v7) is not supported because thecryptgTelethon extension has no prebuilt wheel for it. This covers servers, desktops, NAS devices, Raspberry Pi 4/5, and Apple Silicon via emulation.
Prerequisites
- Python 3.12 or Docker
- A Telegram API ID and API hash from my.telegram.org
- A Telegram account that can access every configured channel
Local Quick Start
- Create a virtual environment and install dependencies:
python -m venv .venvthen.venv\Scripts\pip install -r requirements.txton Windows, or.venv/bin/pip install -r requirements.txton Linux/macOS. - Copy
config.example.jsontoconfig.jsonand enter your Telegram values. - Run
python downloadv5.py. The first run requests Telegram login verification if no session file exists.
Backups are written to channels/; logs are written to logs/app.log. Stop gracefully with Ctrl+C.
Docker
Option A: Docker Compose (recommended)
The example docker-compose.yml uses the pre-built image from Docker Hub and supports linux/amd64 and linux/arm64.
Before running, create the folders and config file so the container can write to them. The compose file mounts local paths for config, session, data, channels, and logs:
mkdir -p data channels logs
cp config.example.json config.json
# edit config.json with your Telegram values
On Linux, if the container runs as a non-root user, make sure the current user has read+write access to these folders (the example compose runs as
root).
Then start the stack:
docker compose up -d
docker compose logs -f telegram-backup
This is the docker-compose.yml:
version: "3.9"
services:
telegram-backup:
image: hoelee/telegram-backup-downloader:latest
container_name: telegram-backup
restart: unless-stopped
user: root
volumes:
- ./config.json:/app/config.json:ro
- ./telegram_session.session:/app/telegram_session.session
- ./data:/app/data
- ./channels:/app/channels
- ./logs:/app/logs
ports:
- "8080:8080"
environment:
- TZ=Asia/Kuala_Lumpur
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8080/health', timeout=3)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
Set status_port to 8080 in config.json to use the health check and expose the status API.
Option B: docker run
mkdir -p data channels logs
cp config.example.json config.json
docker run -d \
--name telegram-backup \
--restart unless-stopped \
-v $(pwd)/config.json:/app/config.json:ro \
-v $(pwd)/telegram_session.session:/app/telegram_session.session \
-v $(pwd)/data:/app/data \
-v $(pwd)/channels:/app/channels \
-v $(pwd)/logs:/app/logs \
-p 8080:8080 \
-e TZ=Asia/Kuala_Lumpur \
hoelee/telegram-backup-downloader:latest
Follow logs with docker logs -f telegram-backup.
Option C: Build from source
cp config.example.json config.json
docker compose -f docker-compose.yml up -d --build
docker compose logs -f telegram-backup
Configuration
| Key | Required | Default | Description |
|---|---|---|---|
api_id |
Yes | - | Numeric Telegram API ID. |
api_hash |
Yes | - | Telegram API hash. |
phone_number |
Yes | - | Account phone number in international format. |
session_name |
Yes | - | Telethon session basename. |
channels |
Yes | - | Channel usernames or numeric peer IDs. |
parallel_downloads |
No | 3 |
Number of media workers. |
download_timeout_seconds |
No | 600 |
Per-download timeout. |
download_retry_count |
No | 3 |
Attempts made in one processing pass. |
max_lifetime_retries |
No | 20 |
Total failed passes before an item is dropped; 0 disables the cap. |
queue_max_size |
No | 5000 |
Normal download queue capacity. |
min_disk_space_gb |
No | 6 |
Pause media downloads below this free space. |
channel_auto_disable_after |
No | 5 |
Consecutive resolution failures before disabling a channel; 0 disables this. |
media_record_ttl_days |
No | 90 |
Retention for completed media DB records; 0 disables pruning. |
retry_drop_log |
No | true |
Write discarded downloads to logs/dropped_downloads.jsonl. |
resync_interval_minutes |
No | 60 |
Periodic backfill interval; 0 disables it. |
status_port |
No | 0 |
HTTP port; 0 disables the server. |
db_path |
No | telegram_state.db |
SQLite state database path. |
channel_overrides |
No | {} |
Per-channel controls. Use turnon: false to skip a channel without removing it from channels. Example: {"-1001":{"turnon":false}}. Change is detected by config watcher — no restart needed. |
manual_downloads |
No | {} |
Message IDs to prioritize, keyed by channel ID. Useful to force-retry specific messages. Example: {"-1001":[42,43,44]}. Change is detected by config watcher — no restart needed. |
config.json is watched every 10 seconds. Changes to channels, overrides, and manual downloads are applied without restarting. Do not set status_port, db_path, worker count, or API credentials expecting a live process to rebind/recreate those resources; restart after changing them.
HTTP API
The API listens on 0.0.0.0:<status_port> with no authentication. Only expose it on a trusted network.
| Method | Endpoint | Description |
|---|---|---|
| GET | /health |
Returns {"status":"ok"}. |
| GET | /status |
Connection, queue, workers, disk, database, failure, and channel status. |
| GET | /logs?lines=100 |
Last 1-5000 lines of logs/app.log. |
| POST | /reload |
Reloads config.json. |
| POST | /db/cleanup |
Prunes expired records and vacuums SQLite. |
| POST | /channel/{id}/enable |
Enables a channel override and resolves channels. |
| POST | /channel/{id}/disable |
Disables a channel override. |
Troubleshooting
- Login problems: delete only the session file if you intentionally need to authenticate again, then restart.
- No downloads: verify the account belongs to or can view the channel, and confirm the channel override is enabled.
- Downloads paused: inspect
/statusor the log for disk-space warnings. Downloads resume automatically after space is recovered. - Repeated failed media: inspect
logs/app.log; items reaching the lifetime cap are recorded inlogs/dropped_downloads.jsonlwhen enabled. - Port unavailable: set
status_portto another free port, update compose port mapping if needed, and restart. - Database location in Docker: set
db_pathtodata/telegram_state.dbif you want the database in the mounteddatadirectory.