From 4090281e249a59d78fff658acadb6d920016c603 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:34:49 +0000 Subject: [PATCH 1/3] Initial plan From bd06bbf721d5fd863dafab05bd78408aab837595 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:56:45 +0000 Subject: [PATCH 2/3] Add complete Docker support with environment variables Co-authored-by: phamthainb <55950535+phamthainb@users.noreply.github.com> --- .dockerignore | 35 ++++++++++++++++++++++ .env.example | 8 +++++ .gitignore | 7 ++++- Dockerfile | 28 ++++++++++++++++++ README.md | 60 ++++++++++++++++++++++++++++++++++++++ bot.js | 16 ++++++---- docker-compose.example.yml | 28 ++++++++++++++++++ docker-compose.yml | 26 +++++++++++++++++ package-lock.json | 20 ++++--------- package.json | 8 ++++- 10 files changed, 214 insertions(+), 22 deletions(-) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.example.yml create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..157f524 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,35 @@ +# Ignore version control +.git +.gitignore + +# Ignore documentation and demo files +README.md +demo/ +*.md + +# Ignore dependency directories +node_modules/ + +# Ignore local development files +.vscode/ +.DS_Store +.env +dev.sh + +# Ignore test files +test.js + +# Ignore build artifacts and logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Ignore local data files +servers.json +keys/ +data/ + +# Ignore docker files (to prevent recursion) +Dockerfile +docker-compose*.yml +.dockerignore \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2b94338 --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# Telegram Bot Configuration +BOT_TOKEN=123456789:ABCdefGHIjklMNO_pQRstuVWxyZ +CHAT_ID=987654321 +OWNER_IDS=111111111,222222222 + +# SSH Configuration (if using Docker) +PATH_PRIVATEKEY=/app/keys/id_rsa +SERVERS_FILE=/var/telegram-ssh/servers.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index 821e3d0..343fe22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ node_modules servers.json .env -dev.sh \ No newline at end of file +dev.sh + +# Docker-related files +keys/ +data/ +docker-compose.override.yml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6796eea --- /dev/null +++ b/Dockerfile @@ -0,0 +1,28 @@ +# Use official Node.js runtime as base image +FROM node:18-alpine + +# Set working directory +WORKDIR /app + +# Copy package files and install dependencies +COPY package*.json ./ +RUN npm install --production && npm cache clean --force + +# Copy application files +COPY bot.js helper.js ./ + +# Create directories for SSH keys and data +RUN mkdir -p /var/telegram-ssh /app/keys + +# Create non-root user for security +RUN addgroup -g 1001 -S telegram && \ + adduser -S telegram -u 1001 -G telegram + +# Change ownership of app directory +RUN chown -R telegram:telegram /app /var/telegram-ssh + +# Switch to non-root user +USER telegram + +# Default command +CMD ["node", "bot.js"] \ No newline at end of file diff --git a/README.md b/README.md index 2c8c6ac..3c635e3 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,66 @@ A simple SSH manager and client for your servers, integrated with Telegram for e ## Setup +### Option 1: Docker (Recommended) + +1. **Prerequisites**: Make sure Docker and Docker Compose are installed. + +2. **Configuration**: + + - Copy the example environment file and edit it with your values: + ```bash + cp .env.example .env + # Edit .env with your bot token, chat ID, and owner IDs + ``` + + - Create directories for SSH keys and data: + ```bash + mkdir -p keys data + ``` + + - Copy your SSH private key to the keys directory: + ```bash + cp /path/to/your/private/key keys/id_rsa + chmod 600 keys/id_rsa + ``` + +3. **Run with Docker Compose**: + + ```bash + # Using .env file + docker-compose up -d + + # Or specify environment variables directly + BOT_TOKEN="your-token" CHAT_ID="your-chat-id" OWNER_IDS="owner1,owner2" docker-compose up -d + ``` + +4. **Alternative Docker run**: + + ```bash + # Build the image + docker build -t telegram-ssh . + + # Run the container + docker run -d \ + --name telegram-ssh \ + --restart unless-stopped \ + -e BOT_TOKEN="your-telegram-bot-token" \ + -e CHAT_ID="your-chat-id" \ + -e OWNER_IDS="comma-separated-owner-ids" \ + -e PATH_PRIVATEKEY="/app/keys/id_rsa" \ + -e SERVERS_FILE="/var/telegram-ssh/servers.json" \ + -v ./keys:/app/keys:ro \ + -v ./data:/var/telegram-ssh \ + telegram-ssh + ``` + +5. **View logs**: + ```bash + docker-compose logs -f telegram-ssh + ``` + +### Option 2: Direct Node.js + 1. **SSH Keys**: Ensure your SSH keys are set up on each server you want to connect to. 2. **Configuration**: diff --git a/bot.js b/bot.js index 83b7b34..531a876 100644 --- a/bot.js +++ b/bot.js @@ -17,32 +17,36 @@ const argv = yargs(hideBin(process?.argv)) alias: "b", describe: "Telegram bot token", type: "string", - demandOption: true, + demandOption: !process.env.BOT_TOKEN, + default: process.env.BOT_TOKEN, }) .option("chat_id", { alias: "c", describe: "Telegram chat ID", type: "string", - demandOption: true, + demandOption: !process.env.CHAT_ID, + default: process.env.CHAT_ID, }) .option("owner_ids", { alias: "o", describe: "Comma-separated list of owner chat IDs", type: "string", - demandOption: true, + demandOption: !process.env.OWNER_IDS, + default: process.env.OWNER_IDS, }) .option("path_privatekey", { alias: "p", describe: "Path to SSH private key", type: "string", - demandOption: true, + demandOption: !process.env.PATH_PRIVATEKEY, + default: process.env.PATH_PRIVATEKEY, }) .option("servers_file", { alias: "s", describe: "Path to servers JSON file", type: "string", - demandOption: true, - default: "/var/telegram-ssh/servers.json", + demandOption: !process.env.SERVERS_FILE, + default: process.env.SERVERS_FILE || "/var/telegram-ssh/servers.json", }).argv; const TOKEN = argv?.bot_token, diff --git a/docker-compose.example.yml b/docker-compose.example.yml new file mode 100644 index 0000000..ce0dc83 --- /dev/null +++ b/docker-compose.example.yml @@ -0,0 +1,28 @@ +version: '3.8' + +services: + telegram-ssh: + build: . + container_name: telegram-ssh + restart: unless-stopped + environment: + # Replace with your actual values or use .env file + - BOT_TOKEN=123456789:ABCdefGHIjklMNO_pQRstuVWxyZ + - CHAT_ID=987654321 + - OWNER_IDS=111111111,222222222 + - PATH_PRIVATEKEY=/app/keys/id_rsa + - SERVERS_FILE=/var/telegram-ssh/servers.json + volumes: + # Mount your SSH private key directory + # Make sure to place your private key in ./keys/id_rsa + - ./keys:/app/keys:ro + # Mount data directory for persistent server list + - ./data:/var/telegram-ssh + # Uncomment for custom network configuration + # networks: + # - telegram-ssh-network + +# Uncomment for custom network +# networks: +# telegram-ssh-network: +# driver: bridge \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..08928d7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + telegram-ssh: + build: . + container_name: telegram-ssh + restart: unless-stopped + environment: + - BOT_TOKEN=${BOT_TOKEN} + - CHAT_ID=${CHAT_ID} + - OWNER_IDS=${OWNER_IDS} + - PATH_PRIVATEKEY=/app/keys/id_rsa + - SERVERS_FILE=/var/telegram-ssh/servers.json + volumes: + # Mount your SSH private key (adjust path as needed) + - ./keys:/app/keys:ro + # Mount data directory for persistent server list + - ./data:/var/telegram-ssh + # Optional: add network configuration if needed + # networks: + # - telegram-ssh-network + +# Optional: define custom network +# networks: +# telegram-ssh-network: +# driver: bridge \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 472f6e6..c5163df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,20 @@ { "name": "telegram-ssh", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "telegram-ssh", + "version": "1.0.0", "dependencies": { "dotenv": "^16.3.1", "node-telegram-bot-api": "^0.61.0", - "nodemon": "^3.0.1", "ssh2": "^1.14.0", "yargs": "^17.7.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" } }, "node_modules/abbrev": { @@ -549,19 +554,6 @@ "node": ">= 0.12" } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", diff --git a/package.json b/package.json index 5059147..17cf5b6 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,15 @@ { + "name": "telegram-ssh", + "version": "1.0.0", + "description": "A simple SSH manager and client for your servers, integrated with Telegram for easy control and monitoring.", + "main": "bot.js", "dependencies": { "dotenv": "^16.3.1", "node-telegram-bot-api": "^0.61.0", - "nodemon": "^3.0.1", "ssh2": "^1.14.0", "yargs": "^17.7.2" + }, + "devDependencies": { + "nodemon": "^3.0.1" } } From b5a89d052606bc5d47eabcfd15a85a52b94b44ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:58:37 +0000 Subject: [PATCH 3/3] Final Docker implementation with comprehensive documentation and troubleshooting Co-authored-by: phamthainb <55950535+phamthainb@users.noreply.github.com> --- README.md | 52 +++++++++++++++++++++++++------------- docker-compose.example.yml | 2 -- docker-compose.yml | 2 -- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3c635e3..876d0ad 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,17 @@ A simple SSH manager and client for your servers, integrated with Telegram for e - **SSH Connection**: Connect and execute commands on your servers via SSH. - **Telegram Integration**: Interact with your servers through Telegram commands. -## Command-Line Options +## Configuration Options -- **`--bot_token`, `-b`**: The Telegram bot token used for authentication with the Telegram API. This is required to interact with the Telegram bot. +The bot can be configured via command-line arguments or environment variables: - - Example: `--bot_token "123456789:ABCdefGHIjklMNO_pQRstuVWxyZ"` - -- **`--chat_id`, `-c`**: The Telegram chat ID where the bot will send messages. This is the chat where you'll interact with the bot. - - - Example: `--chat_id "987654321"` - -- **`--owner_ids`, `-o`**: Comma-separated list of owner chat IDs who have control over the bot. Only these users can execute bot commands. - - - Example: `--owner_ids "111111111,222222222"` - -- **`--path_privatekey`, `-p`**: Path to the SSH private key file used to authenticate with your servers. Ensure this key matches the public key configured on your servers. - - - Example: `--path_privatekey "/home/user/.ssh/id_rsa"` - -- **`--servers_file`, `-s`**: Path to the JSON file that contains the details of your servers. This file should be in the format expected by the bot. - - Example: `--servers_file "/path/to/servers.json"` +| CLI Argument | Environment Variable | Description | Required | +|-------------|---------------------|-------------|----------| +| `--bot_token`, `-b` | `BOT_TOKEN` | Telegram bot token | Yes | +| `--chat_id`, `-c` | `CHAT_ID` | Telegram chat ID | Yes | +| `--owner_ids`, `-o` | `OWNER_IDS` | Comma-separated owner chat IDs | Yes | +| `--path_privatekey`, `-p` | `PATH_PRIVATEKEY` | Path to SSH private key | Yes | +| `--servers_file`, `-s` | `SERVERS_FILE` | Path to servers JSON file | No (default: `/var/telegram-ssh/servers.json`) | ## Setup @@ -146,4 +137,29 @@ docker run -d -p 2223:22 --name ubuntu-server03 -e ROOT_PASSWORD="my_password" t - [ ] Implement `try-catch` blocks for SSH failures. - [ ] Automatically close sessions after a period of inactivity. +## Troubleshooting + +### Docker Issues + +- **Module not found errors**: Ensure your Docker build completed successfully and all dependencies were installed. +- **Permission denied on SSH keys**: Make sure your SSH key file has proper permissions (`chmod 600 keys/id_rsa`). +- **Volume mount issues**: Verify that the `./keys` and `./data` directories exist and have correct permissions. + +### General Issues + +- **Bot not responding**: Check that your `BOT_TOKEN` is valid and the bot is added to your chat. +- **SSH connection fails**: Verify that your SSH key is properly configured on the target servers. +- **Permission denied**: Ensure your `OWNER_IDS` includes your Telegram user ID. + +### Getting Help + +Check the logs for detailed error messages: +```bash +# For Docker Compose +docker compose logs -f telegram-ssh + +# For direct Docker run +docker logs telegram-ssh +``` + --- diff --git a/docker-compose.example.yml b/docker-compose.example.yml index ce0dc83..711c691 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: telegram-ssh: build: . diff --git a/docker-compose.yml b/docker-compose.yml index 08928d7..4d1b2ab 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: telegram-ssh: build: .