---
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.**
[](https://python.org)
[](https://fastapi.tiangolo.com)
[](https://www.mongodb.com/atlas)
[](LICENSE)
[](https://github.com/NitinBot001/TG-Storage)
---
## ✨ 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.png` or `/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
```bash
git clone https://github.com/NitinBot001/TG-Storage.git
cd TG-Storage
```
### 2. Install dependencies
```bash
pip install -r requirements.txt
```
### 3. Create your Telegram bot(s)
1. Open [@BotFather](https://t.me/BotFather) on Telegram
2. Send `/newbot` and follow the prompts
3. Copy the token (looks like `1234567890:AAExampleTokenHere`)
4. Repeat for as many bots as you want (more bots = higher upload throughput)
### 4. Set up your Telegram channel
1. Create a **private channel** in Telegram
2. Add all your bots as **Administrators** with permission to **post messages**
3. Get the channel ID — forward any message from the channel to [@JsonDumpBot](https://t.me/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:
```bash
cp .env.example .env
```
```env
# Telegram
CHANNEL_ID=-1001234567890
# MongoDB Atlas (get from: Atlas → Connect → Drivers → Python)
MONGODB_URI=mongodb+srv://:@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
```bash
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:**
```bash
# 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:**
```json
{
"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`).
```bash
curl -H "X-API-Key: your-key" \
http://localhost:8082/file/550e8400-... \
-o downloaded.jpg
```
---
### `GET /files` — List all files
```bash
curl -H "X-API-Key: your-key" \
"http://localhost:8082/files?limit=50&offset=0"
```
**Response:**
```json
{
"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.
```bash
curl -X DELETE -H "X-API-Key: your-key" \
http://localhost:8082/file/550e8400-...
```
---
### `GET /health` — Health check
```bash
curl http://localhost:8082/health
```
```json
{
"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](https://vercel.com) (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:
```bash
# 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
1. Go to [vercel.com/new](https://vercel.com/new)
2. Click **"Import Git Repository"**
3. Select `NitinBot001/TG-Storage`
4. Framework preset: **Other**
5. 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:
```python
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:
```python
raw_tokens = [...] # the old file-reading block
```
with:
```python
raw_tokens = _get_tokens()
```
---
### Step 5 — The `vercel.json` is already included
```json
{
"version": 2,
"builds": [{ "src": "main.py", "use": "@vercel/python" }],
"routes": [{ "src": "/(.*)", "dest": "main.py" }]
}
```
---
### Step 6 — Redeploy
Push your changes to GitHub:
```bash
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)*
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 8082
CMD ["python", "server.py"]
```
```bash
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_KEY` publicly — it controls all file operations
- The `/cdn/*` endpoint is intentionally public — anyone with the URL can access the file
- Bot tokens in `tokens.txt` should 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.
---