diff --git a/.env.example b/.env.example
index 28e1c00..498ee75 100644
--- a/.env.example
+++ b/.env.example
@@ -25,8 +25,13 @@ API_HASH=
OWNER_ID=
BOT_TOKEN=
-BOT_USERNAME= # without @
+# Optional: bot username without @. Usually auto-fetched from BOT_TOKEN.
+BOT_USERNAME=
MONGO_URI=
+DB_NAME=Ether
+SESSION_NAME=etheruserbot
DEBUG=False
+WEB_SERVICE=False
+PORT=8080
diff --git a/Procfile b/Procfile
index eb131d6..25fcdc8 100644
--- a/Procfile
+++ b/Procfile
@@ -1 +1 @@
-worker: python3 main.py
+worker: python main.py
diff --git a/README.md b/README.md
index dda08cf..4207d92 100644
--- a/README.md
+++ b/README.md
@@ -103,20 +103,21 @@ Ether uses environment variables for configuration. These can be set in a `.env`
| :--- | :--- | :--- |
| `API_ID` | Required | Your Telegram API ID from [my.telegram.org](https://my.telegram.org) |
| `API_HASH` | Required | Your Telegram API Hash from [my.telegram.org](https://my.telegram.org) |
-| `BOT_TOKEN` | Required | Your Bot Token from [@BotFather](https://t.me/BotFather) |
| `OWNER_ID` | Required | Your numeric Telegram User ID |
+| `BOT_TOKEN` | Required | Your Bot Token from [@BotFather](https://t.me/BotFather) |
| `MONGO_URI` | Required | MongoDB Atlas connection string |
-| `BOT_USERNAME` | Required | Your Bot's username (without @) |
+| `BOT_USERNAME` | Optional | Auto-fetched from `BOT_TOKEN`; set manually only if needed |
+| `SESSION_NAME` | Optional | MongoDB session document name (Default: `etheruserbot`) |
| `DB_NAME` | Optional | Database name (Default: `Ether`) |
| `DEBUG` | Optional | Set to `true` for verbose logging (Default: `false`) |
-| `WEB_SERVICE` | Optional | Set to `true` for cloud keep-alive services |
-| `PORT` | Optional | Port for the web service (Default: `8080`) |
+| `WEB_SERVICE` | Optional | Set to `true` when the host requires an HTTP health endpoint |
+| `PORT` | Optional | Port for the web service (Default: `8080`; Render uses `10000`) |
---
## Deployment Options
-Ether is designed to be deployed anywhere. Choose the platform that fits your needs.
+Ether is a long-running Telegram client. For reliable operation, use a host that allows long-lived processes and provide a persistent MongoDB database for sessions and settings.
@@ -126,30 +127,57 @@ Ether is designed to be deployed anywhere. Choose the platform that fits your ne
+### Deployment Matrix
+
+| Target | Files Used | Runtime Type | How to Verify |
+| :--- | :--- | :--- | :--- |
+| Render | `render.yaml`, `Dockerfile` | Docker web service | HTTP health check at `/health` |
+| Heroku | `app.json`, `heroku.yml`, `Dockerfile` | Container worker dyno | Worker logs and Telegram `/login` |
+| Docker Compose / VPS | `docker-compose.yml`, `Dockerfile` | Local Docker service | `docker compose config` and `/health` |
+| Manual Python | `requirements.txt`, `main.py` | Local Python process | Import and compile checks |
+| JustRunMyApp / Generic Docker Host | `Dockerfile` | Long-running Docker container | Same env vars and health endpoint rules as Docker |
+
### Quick Start Guides
#### 1. Cloud Hosting (Render - Recommended)
-Render provides the most stable environment for Ether with native Docker support.
+Render should be deployed as a Docker **Web Service** because Render requires web services to bind an HTTP port.
+
1. **Fork** this repository to your own GitHub account.
2. Click the **Deploy to Render** button above.
3. Connect your GitHub account and select the forked repository.
-4. Configure the **Environment Variables** (see [Configuration](#configuration)).
- * **Crucial:** Ensure `WEB_SERVICE` is set to `true` to prevent the service from sleeping.
-5. Render will automatically build and deploy the container.
+4. Use the checked-in `render.yaml` blueprint:
+ * Runtime: `docker`
+ * Dockerfile: `./Dockerfile`
+ * Health check path: `/health`
+ * `PORT=10000`
+ * `WEB_SERVICE=true`
+5. Set the required environment variables from [Configuration](#configuration).
+6. Deploy, then open:
+ ```text
+ https://your-app.onrender.com/health
+ ```
+ Expected response:
+ ```json
+ {"status":"healthy"}
+ ```
+7. Open your Telegram bot and run `/login`.
+
+> [!IMPORTANT]
+> Render Free web services sleep after idle periods and can restart at any time. The HTTP endpoint keeps the deploy valid, but it does not make the free plan always-on. Use a paid Render instance, VPS, or another always-on host for a 24/7 userbot.
---
### Keep-Alive & Automation (Cloud)
-Cloud providers like Render often put free-tier apps to "sleep" after inactivity. Use these tools to ensure Ether stays online 24/7.
+Cloud providers often put free-tier apps to sleep after inactivity. External monitors can reduce idle sleep, but a paid always-on service or VPS is the more reliable option for a 24/7 userbot.
#### UptimeRobot (Keep-Alive)
-To prevent Render from sleeping, set up a monitor to ping your bot's URL:
+To keep a Render web service receiving inbound HTTP traffic, set up a monitor to ping the health endpoint:
1. Go to [UptimeRobot](https://uptimerobot.com/) and create a free account.
2. Click **Add New Monitor**.
3. **Monitor Type**: `HTTP(s)`
4. **Friendly Name**: `Ether Userbot`
-5. **URL**: Your Render app URL (e.g., `https://your-app.onrender.com/`)
+5. **URL**: `https://your-app.onrender.com/health`
6. **Monitoring Interval**: Every `5 minutes`.
7. Click **Create Monitor**.
@@ -157,28 +185,50 @@ To prevent Render from sleeping, set up a monitor to ping your bot's URL:
If you need to trigger specific bot actions or ensure the web service remains active via external triggers:
1. Create an account at [Cron-job.org](https://cron-job.org/).
2. Create a **New Cronjob**.
-3. **URL**: Your Render app URL.
+3. **URL**: `https://your-app.onrender.com/health`
4. **Schedule**: Every 5 or 10 minutes.
5. This acts as a secondary heart-beat for your bot.
---
#### 2. Heroku Deployment
-Ideal for users familiar with the Heroku ecosystem.
+Heroku should be deployed as a container **worker** dyno. Do not run a web dyno unless you add a separate web process.
+
1. Click the **Deploy to Heroku** button above.
2. Enter a unique app name and fill in the required environment variables.
3. Once the build finishes, go to the **Resources** tab.
-4. **Important:** Turn off the `web` dyno and turn **ON** the `worker` dyno.
-5. Render will automatically build and deploy the container.
+4. Confirm the `worker` dyno is enabled and the `web` dyno is disabled.
+5. Set `WEB_SERVICE=false` for worker-only Heroku deployments.
+6. Check logs:
+ ```bash
+ heroku logs --tail --ps worker -a your-app-name
+ ```
+7. Open your Telegram bot and run `/login`.
+
+CLI deployment:
+```bash
+heroku create your-app-name
+heroku stack:set container -a your-app-name
+heroku config:set API_ID=... API_HASH=... OWNER_ID=... BOT_TOKEN=... MONGO_URI=... WEB_SERVICE=false -a your-app-name
+git push heroku main
+heroku ps:scale web=0 worker=1 -a your-app-name
+```
+
+> [!NOTE]
+> Heroku no longer has free dynos. Use a paid dyno type appropriate for a long-running worker.
---
#### 3. JustRunMyApp (One-Click)
-A simple, zero-config deployment platform.
+Use this path only if the platform supports long-running Docker containers and runtime environment variables.
+
1. Click the **Deploy Now** button for JustRunMyApp above.
-2. Paste the repository URL: `https://github.com/LearningBotsOfficial/Ether`
-3. Follow the on-screen prompts to set your Environment Variables.
-4. Launch the app and wait for the status to show "Running".
+2. Paste the repository URL: `https://github.com/LearningBotsOfficial/Ether`.
+3. Choose Dockerfile-based deployment.
+4. Set the required environment variables from [Configuration](#configuration).
+5. If the platform requires an HTTP endpoint, set `WEB_SERVICE=true` and `PORT` to the platform-provided port.
+6. Launch the app and wait for the status to show `Running`.
+7. If a public URL is provided, verify `/health`.
#### 4. Docker Deployment (Local / VPS)
The preferred method for developers and privacy-focused users.
@@ -191,10 +241,20 @@ cp .env.example .env
nano .env
# 3. Build and launch with Docker Compose
-docker-compose up -d --build
+docker compose up -d --build
+
+# 4. Verify the service
+docker compose ps
+curl http://localhost:8080/health
```
+
+For Windows PowerShell, the health check command is:
+```powershell
+Invoke-RestMethod http://localhost:8080/health
+```
+
> [!TIP]
-> Using Docker Compose handles the health checks and automatic restarts for you.
+> Docker Compose sets `WEB_SERVICE=true`, exposes `${PORT:-8080}`, and uses the `/health` endpoint for container health checks. If you set `PORT` in `.env`, use that value instead of `8080` in the health check URL.
#### 5. Manual Setup (Linux / VPS / Windows)
For users who want full control over the environment.
@@ -221,7 +281,8 @@ For users who want full control over the environment.
.venv\Scripts\activate
# Install dependencies
- pip install -r requirements.txt
+ python -m pip install --upgrade pip
+ python -m pip install -r requirements.txt
```
4. **Configure Environment Variables**
@@ -237,6 +298,12 @@ For users who want full control over the environment.
python main.py
```
+ If your host requires a health endpoint, set:
+ ```bash
+ export WEB_SERVICE=true
+ export PORT=8080
+ ```
+
---
### Managing Dependencies & Upgrading
@@ -244,30 +311,28 @@ For users who want full control over the environment.
#### Adding or Removing Packages
To add a new library:
```bash
-pip install
-# Then update requirements.txt
-pip freeze > requirements.txt
+python -m pip install
+# Then add the reviewed direct dependency pin to requirements.txt
```
To remove a library:
```bash
-pip uninstall
-# Then update requirements.txt
-pip freeze > requirements.txt
+python -m pip uninstall
+# Then remove the direct dependency pin from requirements.txt
```
-#### Upgrading All Packages
-To upgrade all dependencies to their latest versions:
+#### Syncing Pinned Dependencies
+Install exactly the versions listed in `requirements.txt`:
```bash
-pip install --upgrade -r requirements.txt
-pip freeze > requirements.txt
+python -m pip install -r requirements.txt
```
-#### Syncing Environment
-Whenever you pull new changes from GitHub that include an updated `requirements.txt`, simply run:
+If you use `uv`:
```bash
-pip install -r requirements.txt
+uv pip install -r requirements.txt
```
-This ensures your local `.venv` matches the project's requirements.
+
+#### Upgrading Dependency Pins
+Pinned requirements do not upgrade automatically. To upgrade safely, check the latest package versions, edit `requirements.txt`, sync the environment, and run the verification commands in the deployment section.
---
diff --git a/app.json b/app.json
index 42d81f6..4d0efd2 100644
--- a/app.json
+++ b/app.json
@@ -34,7 +34,7 @@
"required": true
},
"WEB_SERVICE": {
- "description": "Set to true to enable the keep-alive web service (requires 'web' process type).",
+ "description": "Set to false for the default Heroku worker dyno. Use true only if you add a web process.",
"value": "false",
"required": false
},
@@ -51,4 +51,4 @@
}
},
"stack": "container"
-}
\ No newline at end of file
+}
diff --git a/docker-compose.yml b/docker-compose.yml
index e4b5cde..119945a 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,5 +1,3 @@
-version: '3.8'
-
services:
ether-userbot:
build: .
@@ -7,15 +5,18 @@ services:
restart: unless-stopped
env_file:
- .env
+ environment:
+ WEB_SERVICE: "true"
+ PORT: "${PORT:-8080}"
+ ports:
+ - "${PORT:-8080}:${PORT:-8080}"
volumes:
- # Map the specific directories where data is generated
- ./media:/app/media
- ./logs:/app/logs
- # Map session files explicitly to persist logins
- ./sessions:/app/sessions
- # Note: Since the bot creates session files in the root dir by default
- # you may need to map them explicitly or configure SESSION_DIR in .env
- - ./:/app/sessions_data # Or bind mount specific .session files
- # If the app relies heavily on an external MongoDB,
- # network settings can be configured here.
- network_mode: bridge
+ healthcheck:
+ test: ["CMD-SHELL", "python -c \"import os, urllib.request; urllib.request.urlopen('http://127.0.0.1:' + os.getenv('PORT', '8080') + '/health', timeout=5).read()\""]
+ interval: 30s
+ timeout: 10s
+ retries: 3
+ start_period: 20s
diff --git a/heroku.yml b/heroku.yml
index 7b13190..c8ad1f4 100644
--- a/heroku.yml
+++ b/heroku.yml
@@ -1,3 +1,5 @@
build:
docker:
worker: Dockerfile
+run:
+ worker: python main.py
diff --git a/plugins/logger.py b/plugins/logger.py
index f0ad82b..887d8d1 100644
--- a/plugins/logger.py
+++ b/plugins/logger.py
@@ -20,7 +20,7 @@
# =============================================================================
import time
-from datetime import datetime, timedelta
+from datetime import UTC, datetime, timedelta
from telethon import events
from utils.logger import get_logger
from utils.task_helper import safe_run
@@ -179,14 +179,15 @@ async def cache_messages(event):
):
return
- expire_at = datetime.utcnow() + timedelta(hours=48)
+ now = datetime.now(UTC)
+ expire_at = now + timedelta(hours=48)
await msg_col.insert_one({
"msg_id": event.id,
"chat_id": event.chat_id,
"sender_id": event.sender_id,
"text": event.text,
- "date": datetime.utcnow(),
+ "date": now,
"expire_at": expire_at
})
diff --git a/render.yaml b/render.yaml
index 1fd3bbf..220a95e 100644
--- a/render.yaml
+++ b/render.yaml
@@ -7,10 +7,10 @@ services:
plan: free
region: oregon
- autoDeploy: false
+ autoDeployTrigger: off
- # Use root endpoint for health checks (always available)
- healthCheckPath: /
+ # Use the lightweight health endpoint for Render health checks.
+ healthCheckPath: /health
envVars:
# Telegram API Credentials (Required - Get from my.telegram.org)
@@ -32,7 +32,7 @@ services:
- key: MONGO_URI
sync: false
- # Port (Render will override with dynamic port)
+ # Public HTTP port for the health-check web service.
- key: PORT
value: "10000"
diff --git a/requirements.txt b/requirements.txt
index 8183364..38ed314 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
-aiohttp==3.13.5
-fastapi==0.136.1
+aiohttp==3.14.1
+fastapi==0.136.3
psutil==7.2.2
-pymongo[srv]==4.13.0
-python-dotenv==1.2.0
-telethon==1.43.0
-uvicorn[standard]==0.47.0
\ No newline at end of file
+pymongo==4.17.0
+python-dotenv==1.2.2
+telethon==1.43.2
+uvicorn[standard]==0.49.0