Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 68 additions & 65 deletions plugins/zeabur/skills/zeabur-server-ssh/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,88 @@
---
name: zeabur-server-ssh
description: Use when debugging services on a user's dedicated server via SSH. Use when needing to inspect pods, check container logs, view k8s resources, or run kubectl commands on the server. Use when "service exec" is insufficient and you need server-level access. Use when user says "check my server", "debug pod", "kubectl", "SSH into server", "check k8s", or "inspect cluster".
description: Use when debugging services on a user's dedicated server via SSH. Use when needing to run a command on the server, inspect pods, check container logs, view k8s resources, or run kubectl commands. Use when "service exec" is insufficient and you need server-level access. Use when user says "check my server", "run X on my server", "debug pod", "kubectl", "SSH into server", "check k8s", or "inspect cluster".
---

# Zeabur Server SSH + kubectl

> **Always use `npx zeabur@latest` to invoke Zeabur CLI.** Never use `zeabur` directly or any other installation method.

SSH into a user's dedicated server and use kubectl to debug Kubernetes workloads. Zeabur dedicated servers run k3s with kubectl pre-installed.
Run commands on a user's dedicated server and use kubectl to debug Kubernetes workloads. Zeabur dedicated servers run k3s with kubectl pre-installed.

## Step 1: Get SSH Credentials
## Run a command: `server exec` (recommended)

Run a command on the server in one step. The CLI fetches the credentials and opens
the connection internally, so **you never handle the password** — passwords with
special characters just work, and no `ssh2`/`sshpass` is needed.

```bash
npx zeabur@latest server ssh-info --id <server-id> -i=false
npx zeabur@latest server exec --id <server-id> -- <command>
```

Output is JSON:
```json
{"ip":"1.2.3.4","port":22,"username":"root","password":"xxx"}
```
Examples:

If you don't know the server ID, list servers first:
```bash
npx zeabur@latest server list -i=false
# Single command
npx zeabur@latest server exec --id <server-id> -- sudo kubectl get pods -A -o wide

# Compound command — quote it as ONE argument so && / | stay intact
npx zeabur@latest server exec --id <server-id> -- 'echo "=== PODS ===" && sudo kubectl get pods -A && echo "=== EVENTS ===" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20'
```

## Step 2: Run Commands via SSH
Notes:

Use the Node.js `ssh2` method by default. Use `sshpass` only when its availability is already known.
- Everything after `--` is the remote command, joined like `ssh host <command>`.
Quote a compound command (with `&&` / `|` / redirects) as a **single argument**.
- stdout/stderr stream live; the remote command's **exit code is propagated**.
- If you don't know the server ID, list servers first:
```bash
npx zeabur@latest server list -i=false
```
(or use the `zeabur-server-list` skill).

### Option A: sshpass (only if already known to be available)
## Common kubectl Commands

```bash
# Single command
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> sudo kubectl get pods -A
Pass any of these as the command to `server exec`. **Always use `sudo kubectl`** —
the SSH user may not have direct access to the k3s kubeconfig.

| Task | Command |
|------|---------|
| List all pods | `sudo kubectl get pods -A -o wide` |
| Problem pods only | `sudo kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded` |
| Pod logs | `sudo kubectl logs <pod-name> -n <namespace> --tail=100` |
| Exec into container | `sudo kubectl exec <pod-name> -n <namespace> -- <command>` |
| Node resources | `sudo kubectl top nodes` |
| Pod resources | `sudo kubectl top pods -A --sort-by=memory \| head -20` |
| Describe pod | `sudo kubectl describe pod <pod-name> -n <namespace>` |
| Recent events | `sudo kubectl get events -A --sort-by=.lastTimestamp \| tail -30` |
| Restart deployment | `sudo kubectl rollout restart deployment/<name> -n <namespace>` |

## Fallback: manual SSH (only if `server exec` is unavailable)

Use this **only** if `server exec` isn't available (e.g. an older CLI). Otherwise
prefer `server exec` above — this path is fragile with special-character passwords.

# Multiple commands in one SSH call
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> '
echo "=== PODS ===" && sudo kubectl get pods -A &&
echo "=== SERVICES ===" && sudo kubectl get svc -A &&
echo "=== EVENTS ===" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20
'
### Step 1: Get SSH credentials

```bash
npx zeabur@latest server ssh-info --id <server-id> -i=false
```

### Option B: Node.js ssh2 (default)
Output is JSON: `{"ip":"1.2.3.4","port":22,"username":"root","password":"xxx"}`

### Step 2: Connect

The Zeabur agent sandbox has `ssh2` pre-installed. Use this approach by default:
Use the Node.js `ssh2` method by default; use `sshpass` only when its availability
is already known. Do NOT run `which sshpass` to check — it wastes a step where it's
never installed.

```bash
# sshpass (only if already known to be available)
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> sudo kubectl get pods -A
```

```bash
# Node.js ssh2 (the Zeabur agent sandbox has it pre-installed)
NODE_PATH=$([ -d /root/.global/node_modules ] && echo /root/.global/node_modules || echo /home/vercel-sandbox/.global/node_modules) node -e "
const {Client} = require('ssh2');
const c = new Client();
Expand All @@ -68,46 +103,14 @@ c.on('ready', () => {
"
```

For multiple commands, join them with `&&` in the command string:

```bash
NODE_PATH=$([ -d /root/.global/node_modules ] && echo /root/.global/node_modules || echo /home/vercel-sandbox/.global/node_modules) node -e "
const {Client} = require('ssh2');
const c = new Client();
c.on('ready', () => {
c.exec('echo \"=== PODS ===\" && sudo kubectl get pods -A && echo \"=== SERVICES ===\" && sudo kubectl get svc -A && echo \"=== EVENTS ===\" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20', (err, stream) => {
if (err) { console.error(err); process.exit(1); }
let out = '';
stream.on('data', d => out += d);
stream.stderr.on('data', d => out += d);
stream.on('close', () => { console.log(out); c.end(); });
});
}).connect({host:'<ip>', port:<port>, username:'<username>', password:'<password>'});
"
```

## Common kubectl Commands

**Always use `sudo kubectl`** — the SSH user may not have direct access to the k3s kubeconfig.

| Task | Command |
|------|---------|
| List all pods | `sudo kubectl get pods -A -o wide` |
| Problem pods only | `sudo kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded` |
| Pod logs | `sudo kubectl logs <pod-name> -n <namespace> --tail=100` |
| Exec into container | `sudo kubectl exec <pod-name> -n <namespace> -- <command>` |
| Node resources | `sudo kubectl top nodes` |
| Pod resources | `sudo kubectl top pods -A --sort-by=memory \| head -20` |
| Describe pod | `sudo kubectl describe pod <pod-name> -n <namespace>` |
| Recent events | `sudo kubectl get events -A --sort-by=.lastTimestamp \| tail -30` |
| Restart deployment | `sudo kubectl rollout restart deployment/<name> -n <namespace>` |

## Tips

- **Use Node.js ssh2 by default (Option B)**: Only use `sshpass` (Option A) if you already know it's available. Do NOT run `which sshpass` to check — it wastes a step in environments where it's never installed.
- **Combine commands**: Batch related checks with `&&` in a single SSH call to reduce round trips.
- **Do NOT use `bash -c '...'` over SSH**: Pass commands directly in SSH quotes. Using `bash -c` causes quoting conflicts.
- **Use `-o wide`**: Adds node name and IP to pod listings, useful for debugging scheduling issues.
- **Namespace matters**: Zeabur services typically run in non-default namespaces. Use `-A` (all namespaces) first to locate the right namespace, then scope subsequent commands with `-n <namespace>`.
- **Read project docs first**: If a fix attempt fails, exec into the container and check README or config files before blindly checking metrics: `sudo kubectl exec <pod> -n <ns> -- cat /app/README.md`
- To find server IDs, use the `zeabur-server-list` skill. For simpler container commands that don't need server-level access, use the `zeabur-service-exec` skill instead.
- **Combine commands**: batch related checks with `&&` in a single `server exec`
call to reduce round trips.
- **Use `-o wide`**: adds node name and IP to pod listings, useful for scheduling issues.
- **Namespace matters**: Zeabur services usually run in non-default namespaces. Use
`-A` (all namespaces) first to locate the right one, then scope with `-n <namespace>`.
- **Read project docs first**: if a fix attempt fails, exec into the container and
check README/config before blindly checking metrics: `sudo kubectl exec <pod> -n <ns> -- cat /app/README.md`
- To find server IDs, use the `zeabur-server-list` skill. For simpler container
commands that don't need server-level access, use the `zeabur-service-exec` skill.
133 changes: 68 additions & 65 deletions skills/zeabur-server-ssh/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,88 @@
---
name: zeabur-server-ssh
description: Use when debugging services on a user's dedicated server via SSH. Use when needing to inspect pods, check container logs, view k8s resources, or run kubectl commands on the server. Use when "service exec" is insufficient and you need server-level access. Use when user says "check my server", "debug pod", "kubectl", "SSH into server", "check k8s", or "inspect cluster".
description: Use when debugging services on a user's dedicated server via SSH. Use when needing to run a command on the server, inspect pods, check container logs, view k8s resources, or run kubectl commands. Use when "service exec" is insufficient and you need server-level access. Use when user says "check my server", "run X on my server", "debug pod", "kubectl", "SSH into server", "check k8s", or "inspect cluster".
---

# Zeabur Server SSH + kubectl

> **Always use `npx zeabur@latest` to invoke Zeabur CLI.** Never use `zeabur` directly or any other installation method.

SSH into a user's dedicated server and use kubectl to debug Kubernetes workloads. Zeabur dedicated servers run k3s with kubectl pre-installed.
Run commands on a user's dedicated server and use kubectl to debug Kubernetes workloads. Zeabur dedicated servers run k3s with kubectl pre-installed.

## Step 1: Get SSH Credentials
## Run a command: `server exec` (recommended)

Run a command on the server in one step. The CLI fetches the credentials and opens
the connection internally, so **you never handle the password** — passwords with
special characters just work, and no `ssh2`/`sshpass` is needed.

```bash
npx zeabur@latest server ssh-info --id <server-id> -i=false
npx zeabur@latest server exec --id <server-id> -- <command>
```

Output is JSON:
```json
{"ip":"1.2.3.4","port":22,"username":"root","password":"xxx"}
```
Examples:

If you don't know the server ID, list servers first:
```bash
npx zeabur@latest server list -i=false
# Single command
npx zeabur@latest server exec --id <server-id> -- sudo kubectl get pods -A -o wide

# Compound command — quote it as ONE argument so && / | stay intact
npx zeabur@latest server exec --id <server-id> -- 'echo "=== PODS ===" && sudo kubectl get pods -A && echo "=== EVENTS ===" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

## Step 2: Run Commands via SSH
Notes:

Use the Node.js `ssh2` method by default. Use `sshpass` only when its availability is already known.
- Everything after `--` is the remote command, joined like `ssh host <command>`.
Quote a compound command (with `&&` / `|` / redirects) as a **single argument**.
- stdout/stderr stream live; the remote command's **exit code is propagated**.
- If you don't know the server ID, list servers first:
```bash
npx zeabur@latest server list -i=false
```
(or use the `zeabur-server-list` skill).

### Option A: sshpass (only if already known to be available)
## Common kubectl Commands

```bash
# Single command
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> sudo kubectl get pods -A
Pass any of these as the command to `server exec`. **Always use `sudo kubectl`** —
the SSH user may not have direct access to the k3s kubeconfig.

| Task | Command |
|------|---------|
| List all pods | `sudo kubectl get pods -A -o wide` |
| Problem pods only | `sudo kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded` |
| Pod logs | `sudo kubectl logs <pod-name> -n <namespace> --tail=100` |
| Exec into container | `sudo kubectl exec <pod-name> -n <namespace> -- <command>` |
| Node resources | `sudo kubectl top nodes` |
| Pod resources | `sudo kubectl top pods -A --sort-by=memory \| head -20` |
| Describe pod | `sudo kubectl describe pod <pod-name> -n <namespace>` |
| Recent events | `sudo kubectl get events -A --sort-by=.lastTimestamp \| tail -30` |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
| Restart deployment | `sudo kubectl rollout restart deployment/<name> -n <namespace>` |

## Fallback: manual SSH (only if `server exec` is unavailable)

Use this **only** if `server exec` isn't available (e.g. an older CLI). Otherwise
prefer `server exec` above — this path is fragile with special-character passwords.

# Multiple commands in one SSH call
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> '
echo "=== PODS ===" && sudo kubectl get pods -A &&
echo "=== SERVICES ===" && sudo kubectl get svc -A &&
echo "=== EVENTS ===" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20
'
### Step 1: Get SSH credentials

```bash
npx zeabur@latest server ssh-info --id <server-id> -i=false
```

### Option B: Node.js ssh2 (default)
Output is JSON: `{"ip":"1.2.3.4","port":22,"username":"root","password":"xxx"}`

### Step 2: Connect

The Zeabur agent sandbox has `ssh2` pre-installed. Use this approach by default:
Use the Node.js `ssh2` method by default; use `sshpass` only when its availability
is already known. Do NOT run `which sshpass` to check — it wastes a step where it's
never installed.

```bash
# sshpass (only if already known to be available)
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> sudo kubectl get pods -A
```

```bash
# Node.js ssh2 (the Zeabur agent sandbox has it pre-installed)
NODE_PATH=$([ -d /root/.global/node_modules ] && echo /root/.global/node_modules || echo /home/vercel-sandbox/.global/node_modules) node -e "
const {Client} = require('ssh2');
const c = new Client();
Expand All @@ -68,46 +103,14 @@ c.on('ready', () => {
"
```

For multiple commands, join them with `&&` in the command string:

```bash
NODE_PATH=$([ -d /root/.global/node_modules ] && echo /root/.global/node_modules || echo /home/vercel-sandbox/.global/node_modules) node -e "
const {Client} = require('ssh2');
const c = new Client();
c.on('ready', () => {
c.exec('echo \"=== PODS ===\" && sudo kubectl get pods -A && echo \"=== SERVICES ===\" && sudo kubectl get svc -A && echo \"=== EVENTS ===\" && sudo kubectl get events -A --sort-by=.lastTimestamp | tail -20', (err, stream) => {
if (err) { console.error(err); process.exit(1); }
let out = '';
stream.on('data', d => out += d);
stream.stderr.on('data', d => out += d);
stream.on('close', () => { console.log(out); c.end(); });
});
}).connect({host:'<ip>', port:<port>, username:'<username>', password:'<password>'});
"
```

## Common kubectl Commands

**Always use `sudo kubectl`** — the SSH user may not have direct access to the k3s kubeconfig.

| Task | Command |
|------|---------|
| List all pods | `sudo kubectl get pods -A -o wide` |
| Problem pods only | `sudo kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded` |
| Pod logs | `sudo kubectl logs <pod-name> -n <namespace> --tail=100` |
| Exec into container | `sudo kubectl exec <pod-name> -n <namespace> -- <command>` |
| Node resources | `sudo kubectl top nodes` |
| Pod resources | `sudo kubectl top pods -A --sort-by=memory \| head -20` |
| Describe pod | `sudo kubectl describe pod <pod-name> -n <namespace>` |
| Recent events | `sudo kubectl get events -A --sort-by=.lastTimestamp \| tail -30` |
| Restart deployment | `sudo kubectl rollout restart deployment/<name> -n <namespace>` |

## Tips

- **Use Node.js ssh2 by default (Option B)**: Only use `sshpass` (Option A) if you already know it's available. Do NOT run `which sshpass` to check — it wastes a step in environments where it's never installed.
- **Combine commands**: Batch related checks with `&&` in a single SSH call to reduce round trips.
- **Do NOT use `bash -c '...'` over SSH**: Pass commands directly in SSH quotes. Using `bash -c` causes quoting conflicts.
- **Use `-o wide`**: Adds node name and IP to pod listings, useful for debugging scheduling issues.
- **Namespace matters**: Zeabur services typically run in non-default namespaces. Use `-A` (all namespaces) first to locate the right namespace, then scope subsequent commands with `-n <namespace>`.
- **Read project docs first**: If a fix attempt fails, exec into the container and check README or config files before blindly checking metrics: `sudo kubectl exec <pod> -n <ns> -- cat /app/README.md`
- To find server IDs, use the `zeabur-server-list` skill. For simpler container commands that don't need server-level access, use the `zeabur-service-exec` skill instead.
- **Combine commands**: batch related checks with `&&` in a single `server exec`
call to reduce round trips.
- **Use `-o wide`**: adds node name and IP to pod listings, useful for scheduling issues.
- **Namespace matters**: Zeabur services usually run in non-default namespaces. Use
`-A` (all namespaces) first to locate the right one, then scope with `-n <namespace>`.
- **Read project docs first**: if a fix attempt fails, exec into the container and
check README/config before blindly checking metrics: `sudo kubectl exec <pod> -n <ns> -- cat /app/README.md`
- To find server IDs, use the `zeabur-server-list` skill. For simpler container
commands that don't need server-level access, use the `zeabur-service-exec` skill.
Loading