Skip to main content
Ubuntu Desktop with XFCE, accessible via noVNC on port 6080. noVNC provides browser-based access to the desktop through VNC over WebSocket—you can view and interact with the desktop directly in your browser without installing a VNC client.

Set up the desktop environment

Install XFCE with all the essentials: file manager, text editor, LibreOffice, and more. noVNC provides browser-based access without a native VNC client.
// template.ts
import { Template, waitForPort } from 'e2b'

export const template = Template()
  .fromUbuntuImage('22.04')
  // Desktop environment and system utilities
  .runCmd([
    'yes | unminimize',
    'apt-get update',
    'apt-get install -y \
      xserver-xorg \
      xorg \
      x11-xserver-utils \
      xvfb \
      x11-utils \
      xauth \
      xfce4 \
      xfce4-goodies \
      util-linux \
      sudo \
      curl \
      git \
      wget \
      python3-pip \
      xdotool \
      scrot \
      ffmpeg \
      x11vnc \
      net-tools \
      netcat \
      x11-apps \
      libreoffice \
      xpdf \
      gedit \
      xpaint \
      tint2 \
      galculator \
      pcmanfm',
    'apt-get clean',
    'rm -rf /var/lib/apt/lists/*',
  ])
  // noVNC and websockify for browser-based VNC access
  .runCmd([
    'git clone --branch e2b-desktop https://github.com/e2b-dev/noVNC.git /opt/noVNC',
    'ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html',
    'git clone --branch v0.12.0 https://github.com/novnc/websockify /opt/noVNC/utils/websockify',
  ])
  // Set default terminal
  .runCmd(
    'ln -sf /usr/bin/xfce4-terminal.wrapper /etc/alternatives/x-terminal-emulator'
  )
  .copy('start_command.sh', '/start_command.sh')
  .runCmd('chmod +x /start_command.sh')
  .setStartCmd('/start_command.sh', waitForPort(6080))

The startup script initializes the display server, desktop environment, and VNC stack. It starts Xvfb (a virtual framebuffer), launches the XFCE session, runs x11vnc to share the display, and starts noVNC to bridge VNC to WebSocket for browser access.
start_command.sh
#!/bin/bash

# Set display
export DISPLAY=${DISPLAY:-:0}

# Start Xvfb
Xvfb $DISPLAY -ac -screen 0 1024x768x24 -nolisten tcp &
sleep 2

# Start XFCE session
startxfce4 &
sleep 5

# Start VNC server
x11vnc -bg -display $DISPLAY -forever -wait 50 -shared -rfbport 5900 -nopw \
    -noxdamage -noxfixes -nowf -noscr -ping 1 -repeat -speeds lan &
sleep 2

# Start noVNC server
cd /opt/noVNC/utils && ./novnc_proxy --vnc localhost:5900 --listen 6080 --web /opt/noVNC --heartbeat 30 &
sleep 2

Build and publish

Build the template. The desktop environment needs 8 CPUs and 8GB RAM for smooth rendering, window compositing, and running desktop applications like LibreOffice.
// build.ts
import { Template, defaultBuildLogger } from 'e2b'
import { template as desktopTemplate } from './template'

await Template.build(desktopTemplate, 'desktop', {
  cpuCount: 8,
  memoryMB: 8192,
  onBuildLogs: defaultBuildLogger(),
})

Connect to the desktop

Create a sandbox and open the URL in your browser. You’ll see a full Ubuntu desktop running in your sandbox.
import { Sandbox } from 'e2b'

const sandbox = await Sandbox.create('desktop', { timeoutMs: 60_000 })

const url = sandbox.getHost(6080)
console.log('Desktop available at:', url)