Skip to content

Instantly share code, notes, and snippets.

@billchurch
Last active September 27, 2025 12:04
Show Gist options
  • Select an option

  • Save billchurch/aee7b845c366a03ccc9285c5af484840 to your computer and use it in GitHub Desktop.

Select an option

Save billchurch/aee7b845c366a03ccc9285c5af484840 to your computer and use it in GitHub Desktop.
Example of using 1password ssh agent to get uptime from a remote ssh server
/**
* Simple SSH client using agent-based auth with ssh2.
*
* Env:
* SSH_HOST: hostname or IP, required
* SSH_PORT: port number, defaults to 22
* SSH_USER: username, defaults to OS user
* SSH_AUTH_SOCK: path to agent socket, required for agent auth
* COMMAND: command to run, defaults to "uptime"
*
* Examples:
* SSH_AUTH_SOCK="$HOME/.1password/agent.sock" \
* SSH_HOST=192.168.1.2 SSH_USER=pi node agent-uptime.mjs
*
* # Using default system agent
* SSH_HOST=192.168.1.2 SSH_USER=pi node agent-uptime.mjs
*/
import os from 'node:os';
import { Client } from 'ssh2';
/**
* Run a command on a remote host using agent auth.
*
* @param {object} opts connection and command options
* @param {string} opts.host remote host or IP
* @param {number} [opts.port=22] remote SSH port
* @param {string} opts.username SSH username
* @param {string} [opts.command='uptime'] command to execute
* @returns {Promise<{ code:number, stdout:string, stderr:string }>}
*/
export function runWithAgent(opts) {
const {
host,
port = 22,
username,
command = 'uptime',
} = opts;
const agentSock = process.env.SSH_AUTH_SOCK;
if (!agentSock) {
throw new Error('SSH_AUTH_SOCK is not set, no agent available');
}
return new Promise((resolve, reject) => {
const conn = new Client();
let stdout = '';
let stderr = '';
const onError = (err) => {
conn.end();
reject(err);
};
conn.on('ready', () => {
conn.exec(command, (err, stream) => {
if (err) return onError(err);
stream.on('close', (code) => {
conn.end();
resolve({ code, stdout, stderr });
});
stream.on('data', (data) => {
stdout += String(data);
});
stream.stderr.on('data', (data) => {
stderr += String(data);
});
});
});
conn.on('error', onError);
conn.connect({
host,
port,
username,
agent: agentSock,
// Set true only if you also want remote agent forwarding
// agentForward: true,
tryKeyboard: false,
readyTimeout: 20000,
});
});
}
/**
* CLI entry point.
* Reads env, runs the command, prints output, sets exit code.
*/
async function main() {
const host = process.env.SSH_HOST || '127.0.0.1';
const port = Number(process.env.SSH_PORT || 22);
const username = process.env.SSH_USER || os.userInfo().username;
const command = process.env.COMMAND || 'uptime';
try {
const { code, stdout, stderr } = await runWithAgent({
host,
port,
username,
command,
});
if (stdout) process.stdout.write(stdout);
if (stderr) process.stderr.write(stderr);
process.exitCode = Number.isInteger(code) ? code : 0;
} catch (err) {
console.error('SSH failed:', err.message);
process.exitCode = 1;
}
}
if (import.meta.url === `file://${process.argv[1]}`) {
main();
}
@billchurch
Copy link
Author

Boring example:

$ SSH_HOST=192.168.0.20 SSH_USER=root node agent-uptime.mjs 
 07:43:08 up 66 days, 18:42,  0 user,  load average: 0.70, 0.64, 0.71

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment