简体   繁体   English

连接到远程 SSH 服务器(通过 Node.js/html5 控制台)

[英]Connecting to remote SSH server (via Node.js/html5 console)

I have been scouring the face of the web looking to answer a question which I had thought would be simple.我一直在网上搜索,希望回答一个我认为很简单的问题。 My goal is straight forward.我的目标很明确。 I want to build out a simple web-based SSH client using Node.js module(s).我想使用 Node.js 模块构建一个简单的基于 Web 的 SSH 客户端。 I have found several options if I want to connect to the node server itself, but can't seem to find any examples of connecting to a REMOTE server.如果我想连接到节点服务器本身,我已经找到了几个选项,但似乎找不到任何连接到远程服务器的示例。

Essentially the outcome I am looking for is a workflow like this : Connect to webserver -> Click on a server name in a list of servers -> Enter SSH session to the server I clicked on基本上,我正在寻找的结果是这样的工作流程:连接到网络服务器 -> 单击服务器列表中的服务器名称 -> 输入到我单击的服务器的 SSH 会话

The only thing I have found that's even remotely close to what I am looking for is guacamole .我发现的唯一与我正在寻找的东西非常接近的东西是guacamole I do not want to use guacamole, however, as I want this application to be OS independent.但是,我不想使用鳄梨酱,因为我希望此应用程序独立于操作系统。 Currently I am building it on a windows 10 platform, and will port it over to fedora when I am done.目前我正在 Windows 10 平台上构建它,并在完成后将其移植到 Fedora。

I found this tutorial for creating an SSH terminal .我找到了创建 SSH 终端的教程。 However, all this does is creates (or attempts to create) an SSH connection to the local system.然而,这一切只是创建(或尝试创建)到本地系统的 SSH 连接。

Another options that looked absolutely fantastic was tty.js .另一个看起来非常棒的选项是tty.js Alas, the bottom-line is the same as the above tutorial.唉,底线与上述教程相同。 The module only allows you to connect to the node.js server, NOT to remote servers.该模块只允许您连接到 node.js 服务器,而不是远程服务器。

Anyone have information on a possible path to this goal?任何人都有关于实现这一目标的可能途径的信息?

This is easily doable with modules like ssh2 , xterm , and socket.io .这可以通过ssh2xtermsocket.io等模块轻松实现。

Here's an example:下面是一个例子:

  1. npm install ssh2 xterm socket.io
  2. Create index.html :创建index.html
<html>
  <head>
    <title>SSH Terminal</title>
    <link rel="stylesheet" href="/src/xterm.css" />
    <script src="/src/xterm.js"></script>
    <script src="/addons/fit/fit.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      window.addEventListener('load', function() {
        var terminalContainer = document.getElementById('terminal-container');
        var term = new Terminal({ cursorBlink: true });
        term.open(terminalContainer);
        term.fit();

        var socket = io.connect();
        socket.on('connect', function() {
          term.write('\r\n*** Connected to backend***\r\n');

          // Browser -> Backend
          term.on('data', function(data) {
            socket.emit('data', data);
          });

          // Backend -> Browser
          socket.on('data', function(data) {
            term.write(data);
          });

          socket.on('disconnect', function() {
            term.write('\r\n*** Disconnected from backend***\r\n');
          });
        });
      }, false);
    </script>
    <style>
      body {
        font-family: helvetica, sans-serif, arial;
        font-size: 1em;
        color: #111;
      }
      h1 {
        text-align: center;
      }
      #terminal-container {
        width: 960px;
        height: 600px;
        margin: 0 auto;
        padding: 2px;
      }
      #terminal-container .terminal {
        background-color: #111;
        color: #fafafa;
        padding: 2px;
      }
      #terminal-container .terminal:focus .terminal-cursor {
        background-color: #fafafa;
      }
    </style>
  </head>
  <body>
    <div id="terminal-container"></div>
  </body>
</html>
  1. Create server.js :创建server.js
var fs = require('fs');
var path = require('path');
var server = require('http').createServer(onRequest);

var io = require('socket.io')(server);
var SSHClient = require('ssh2').Client;

// Load static files into memory
var staticFiles = {};
var basePath = path.join(require.resolve('xterm'), '..');
[ 'addons/fit/fit.js',
  'src/xterm.css',
  'src/xterm.js'
].forEach(function(f) {
  staticFiles['/' + f] = fs.readFileSync(path.join(basePath, f));
});
staticFiles['/'] = fs.readFileSync('index.html');

// Handle static file serving
function onRequest(req, res) {
  var file;
  if (req.method === 'GET' && (file = staticFiles[req.url])) {
    res.writeHead(200, {
      'Content-Type': 'text/'
                      + (/css$/.test(req.url)
                         ? 'css'
                         : (/js$/.test(req.url) ? 'javascript' : 'html'))
    });
    return res.end(file);
  }
  res.writeHead(404);
  res.end();
}

io.on('connection', function(socket) {
  var conn = new SSHClient();
  conn.on('ready', function() {
    socket.emit('data', '\r\n*** SSH CONNECTION ESTABLISHED ***\r\n');
    conn.shell(function(err, stream) {
      if (err)
        return socket.emit('data', '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
      socket.on('data', function(data) {
        stream.write(data);
      });
      stream.on('data', function(d) {
        socket.emit('data', d.toString('binary'));
      }).on('close', function() {
        conn.end();
      });
    });
  }).on('close', function() {
    socket.emit('data', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
  }).on('error', function(err) {
    socket.emit('data', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
  }).connect({
    host: '192.168.100.105',
    username: 'foo',
    password: 'barbaz'
  });
});

server.listen(8000);
  1. Edit the SSH server configuration passed to .connect() in server.js编辑传递给server.js .connect()的 SSH 服务器配置
  2. node server.js
  3. Visit http://localhost:8000 in your browser在浏览器中访问http://localhost:8000

Just adding updated code to @mscdex great answer because the libraries have changed over the years.只是将更新的代码添加到@mscdex 很好的答案,因为这些年来库已经发生了变化。

Libraries:图书馆:

npm install express socket.io ssh2 xterm xterm-addon-fit

index.html:索引.html:

<html>
  <head>
    <title>SSH Terminal</title>
    <link rel="stylesheet" href="/xterm.css" />
    <script src="/xterm.js"></script>
    <script src="/xterm-addon-fit.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script>
      window.addEventListener('load', function() {
        var terminalContainer = document.getElementById('terminal-container');
        const term = new Terminal({ cursorBlink: true });        
        const fitAddon = new FitAddon.FitAddon();
        term.loadAddon(fitAddon);
        term.open(terminalContainer);
        fitAddon.fit();

        var socket = io() //.connect();
        socket.on('connect', function() {
          term.write('\r\n*** Connected to backend ***\r\n');
        });

        // Browser -> Backend
        term.onKey(function (ev) {
          socket.emit('data', ev.key);
        });

        // Backend -> Browser
        socket.on('data', function(data) {
          term.write(data);
        });

        socket.on('disconnect', function() {
          term.write('\r\n*** Disconnected from backend ***\r\n');
        });
      }, false);
    </script>
    <style>
      body {
        font-family: helvetica, sans-serif, arial;
        font-size: 1em;
        color: #111;
      }
      h1 {
        text-align: center;
      }
      #terminal-container {
        width: 960px;
        height: 600px;
        margin: 0 auto;
        padding: 2px;
      }
      #terminal-container .terminal {
        background-color: #111;
        color: #fafafa;
        padding: 2px;
      }
      #terminal-container .terminal:focus .terminal-cursor {
        background-color: #fafafa;
      }
    </style>
  </head>
  <body>
    <h3>WebSSH</h3>
    <div id="terminal-container"></div>
  </body>
</html>

server.js:服务器.js:

var fs = require('fs');
var path = require('path');
var server = require('http').createServer(onRequest);

var io = require('socket.io')(server);
var SSHClient = require('ssh2').Client;

// Load static files into memory
var staticFiles = {};
var basePath = path.join(require.resolve('xterm'), '..');
staticFiles['/xterm.css'] = fs.readFileSync(path.join(basePath, '../css/xterm.css'));
staticFiles['/xterm.js'] = fs.readFileSync(path.join(basePath, 'xterm.js'));
basePath = path.join(require.resolve('xterm-addon-fit'), '..');
staticFiles['/xterm-addon-fit.js'] = fs.readFileSync(path.join(basePath, 'xterm-addon-fit.js'));
staticFiles['/'] = fs.readFileSync('index.html');

// Handle static file serving
function onRequest(req, res) {
  var file;
  if (req.method === 'GET' && (file = staticFiles[req.url])) {
    res.writeHead(200, {
      'Content-Type': 'text/'
        + (/css$/.test(req.url)
        ? 'css'
        : (/js$/.test(req.url) ? 'javascript' : 'html'))
    });
    return res.end(file);
  }
  res.writeHead(404);
  res.end();
}

io.on('connection', function(socket) {
  var conn = new SSHClient();
  conn.on('ready', function() {
    socket.emit('data', '\r\n*** SSH CONNECTION ESTABLISHED ***\r\n');
    conn.shell(function(err, stream) {
      if (err)
        return socket.emit('data', '\r\n*** SSH SHELL ERROR: ' + err.message + ' ***\r\n');
      socket.on('data', function(data) {
        stream.write(data);
      });
      stream.on('data', function(d) {
        socket.emit('data', d.toString('binary'));
      }).on('close', function() {
        conn.end();
      });
    });
  }).on('close', function() {
    socket.emit('data', '\r\n*** SSH CONNECTION CLOSED ***\r\n');
  }).on('error', function(err) {
    socket.emit('data', '\r\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\r\n');
  }).connect({
    host: 'domain.tld',
    port: 22,
    username: 'root',
    privateKey: require('fs').readFileSync('path/to/keyfile')
  });
});

let port = 8000;
console.log('Listening on port', port)
server.listen(port);

Same as the above answer but actually using express and modern syntax and libraries与上述答案相同,但实际上使用了快速和现代的语法和库

 const express = require('express'); const app = express(); const http = require('http').Server(app); const io = require('socket.io')(http, { cors: { origin: "*" } }); app.set('view engine', 'ejs'); app.use(express.urlencoded({ extended: false, limit: '150mb' })); app.use(express.static(__dirname + '/public')); app.use('/xterm.css', express.static(require.resolve('xterm/css/xterm.css'))); app.use('/xterm.js', express.static(require.resolve('xterm'))); app.use('/xterm-addon-fit.js', express.static(require.resolve('xterm-addon-fit'))); const SSHClient = require('ssh2').Client; app.get('/', (req, res) => { // res.sendFile(__dirname + '/index.html'); res.render('index'); // I am using ejs as my templating engine but HTML file work just fine. }); io.on('connection', function(socket) { var conn = new SSHClient(); conn.on('ready', function() { socket.emit('data', '\\r\\n*** SSH CONNECTION ESTABLISHED ***\\r\\n'); conn.shell(function(err, stream) { if (err) return socket.emit('data', '\\r\\n*** SSH SHELL ERROR: ' + err.message + ' ***\\r\\n'); socket.on('data', function(data) { stream.write(data); }); stream.on('data', function(d) { socket.emit('data', d.toString('binary')); }).on('close', function() { conn.end(); }); }); }).on('close', function() { socket.emit('data', '\\r\\n*** SSH CONNECTION CLOSED ***\\r\\n'); }).on('error', function(err) { socket.emit('data', '\\r\\n*** SSH CONNECTION ERROR: ' + err.message + ' ***\\r\\n'); }).connect({ host: '192.168.0.103', port: 22, username: 'kali', password: 'kali' }); }); http.listen(3000, () => { console.log('Listening on http://localhost:3000'); });
 * { padding: 0%; margin: 0%; box-sizing: border-box; } body { font-family: Helvetica, sans-serif, arial; font-size: 1em; color: #111; } h1 { text-align: center; } #terminal-container { width: 960px; height: 600px; margin: 0 auto; padding: 2px; } #terminal-container .terminal { background-color: #111; color: #fafafa; padding: 2px; } #terminal-container .terminal:focus .terminal-cursor { background-color: #fafafa; }
 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>SSH SERVER</title> <link rel="stylesheet" href="/xterm.css" /> <script defer src="/xterm.js"></script> <script defer src="/xterm-addon-fit.js"></script> <script defer src="/socket.io/socket.io.js"></script> <script defer src='/js/app.js'></script> <link rel='stylesheet' href='/css/main.css'> </head> <body> <h3>WebSSH</h3> <div id="terminal-container"></div> <script> // PLEASE USE A SEPERATE FILE FOR THE JS and defer it // like the above app.js file window.addEventListener('load', function() { const terminalContainer = document.getElementById('terminal-container'); const term = new Terminal({ cursorBlink: true }); const fitAddon = new FitAddon.FitAddon(); term.loadAddon(fitAddon); term.open(terminalContainer); fitAddon.fit(); const socket = io() //.connect(); socket.on('connect', function() { term.write('\\r\\n*** Connected to backend ***\\r\\n'); }); // Browser -> Backend term.onKey(function(ev) { socket.emit('data', ev.key); }); // Backend -> Browser socket.on('data', function(data) { term.write(data); }); socket.on('disconnect', function() { term.write('\\r\\n*** Disconnected from backend ***\\r\\n'); }); }, false); </script> </body> </html>

Try also noVnc.也试试 noVnc。 However, a little dig within the page of xterm.js reveals other solutions, like但是,在xterm.js的页面中稍微挖掘xterm.js就会发现其他解决方案,例如

WebSSH2网络SSH2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM