Nuxt.js Integrating With noVNC

Nuxt.js Integrating With noVNC

Nuxt.js Integrating With noVNC

近期作者遇到需要使用VNC連線到FAB內網的需求,
有評估過使用Python、C#等程式寫一個簡單的UI,讓User點Icon開啟VNC,
但考慮到需要一次性部署到30~50台以上的電腦...
再加上更新版本還要寫一個更新的Service,又有網段差異,最終選擇Web開發


要讓User在OA與FAB網段都能使用
開放條件只有Port 80,因此需要掛代理
最終畫出來的圖就變成這樣

Tower of God 666


Deployed Kit(部署套件)

# node.js (v18.19.0)
# package.json / 主要套件3個
{
	"@novnc/novnc": "^1.4.0",
	"nuxt": "^3.11.1"
}

Step1. Setting Nginx

Proxy Host: 192.168.1.51
Let  "location /vnc/"  URL Tag Redirect to WS Server(http://192.168.1.51:8112/)

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen       80;
        server_name  0.0.0.0;

        location / {
            proxy_pass http://localhost:8080;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        location /vnc/ {
            add_header      Access-Control-Allow-Origin *;
            add_header      Access-Control-Allow-Headers "Accept, X-Token, Content-Type";
            add_header      Access-Control-Allow-Methods "GET, POST, DELETE, PATCH, PUT, OPTIONS";
            proxy_pass      http://192.168.1.51:8112/;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }
    }
}

Step2. Build a WebSocket(WS) Server For RFB

Create WS Server With "192.168.1.51:8112"

and Replace URL!!
"/vnc/192.168.1.51:5900" (From Nginx)
Replace to "192.168.1.51:5900"(WS Server)

import http from 'http'
import net from 'net'
import { WebSocketServer } from 'ws'
const vnc_port = 8112
const vnc_server = http.createServer()
vnc_server.listen(vnc_port, () => {
  const web_socket_server = new WebSocketServer({ server: vnc_server })
  web_socket_server.on('connection', web_socket_handler)
})

const web_socket_handler = (client, req) => {
  // Replace URL
  const url = req.url
  const host = '192.168.1.51'
  const port = Number(url.substring(url.indexOf(':') + 1))
  console.log(`Nginx ${url} Replace to ${host}:${port}`)

  // Creat Connection
  const target = net.createConnection(port, host, () => {
    console.log('Client connect WS Server')
  })

  // WS Server Event
  target.on('data', (data) => {
    try {
      client.send(data)
    } catch (error) {
      target.end()
    }
  })

  target.on('end', () => {
    console.log('WS Server Disconnect')
    client.close()
  })

  target.on('error', () => {
    console.log('WS Server Error')
    target.end()
    client.close()
  })

  // Client Event
  client.on('message', (msg) => {
    target.write(msg)
  })

  client.on('close', (code, reason) => {
    console.log(`Client Disconnect:${code} [${reason}]`)
    target.end()
  })

  client.on('error', (error) => {
    console.log(`Client Error: ${error}`)
    target.end()
  })
}

Step3. Build a novnc.vue Page For Client

When User into novnc page, the Client will use RFB(WebSocket subprotocol for RFB) to Connect WS Server , then WS Server Will Transfer RFB message to VNC Server(Two-way communication)

<template>
  <div>
    <div id="screen" class="full" />
  </div>
</template>

<script>
import RFB from '@novnc/novnc/core/rfb'

export default {
  data () {
    return {
      url: 'ws://192.168.1.51:8112/vnc/192.168.1.51:5900',
      rfb: null
    }
  },
  mounted () {
    this.connectVnc()
  },
  beforeUnmount () {
    this.rfb && this.rfb.disconnect()
  },
  methods: {
    disconnectedFromServer (msg) {
      if (msg.detail.clean) {
        // console.log('msg.detail.clean')
      } else {
        // console.log('GG')
      }
      this.rfb = null
    },
    connectedToServer () {
      console.log('Connect Success')
    },
    connectVnc () {
      const rfb = new RFB(document.getElementById('screen'), this.url, {
        credentials: { password: '1234' }
      })
      rfb.addEventListener('connect', this.connectedToServer)
      rfb.addEventListener('disconnect', this.disconnectedFromServer)

      rfb.scaleViewport = true
      rfb.resizeSession = true
      this.rfb = rfb
    }
  }
}
</script>
<style scoped>
.full{
  width: 1920px;
  height: 720px;
}
</style>

Step4. VNC Setting (TightVNC)

Use Default


Enjoy !