Configuration

Almost everything is set in the dashboard and stored in SQLite (data/db.sqlite); changes apply without a restart. Environment variables cover only what the process needs before it starts: where data lives, which port to listen on and how to sit behind a proxy.

Dashboard settings

Where What
Settings → Telegram API apiId and apiHash from my.telegram.org
Settings → Accounts Telegram accounts (phone, login code, optional 2FA)
Settings → Downloads Concurrent downloads (1–50, the starting point of the adaptive concurrency), attempts per file (1–20, counting the first), bandwidth limit (0 = unlimited)
Settings → Downloads (disk) Library size cap (maxTotalSize) and Auto-rotate when full, see disk rotation
Settings (other sections) Proxy (SOCKS5, SOCKS4, HTTP, MTProxy), dashboard and guest passwords, share links, CSP and HTTPS policy, rescue mode, appearance
Chats → a chat Monitor on/off, media types, senders, forum topics, which account reads it, Forward to (auto-forward destination, forward account, delete after forward)
Maintenance Updates, database tools, logs, sessions, cluster pairing and sweep, seekbar previews, NSFW review
Safety & AI Face recognition and its sidecar, see AI
Backup Destinations and schedules, see Backup

Settings that 3.x does not act on (rateLimits and pollingInterval) are kept as they are but have no effect.

Advanced settings

These keys are stored in the same configuration. The advanced.* ones are edited under Settings → Advanced (for example Min Workers, Max Workers and Scaler Tick), the disk cap and rotation switch under Settings → Downloads; diskManagement.sweepIntervalMin keeps its 2.x value. Values outside the range are clamped when saved.

Key Default Meaning
advanced.downloader.minConcurrency 3 (1–100) Fewest files downloading at once when the queue is idle or after a Telegram FloodWait.
advanced.downloader.maxConcurrency 20 (1–100) Most files downloading at once while the queue is long. Starts at Concurrent downloads and grows by up to 3 per step. Set it equal to Concurrent downloads for a fixed number.
advanced.downloader.scalerIntervalSec 5 (1–600) Seconds between scaling steps.
diskManagement.enabled false Auto-rotate when full. When on, the oldest downloads and their files are deleted until the library is under maxTotalSize. Pinned and rescued items, files still downloading and files outside the downloads folder are never deleted.
diskManagement.maxTotalSize 50GB Library cap, e.g. 500GB or 1.5TB (binary units). Measured as the sum of catalog file sizes, not free disk space. An unreadable value means no cap.
diskManagement.sweepIntervalMin 10 (1–1440) Minutes between rotation sweeps. The first sweep runs 5 s after start or a settings change.
advanced.diskRotator.maxDeletesPerSweep 5000 Most downloads one sweep may delete.
advanced.integrity.intervalMin 60 (at least 60 is used) Minutes between integrity sweeps, which drop catalog rows whose file is missing. Never deletes files; skips pruning when more than half of the library looks missing.
advanced.seekbar.*, advanced.nsfw.*, advanced.ai.*   See AI.

Auto-forward is set per chat in its autoForward block (enabled, destination, deleteAfterForward) plus forwardAccount; the destination is me, a chat ID, @username, a t.me link, or empty for the “Telegram Downloader Storage” channel. See Features.

Environment variables

Every variable below is read by the current code. Names not listed here are ignored.

Server (tgdl-server)

Variable Default Meaning
TGDL_DATA_DIR required; /app/data in Docker, ./data with the launchers Database, sessions, thumbnails, logs and backups. Created with mode 0700.
TGDL_DOWNLOADS_DIR <data>/downloads Put media on another disk. The database and thumbnails stay in the data folder. In Docker, also mount that path into the container.
PORT 3000 HTTP and WebSocket port.
TGDL_BIND_HOST all interfaces Literal IPv4/IPv6 address to listen on, e.g. 127.0.0.1 behind a reverse proxy on the same host.
TGDL_SESSION_TTL_DAYS 7 Lifetime of a new dashboard sign-in, 1–3650 days.
TGDL_SECURE_COOKIES 0 Set to 1 when the dashboard is served over HTTPS.
TRUST_PROXY loopback when unset Which proxies may set X-Forwarded-*: a hop count (1), a comma list of IPs, CIDRs or loopback, linklocal, uniquelocal, or empty to trust none. The Compose file sets 1.
TGDL_CSP on off disables the Content-Security-Policy header (emergency use only).
COMPRESSION_LEVEL 6 gzip/deflate response compression level, 0–9.
TGDL_METRICS_TOKEN unset When set, GET /metrics requires ?token=<value>.
FFMPEG_PATH ffmpeg ffmpeg used for thumbnails, seekbar previews and video operations.
FFPROBE_PATH ffprobe beside FFMPEG_PATH, then on PATH ffprobe used to read video durations for seekbar previews.
FFMPEG_HWACCEL unset Hardware video decoding for thumbnails and seekbar previews: vaapi, qsv, cuda, videotoolbox, d3d11va or dxva2. Overrides Settings → Advanced; a backend that fails on the host falls back to the CPU.
FASTSTART_CONCURRENCY 2 Parallel MP4 faststart rewrites (max 8).
TGDL_DOWNLOAD_THREADS 4 Parts of one file fetched at the same time (1–16). An account that gets a FLOOD_WAIT during a file drops to half for its next files and climbs back by one after 8 files without one. 1 fetches one part at a time, as before 3.4.15.
TGDL_VERIFY_CHUNKS 0 1 checks every part against Telegram’s chunk hashes. It uses 128 KiB parts one at a time, so downloads are several times slower.
WATCHTOWER_URL unset (http://watchtower:8080 in Compose) Enables Install update through the watchtower sidecar.
WATCHTOWER_HTTP_API_TOKEN generated Token shared with watchtower. When unset, it is generated once in data/watchtower/api-token.
PUBLIC_URL unset This instance’s own address as seen by cluster peers. See Cluster mode.
TZ host Time zone for logs and schedules.
GOMEMLIMIT unset Go runtime soft memory limit, e.g. 1GiB. Not a hard cap.

Advanced update timings, rarely needed: UPDATE_SNAPSHOT_TIMEOUT_MS (900000, 15 minutes, for the pre-update database snapshot), UPDATE_BACKUP_KEEP (5 pre-update snapshots), UPDATE_STALL_AFTER_MS (600000) and UPDATE_OVERLAY_STALL_MS (120000).

BACKUP_DROPBOX_CHUNK_BYTES sets the Dropbox upload chunk size (4–148 MiB, default 8 MiB); see Backup.

AI sidecars

Read by tgdl-server to reach the optional companion containers. An empty value counts as unset. Details in AI.

Variable Meaning
TGDL_NSFW_SIDECAR_URL URL of the tgdl-nsfw container, e.g. http://tgdl-nsfw:8012. Wins over advanced.nsfw.sidecarUrl.
TGDL_NSFW_API_TOKEN Token sent to the NSFW sidecar; must equal its TGDL_NSFW_API_TOKEN.
TGDL_NSFW_PATH_MAP appPath=sidecarPath rules when the sidecar mounts the downloads elsewhere.
TGDL_FACES_SIDECAR_URL URL of the tgdl-faces container. Wins over the dashboard’s External URL.
FACES_SERVICE_URL Same, used only when neither TGDL_FACES_SIDECAR_URL nor a dashboard URL is set (the 2.x compose name).
TGDL_FACES_SIDECAR_TOKEN Token sent to the faces sidecar; must equal its TGDL_FACES_API_TOKEN.
TGDL_FACES_PATH_MAP Path rules for the faces sidecar, like TGDL_NSFW_PATH_MAP.

Face tuning variables from 2.x are also honoured: TGDL_FACES_MIN_DETECTION_SCORE, TGDL_FACES_MIN_FACE_SIZE_PX, TGDL_FACES_FILE_TYPES, TGDL_FACES_EXCLUDE_EXTENSIONS, TGDL_FACES_BATCH_SIZE, TGDL_FACES_CPU_THROTTLE_RATIO, TGDL_FACES_SIDECAR_WAIT_MS, TGDL_FACES_REQUEST_TIMEOUT_MS, TGDL_FACES_MAX_RETRIES, TGDL_FACES_MAX_CONCURRENCY, TGDL_FACES_EPSILON, TGDL_FACES_MIN_POINTS and TGDL_FACES_LABEL_MATCH_EPS. Normally the dashboard settings are enough.

Launchers (runner.sh, run_safe.bat, watchdog.ps1, npm start)

Variable Default Meaning
TGDL_SERVER_BIN core-service/tgdl-server Run your own binary; skips the release download.
TGDL_RELEASE_REPO botnick/telegram-media-downloader GitHub repository to download the release from.
TGDL_RELEASE_BASE_URL GitHub release of the checkout’s version Mirror for the release archive and SHA256SUMS (runner.sh only).

The launchers do not read .env. Export variables in the shell, the systemd unit or the PM2 config instead.

Docker Compose (.env)

Compose reads .env next to docker-compose.yml. Start from .env.example.

Variable Default Meaning
TGDL_PORT 3000 Host port mapped to the container’s port 3000.
TGDL_MEM_LIMIT 8g Container memory limit.
TZ, TGDL_DOWNLOADS_DIR, TRUST_PROXY, TGDL_SECURE_COOKIES, WATCHTOWER_URL, WATCHTOWER_HTTP_API_TOKEN, TGDL_NSFW_SIDECAR_URL, TGDL_NSFW_API_TOKEN see above Passed to the server.
WATCHTOWER_HTTP_API_PERIODIC_POLLS false true lets watchtower update all containers on a schedule, not only on Install update.
WATCHTOWER_SCHEDULE 0 0 4 * * * When to check, as a 6-field cron (seconds first) in the container’s TZ; default daily at 04:00.

To pass other server variables (TGDL_CSP, COMPRESSION_LEVEL, TGDL_METRICS_TOKEN, PUBLIC_URL, FFMPEG_HWACCEL, FACES_SERVICE_URL, …) add them to the environment: list of the telegram-downloader service.

Ignored since 3.0

NODE_ENV, NODE_OPTIONS, TGDL_HEAP_MB, TGDL_GO_CORE, TGDL_GO_FEATURES, TGDL_CORE_BIN, TGDL_CORE_RELEASE_URL, TGDL_UID, TGDL_GID, SEEKBAR_SIDECAR_URL and BACKUP_WORKERS_PER_DEST have no effect on the 3.x server. Leaving them in .env is harmless.

Data folder

data/
├── db.sqlite            # settings, catalog, jobs, sessions (WAL mode)
├── secret.key           # encrypts Telegram sessions: back it up
├── sessions/native/     # encrypted Telegram logins
├── downloads/<chat>/    # media (or TGDL_DOWNLOADS_DIR)
├── thumbs/              # generated thumbnails
├── photos/              # cached chat and profile photos
├── seekbar/             # video preview sprites (<id>.webp + <id>.json)
├── backups/             # database snapshots, incl. db-pre-update-*.sqlite
├── logs/              # 2.x log files (3.x logs to standard output)
└── watchtower/api-token # generated update token

Back up at least db.sqlite, secret.key and sessions/. Losing secret.key makes the saved Telegram logins unreadable; you would have to sign in again.