Spaces:
Sleeping
title: TG Storage
emoji: π
colorFrom: red
colorTo: gray
sdk: docker
pinned: false
π‘ TG Storage
Infinite file storage powered by Telegram β with a clean REST API, public CDN URLs, and a built-in test UI.
β¨ What is TG Storage?
TG Storage turns any Telegram channel into a free, unlimited cloud storage backend. You upload files through a REST API β they get stored in your Telegram channel β and you get back a permanent, public CDN URL to share anywhere.
No S3. No GCS. No storage bills.
Key features
- π REST API β Upload, download, list, and delete files via HTTP
- π Public CDN URLs β Shareable links with no auth required (
/cdn/your-path) - π·οΈ Custom paths β Assign vanity paths like
/cdn/images/logo.pngor/cdn/avatar.jpg - π€ Multi-bot pool β Add multiple bot tokens to spread Telegram rate limits
- π§ MongoDB Atlas β File metadata stored in the cloud, zero local state
- π₯οΈ Built-in UI β Drop-in browser interface to test everything at
/ - β‘ Pure httpx β No telegram library dependencies, raw Bot API calls only
π Project Structure
TG-Storage/
βββ main.py # FastAPI app β all routes & lifespan
βββ db.py # MongoDB Atlas async layer (Motor)
βββ tg.py # Telegram Bot API client (pure httpx)
βββ server.py # Uvicorn entry point
βββ frontend.html # Built-in browser test UI
βββ requirements.txt # Python dependencies
βββ vercel.json # Vercel deployment config
βββ .env.example # Environment variable template
βββ tokens.txt # (you create) one bot token per line
π οΈ Setup & Installation
1. Clone the repo
git clone https://github.com/NitinBot001/TG-Storage.git
cd TG-Storage
2. Install dependencies
pip install -r requirements.txt
3. Create your Telegram bot(s)
- Open @BotFather on Telegram
- Send
/newbotand follow the prompts - Copy the token (looks like
1234567890:AAExampleTokenHere) - Repeat for as many bots as you want (more bots = higher upload throughput)
4. Set up your Telegram channel
- Create a private channel in Telegram
- Add all your bots as Administrators with permission to post messages
- Get the channel ID β forward any message from the channel to @JsonDumpBot and look for
"chat": { "id": -1001234567890 }
5. Create tokens.txt
# tokens.txt β one bot token per line, lines starting with # are ignored
1234567890:AAExampleToken1Here
9876543210:AAExampleToken2Here
6. Configure environment
Copy .env.example to .env and fill in your values:
cp .env.example .env
# Telegram
CHANNEL_ID=-1001234567890
# MongoDB Atlas (get from: Atlas β Connect β Drivers β Python)
MONGODB_URI=mongodb+srv://<user>:<password>@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority
MONGO_DB_NAME=tgstorage
# API auth key β clients must send this in X-API-Key header
ADMIN_API_KEY=your-secret-key-here
# Public base URL β used to build CDN links
# Local dev: http://localhost:8082
# Production: https://your-vercel-app.vercel.app
BASE_URL=http://localhost:8082
7. Run the server
python server.py
Server starts at http://localhost:8082 Open it in your browser to access the built-in test UI.
π API Reference
All endpoints except / and /cdn/* require the header:
X-API-Key: your-secret-key-here
POST /upload β Upload a file
Form fields:
| Field | Type | Required | Description |
|---|---|---|---|
file |
file | β | The file to upload (any format) |
custom_path |
string | β | Vanity CDN path, e.g. images/logo.png |
Example:
# Upload with auto-generated ID
curl -X POST http://localhost:8082/upload \
-H "X-API-Key: your-key" \
-F "file=@photo.jpg"
# Upload with custom path
curl -X POST http://localhost:8082/upload \
-H "X-API-Key: your-key" \
-F "file=@logo.png" \
-F "custom_path=brand/logo.png"
Response:
{
"file_id": "550e8400-e29b-41d4-a716-446655440000",
"filename": "logo.png",
"mime_type": "image/png",
"size_bytes": 20480,
"custom_path": "brand/logo.png",
"public_url": "http://localhost:8082/cdn/brand/logo.png",
"cdn_url_by_id": "http://localhost:8082/cdn/550e8400-...",
"cdn_url_by_path": "http://localhost:8082/cdn/brand/logo.png",
"uploaded_at": "2025-01-01T12:00:00"
}
GET /cdn/{path} β Public CDN URL (no auth)
Works with both the UUID file_id and any assigned custom path:
GET /cdn/550e8400-e29b-41d4-a716-446655440000 β by file_id
GET /cdn/logo.png β by custom_path
GET /cdn/images/avatar.jpg β by nested custom_path
Files are served inline β images, PDFs, and videos render directly in the browser.
GET /file/{file_id} β Download (auth required)
Forces a file download (Content-Disposition: attachment).
curl -H "X-API-Key: your-key" \
http://localhost:8082/file/550e8400-... \
-o downloaded.jpg
GET /files β List all files
curl -H "X-API-Key: your-key" \
"http://localhost:8082/files?limit=50&offset=0"
Response:
{
"total": 42,
"limit": 50,
"offset": 0,
"files": [
{
"file_id": "...",
"filename": "photo.jpg",
"mime_type": "image/jpeg",
"size_bytes": 204800,
"custom_path": "photos/summer.jpg",
"public_url": "http://localhost:8082/cdn/photos/summer.jpg",
"uploaded_at": "2025-01-01T12:00:00"
}
]
}
DELETE /file/{file_id} β Delete a record
Removes the metadata from MongoDB. The Telegram message remains in the channel.
curl -X DELETE -H "X-API-Key: your-key" \
http://localhost:8082/file/550e8400-...
GET /health β Health check
curl http://localhost:8082/health
{
"status": "ok",
"timestamp": "2025-01-01T12:00:00",
"total_files": 42,
"base_url": "http://localhost:8082"
}
π Deploy to Vercel
Vercel runs Python serverless functions β perfect for this API.
Prerequisites
- A Vercel account (free tier works)
- The repo pushed to GitHub at
https://github.com/NitinBot001/TG-Storage
Step 1 β Add tokens.txt to the repo (or use env var)
β οΈ Do not commit real bot tokens to a public repo.
Instead, encode your tokens as a single environment variable:
On your machine, run:
# Join tokens with a newline, then base64-encode
python -c "
import base64
tokens = '1234567890:TokenOne\n9876543210:TokenTwo'
print(base64.b64encode(tokens.encode()).decode())
"
Copy the output β you'll add it as TOKENS_B64 in Vercel. Then update tg.py to decode it (see Step 4).
Step 2 β Import project in Vercel
- Go to vercel.com/new
- Click "Import Git Repository"
- Select
NitinBot001/TG-Storage - Framework preset: Other
- Click Deploy (it will fail β that's fine, we need to add env vars first)
Step 3 β Add environment variables
In your Vercel project β Settings β Environment Variables, add:
| Name | Value |
|---|---|
CHANNEL_ID |
-1001234567890 |
MONGODB_URI |
mongodb+srv://... |
MONGO_DB_NAME |
tgstorage |
ADMIN_API_KEY |
your-secret-key |
BASE_URL |
https://your-app.vercel.app |
TOKENS_B64 |
(base64 string from Step 1) |
Step 4 β Update tg.py to read TOKENS_B64
Replace the _tokens_path() function in tg.py with this loader that checks for the env var first:
import base64, tempfile, os
def _get_tokens() -> list[str]:
"""Read tokens from TOKENS_B64 env var (Vercel) or tokens.txt (local)."""
b64 = os.getenv("TOKENS_B64", "").strip()
if b64:
decoded = base64.b64decode(b64).decode("utf-8")
return [l.strip() for l in decoded.splitlines() if l.strip() and not l.startswith("#")]
# Fallback to file
for candidate in [Path(__file__).parent / "tokens.txt", Path(os.getcwd()) / "tokens.txt"]:
if candidate.exists():
return [l.strip() for l in candidate.read_text(encoding="utf-8").splitlines()
if l.strip() and not l.startswith("#")]
raise FileNotFoundError("No tokens found. Set TOKENS_B64 env var or create tokens.txt.")
Then in init_bot_pool() replace:
raw_tokens = [...] # the old file-reading block
with:
raw_tokens = _get_tokens()
Step 5 β The vercel.json is already included
{
"version": 2,
"builds": [{ "src": "main.py", "use": "@vercel/python" }],
"routes": [{ "src": "/(.*)", "dest": "main.py" }]
}
Step 6 β Redeploy
Push your changes to GitHub:
git add tg.py
git commit -m "feat: support TOKENS_B64 for Vercel deployment"
git push
Vercel auto-deploys on every push. Your API will be live at:
https://tg-storage-xxxx.vercel.app
Update BASE_URL in Vercel env vars to match your actual deployment URL.
β οΈ Vercel Limitations
| Limitation | Impact |
|---|---|
| 10s function timeout (Hobby plan) | Large file uploads may time out. Upgrade to Pro (60s) or use a VPS. |
| 4.5 MB request body limit | Files larger than 4.5 MB cannot be uploaded via Vercel's edge. Use a VPS for large files. |
| Serverless = stateless | The bot pool reinitializes on every cold start. tokens.txt won't persist β use TOKENS_B64. |
| No persistent filesystem | MongoDB Atlas handles all state β this is fine. |
For large files or heavy usage, deploy on a VPS (Railway, Render, DigitalOcean) instead β run python server.py directly with no changes needed.
π³ Self-host with Docker (optional)
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 8082
CMD ["python", "server.py"]
docker build -t tg-storage .
docker run -p 8082:8082 --env-file .env -v $(pwd)/tokens.txt:/app/tokens.txt tg-storage
π Security Notes
- Never expose
ADMIN_API_KEYpublicly β it controls all file operations - The
/cdn/*endpoint is intentionally public β anyone with the URL can access the file - Bot tokens in
tokens.txtshould never be committed to a public repo - MongoDB URI contains credentials β keep it in
.env/ Vercel environment variables only
π License
MIT β free to use, modify, and deploy.
β Star on GitHub