--- name: linux-ssh-operator-skill description: 通过 SSH 连接并操作 Linux 服务器:执行远程命令、查看日志、管理 systemd 服务、传输文件(scp/rsync)、配置 SSH 别名、安装公钥启用免密登录、SSH 隧道/端口转发、跳板机、内网穿透、排障。用户提到 ssh/scp/rsync、远程服务器 IP:端口、配置 ssh 别名、ssh-copy-id、免密登录、systemctl/journalctl、部署到服务器、在服务器上运行命令、远程拷贝文件、SSH 隧道、端口转发、跳板机、堡垒机、服务器上看一下、帮我连上服务器、查看服务器日志 等场景时使用。 --- # Linux SSH Operator ## Overview Use SSH to connect to Linux servers and perform safe, repeatable remote operations (commands, logs, services, file transfer, alias bootstrap, passwordless login, tunnels). ## Workflow 1. Confirm authorization and the target (host, port, user). 2. Prefer SSH keys (recommended) for non-interactive runs; avoid storing passwords in files or chat logs. 3. Start with read-only checks, then apply changes, then verify. 4. If a password prompt or interactive tool is required, run the SSH command in a real terminal/TTY (or enable TTY in your runner). ## Quick Start ### Set up SSH keys (recommended) Generate a key (ed25519): ```bash ssh-keygen -t ed25519 -C "codex" -f ~/.ssh/id_ed25519 ``` Install the public key on the server (example uses port 22): ```bash ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 22 USER@SERVER_IP ``` Optional: create an alias in `~/.ssh/config`: ```sshconfig Host my-server HostName SERVER_IP Port 22 User USER IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yes ``` Then connect: ```bash ssh my-server ``` ### Bootstrap alias + passwordless login When the user provides an alias, host/IP, and password and wants `ssh alias` to work immediately: 1. Write or update the alias with the helper script: ```bash ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_alias_setup.sh my-server 192.168.1.10 --user root --install-key ``` 2. If `ssh-copy-id` prompts for a password, run in a TTY and enter the password once. 3. Verify passwordless login: ```bash ssh -o BatchMode=yes my-server 'echo SSH_OK; id -un 2>/dev/null || echo root' ``` 4. Remind the user that `scp` and `rsync` can reuse the same alias: ```bash scp ./file.txt my-server:/root/ rsync -av ./dir/ my-server:/root/dir/ ``` Notes: - `scripts/ssh_alias_setup.sh` auto-generates `~/.ssh/id_ed25519` if it does not exist. - It updates `~/.ssh/config` idempotently and defaults to `root`, port `22`, and `StrictHostKeyChecking=accept-new`. - For tests, set `SSH_CONFIG_FILE=/path/to/temp-config`. ### Run remote commands - Direct: ```bash ssh my-server uname -a ``` - With sudo (often needs a TTY): ```bash ssh -tt my-server sudo systemctl status nginx --no-pager ``` - Via wrapper script (consistent options; supports env defaults like `REMOTE_USER`, `REMOTE_PORT`, `REMOTE_KEY`): - If you installed this Skill globally in `~/.claude/skills/`, use the absolute paths below (recommended so both Claude Code + OpenCode can find it). ```bash ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_run.sh my-server -- uname -a ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_run.sh --tty --sudo my-server -- systemctl restart nginx ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_run.sh --compress my-server -- cat /var/log/big.log ``` ### Transfer files Upload (scp): ```bash ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_copy.sh push my-server ./local.txt /tmp/local.txt ``` Download (scp): ```bash ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_copy.sh pull my-server /var/log/syslog ./syslog ``` Incremental sync (rsync — preferred for directories or large files): ```bash ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_copy.sh --rsync push my-server ./dist/ /var/www/html/ ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_copy.sh --rsync --delete push my-server ./dist/ /var/www/html/ ~/.claude/skills/linux-ssh-operator-skill/scripts/ssh_copy.sh --rsync pull my-server /var/log/ ./logs/ ``` ### SSH Tunneling / Port Forwarding Local forward (access remote service on a local port): ```bash # Access remote MySQL (3306) at localhost:13306 ssh -L 13306:127.0.0.1:3306 my-server -N ``` Remote forward (expose a local port on the server): ```bash # Make local :8080 accessible on server's :18080 ssh -R 18080:127.0.0.1:8080 my-server -N ``` Jump host (bastion → target): ```bash ssh -J bastion-user@bastion:22 target-user@target-host ``` Or configure in `~/.ssh/config`: ```sshconfig Host target-internal HostName 10.0.0.50 User ubuntu ProxyJump bastion ``` ### SSH Multiplexing (faster repeated connections) Add to `~/.ssh/config` to reuse the same TCP connection: ```sshconfig Host * ControlMaster auto ControlPath ~/.ssh/ctrl-%h-%p-%r ControlPersist 60s ``` The first `ssh my-server` opens a master connection; subsequent connections reuse it without re-handshaking. ## Common Ops (snippets) - Disk: `df -h`, `du -sh /path/* | sort -h` - Memory/CPU: `free -h`, `top`, `ps aux --sort=-%mem | head` - Logs: `journalctl -u SERVICE -n 200 --no-pager`, `tail -n 200 -f /path/log` - Services: `systemctl status|restart|stop|enable SERVICE` - Networking: `ss -lntp`, `ip a`, `ip r`, `curl -v http://127.0.0.1:PORT/` - Docker: `docker ps`, `docker logs -f CONTAINER`, `docker exec -it CONTAINER bash` - Config test: `nginx -t`, `sshd -T` - Open files: `lsof -i :PORT`, `fuser PORT/tcp` ## Safety - Never store or paste passwords in repo files or chat logs. - Avoid `StrictHostKeyChecking=no`; prefer verifying host keys (or use `accept-new` only when appropriate). - For destructive commands (rm, shutdown, firewall changes), ask for explicit user confirmation and show the exact command first. ## References - SSH security + troubleshooting: `references/ssh-playbook.md` ## Scripts - `scripts/ssh_alias_setup.sh`: create/update SSH aliases and optionally run `ssh-copy-id`. - `scripts/ssh_run.sh`: run remote commands with consistent options (supports `--compress`, `--tty`, `--sudo`). - `scripts/ssh_copy.sh`: push/pull files via scp or rsync (use `--rsync` for incremental transfers).