skip to Main Content

I am working on a new project where I need to connect to a docker container from web?
By connect I mean I will create a shell in the website and tat shell will be able to connect to the running container.

I am not able to figure out how to proceed with the project.
Can anyone help me out?

3

Answers


  1. From what I know there is no out of the box solution, you should make your own api executing command on your container running docker exec <id> <command> and returning the output, mind escape the command.

    However you should know that letting a user run commands inside a docker is dangerous as it could impact your host.

    Login or Signup to reply.
  2. You should be able to use Docker APIs for this (https://docs.docker.com/engine/api/) along with a framework that wraps the APIs. For example refer dockerode.

    Login or Signup to reply.
  3. You could combine some JavaScript modules. node-pty and xterm being the most important. Additionally, ws is useful, but could be replaced but something else.

    Note: this is not a production ready example. In particular, you should take care of safety measurements, or better yet, let no one but yourself use it.

    server.js

    import { WebSocketServer, createWebSocketStream } from 'ws';
    import pty from 'node-pty';
    
    const wss = new WebSocketServer({ port: 3000 });
    
    wss.on('connection', (ws) => {
        console.log('new connection');
    
        const duplex = createWebSocketStream(ws, { encoding: 'utf8' });
    
        const proc = pty.spawn('docker', ['run', "--rm", "-ti", "ubuntu", "bash"], {
            name: 'xterm-color',
        });
    
        const onData = proc.onData((data) => duplex.write(data));
    
        const exit = proc.onExit(() => {
            console.log("process exited");
            onData.dispose();
            exit.dispose();
        });
    
        duplex.on('data', (data) => proc.write(data.toString()));
    
        ws.on('close', function () {
            console.log('stream closed');
            proc.kill();
            duplex.destroy();
        });
    
    });
    

    index.html

    <!doctype html>
    <html>
    
    <head>
        <link rel="stylesheet" href="node_modules/xterm/css/xterm.css" />
        <script src="node_modules/xterm/lib/xterm.js"></script>
    </head>
    
    <body>
        <div id="terminal"></div>
        <script type="module">
            const term = new Terminal();
            term.open(document.getElementById('terminal'));
            const ws = new WebSocket('ws://localhost:3000');
            ws.onmessage = async ({ data }) => term.write(await data.text());
            term.onData((data) => ws.send(data));
        </script>
    </body>
    
    </html>
    

    Note: I am using the statics from the node modules folder, in your real code you probably want to use a bundler for this.

    I am serving the entire project with nginx on port 8080 for simplicity. And then I start the server with node.

    docker run -d --rm -p 8080:8080 -v "$PWD:/usr/share/nginx/html" nginxinc/nginx-unprivileged
    node server.mjs
    

    Afterwards, I can open http://localhost:8080 in my browser, and get a shell.

    The dependencies in my package.json are these:

    "dependencies": {
        "node-pty": "^0.10.1",
        "ws": "^8.7.0",
        "xterm": "^4.18.0"
      }
    

    You can view the code in this repo: https://github.com/bluebrown/web-shell.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search