Telegram Archive
Automated Telegram backup with Docker. Performs incremental backups of messages and media on a configurable schedule.
Features
π¦ Backup Engine
- Incremental backups β Only downloads new messages since last backup
- Scheduled execution β Configurable cron schedule (default: every 6 hours)
- Real-time listener β Catch edits, deletions, and new messages instantly between backups
- Album support β Groups photos/videos sent together as albums
- Service messages β Tracks group photo changes, title changes, user joins/leaves
- Forwarded message info β Shows original sender name for forwarded messages
- Channel signatures β Displays post author when channels have signatures enabled
- Media deduplication β Symlinks identical files to save disk space
- Avatars always fresh β Profile photos updated on every backup run
π¬ Media Support
- Photos, videos, documents, stickers, GIFs
- Voice messages and audio files with in-browser player
- Polls with vote counts and results
- Configurable size limits and selective download
π Web Viewer
- Telegram-like dark UI β Feels like the real app
- Mobile-friendly β Responsive design with iOS/Android optimizations
- Integrated lightbox β View photos and videos without leaving the page
- Keyboard navigation β Arrow keys to browse media, Esc to close
- Real-time updates β WebSocket sync shows new messages instantly
- Push notifications β Get notified even when browser is closed
- Chat search β Find messages by text content
- JSON export β Download chat history with date range filters
π Security & Privacy
- Optional authentication β Password-protect your viewer
- Restricted sharing β Share specific chats via
DISPLAY_CHAT_IDS - Mass deletion protection β Rate limiting prevents accidental data loss
- Runs as non-root β Docker best practices
ποΈ Database
- SQLite (default) β Zero config, single file
- PostgreSQL β For larger deployments with real-time LISTEN/NOTIFY
πΊοΈ Roadmap
See docs/CHANGELOG.md for complete version history.
Have a feature request? Open an issue!
πΈ Screenshots
Docker Images
Two separate Docker images are available (v4.0+):
| Image | Purpose | Size |
|---|---|---|
drumsergio/telegram-archive |
Backup scheduler (requires Telegram credentials) | ~300MB |
drumsergio/telegram-archive-viewer |
Web viewer only (no Telegram client) | ~150MB |
π¦ Upgrading from v3.x? See Upgrading from v3.x to v4.0 for migration instructions.
Quick Start
1. Get Telegram API Credentials
- Go to https://my.telegram.org/apps
- Log in with your phone number
- Create a new application (any name/platform)
- Note your API ID (numbers) and API Hash (letters+numbers)
2. Deploy with Docker
# Clone the repository git clone https://github.com/GeiserX/Telegram-Archive cd Telegram-Archive # Create data directories mkdir -p data/session data/backups chmod -R 755 data/ # Configure environment cp .env.example .env
Edit .env with your credentials:
TELEGRAM_API_ID=12345678 # Your API ID TELEGRAM_API_HASH=abcdef123456 # Your API Hash TELEGRAM_PHONE=+1234567890 # Your phone (with country code)
3. Authenticate with Telegram
Option A: Using the provided scripts (recommended for fresh installs)
# Run authentication ./init_auth.sh # Linux/Mac # init_auth.bat # Windows
Option B: Direct Docker command (for existing deployments or re-authentication)
If your session expires or you need to re-authenticate an existing container:
# Generic command - adjust volume paths and credentials
docker run -it --rm \
-e TELEGRAM_API_ID=YOUR_API_ID \
-e TELEGRAM_API_HASH=YOUR_API_HASH \
-e TELEGRAM_PHONE=+YOUR_PHONE_NUMBER \
-e SESSION_NAME=telegram_backup \
-v /path/to/your/session:/data/session \
drumsergio/telegram-archive:latest \
python -m src authExample for docker compose deployment:
# If using docker compose with a session volume docker run -it --rm \ --env-file .env \ -v telegram-archive_session:/data/session \ drumsergio/telegram-archive:latest \ python -m src auth # Then restart the backup container docker compose restart telegram-backup
What happens during authentication:
- The script connects to Telegram's servers
- Telegram sends a verification code to your Telegram app (check "Telegram" chat)
- Enter the code when prompted
- If you have 2FA enabled, enter your password when prompted
- Session is saved to the mounted volume for future use
4. Start Services
View your backup at http://localhost:8000
Common Issues
| Problem | Solution |
|---|---|
Permission denied |
Run chmod -R 755 data/ |
init_auth.sh: command not found |
Run chmod +x init_auth.sh first |
| Viewer shows no data | Both containers need same database path - see Database Configuration |
Failed to authorize |
Re-run ./init_auth.sh |
Web Viewer
The standalone viewer image (drumsergio/telegram-archive-viewer) lets you browse backups without running the backup scheduler.
# Example: Viewer-only deployment services: telegram-viewer: image: drumsergio/telegram-archive-viewer:latest ports: - "8000:8000" environment: BACKUP_PATH: /data/backups DATABASE_DIR: /data/db VIEWER_USERNAME: admin VIEWER_PASSWORD: your-secure-password VIEWER_TIMEZONE: Europe/Madrid volumes: - /path/to/backups:/data/backups:ro - /path/to/db:/data/db:ro
Browse your backups at http://localhost:8000
Configuration
All settings are configured via environment variables. Set them in your .env file or as environment: entries in docker-compose.yml. See .env.example for a ready-to-use template.
ENABLE_LISTENERis a master switch. When set tofalse(the default), allLISTEN_*andMASS_OPERATION_*variables have no effect. You only need to configure those when you setENABLE_LISTENER=true.
Environment Variables
The Scope column shows whether each variable applies to the backup scheduler (B), the web viewer (V), or both (B/V).
| Variable | Default | Scope | Description |
|---|---|---|---|
| Telegram Credentials | |||
TELEGRAM_API_ID |
required | B | API ID from my.telegram.org |
TELEGRAM_API_HASH |
required | B | API Hash from my.telegram.org |
TELEGRAM_PHONE |
required | B | Phone number with country code (e.g., +1234567890) |
| Backup Schedule & Storage | |||
SCHEDULE |
0 */6 * * * |
B | Cron expression for backup frequency |
BACKUP_PATH |
/data/backups |
B/V | Base path for backup data and media |
DOWNLOAD_MEDIA |
true |
B | Download media files (photos, videos, documents) |
MAX_MEDIA_SIZE_MB |
100 |
B | Skip media files larger than this (MB) |
BATCH_SIZE |
100 |
B | Messages processed per database batch |
DATABASE_TIMEOUT |
60.0 |
B/V | Database operation timeout in seconds |
SESSION_NAME |
telegram_backup |
B | Telethon session file name |
DEDUPLICATE_MEDIA |
true |
B | Symlink identical media files across chats to save disk space |
SYNC_DELETIONS_EDITS |
false |
B | Batch-check ALL messages for edits/deletions each run (expensive!) |
VERIFY_MEDIA |
false |
B | Re-download missing or corrupted media files |
STATS_CALCULATION_HOUR |
3 |
B | Hour (0-23) to recalculate backup statistics daily |
PRIORITY_CHAT_IDS |
- | B | Comma-separated chat IDs to process first in all operations |
LOG_LEVEL |
INFO |
B/V | Logging verbosity: DEBUG, INFO, WARNING/WARN, ERROR |
| Chat Filtering | See Chat Filtering below | ||
CHAT_IDS |
- | B | Whitelist mode: backup ONLY these chats (ignores all other filters) |
CHAT_TYPES |
private,groups,channels |
B | Type-based mode: comma-separated chat types to backup |
GLOBAL_EXCLUDE_CHAT_IDS |
- | B | Exclude specific chats (any type) |
GLOBAL_INCLUDE_CHAT_IDS |
- | B | Force-include specific chats (any type) |
PRIVATE_EXCLUDE_CHAT_IDS |
- | B | Exclude specific private chats |
PRIVATE_INCLUDE_CHAT_IDS |
- | B | Force-include specific private chats |
GROUPS_EXCLUDE_CHAT_IDS |
- | B | Exclude specific groups |
GROUPS_INCLUDE_CHAT_IDS |
- | B | Force-include specific groups |
CHANNELS_EXCLUDE_CHAT_IDS |
- | B | Exclude specific channels |
CHANNELS_INCLUDE_CHAT_IDS |
- | B | Force-include specific channels |
| Real-time Listener | See Real-time Listener below | ||
ENABLE_LISTENER |
false |
B | Master switch β enables all LISTEN_* features below |
LISTEN_EDITS |
true |
B | Apply text edits in real-time |
LISTEN_DELETIONS |
true |
B | Mirror deletions (protected by mass operation rate limiting) |
LISTEN_NEW_MESSAGES |
true |
B | Save new messages in real-time between scheduled backups |
LISTEN_NEW_MESSAGES_MEDIA |
false |
B | Also download media immediately (vs. next scheduled backup) |
LISTEN_CHAT_ACTIONS |
true |
B | Track chat photo, title, and member changes |
MASS_OPERATION_THRESHOLD |
10 |
B | Max operations per chat before rate limiting triggers |
MASS_OPERATION_WINDOW_SECONDS |
30 |
B | Sliding window for counting operations (seconds) |
MASS_OPERATION_BUFFER_DELAY |
2.0 |
B | Seconds to buffer operations before applying |
| Database | See Database Configuration below | ||
DATABASE_URL |
- | B/V | Full database URL (highest priority, overrides all below) |
DB_TYPE |
sqlite |
B/V | Database engine: sqlite or postgresql |
DB_PATH |
$BACKUP_PATH/telegram_backup.db |
B/V | Path to SQLite database file |
DATABASE_PATH |
- | B/V | Full path to SQLite file (v2 compatible alias for DB_PATH) |
DATABASE_DIR |
- | B/V | Directory containing telegram_backup.db (v2 compatible) |
POSTGRES_HOST |
localhost |
B/V | PostgreSQL host |
POSTGRES_PORT |
5432 |
B/V | PostgreSQL port |
POSTGRES_USER |
telegram |
B/V | PostgreSQL username |
POSTGRES_PASSWORD |
- | B/V | PostgreSQL password (required when using PostgreSQL) |
POSTGRES_DB |
telegram_backup |
B/V | PostgreSQL database name |
| Viewer & Authentication | |||
VIEWER_USERNAME |
- | V | Web viewer username (both username and password required to enable auth) |
VIEWER_PASSWORD |
- | V | Web viewer password |
AUTH_SESSION_DAYS |
30 |
V | Days before re-authentication is required |
DISPLAY_CHAT_IDS |
- | V | Restrict viewer to specific chats (comma-separated IDs) |
VIEWER_TIMEZONE |
Europe/Madrid |
V | Timezone for displayed timestamps (tz database names) |
SHOW_STATS |
true |
V | Show backup statistics dropdown in viewer header |
| Security | |||
CORS_ORIGINS |
* |
V | Allowed CORS origins, comma-separated (e.g., https://my.domain.com). Credentials auto-disabled when * |
SECURE_COOKIES |
auto |
V | Secure flag on auth cookies. Auto-detects from request protocol (X-Forwarded-Proto / scheme). Override with true or false |
| Notifications | |||
PUSH_NOTIFICATIONS |
basic |
V | off = disabled, basic = in-browser only, full = Web Push (works with browser closed) |
VAPID_PRIVATE_KEY |
auto-generated | V | Custom VAPID private key for Web Push |
VAPID_PUBLIC_KEY |
auto-generated | V | Custom VAPID public key for Web Push |
VAPID_CONTACT |
mailto:admin@example.com |
V | Contact email included in Web Push requests |
Chat Filtering
There are two modes for selecting which chats to backup:
Mode 1 β Whitelist (simple): set CHAT_IDS to backup only those specific chats. All other filtering variables are ignored.
CHAT_IDS=-1001234567890,-1009876543210 # Only these 2 chats, nothing elseMode 2 β Type-based (default): use CHAT_TYPES to backup all chats of certain types, then fine-tune with include/exclude lists:
# Backup all private chats and groups (no channels) CHAT_TYPES=private,groups # Backup all channels except one CHAT_TYPES=channels CHANNELS_EXCLUDE_CHAT_IDS=-1001234567890 # Backup all groups plus one specific channel CHAT_TYPES=groups CHANNELS_INCLUDE_CHAT_IDS=-1001234567890
*_INCLUDE_*variables are additive β they add chats to whatCHAT_TYPESalready selects. For exclusive selection, useCHAT_IDSinstead.
Chat ID format β Telegram uses "marked" IDs:
- Users: positive numbers (
123456789) - Basic groups: negative (
-123456789) - Supergroups/Channels: negative with
-100prefix (-1001234567890)
Find a chat's ID by forwarding a message to @userinfobot.
Real-time Listener
The scheduled backup only captures new messages. To also track edits and deletions between backups, enable the real-time listener:
ENABLE_LISTENER: "true" # Master switch β required LISTEN_EDITS: "true" # Track text edits (safe, default: true) LISTEN_DELETIONS: "true" # Mirror deletions (default: true, protected by rate limiting) LISTEN_NEW_MESSAGES: "true" # Save new messages instantly (default: true)
How it works: stays connected to Telegram between scheduled backups, captures changes as they happen, and automatically reconnects if disconnected.
Backup protection: when LISTEN_DELETIONS=true, deletions are protected by the mass operation rate limiter. Set LISTEN_DELETIONS=false to never delete anything from your backup.
Alternative β batch sync: set SYNC_DELETIONS_EDITS=true to check ALL backed-up messages on each scheduled run. This is expensive and slow β only use for a one-time catch-up, then switch to the real-time listener.
Mass Operation Protection
When the listener is enabled and LISTEN_DELETIONS=true, a sliding-window rate limiter protects against mass deletion attacks:
- Operations are buffered for
MASS_OPERATION_BUFFER_DELAYseconds before being applied - A sliding window tracks operations per chat over
MASS_OPERATION_WINDOW_SECONDS - When
MASS_OPERATION_THRESHOLDis exceeded, the entire buffer is discarded β zero changes written
Example: someone deletes 50 messages in 10 seconds with default settings (threshold=10, window=30s) β the first 10 are applied, remaining 40 are blocked. For zero deletions from your backup, set LISTEN_DELETIONS=false.
Database Configuration
Telegram Archive supports SQLite (default, zero-config) and PostgreSQL (better for large deployments with real-time LISTEN/NOTIFY).
Viewer shows no data? Both backup and viewer containers must access the same database. Ensure
DB_TYPEandDB_PATH(orDATABASE_URL) match in both services.
SQLite path resolution (highest priority first): DATABASE_URL β DATABASE_PATH β DATABASE_DIR β DB_PATH β $BACKUP_PATH/telegram_backup.db
Using PostgreSQL:
- Uncomment the
postgresservice indocker-compose.yml - Set
DB_TYPE=postgresqlandPOSTGRES_PASSWORDin your.env - Uncomment
depends_onin both backup and viewer services - Run
docker compose up -d
Updating to Latest Version
Using Pre-built Images (Recommended)
If you're using the default docker-compose.yml with images from Docker Hub:
# Pull latest images and recreate containers
docker compose pull
docker compose up -dOr in one command:
docker compose up -d --pull always
Note: Running
git pullonly updates source code, not Docker images. You must usedocker compose pullto get new container versions.
Building from Source
If you've modified the code or prefer building locally:
git pull docker build -t drumsergio/telegram-archive:latest . docker build -t drumsergio/telegram-archive-viewer:latest -f Dockerfile.viewer . docker compose up -d
Pinning Versions
For production stability, pin to specific versions instead of latest:
services: telegram-backup: image: drumsergio/telegram-archive:v5.3.7 # Pin to specific version
Check Releases for available versions.
β οΈ Upgrading (Breaking Changes)
For major version upgrades with breaking changes and migration scripts, see docs/CHANGELOG.md.
CLI Commands
Local Development
Option 1: Install with pip (Recommended)
Install the package in editable mode to get the telegram-archive command:
# Install in editable mode pip install -e . # Now telegram-archive is available system-wide telegram-archive --help telegram-archive --data-dir ./data list-chats telegram-archive --data-dir ./data stats telegram-archive --data-dir ./data backup # Export to JSON telegram-archive --data-dir ./data export -o backup.json -s 2024-01-01 -e 2024-12-31
Option 2: Run directly without installation
For development without installing, use the telegram-archive executable script:
# Show all available commands ./telegram-archive --help # Use custom data directory (instead of /data) ./telegram-archive --data-dir ./data list-chats ./telegram-archive --data-dir ./data stats ./telegram-archive --data-dir ./data backup # Or symlink to PATH for easier access sudo ln -s $(pwd)/telegram-archive /usr/local/bin/telegram-archive telegram-archive --data-dir ./data list-chats
Docker Usage
All commands use the unified python -m src interface inside containers:
# Show all available commands docker compose exec telegram-backup python -m src --help # View statistics docker compose exec telegram-backup python -m src stats # List chats docker compose exec telegram-backup python -m src list-chats # Export to JSON docker compose exec telegram-backup python -m src export -o backup.json # Export date range docker compose exec telegram-backup python -m src export -o backup.json -s 2024-01-01 -e 2024-12-31 # Manual backup run (one-time) docker compose exec telegram-backup python -m src backup # Re-authenticate (if session expires) docker compose exec -it telegram-backup python -m src auth
Data Storage
data/
βββ session/
β βββ telegram_backup.session
βββ backups/
βββ telegram_backup.db
βββ media/
βββ {chat_id}/
βββ {files}
Troubleshooting
| Problem | Solution |
|---|---|
| "Failed to authorize" | Run ./init_auth.sh again |
| "Permission denied" | chmod -R 755 data/ |
| Media files missing/corrupted | Set VERIFY_MEDIA=true to re-download them |
| Backup interrupted | Set VERIFY_MEDIA=true once to recover missing files |
| "duplicate key value violates unique constraint reactions_pkey" | See Reactions Sequence Fix below |
Reactions Sequence Fix (PostgreSQL)
If you see this error during backup:
duplicate key value violates unique constraint "reactions_pkey"
DETAIL: Key (id)=(XXXX) already exists
Cause: The PostgreSQL sequence for reactions.id got out of sync with the actual data. This commonly occurs after database restores or migrations.
Solutions:
-
Upgrade to v4.1.2+ (recommended) - The code automatically detects and recovers from this issue.
-
Manual fix - Run this SQL command:
docker exec -i <postgres-container> psql -U telegram -d telegram_backup -c \ "SELECT setval('reactions_id_seq', COALESCE((SELECT MAX(id) FROM reactions), 0) + 1, false);"
Or use the provided script:
curl -O https://raw.githubusercontent.com/GeiserX/Telegram-Archive/master/scripts/fix_reactions_sequence.sql docker exec -i <postgres-container> psql -U telegram -d telegram_backup < fix_reactions_sequence.sql
Limitations
- Secret chats not supported (API limitation)
- Edit history not tracked (only latest version stored; enable
ENABLE_LISTENER=trueto track edits in real-time) - Deleted messages before first backup cannot be recovered
License
GPL-3.0. See LICENSE for details.
Built with Telethon.


