Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 43 additions & 24 deletions porting/kasmvnc/Dockerfile → apps/kasmvnc/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ghcr.io/trueforge-org/python-node:3.13.12 AS wwwstage
FROM ghcr.io/trueforge-org/python-node:3.14.4 AS wwwstage

ARG KASMWEB_RELEASE="46412d23aff1f45dffa83fafb04a683282c8db58"
USER root
Expand Down Expand Up @@ -26,7 +26,7 @@ RUN \
if [ -f index.html ]; then cp index.html vnc.html; elif [ -f vnc.html ]; then cp vnc.html index.html; fi && \
mkdir Downloads

FROM ghcr.io/trueforge-org/ubuntu:24.04 AS buildstage
FROM ghcr.io/trueforge-org/ubuntu:26.04 AS buildstage

ARG KASMVNC_COMMIT="e04731870baebd2784983fb48197a2416c7d3519"
USER root
Expand Down Expand Up @@ -74,6 +74,7 @@ RUN \
libssl-dev \
libpixman-1-dev \
libpam0g-dev \
libcrypt-dev \
procps \
passwd \
libwayland-dev \
Expand Down Expand Up @@ -105,11 +106,13 @@ RUN \
sed -i \
-e '/find_package(FLTK/s@^@#@' \
-e '/add_subdirectory(tests/s@^@#@' \
-e '/cmake_policy(SET CMP0022 OLD)/s@^@#@' \
CMakeLists.txt && \
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DBUILD_VIEWER:BOOL=OFF \
-DENABLE_GNUTLS:BOOL=OFF \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
. && \
make -j4 && \
echo "**** build xorg ****" && \
Expand Down Expand Up @@ -163,7 +166,7 @@ RUN \
cp /src/unix/xserver/hw/vnc/Xvnc.man man/man1/Xvnc.1 && \
mkdir lib && \
cd lib && \
ln -s /usr/lib/xorg/modules/dri dri && \
ln -s "/usr/lib/$(uname -m)-linux-gnu/dri" dri && \
cd /src && \
mkdir -p builder/www && \
cp -ax /www/* builder/www/ && \
Expand Down Expand Up @@ -214,7 +217,7 @@ RUN \
rm -f package-lock.json

# runtime stage
FROM ghcr.io/trueforge-org/ubuntu:24.04
FROM ghcr.io/trueforge-org/python-node:3.14.4

# set version label
ARG VERSION
Expand All @@ -235,8 +238,24 @@ ENV DISPLAY=:1 \

# copy over build output
COPY --from=nodebuilder /kclient /kclient
RUN rm -f /usr/local/man
COPY --from=buildstage /build-out/ /

# rebuild kclient native modules for current node version
RUN \
echo "**** rebuild kclient for runtime node version ****" && \
apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
python3 \
libpulse-dev && \
cd /kclient && \
npm rebuild && \
apt-get remove -y build-essential python3 libpulse-dev && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

RUN \
echo "**** install deps ****" && \
apt-get update && \
Expand All @@ -258,13 +277,13 @@ RUN \
libjpeg-turbo8 \
libnotify-bin \
libstdc++6 \
libwebp6 \
libwebp7 \
libxfont2 \
libxshmfence1 \
mcookie \
util-linux \
libgl1-mesa-dri \
libgbm1 \
libgl1-mesa-glx \
libgl1 \
mesa-vulkan-drivers \
nginx \
openbox \
Expand All @@ -284,21 +303,19 @@ RUN \
xserver-xorg-video-intel \
xserver-xorg-video-nouveau \
xserver-xorg-video-qxl \
xkbcomp \
xkeyboard-config \
xterm \
cups-pdf && \
echo "**** printer config ****" && \
sed -i \
"s:^#Out.*:Out /home/kasm-user/PDF:" \
/etc/cups/cups-pdf.conf && \
sed -i \
's/^SystemGroup .*/SystemGroup lpadmin root/' \
/etc/cups/cups-files.conf && \
xkb-data \
xterm && \
echo "**** filesystem setup ****" && \
ln -s /usr/local/share/kasmvnc /usr/share/kasmvnc && \
ln -s /usr/local/etc/kasmvnc /etc/kasmvnc && \
ln -s /usr/local/lib/kasmvnc /usr/lib/kasmvncserver && \
mkdir -p /var/lib/nginx/body /var/lib/nginx/fastcgi /var/lib/nginx/proxy /var/lib/nginx/scgi /var/lib/nginx/uwsgi && \
chown -R apps:apps /var/lib/nginx && \
mkdir -p /etc/nginx/conf.d && \
chown -R apps:apps /etc/nginx/conf.d && \
mkdir -p /var/log/nginx && \
chown -R apps:apps /var/log/nginx && \
sed -i 's|pid /run/nginx.pid;|pid /tmp/nginx.pid;|g' /etc/nginx/nginx.conf && \
echo "**** openbox tweaks ****" && \
sed -i \
-e 's/NLIMC/NLMC/g' \
Expand All @@ -308,20 +325,21 @@ RUN \
echo "**** user perms ****" && \
echo "apps:apps" | chpasswd && \
usermod -s /bin/bash apps && \
groupadd wheel && \
echo '%wheel ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/wheel && \
adduser apps wheel && \
echo "**** proot-apps ****" && \
mkdir /proot-apps/ && \
PAPPS_RELEASE=$(curl -sX GET "https://api.github.com/repos/linuxserver/proot-apps/releases/latest" \
(PAPPS_RELEASE=$(curl -sX GET "https://api.github.com/repos/linuxserver/proot-apps/releases/latest" \
| awk '/tag_name/{print $4;exit}' FS='[""]') && \
curl -L https://github.com/linuxserver/proot-apps/releases/download/${PAPPS_RELEASE}/proot-apps-$TARGETARCH.tar.gz \
| tar -xzf - -C /proot-apps/ && \
echo "${PAPPS_RELEASE}" > /proot-apps/pversion && \
echo "${PAPPS_RELEASE}" > /proot-apps/pversion) || echo "proot-apps download failed, skipping" && \
echo "**** kasm support ****" && \
useradd \
(id kasm-user >/dev/null 2>&1 || useradd \
-u 1000 -U \
-d /home/kasm-user \
-s /bin/bash kasm-user && \
-s /bin/bash kasm-user) && \
echo "kasm-user:kasm" | chpasswd && \
adduser kasm-user wheel && \
mkdir -p /home/kasm-user && \
Expand All @@ -347,8 +365,8 @@ RUN \
usermod -aG docker apps && \
echo 'hosts: files dns' > /etc/nsswitch.conf && \
echo "**** theme ****" && \
curl -s https://raw.githubusercontent.com/thelamer/lang-stash/master/theme.tar.gz \
| tar xzvf - -C /usr/share/themes/Clearlooks/openbox-3/ && \
(curl -s https://raw.githubusercontent.com/thelamer/lang-stash/master/theme.tar.gz \
| tar xzvf - -C /usr/share/themes/Clearlooks/openbox-3/) || echo "theme download failed, skipping" && \
echo "**** cleanup ****" && \
rm -rf \
/tmp/* && \
Expand All @@ -357,6 +375,7 @@ RUN \

# add local files
USER apps
COPY --chmod=0755 ./root/ /
COPY --chmod=0755 . /


Expand Down
5 changes: 5 additions & 0 deletions apps/kasmvnc/container-test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/trueforge-org/forgetool/refs/heads/main/pkg/containers/test/container-test.schema.json

tcp:
- port: '3000'
- port: '3001'
Comment thread
Crow-Control marked this conversation as resolved.
File renamed without changes.
File renamed without changes.
32 changes: 32 additions & 0 deletions apps/kasmvnc/settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/trueforge-org/forgetool/refs/heads/main/schemas/container-settings.schema.json
schema_version: 1
upstream_env_url: "https://github.com/kasmtech/KasmVNC"
ports:
- port: 3000
protocol: tcp
required: false
- port: 3001
protocol: tcp
required: false
env:
- name: TZ
default: "Etc/UTC"
required: false
- name: CUSTOM_PORT
default: "3000"
required: false
- name: CUSTOM_HTTPS_PORT
default: "3001"
required: false
- name: CUSTOM_USER
default: "apps"
required: false
- name: PASSWORD
default: ""
required: false
- name: SUBFOLDER
default: "/"
required: false
Comment thread
Crow-Control marked this conversation as resolved.
volumes:
- path: /config
required: true
167 changes: 167 additions & 0 deletions apps/kasmvnc/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#!/usr/bin/env bash

# default file copies first run
if [[ ! -f /config/.config/openbox/autostart ]]; then
mkdir -p /config/.config/openbox
cp /defaults/autostart /config/.config/openbox/autostart
chown -R apps:apps /config/.config/openbox
fi
if [[ ! -f /config/.config/openbox/menu.xml ]]; then
mkdir -p /config/.config/openbox
cp /defaults/menu.xml /config/.config/openbox/menu.xml
chown -R apps:apps /config/.config
fi

# XDG Home
export XDG_RUNTIME_DIR="${HOME}/.XDG"
if [ ! -d "${XDG_RUNTIME_DIR}" ]; then
mkdir -p "${XDG_RUNTIME_DIR}"
chown apps:apps "${XDG_RUNTIME_DIR}"
fi

# Create cache directory for openbox
if [ ! -d "/config/.cache/openbox" ]; then
mkdir -p "/config/.cache/openbox"
chown -R apps:apps "/config/.cache"
fi

# Locale Support
if [ ! -z ${LC_ALL+x} ]; then
export LANGUAGE="${LC_ALL%.UTF-8}"
export LANG="${LC_ALL}"
fi

# Remove window borders (write to /tmp since /etc is read-only with --read-only)
if [[ ! -z ${NO_DECOR+x} ]] && [[ ! -f /tmp/decorlock ]]; then
if [ -w /etc/xdg/openbox/rc.xml ]; then
sed -i \
's|</applications>| <application class="*"> <decor>no</decor> </application>\n</applications>|' \
/etc/xdg/openbox/rc.xml
fi
touch /tmp/decorlock
fi

# Fullscreen everything in openbox unless the user explicitly disables it
if [[ ! -z ${NO_FULL+x} ]] && [[ ! -f /tmp/fulllock ]]; then
if [ -w /etc/xdg/openbox/rc.xml ]; then
sed -i \
'/<application class="\*"><maximized>yes<\/maximized><\/application>/d' \
/etc/xdg/openbox/rc.xml
fi
touch /tmp/fulllock
fi

# Add proot-apps if available
if [ -d /proot-apps ] && [ "$(ls -A /proot-apps 2>/dev/null)" ]; then
if [ ! -f "${HOME}/.local/bin/proot-apps" ]; then
mkdir -p ${HOME}/.local/bin/
cp /proot-apps/* ${HOME}/.local/bin/ 2>/dev/null || true
echo 'export PATH="$HOME/.local/bin:$PATH"' >> $HOME/.bashrc
chown -R apps:apps ${HOME}/.local/ ${HOME}/.bashrc 2>/dev/null || true
elif [ -f /proot-apps/pversion ] && [ -f ${HOME}/.local/bin/pversion ] && ! diff -q /proot-apps/pversion ${HOME}/.local/bin/pversion > /dev/null 2>&1; then
cp /proot-apps/* ${HOME}/.local/bin/ 2>/dev/null || true
chown -R apps:apps ${HOME}/.local/bin/ 2>/dev/null || true
fi
fi

# nginx Path - use /tmp since we may not be able to write to /etc/nginx
NGINX_CONFIG=/tmp/nginx-default.conf

# user passed env vars
CPORT="${CUSTOM_PORT:-3000}"
CHPORT="${CUSTOM_HTTPS_PORT:-3001}"
CUSER="${CUSTOM_USER:-apps}"
SFOLDER="${SUBFOLDER:-/}"

# create self signed cert
if [ ! -f "/config/ssl/cert.pem" ]; then
mkdir -p /config/ssl
openssl req -new -x509 \
-days 3650 -nodes \
-out /config/ssl/cert.pem \
-keyout /config/ssl/cert.key \
-subj "/C=US/ST=CA/L=Carlsbad/O=Linuxserver.io/OU=LSIO Server/CN=*"
chmod 600 /config/ssl/cert.key
chown -R apps:apps /config/ssl
fi

# modify nginx config
cp /defaults/default.conf ${NGINX_CONFIG}
sed -i "s/3000/$CPORT/g" ${NGINX_CONFIG}
sed -i "s/3001/$CHPORT/g" ${NGINX_CONFIG}
sed -i "s|SUBFOLDER|$SFOLDER|g" ${NGINX_CONFIG}
if [ ! -z ${DISABLE_IPV6+x} ]; then
sed -i '/listen \[::\]/d' ${NGINX_CONFIG}
fi
if [ ! -z ${PASSWORD+x} ]; then
mkdir -p /tmp/nginx
printf "${CUSER}:$(openssl passwd -apr1 ${PASSWORD})\n" > /tmp/nginx/.htpasswd
sed -i 's/#//g' ${NGINX_CONFIG}
sed -i "s|/etc/nginx/.htpasswd|/tmp/nginx/.htpasswd|g" ${NGINX_CONFIG}
fi

# Copy nginx config to the right place if writable
if [ -w /etc/nginx/conf.d/ ]; then
cp ${NGINX_CONFIG} /etc/nginx/conf.d/default.conf
elif [ -d /etc/nginx/http.d/ ] && [ -w /etc/nginx/http.d/ ]; then
cp ${NGINX_CONFIG} /etc/nginx/http.d/default.conf
fi

# Set DISPLAY for X server
export DISPLAY=:1

# Start PulseAudio in the background
/usr/bin/pulseaudio \
--log-level=0 \
--log-target=stderr \
--exit-idle-time=-1 > /dev/null 2>&1 &

# Start Xvnc server in background
# Pass gpu flags if mounted
HW3D=""
if ls /dev/dri/renderD* 1> /dev/null 2>&1 && [ -z ${DISABLE_DRI+x} ] && ! which nvidia-smi > /dev/null 2>&1; then
HW3D="-hw3d"
fi
DRINODE="${DRINODE:-/dev/dri/renderD128}"

/usr/local/bin/Xvnc $DISPLAY \
${HW3D} \
-PublicIP 127.0.0.1 \
-drinode ${DRINODE} \
-disableBasicAuth \
-SecurityTypes None \
-AlwaysShared \
-http-header Cross-Origin-Embedder-Policy=require-corp \
-http-header Cross-Origin-Opener-Policy=same-origin \
-geometry 1024x768 \
-sslOnly 0 \
-RectThreads 0 \
-websocketPort 6901 \
-interface 0.0.0.0 \
-Log *:stdout:10 &

# Wait for X server to be ready
sleep 2

# Start window manager
cd $HOME
/bin/bash /defaults/startwm.sh &

# Wait for window manager to start
sleep 2

# Start nginx (kill any zombie processes first)
if pgrep -f "[n]ginx:" >/dev/null; then
echo "Zombie nginx processes detected, cleaning up"
pkill -ef '[n]ginx:' 2>/dev/null || true
sleep 1
fi

# Start nginx in background
if [ -f /etc/nginx/conf.d/default.conf ] || [ -f /etc/nginx/http.d/default.conf ] || [ -f ${NGINX_CONFIG} ]; then
/usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf &
fi

# Start kclient Node.js wrapper in foreground (this becomes our main process)
cd /kclient
exec node index.js
Loading
Loading