Install
openclaw skills install @ckaorceu/remote-terminalRemote Linux terminal control skill. Use when the user wants to (1) connect to a remote Linux server and execute commands, (2) perform SSH operations on remote hosts, (3) manage multiple remote servers, (4) run shell commands on remote machines. Triggers on phrases like "connect to server", "SSH to", "run on remote", "execute on production", "login to my server", "在服务器上执行", "远程连接", "SSH到".
openclaw skills install @ckaorceu/remote-terminalExecute commands on remote Linux servers through SSH, Telnet, or web terminals. Supports password authentication, SSH keys, and SSH config aliases.
ssh user@hostname "command"
If the user has ~/.ssh/config configured:
ssh <alias> "command"
sshpass -p 'password' ssh user@hostname "command"
Key-based authentication (most secure):
ssh -i ~/.ssh/id_rsa user@hostname "command"
Using SSH config aliases:
# Example ~/.ssh/config
Host production
HostName 192.168.1.100
User admin
Port 22
IdentityFile ~/.ssh/id_rsa
# Usage
ssh production "docker ps"
Password authentication:
sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@hostname "command"
# Using expect for interactive telnet
expect -c '
spawn telnet hostname
expect "login:"
send "username\r"
expect "Password:"
send "password\r"
expect "$ "
send "command\r"
expect "$ "
send "exit\r"
'
For web-based terminals, use curl or HTTP requests to the terminal's API:
# Example: ttyd WebSocket connection (requires wscat or similar)
wscat -c ws://hostname:7681/ws
Before executing dangerous commands, ask the user to confirm:
Dangerous command patterns:
rm -rf, rm -r, del, eraseshutdown, reboot, poweroff, haltmkfs, fdisk, parted, ddchmod 777, chown -R> /dev/, truncatekill -9, pkill, killalliptables, ufw, firewall-cmdDROP DATABASE, DELETE FROM, TRUNCATEConfirmation format:
⚠️ Dangerous command detected:
rm -rf /var/log/*This will permanently delete files. Proceed? (yes/no)
These commands are blocked by default and require explicit user override:
rm -rf / (entire filesystem)mkfs on mounted drivesdd to primary disk/dev/sda or similarAll remote commands are logged with timestamp, target host, and command:
[2026-03-21 15:30:45] [production] docker ps
[2026-03-21 15:31:02] [staging] systemctl restart nginx
Log location: ~/.qclaw/logs/remote-terminal.log
Parse the user's request to identify:
Example prompts:
Construct the appropriate SSH command based on:
If command matches dangerous patterns:
Run the command and return:
Record the operation in the log file for audit trail.
ssh host "uptime && free -h && df -h"
ssh host "docker ps -a"
ssh host "docker logs container_name"
ssh host "docker restart container_name"
ssh host "systemctl status nginx"
ssh host "sudo systemctl restart nginx"
ssh host "journalctl -u nginx -f --no-pager -n 50"
# View file
ssh host "cat /var/log/nginx/error.log | tail -50"
# Copy file to local
scp user@host:/remote/path /local/path
# Copy file to remote
scp /local/path user@host:/remote/path
ssh host "ps aux | grep nginx"
ssh host "top -b -n 1 | head -20"
For commands requiring interaction, use ssh -t for pseudo-terminal:
ssh -t host "sudo nano /etc/nginx/nginx.conf"
ssh -t host "htop"
Note: Interactive sessions require the -t flag to allocate a PTY.
Execute the same command on multiple hosts:
for host in web1 web2 web3; do
echo "=== $host ==="
ssh $host "uptime"
done
For larger fleets:
# Using pssh (parallel-ssh)
pssh -h hosts.txt "uptime"
# hosts.txt format
# web1.example.com
# web2.example.com
# web3.example.com
Hosts can be stored in ~/.qclaw/workspace/memory/hosts.json:
{
"hosts": {
"production": {
"host": "192.168.1.100",
"user": "admin",
"method": "ssh-key",
"key": "~/.ssh/id_rsa",
"tags": ["web", "critical"]
},
"staging": {
"host": "staging.example.com",
"user": "deploy",
"method": "ssh-config",
"alias": "staging",
"tags": ["web", "testing"]
}
}
}
# From SSH config
grep "^Host " ~/.ssh/config | awk '{print $2}'
# From stored hosts.json
cat ~/.qclaw/workspace/memory/hosts.json
# Check if host is reachable
ping hostname
# Check if SSH port is open
nc -zv hostname 22
# Try with verbose output
ssh -vvv user@hostname
# Check key permissions
chmod 600 ~/.ssh/id_rsa
# Try with specific key
ssh -i ~/.ssh/id_rsa user@hostname
# Check if key is added to agent
ssh-add -l
ssh-add ~/.ssh/id_rsa
# Remove old host key
ssh-keygen -R hostname
# Or temporarily disable check (not recommended for production)
ssh -o StrictHostKeyChecking=no user@hostname
For commands returning JSON:
ssh host "docker inspect container --format '{{json .}}'" | jq .
For commands like docker ps, ps aux:
# Return as-is for readable tables
ssh host "docker ps --format 'table {{.Names}}\t{{.Status}}'"
# Parse for structured data
ssh host "docker ps --format '{{json .}}'" | jq .
ssh_exec.py - Python wrapper for SSH operations with logginghost_manager.py - Manage host configurationsparallel_exec.py - Execute commands on multiple hostsssh_config_guide.md - SSH config file examples and patternssecurity_best_practices.md - Security guidelines for remote access