Skip to content

Commit 48c81c9

Browse files
matifaliParkreiner
andauthored
kasm VNC (#250)
Co-authored-by: Michael Smith <[email protected]>
1 parent acd5edf commit 48c81c9

File tree

4 files changed

+284
-0
lines changed

4 files changed

+284
-0
lines changed

kasmvnc/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
display_name: KasmVNC
3+
description: A modern open source VNC server
4+
icon: ../.icons/kasmvnc.svg
5+
maintainer_github: coder
6+
verified: true
7+
tags: [helper, vnc, desktop]
8+
---
9+
10+
# KasmVNC
11+
12+
Automatically install [KasmVNC](https://kasmweb.com/kasmvnc) in a workspace, and create an app to access it via the dashboard.
13+
14+
```tf
15+
module "kasmvnc" {
16+
source = "registry.coder.com/modules/kasmvnc/coder"
17+
version = "1.0.21"
18+
agent_id = coder_agent.example.id
19+
desktop_environment = "xfce"
20+
}
21+
```
22+
23+
> **Note:** This module only works on workspaces with a pre-installed desktop environment. As an example base image you can use `codercom/enterprise-desktop` image.

kasmvnc/main.test.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { describe, expect, it } from "bun:test";
2+
import {
3+
runTerraformApply,
4+
runTerraformInit,
5+
testRequiredVariables,
6+
} from "../test";
7+
8+
const allowedDesktopEnvs = ["xfce", "kde", "gnome", "lxde", "lxqt"] as const;
9+
type AllowedDesktopEnv = (typeof allowedDesktopEnvs)[number];
10+
11+
type TestVariables = Readonly<{
12+
agent_id: string;
13+
desktop_environment: AllowedDesktopEnv;
14+
port?: string;
15+
kasm_version?: string;
16+
}>;
17+
18+
describe("Kasm VNC", async () => {
19+
await runTerraformInit(import.meta.dir);
20+
testRequiredVariables<TestVariables>(import.meta.dir, {
21+
agent_id: "foo",
22+
desktop_environment: "gnome",
23+
});
24+
25+
it("Successfully installs for all expected Kasm desktop versions", async () => {
26+
for (const v of allowedDesktopEnvs) {
27+
const applyWithEnv = () => {
28+
runTerraformApply<TestVariables>(import.meta.dir, {
29+
agent_id: "foo",
30+
desktop_environment: v,
31+
});
32+
};
33+
34+
expect(applyWithEnv).not.toThrow();
35+
}
36+
});
37+
});

kasmvnc/main.tf

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
coder = {
6+
source = "coder/coder"
7+
version = ">= 0.12"
8+
}
9+
}
10+
}
11+
12+
variable "agent_id" {
13+
type = string
14+
description = "The ID of a Coder agent."
15+
}
16+
17+
variable "port" {
18+
type = number
19+
description = "The port to run KasmVNC on."
20+
default = 6800
21+
}
22+
23+
variable "kasm_version" {
24+
type = string
25+
description = "Version of KasmVNC to install."
26+
default = "1.3.2"
27+
}
28+
29+
variable "desktop_environment" {
30+
type = string
31+
description = "Specifies the desktop environment of the workspace. This should be pre-installed on the workspace."
32+
validation {
33+
condition = contains(["xfce", "kde", "gnome", "lxde", "lxqt"], var.desktop_environment)
34+
error_message = "Invalid desktop environment. Please specify a valid desktop environment."
35+
}
36+
}
37+
38+
resource "coder_script" "kasm_vnc" {
39+
agent_id = var.agent_id
40+
display_name = "KasmVNC"
41+
icon = "/icon/kasmvnc.svg"
42+
script = templatefile("${path.module}/run.sh", {
43+
PORT : var.port,
44+
DESKTOP_ENVIRONMENT : var.desktop_environment,
45+
VERSION : var.kasm_version
46+
})
47+
run_on_start = true
48+
}
49+
50+
resource "coder_app" "kasm_vnc" {
51+
agent_id = var.agent_id
52+
slug = "kasm-vnc"
53+
display_name = "kasmVNC"
54+
url = "http://localhost:${var.port}"
55+
icon = "/icon/kasmvnc.svg"
56+
subdomain = true
57+
share = "owner"
58+
healthcheck {
59+
url = "http://localhost:${var.port}/app"
60+
interval = 5
61+
threshold = 5
62+
}
63+
}

kasmvnc/run.sh

+161
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
#!/usr/bin/env bash
2+
3+
#!/bin/bash
4+
5+
# Function to check if vncserver is already installed
6+
check_installed() {
7+
if command -v vncserver &> /dev/null; then
8+
echo "vncserver is already installed."
9+
return 0 # Don't exit, just indicate it's installed
10+
else
11+
return 1 # Indicates not installed
12+
fi
13+
}
14+
15+
# Function to install kasmvncserver for debian-based distros
16+
install_deb() {
17+
local url=$1
18+
wget $url -O /tmp/kasmvncserver.deb
19+
sudo apt-get install --yes --no-install-recommends --no-install-suggests /tmp/kasmvncserver.deb
20+
sudo adduser $USER ssl-cert
21+
rm /tmp/kasmvncserver.deb
22+
}
23+
24+
# Function to install kasmvncserver for Oracle 8
25+
install_rpm_oracle8() {
26+
local url=$1
27+
wget $url -O /tmp/kasmvncserver.rpm
28+
sudo dnf config-manager --set-enabled ol8_codeready_builder
29+
sudo dnf install oracle-epel-release-el8 -y
30+
sudo dnf localinstall /tmp/kasmvncserver.rpm -y
31+
sudo usermod -aG kasmvnc-cert $USER
32+
rm /tmp/kasmvncserver.rpm
33+
}
34+
35+
# Function to install kasmvncserver for CentOS 7
36+
install_rpm_centos7() {
37+
local url=$1
38+
wget $url -O /tmp/kasmvncserver.rpm
39+
sudo yum install epel-release -y
40+
sudo yum install /tmp/kasmvncserver.rpm -y
41+
sudo usermod -aG kasmvnc-cert $USER
42+
rm /tmp/kasmvncserver.rpm
43+
}
44+
45+
# Function to install kasmvncserver for rpm-based distros
46+
install_rpm() {
47+
local url=$1
48+
wget $url -O /tmp/kasmvncserver.rpm
49+
sudo rpm -i /tmp/kasmvncserver.rpm
50+
rm /tmp/kasmvncserver.rpm
51+
}
52+
53+
# Function to install kasmvncserver for Alpine Linux
54+
install_alpine() {
55+
local url=$1
56+
wget $url -O /tmp/kasmvncserver.tgz
57+
tar -xzf /tmp/kasmvncserver.tgz -C /usr/local/bin/
58+
rm /tmp/kasmvncserver.tgz
59+
}
60+
61+
# Detect system information
62+
distro=$(grep "^ID=" /etc/os-release | awk -F= '{print $2}')
63+
version=$(grep "^VERSION_ID=" /etc/os-release | awk -F= '{print $2}' | tr -d '"')
64+
arch=$(uname -m)
65+
66+
echo "Detected Distribution: $distro"
67+
echo "Detected Version: $version"
68+
echo "Detected Architecture: $arch"
69+
70+
# Map arch to package arch
71+
if [[ "$arch" == "x86_64" ]]; then
72+
if [[ "$distro" == "ubuntu" || "$distro" == "debian" || "$distro" == "kali" ]]; then
73+
arch="amd64"
74+
else
75+
arch="x86_64"
76+
fi
77+
elif [[ "$arch" == "aarch64" || "$arch" == "arm64" ]]; then
78+
if [[ "$distro" == "ubuntu" || "$distro" == "debian" || "$distro" == "kali" ]]; then
79+
arch="arm64"
80+
else
81+
arch="aarch64"
82+
fi
83+
else
84+
echo "Unsupported architecture: $arch"
85+
exit 1
86+
fi
87+
88+
# Check if vncserver is installed, and install if not
89+
if ! check_installed; then
90+
case $distro in
91+
ubuntu | debian | kali)
92+
case $version in
93+
"20.04")
94+
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_focal_${VERSION}_$${arch}.deb"
95+
;;
96+
"22.04")
97+
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_jammy_${VERSION}_$${arch}.deb"
98+
;;
99+
"24.04")
100+
install_deb "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_noble_${VERSION}_$${arch}.deb"
101+
;;
102+
*)
103+
echo "Unsupported Ubuntu/Debian/Kali version: $${version}"
104+
exit 1
105+
;;
106+
esac
107+
;;
108+
oracle)
109+
if [[ "$version" == "8" ]]; then
110+
install_rpm_oracle8 "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_oracle_8_${VERSION}_$${arch}.rpm"
111+
else
112+
echo "Unsupported Oracle version: $${version}"
113+
exit 1
114+
fi
115+
;;
116+
centos)
117+
if [[ "$version" == "7" ]]; then
118+
install_rpm_centos7 "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_centos_core_${VERSION}_$${arch}.rpm"
119+
else
120+
install_rpm "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_centos_core_${VERSION}_$${arch}.rpm"
121+
fi
122+
;;
123+
alpine)
124+
if [[ "$version" == "3.17" || "$version" == "3.18" || "$version" == "3.19" || "$version" == "3.20" ]]; then
125+
install_alpine "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvnc.alpine_$${version}_$${arch}.tgz"
126+
else
127+
echo "Unsupported Alpine version: $${version}"
128+
exit 1
129+
fi
130+
;;
131+
fedora | opensuse)
132+
install_rpm "https://github.com/kasmtech/KasmVNC/releases/download/v${VERSION}/kasmvncserver_$${distro}_$${version}_${VERSION}_$${arch}.rpm"
133+
;;
134+
*)
135+
echo "Unsupported distribution: $${distro}"
136+
exit 1
137+
;;
138+
esac
139+
else
140+
echo "vncserver already installed. Skipping installation."
141+
fi
142+
143+
# Coder port-forwarding from dashboard only supports HTTP
144+
sudo bash -c "cat > /etc/kasmvnc/kasmvnc.yaml <<EOF
145+
network:
146+
protocol: http
147+
websocket_port: ${PORT}
148+
ssl:
149+
require_ssl: false
150+
udp:
151+
public_ip: 127.0.0.1
152+
EOF"
153+
154+
# This password is not used since we start the server without auth.
155+
# The server is protected via the Coder session token / tunnel
156+
# and does not listen publicly
157+
echo -e "password\npassword\n" | vncpasswd -wo -u $USER
158+
159+
# Start the server
160+
printf "🚀 Starting KasmVNC server...\n"
161+
sudo -u $USER bash -c "vncserver -select-de ${DESKTOP_ENVIRONMENT} -disableBasicAuth" > /tmp/kasmvncserver.log 2>&1 &

0 commit comments

Comments
 (0)