TG Storage Cluster transforms Telegram into your personal, unlimited, and free cloud storage backend. By leveraging a "cluster" of Telegram bots, it distributes upload traffic to bypass rate limits and provides a high-performance HTTP API for uploading and streaming files.
- Infinite Storage: Leveraging Telegram's unlimited cloud storage.
- Bot Clustering: Automatically load balances uploads across multiple bots to maximize speed and avoid rate limits.
- Streaming Support: Native HTTP Range requests support (seekable video/audio).
- Proxy Support: Built-in SOCKS/HTTP proxy support for bots (useful for hosting in restricted regions).
- Web Dashboard: Includes a simple drag-and-drop UI for managing files.
- Production Ready: Async architecture powered by FastAPI and Uvicorn.
- Python 3.10 or higher.
- A Telegram account.
- Message @BotFather on Telegram.
- Create new bots using
/newbot. - Tip: Create at least 3-5 bots for better performance.
- Save the API Token for each bot.
- Create a Private Channel in Telegram.
- Add ALL your bots as Administrators to this channel (needed to upload files).
- Get the Channel ID:
- Forward any message from your new channel to @JsonDumpBot.
- Copy the
idvalue (e.g.,-1001234567890).
pip install tgstorage-clusterCreate a project folder and add two files:
File 1: .env (Configuration)
# Required
CHANNEL_ID=-100xxxxxxxxxx # Your Channel ID
ADMIN_API_KEY=my_secure_pass # Master password for the API/Dashboard
# Server Config
HOST=0.0.0.0
PORT=8082
BASE_URL=https://your-domain.com # Public URL (for generating share links)
# Optional Proxy Config (if running on a restricted server)
# PROXY_HOST=127.0.0.1
# PROXY_PORT=1080
# PROXY_USER=user
# PROXY_PASS=passFile 2: tokens.txt (Bot Tokens)
Paste your bot tokens, one per line:
123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
987654321:ZYXwvuTSRqponMLKjihgfeDCBA
tgstorageBase URL: http://your-server-ip:8082 (or your domain)
Authentication: Add header X-API-Key: your_key or query param ?key=your_key.
Endpoint: POST /upload
Content-Type: multipart/form-data
| Parameter | Type | Required | Description |
|---|---|---|---|
file |
File | Yes | The binary file to upload. |
expiration_days |
Int | No | Auto-delete after X days. |
password |
Str | No | Password protect the download link. |
Example (cURL):
curl -X POST "http://127.0.0.1:8082/upload" \
-H "X-API-Key: my_secure_pass" \
-F "file=@/path/to/video.mp4" \
-F "expiration_days=7"Response:
{
"status": "success",
"file_id": "BQACAgQAAx0C...",
"direct_link": "https://your-domain.com/dl/BQACAgQAAx0C.../video.mp4",
"share_link": "https://your-domain.com/share/v7f897s9f7s98f7"
}Endpoint: GET /dl/{file_id}/{filename} or /f/{file_id}/{filename}
Auth: Not required (unless password protected).
- Supports: HTTP Range requests (seekable video/audio).
- Password: If file has a password, add
?password=YOUR_PASSto the URL.
Example:
# Direct download
wget "http://127.0.0.1:8082/dl/BQACAgQAAx0C.../video.mp4"
# With password
wget "http://127.0.0.1:8082/dl/BQACAgQAAx0C.../video.mp4?password=12345"Endpoint: GET /files
Query Parameters:
limit(default: 50)offset(default: 0)search(optional filter)
Example (cURL):
curl "http://127.0.0.1:8082/files?limit=10&search=movie" \
-H "X-API-Key: my_secure_pass"Endpoint: GET /stats
Returns total storage usage, file count, and views.
Example (cURL):
curl "http://127.0.0.1:8082/stats" -H "X-API-Key: my_secure_pass"Endpoint: DELETE /file/{file_id}
Deletes file from Database AND Telegram Channel.
Example (cURL):
curl -X DELETE "http://127.0.0.1:8082/file/BQACAgQAAx0C..." \
-H "X-API-Key: my_secure_pass"For production, never use python -m uvicorn directly. Use a process manager like Systemd and a reverse proxy like Nginx.
Create a service file to keep your bot running in the background and restart it if it crashes.
File: /etc/systemd/system/tgstorage.service
[Unit]
Description=TG Storage Cluster
After=network.target
[Service]
User=root
WorkingDirectory=/path/to/your/project
ExecStart=/usr/local/bin/tgstorage
Restart=always
[Install]
WantedBy=multi-user.targetNote: Run which tgstorage to find the correct path for ExecStart.
Enable & Start:
sudo systemctl daemon-reload
sudo systemctl enable tgstorage
sudo systemctl start tgstorageUsing Nginx allows you to use HTTPS (SSL) and handle large file uploads efficiently.
File: /etc/nginx/sites-available/tgstorage
server {
listen 80;
server_name storage.your-domain.com;
# Increase body size for large uploads (e.g., 2GB)
client_max_body_size 2048M;
# Increase timeouts for large file processing
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
location / {
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Disable buffering for smooth streaming
proxy_buffering off;
proxy_request_buffering off;
}
}Activate & Restart Nginx:
sudo ln -s /etc/nginx/sites-available/tgstorage /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxGenerates additional API keys for third-party apps.
tgstorage-key --owner "NewApp"Here are complete examples for integrating TG Storage Cluster into your applications.
import httpx
import asyncio
import os
API_URL = "http://localhost:8082"
API_KEY = "my_secure_pass"
async def upload_and_share(file_path):
if not os.path.exists(file_path):
print("β File not found!")
return
async with httpx.AsyncClient(timeout=300) as client:
# 1. Prepare Request
files = {'file': open(file_path, 'rb')}
data = {'expiration_days': 7} # Optional: Auto-delete after 7 days
headers = {'X-API-Key': API_KEY}
print(f"π€ Uploading {file_path}...")
try:
# 2. Send Request
response = await client.post(f"{API_URL}/upload", files=files, data=data, headers=headers)
if response.status_code == 200:
result = response.json()
print(f"β
Upload Success!")
print(f"π File ID: {result['file_id']}")
print(f"π Direct Link: {result['direct_link']}")
print(f"π Share Link: {result['share_link']}")
else:
print(f"β Upload Failed: {response.text}")
except Exception as e:
print(f"β Error: {e}")
if __name__ == "__main__":
# Create a dummy file for testing
with open("test.txt", "w") as f: f.write("Hello TG Storage!")
asyncio.run(upload_and_share("test.txt"))Requires axios and form-data packages (npm install axios form-data).
const axios = require('axios');
const fs = require('fs');
const FormData = require('form-data');
const path = require('path');
const API_URL = 'http://localhost:8082';
const API_KEY = 'my_secure_pass';
async function uploadFile(filePath) {
if (!fs.existsSync(filePath)) {
console.error("β File not found!");
return;
}
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
form.append('expiration_days', 7); // Optional
// form.append('password', 'secret123'); // Optional
try {
console.log(`π€ Uploading ${path.basename(filePath)}...`);
const response = await axios.post(`${API_URL}/upload`, form, {
headers: {
...form.getHeaders(),
'X-API-Key': API_KEY
},
maxContentLength: Infinity,
maxBodyLength: Infinity // Prevent axios from capping large files
});
const data = response.data;
console.log('β
Upload Success!');
console.log(`π File ID: ${data.file_id}`);
console.log(`π Direct Link: ${data.direct_link}`);
console.log(`π Share Link: ${data.share_link}`);
} catch (error) {
if (error.response) {
console.error(`β Server Error: ${error.response.status}`, error.response.data);
} else {
console.error(`β Request Error: ${error.message}`);
}
}
}
// Run
// fs.writeFileSync('test.txt', 'Hello TG Storage Node!');
uploadFile('test.txt');const API_URL = "http://localhost:8082";
const API_KEY = "my_secure_pass";
async function uploadFile(fileInput) {
const file = fileInput.files[0];
if (!file) return;
const formData = new FormData();
formData.append("file", file);
formData.append("expiration_days", 7);
try {
const response = await fetch(`${API_URL}/upload`, {
method: "POST",
headers: {
"X-API-Key": API_KEY
},
body: formData
});
if (response.ok) {
const data = await response.json();
console.log("β
Uploaded:", data);
alert(`File Uploaded! Link: ${data.share_link}`);
} else {
console.error("Upload failed");
}
} catch (error) {
console.error("Error:", error);
}
}MIT License. Created by DraxonV1.