Use Case:
Imagine a virtual classroom with students using Chromebooks, iPads, and other types of computers, connecting over the Internet. How would a teacher standardize on the tool sets for students have access toward similar applications? Moreover, how would that same teacher monitor each student’s screen with relative ease? Here is one possible solution that utilizes freely available GPL software to serve this purpose.

Limitations:

  • Update 6/31/20: I haven’t figured out why users using VNC sessions couldn’t access normal UI items, such as smb:///, sftp:///, etc. Hence, these instructions should be considered nerd entertainment. A better method shall follow when I have another long weekend.
  • Currently, TightVNCServer doesn’t forward sound. Hence, any requirement for audio will not be fulfilled with this technology stack. Windows Terminal Service would meet that requirement better, although there are other caveats with that toolset as well.
  • Microsoft applications may not be available on Linux (e.g. Word, Excel, Powerpoint). Open source alternatives are available and included in Ubuntu/Lubuntu.
  • Security isn’t as fool-proof with this setup as one user can browse toward another user’s home directory to a limited extent. The assumption with this setup is that users are behaving and wouldn’t attempt to circumvent the system. Knowledgeable hackers have methods of escalating access levels once normal user access is gained. Instead of deploy techniques such as ‘jail-shell’ and removing read-access to certain directories, it may be easier to control access by creating docker containers for each user. That is the topic of another document.
########################### Task 1: Install Lubuntu ###########################
# Installing the OS is rather straight-forward. It's in another article.
# At this time, we shall only show these
# commands to install commonly programs to make the desktops more useful
 
Follow this list: https://blog.kimconnect.com/useful-ubuntu-settings-for-vnc/
################# Step 2: Install & Configure TightVNC Server #################
 
# Install tightVncServer with LXDE (desktop environment), autocutsel (allowing copy/paste through browser)
sudo apt -y install tightvncserver xfonts-base xorg lxde-core autocutsel
 
# Initialize VNC server for the first time to create the config file
vncserver :1
vncserver -kill :1
 
# Configure VNC config file
# vim /home/$(whoami)/.vnc/xstartup
# Note: as of this writing, 
cat <<EOF > /home/$(whoami)/.vnc/xstartup
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
xrdb $HOME/.Xresources
xsetroot -solid grey
export XKL_XMODMAP_DISABLE=1
 
#openbox &
#/usr/bin/lxsession -s Lubuntu &
# Error:
# main.vala:103 DE is (null)
# main.vala:113 No desktop environment set, fallback to LXDE
# Xlib: extension "RANDR" missing on display :1
# main.vala.134: log directory /home/username/.cache/lxsession/Lubuntu
# main.vala.135: log path: /home/username/.cache/lxsession/Lubuntu/run.log
 
# Requires: sudo apt install xfce4 xfce4-goodies
# As of 5/23/20, the packages above are incomplete
#startxfce4 &
 
# Use the light version of desktop environment
# Requires: sudo apt install xorg lxde-core
lxterminal &
/usr/bin/lxsession -s LXDE &
EOF
sudo chmod +x /home/$(whoami)/.vnc/xstartup
 
# Configure firewall to allow port 5901
sudo ufw allow from any to any port 5901 proto tcp
 
# Restart session 1
sessionId=1
vncserver -kill :$sessionId
rm -f /tmp/.X$sessionId-lock
rm -f /tmp/.X11-unix/X$sessionId
vncserver :$sessionId -geometry 1920x1080 -depth 16 -pixelformat rgb565
####################### Step 3: Install NoVNC & Websockify ########################
# Include packages
sudo apt -y install novnc websockify python-numpy
 
# Generate Cert - this cert can be substituted with a public cert
sudo openssl req -x509 -nodes -newkey rsa:2048 -keyout /etc/ssl/novnc.pem -out /etc/ssl/novnc.pem -days 365
sudo chmod 644 /etc/ssl/novnc.pem
 
# Setup socket to localhost
sessionId=1
portPrefix=908 # This would enable connections to port 9081, 9082, etc
websockify -D --web=/usr/share/novnc/ --cert=/etc/ssl/novnc.pem $portPrefix$sessionId localhost:590$sessionId
 
# Restart VNC session
sessionId=1
vncserver -kill :$sessionId
rm -f /tmp/.X$sessionId-lock
rm -f /tmp/.X11-unix/X$sessionId
vncserver :$sessionId -geometry 1920x1080 -depth 15 -pixelformat rgb565
########################### Step 4: Add Session X+1 ############################
# create new user
user=rambo
password=nintendopower
useradd -m -d /home/$user/ -s /bin/bash $user -p $(openssl passwd -1 $password)
 
# Run-as $user to initialize session 2 config file
sessionId=2
sudo -H -u $user bash -c "vncserver :$sessionId"
# Set password of first-time initialized session
# rambo@webserver01:/home/root$ sessionId=2
# rambo@webserver01:/home/root$ vncserver :$sessionId
# You will require a password to access your desktops.
# Password:
# Warning: password truncated to the length of 8.
# Verify:
# Would you like to enter a view-only password (y/n)? n
# xauth:  file /home/rambo/.Xauthority does not exist
# New 'X' desktop is webserver01:2
# Creating default startup script /home/rambo/.vnc/xstartup
# Starting applications specified in /home/rambo/.vnc/xstartup
# Log file is /home/rambo/.vnc/webserver01:2.log
 
# Pre-empt this error
# xrdb: No such file or directory.
# xrdb: Can't open file '/home/<user>/.Xresources'
touch /home/$user/.Xresources
 
# Configure VNC config file
# vim /home/$user/.vnc/xstartup
sudo -H -u $user bash -c "cat <<EOF > /home/$user/.vnc/xstartup
#!/bin/sh
# Reset screen-specific values
# Uncomment the following two lines for normal desktops (for better performance)
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
 
# Instructing VNC’s GUI framework to read the server user’s .Xresources file.
# .Xresources is where a user can make changes to certain settings of the graphical desktop
# such as terminal colors, cursor themes, and font rendering.
xrdb $HOME/.Xresources
 
xsetroot -solid grey
export XKL_XMODMAP_DISABLE=1
 
# Desktop option 1: lighter
# Requires: sudo apt install xorg lxde-core
lxterminal &
/usr/bin/lxsession -s LXDE &
EOF"
 
# Set config file as readable
sudo -H -u $user bash -c "chmod +x /home/$user/.vnc/xstartup"
 
# Enable the port through the firewall. Must run as a sudoer
sudo ufw allow from any to any port 590$sessionId proto tcp
 
# Start new VNC session
sessionId=2
sudo -H -u $user bash -c "vncserver -kill :$sessionId"
sudo rm -f /tmp/.X$sessionId-lock
sudo rm -f /tmp/.X11-unix/X$sessionId
sudo -H -u $user bash -c "vncserver :$sessionId -geometry 1920x1080 -depth 15 -pixelformat rgb565"
 
# Create new web socker
sudo -H -u $user bash -c "websockify -D --web=/usr/share/novnc/ --cert=/etc/ssl/novnc.pem 908$sessionId localhost:590$sessionId"
###################### Step 5: Creating startup script #######################

# set startup script name
startupScript=/ect/init.d/startVncSessions.sh

# Option 1: Manually set users and session IDs
cat <<EOF >  $startupScript
#!/bin/bash
# /ect/init.d/startVncSessions.sh
# Manually set users and session IDs
declare -A users=(
	["bruce"]=1
	["mike"]=2
	["chuck"]=3
	["rock"]=4
	["tank"]=5
	)

function startSession() {
	username=$1
	sessionId=$2
	sudo -H -u $username bash -c "vncserver -kill :$sessionId"	
	sudo rm -f /tmp/.X$sessionId-lock
	sudo rm -f /tmp/.X11-unix/X$sessionId
	sudo -H -u $username bash -c "vncserver :$sessionId -geometry 1920x1080 -depth 15 -pixelformat rgb565"
	sudo -H -u $username bash -c "websockify -D --web=/usr/share/novnc/ --cert=/etc/ssl/novnc.pem 908$sessionId localhost:590$sessionId"
}

for k in "${!users[@]}"
do
	username=$k
	sessionId=${users[$k]}
	#printf "%s\n" "key: $username value: $sessionId"
	startSession $username $sessionId
done
EOF

# Option 2: obtain a list of users and automatically create a session for each user
cat <<EOF >  $startupScript
#!/bin/bash
# /ect/init.d/startVncSessions.sh
users=$(eval getent passwd {$(awk '/^UID_MIN/ {print $2}' /etc/login.defs)..$(awk '/^UID_MAX/ {print $2}' /etc/login.defs)} | cut -d: -f1)
# converting the string into an associated array with integer keys (as opposed to -A for string keys, aka dictionary)
declare -a arr=( $(echo $users) ) 
function startSession() {
	username=$1
	sessionId=$2
	sudo -H -u $username bash -c "vncserver -kill :$sessionId"	
	sudo rm -f /tmp/.X$sessionId-lock
	sudo rm -f /tmp/.X11-unix/X$sessionId
	sudo -H -u $username bash -c "vncserver :$sessionId -geometry 1920x1080 -depth 15 -pixelformat rgb565"
	sudo -H -u $username bash -c "websockify -D --web=/usr/share/novnc/ --cert=/etc/ssl/novnc.pem 908$sessionId localhost:590$sessionId"
}
for ((i = 0; i < ${#arr[@]}; i++)); do
	username=${arr[$i]}
	# this is the funky way to force bash to perform operations on integers
	sessionId=$(($i+1))	
	echo "$username : $sessionId"
	startSession $username $sessionId
done

# Set script to run at startup
chmod a+x $startupScript
chmod 777 $startupScript # optional: this is to give everyone full access, including editing rights

crontab -e
### add this line ###
@reboot /bin/bash -c '/root/scripts/startVncSessions.sh' &
#####################################################################
########################### Troubleshooting ########################### 
 
# Error: Can't find file /home/rambo/.vnc/webserver01:1.pid
# You'll have to kill the Xtightvnc process manually
# locate pid of vnc services
# Solution: remove the session lock files as shown several times above
 
# Check a user's active session 
username=rambo
ps -ef | grep vnc | grep $username
 
# Kill an active session (as precursor to restarting it)
pidNumber=80000 # Get this info from the output above
kill $pidNumber
 
# Reset VNC password (as precursor to restarting session)
sudo rm -f /home/$user/.vnc/passwd
 
# Enable a range of ports through the firewall
sessionId=3
sudo ufw allow from any to any port 590$sessionId proto tcp
sudo ufw allow from any to any port 908$sessionId proto tcp
 
# Add multiple users
sudo su # runas root
users=(rambo bruce mike)
password=kungfufighting
for user in ${users[@]}; do useradd -m -d /home/$user/ -s /bin/bash $user -p $(openssl passwd -1 $password); done
 
# Change linux password (separate from VNC password)
user=rambo
passwd $user
 
# View users
tail -l /etc/passwd
 
# Delete user
user=rambo
sudo deluser $user
 
# Restart someone's session
username=chuck
sessionId=4
sudo -H -u $username bash -c "vncserver -kill :$sessionId"
sudo rm -f /tmp/.X$sessionId-lock
sudo rm -f /tmp/.X11-unix/X$sessionId
sudo -H -u $username bash -c "vncserver :$sessionId -geometry 1920x1080 -depth 15 -pixelformat rgb565"