Spaces:
Sleeping
Sleeping
| title: TG Storage | |
| emoji: π | |
| colorFrom: red | |
| colorTo: gray | |
| sdk: docker | |
| pinned: false | |
| <div align="center"> | |
| # π‘ 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) | |
| </div> | |
| --- | |
| ## β¨ 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://<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 | |
| ```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. | |
| --- | |
| <div align="center"> | |
| Built with β€οΈ using FastAPI + Telegram Bot API + MongoDB Atlas | |
| <br/> | |
| <a href="https://github.com/NitinBot001/TG-Storage">β Star on GitHub</a> | |
| </div> |