A full terminal in your pocket, via Telegram.
Access any server from your phone using a Telegram Mini App. Smart buttons for interactive prompts, Claude Code integration, voice input, multi-tab tmux sessions — no SSH app needed.
$ claude "fix the login bug"
Reading src/auth.js...
Editing src/auth.js...
Allow Edit tool? [Allow] [Deny] <-- smart buttons appear
- Smart buttons — auto-detects interactive prompts (Y/n, numbered options, Allow/Deny) and shows one-tap buttons
- Claude Code ready — recognizes Claude Code CLI permission prompts with approve/deny buttons
- Auto-approve mode — automatically accepts prompts with safety checks (blocks rm -rf, DROP, DELETE)
- Multi-tab — up to 4 concurrent tmux sessions that survive disconnects
- Voice input — push-to-talk via Web Speech API, with optional Azure Whisper fallback
- Telegram-native auth — HMAC-SHA256 verification, user ID whitelist, IP-bound JWT sessions
- Management API — execute commands via HTTPS when SSH is down
- Mobile controls — buttons for arrow keys, Tab, Esc, Ctrl+C
- Tokyo Night theme — dark theme, optimized for mobile screens
- 889 lines of code — zero frameworks, zero build step, zero transpilation
npx teletty init # creates .env from template
nano .env # set BOT_TOKEN, ALLOWED_USER_IDS, SESSION_SECRET
npx telettygit clone https://github.com/olegchetrean/teletty.git && cd teletty
cp .env.example .env && nano .env
docker compose up -dgit clone https://github.com/olegchetrean/teletty.git && cd teletty
cp .env.example .env && nano .env
npm install
node server.jsHave Claude Code, Cursor, or any AI agent connected to your server? Just give it this prompt — it handles everything: Node.js, tmux, clone, .env, HTTPS, systemd. You only need to create a bot at @BotFather and provide the token.
# Copy and edit nginx config
cp nginx.conf.template /etc/nginx/sites-enabled/teletty.conf
# Edit server_name, then:
sudo nginx -t && sudo nginx -s reload
sudo certbot --nginx -d terminal.yourdomain.com- Open @BotFather
/mybots> your bot > Bot Settings > Menu Button- Set URL:
https://terminal.yourdomain.com/ - Set text:
Terminal
Send any message to your bot, then check logs for [ws] Connected: user=XXXXXXX. Add that ID to ALLOWED_USER_IDS in .env.
Telegram (tap Menu Button)
-> Mini App WebView loads
-> POST /auth (HMAC-SHA256 verification + whitelist check)
-> WebSocket connection established
-> node-pty spawns tmux session
-> xterm.js renders terminal output
-> output-parser detects prompts -> smart buttons appear
The output parser detects 7 types of interactive prompts:
| Prompt Type | Example | Buttons |
|---|---|---|
| Y/n confirmation | Continue? [Y/n] |
Yes / No |
| Numbered options | 1) Install 2) Update |
1: Install / 2: Update |
| Letter options | a) Option A b) Option B |
a / b |
| Allow/Deny | Allow this action? |
Allow / Deny |
| Claude Code | Do you want to proceed? |
Yes / No |
| Tool permission | Bash command: ls |
Yes / No |
| Press Enter | Press Enter to continue |
Enter |
Buttons for dangerous commands (rm -rf, DROP, DELETE, shutdown) are highlighted in red.
Two-click activation for safety:
- First click: "Confirm?" (yellow)
- Second click: Active (red, pulsing) — auto-accepts Y/n and Allow prompts
- Does NOT auto-approve dangerous commands
- Auto-disables after 10 minutes
All via .env file. See .env.example for details.
| Variable | Description |
|---|---|
BOT_TOKEN |
Telegram bot token from @BotFather |
ALLOWED_USER_IDS |
Comma-separated Telegram user IDs |
SESSION_SECRET |
Random string for JWT signing (openssl rand -hex 32) |
| Variable | Default | Description |
|---|---|---|
PORT |
7681 | Server port |
ALLOWED_ORIGINS |
(all) | HTTPS origins for WebSocket |
MAX_SESSIONS |
4 | Max terminal tabs per user |
IDLE_TIMEOUT_MINUTES |
30 | Kill idle sessions after N minutes |
SHELL_COMMAND |
tmux | Shell to spawn |
SHELL_CWD |
/root | Working directory |
MGMT_TOKEN |
(disabled) | Token for management API |
VOICE_LANGUAGE |
en | Voice recognition language |
Your teletty instance is your private terminal. No one else can access it.
| Layer | What it does |
|---|---|
| 1. Telegram HMAC-SHA256 | Only Telegram servers can generate valid auth data. Impossible to forge without your bot token. |
| 2. User ID whitelist | Only YOUR Telegram account (by numeric ID) is allowed. Everyone else gets "Access denied". |
| 3. IP-bound JWT | Session tokens are locked to your IP address. Stolen token = useless from another IP. Expires in 4 hours. |
| 4. initData freshness | Auth data older than 5 minutes is rejected. Prevents replay attacks. |
| 5. Timing-safe auth | All comparisons use crypto.timingSafeEqual. Prevents timing side-channel attacks. |
| 6. Rate limiting | Max 10 auth attempts per minute per IP. Brute force = blocked. |
| 7. Sanitized environment | Terminal sessions only see PATH, HOME, USER, SHELL, LANG, TERM. Server secrets (BOT_TOKEN, SESSION_SECRET) are never leaked to the terminal. |
| File | Lines | Purpose |
|---|---|---|
server.js |
230 | Express + WebSocket server, auth, voice, management API |
auth.js |
87 | Telegram HMAC verification, JWT sessions, whitelist |
terminal-manager.js |
103 | tmux session lifecycle, idle timeout, audit |
output-parser.js |
88 | Smart prompt detection engine (7 types) |
public/app.js |
320 | Frontend: xterm.js, tabs, auto-approve, voice |
public/index.html |
79 | UI layout, Tokyo Night CSS |
bin/teletty.js |
35 | CLI entry point |
npm test26 tests covering output-parser (prompt detection, ANSI stripping, dangerous patterns) and auth (HMAC verification, JWT sessions, whitelist).
- Server management from phone — restart services, check logs, deploy
- Claude Code on the go — run AI coding agents with one-tap approve
- Emergency access — HTTPS management API when SSH is down
- Team access — whitelist multiple Telegram users, each gets isolated sessions
See CONTRIBUTING.md for development setup and guidelines.
MIT -- Oleg Chetrean