SuperAPI AI Directory

zeabur-server-ssh

Deployment & operations

View repository

Updated 10-16 01:11

About this skill

Zeabur Server SSH + kubectl

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

Run commands on a user's dedicated server, and use kubectl to debug Kubernetes workloads on servers that run ZeaburOS.

Check which kind of server you are on before using kubectl

  • ZeaburOS servers run k3s with kubectl pre-installed. Everything in this skill applies.
  • Ubuntu — a rented server that is not running ZeaburOS. It has no k3s and no kubectl; every kubectl command below fails with command not found. server exec still works for ordinary shell commands.

Renting provisions Ubuntu only, so never assume kubectl exists.

Read the machine's kind from the CLI — do not SSH in to work it out:

npx zeabur@latest server get <server-id> -i=false --json | jq -r .os

ZeaburOS or Ubuntu. server list reports the same thing for every server at once, as an OS column and an os field.

Needs CLI 0.21.0 or newer. If os comes back null, the CLI is older — either let npx zeabur@latest fetch the current version, or fall back to the API (see the zeabur-server-rent skill for the token setup that defines $ZAPI_CFG):

curl -sS --max-time 30 -K "$ZAPI_CFG" https://api.zeabur.com/graphql \
  -H "Content-Type: application/json" \
  -d '{"query":"query($id: ObjectID!) { server(_id: $id) { hasK3s } }","variables":{"id":"<server-id>"}}'

hasK3s is three-state and the third state is a trap: true is ZeaburOS, false is Ubuntu only, and null is a server predating the field — which does run ZeaburOS. So the test is hasK3s === false, never !hasK3s; the latter sweeps in every older server and wrongly reports it as a plain VPS.

If you did not check first and a kubectl command fails with command not found, that is the same signal — tell the user the server is a plain Ubuntu VPS instead of retrying the command. Installing ZeaburOS is what adds kubectl; the zeabur-server-rent skill covers how.

One exception. All of the above answers what kind of machine this is. If the user asks specifically whether some binary is present, check the machine — a ZeaburOS server always has kubectl, but a plain Ubuntu VPS may have had it installed by its owner, and the OS field cannot tell you that.

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.

npx zeabur@latest server exec --id <server-id> -- <command>

Examples:

# 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'

Notes:

  • 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 (a pipeline reports only its last stage's status — … | tail hides an upstream failure, so don't rely on the exit code across a pipe).
  • If you don't know the server ID, list servers first:
    npx zeabur@latest server list -i=false
    
    (or use the zeabur-server-list skill).

Common kubectl Commands

ZeaburOS servers only. On a plain Ubuntu VPS these all fail with kubectl: command not found — see the section above.

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. Any command with a pipe (|) or && must be quoted as a single argument, or the local shell splits it and runs part locally — e.g. server exec --id <id> -- 'sudo kubectl top pods -A --sort-by=memory | head -20'.

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.

Step 1: Get SSH credentials

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

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

Step 2: Connect

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.

# sshpass (only if already known to be available)
sshpass -p '<password>' ssh -o StrictHostKeyChecking=no -p <port> <username>@<ip> sudo kubectl get pods -A
# 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();
c.on('ready', () => {
  c.exec('<command>', (err, stream) => {
    if (err) { console.error(err); process.exit(1); }
    let out = '', errOut = '';
    stream.on('data', d => out += d);
    stream.stderr.on('data', d => errOut += d);
    stream.on('close', code => {
      if (out) console.log(out);
      if (errOut) console.error(errOut);
      c.end();
      process.exit(code);
    });
  });
}).connect({host:'<ip>', port:<port>, username:'<username>', password:'<password>'});
"

Tips

  • 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.