Kasm Workspaces with Multiple Printers

Kasm Workspaces with Multiple Printers

The standard Kasm Workspaces solution for printers allows for pass-through access to any printer recognized by the underlying Kasm Agent server or remote Windows server. Reference our documentation on the supported Printer Redirection and group settings for print access (eg: “allow_kasm_printing”).

Kasm Printer Redirection allows for the mapping of a single printer per each workspace session. There are some use cases where it is desirable to allow a user to select from multiple printer options. This can be achieved by directly making the workspace aware of the specific print drivers and creating connections to the printers from within the session.

This article describes a method for allowing a workspace session to access multiple custom printer options. The overall goal of this method is to allow us to use the “lpadmin” command to register a printer using the driver defined by parameter “-m” and the label defined with parameter “-p”. Creating a custom docker image could be omitted by using an existing print driver or by using the file mapping to also install the print device driver.

WARNING - This method bypasses Kasm’s DLP control over access to the printers.

 


 Instructions - Custom Docker Images

This instruction describes a method for allowing a docker workspace session to access multiple custom printer options by first building a custom docker image with the required printer drivers, then using file mapping to set the custom printer options.

For this example we will use a Kasm Ubuntu Desktop source image. However, this similar method can be used for any of the Kasm source docker images.

 

Build the custom docker image

  1. Clone the kasm workspaces github repository.

    1. git clone https://github.com/kasmtech/workspaces-images.git
  2. Change directory into the repository.

    1. cd workspaces-images/
  3. Copy the docker file “dockerfile-kasm-ubuntu-jammy-desktop” to a new file with the suggested named “dockerfile-kasm-multiple-printers“.

    1. cp dockerfile-kasm-ubuntu-jammy-desktop dockerfile-kasm-multiple-printers
  4. (Optional) Remove all docker files except “dockerfile-kasm-multiple-printers” to clean the directory.

    1. ls | grep -v dockerfile-kasm-multiple-printers | grep dockerfile-kasm | xargs rm -f --
  5. Locate the “# Run installations” section or the custom coding section.

    1. For example the “# Run installations” section is near the end of the file and has a block of code similar to the following:

      1. # Run installations RUN \   for SCRIPT in $INST_SCRIPTS; do \     bash ${INST_DIR}${SCRIPT} || exit 1; \   done && \   $STARTUPDIR/set_user_permission.sh $HOME && \   rm -f /etc/X11/xinit/Xclients && \   chown 1000:0 $HOME && \   mkdir -p /home/kasm-user && \   chown -R 1000:0 /home/kasm-user && \   rm -Rf ${INST_DIR}
    2. For some custom dockerfiles the “Custom code” section is in the middle of the file and looks like the example below:

      1. ######### Customize Container Here ########### RUN touch $HOME/Desktop/hello.txt ######### End Customizations ###########
  6. If your dockerfile has a “# Run installations” section break the section into three parts: (1) # Run installation, (2) # Custom code, and (3) # Post-installation. The “Run installation” section will include a RUN command and the for loop. The “Custom code” section will be a placeholder for the addition of custom code in future steps. The “Post-installation” section will be a RUN command and the remainder of the original code block. An example is provided below.

    1. Example - Before changes:

      1. # Run installations RUN \   for SCRIPT in $INST_SCRIPTS; do \     bash ${INST_DIR}${SCRIPT} || exit 1; \   done && \   $STARTUPDIR/set_user_permission.sh $HOME && \   rm -f /etc/X11/xinit/Xclients && \   chown 1000:0 $HOME && \   mkdir -p /home/kasm-user && \   chown -R 1000:0 /home/kasm-user && \   rm -Rf ${INST_DIR}
    2. Example - After changes:

      1. # Run installations RUN \   for SCRIPT in $INST_SCRIPTS; do \     bash ${INST_DIR}${SCRIPT} || exit 1; \   done ######### Customize Container Here ########### ######### End Customizations ########### # Post-installation RUN \ $STARTUPDIR/set_user_permission.sh $HOME && \   rm -f /etc/X11/xinit/Xclients && \   chown 1000:0 $HOME && \   mkdir -p /home/kasm-user && \   chown -R 1000:0 /home/kasm-user && \   rm -Rf ${INST_DIR}
  7. Test build the dockerfile after making the initial changes, but prior to adding any new custom code. In the example build command we are using an image name “kasmweb/multiple-printers” with a tag matching both the kasm version intended for this image and the base tag version used in the dockerfile’s FROM command.

    1. sudo docker build -t kasmweb/multiple-printers:1.17.0 -f dockerfile-kasm-multiple-printers .
    2. The image should successfully build without errors.

  8. In the “custom code” section install the ubuntu linux printer drivers provided by your hardware manufacturer for your model of printer hardware. In many instances linux printer drivers are provided with a manual installation method. This is often the preferred non-interactive method of installation of linux drivers.

    1. Example using the print device driver an HP Deskjet 3600:

      1. The original instructions for this printer driver are located at this link (https://developers.hp.com/hp-linux-imaging-and-printing/install/manual/distros/ubuntu ). The official instructions have been modified to workaround the dockerfile buildx method of running commands as different users. In the example the commands requiring root permissions, then a non-root user, and finally a root user again are separated. Additionally ENV variables are used to ensure consistency of important variables. The “KASM_USER“ and “ROOT_USER“ ENV variables were added to the top of the docker file immediately after the “FROM” command because this was more appropriate for good coding practice. There is also a modification at the bottom of the dockerfile to replace the normal setting of USER prior to the end of the file.

      2. Custom code section - Installs the HP printer drivers for Ubuntu 20.04 and above:

        1. ######### Customize Container Here ########### ENV HPLIP_DRIVER_INSTALLER=/tmp/hplip.tar.gz ENV HPLIP_TEMP_DIR=/tmp/hplip RUN mkdir -p ${HPLIP_TEMP_DIR} RUN \   curl -L -o ${HPLIP_DRIVER_INSTALLER} "http://prdownloads.sourceforge.net/hplip/hplip-3.22.6.tar.gz" && \   tar -xzf ${HPLIP_DRIVER_INSTALLER} -C ${HPLIP_TEMP_DIR} --strip-components=1 && \   rm ${HPLIP_DRIVER_INSTALLER} && \   chown -R ${KASM_USER}:${KASM_USER} ${HPLIP_TEMP_DIR} && \   apt-get update -y && \   apt-get install -y --assume-yes libcups2 cups libcups2-dev cups-bsd cups-client avahi-utils libavahi-client-dev libavahi-core-dev libavahi-common-dev libcupsimage2-dev libdbus-1-dev build-essential gtk2-engines-pixbuf ghostscript openssl libjpeg-dev libatk-adaptor libgail-common libsnmp-dev snmp-mibs-downloader libtool libtool-bin libusb-1.0-0-dev libusb-0.1-4 wget policykit-1 policykit-1-gnome automake1.11 python3-dbus.mainloop.pyqt5 python3-reportlab python3-notify2 python3-pyqt5 python3-dbus python3-gi python3-lxml python3-dev python3-pil python-is-python3 libsane libsane-dev sane-utils xsane && \   cd ${HPLIP_TEMP_DIR} && \   ./configure --with-hpppddir=/usr/share/ppd/HP --libdir=/usr/lib64 --prefix=/usr --enable-network-build --enable-scan-build --enable-fax-build --enable-dbus-build --disable-qt4 --enable-qt5 --disable-class-driver --enable-doc-build --disable-policykit --disable-libusb01_build --disable-udev_sysfs_rules --enable-hpcups-install --disable-hpijs-install --disable-foomatic-ppd-install --disable-foomatic-drv-install --disable-cups-ppd-install --enable-cups-drv-install --enable-apparmor_build --enable-hplip_testing_flag && \   chown -R ${KASM_USER}:${KASM_USER} ${HPLIP_TEMP_DIR} USER ${KASM_USER} RUN \   cd ${HPLIP_TEMP_DIR} && \   make USER ${ROOT_USER} RUN \   cd ${HPLIP_TEMP_DIR} && \   make install && \   usermod -a -G lp kasm-user ######### End Customizations ###########
      3. Top of the dockerfile with the “KASM_USER“ and “ROOT_USER“ ENV variables:

        1. Before:

          1. ARG BASE_TAG="1.17.0-rolling-daily" ARG BASE_IMAGE="core-ubuntu-jammy" FROM kasmweb/$BASE_IMAGE:$BASE_TAG USER root
        2. After:

          1. ARG BASE_TAG="1.17.0-rolling-daily" ARG BASE_IMAGE="core-ubuntu-jammy" FROM kasmweb/$BASE_IMAGE:$BASE_TAG ARG KASM_USER="1000" ARG ROOT_USER="root" USER ${ROOT_USER}
      4. Bottom of the dockerfile with the “KASM_USER“ ENV variable in the “# Userspace Runtime“ section:

        1. Before:

          1. # Userspace Runtime ENV HOME /home/kasm-user WORKDIR $HOME USER 1000 CMD ["--tail-log"]
        2. After:

          1. # Userspace Runtime ENV HOME /home/kasm-user WORKDIR $HOME USER ${KASM_USER} CMD ["--tail-log"]
    2. The full dockerfile for the example using HP Deskjet 3600 is below:

      1. ARG BASE_TAG="1.17.0-rolling-daily" ARG BASE_IMAGE="core-ubuntu-jammy" FROM kasmweb/$BASE_IMAGE:$BASE_TAG ARG KASM_USER="1000" ARG ROOT_USER="root" USER ${ROOT_USER} ENV HOME /home/kasm-default-profile ENV STARTUPDIR /dockerstartup WORKDIR $HOME ### Envrionment config ENV DEBIAN_FRONTEND=noninteractive \ SKIP_CLEAN=true \ KASM_RX_HOME=$STARTUPDIR/kasmrx \ DONT_PROMPT_WSL_INSTALL="No_Prompt_please" \ INST_DIR=$STARTUPDIR/install \ INST_SCRIPTS="/ubuntu/install/tools/install_tools_deluxe.sh \ /ubuntu/install/misc/install_tools.sh \ /ubuntu/install/chrome/install_chrome.sh \ /ubuntu/install/chromium/install_chromium.sh \ /ubuntu/install/firefox/install_firefox.sh \ /ubuntu/install/sublime_text/install_sublime_text.sh \ /ubuntu/install/vs_code/install_vs_code.sh \ /ubuntu/install/nextcloud/install_nextcloud.sh \ /ubuntu/install/remmina/install_remmina.sh \ /ubuntu/install/only_office/install_only_office.sh \ /ubuntu/install/signal/install_signal.sh \ /ubuntu/install/gimp/install_gimp.sh \ /ubuntu/install/zoom/install_zoom.sh \ /ubuntu/install/obs/install_obs.sh \ /ubuntu/install/ansible/install_ansible.sh \ /ubuntu/install/terraform/install_terraform.sh \ /ubuntu/install/telegram/install_telegram.sh \ /ubuntu/install/thunderbird/install_thunderbird.sh \ /ubuntu/install/slack/install_slack.sh \ /ubuntu/install/gamepad_utils/install_gamepad_utils.sh \ /ubuntu/install/cleanup/cleanup.sh" # Copy install scripts COPY ./src/ $INST_DIR # Run installations RUN \ for SCRIPT in $INST_SCRIPTS; do \ bash ${INST_DIR}${SCRIPT} || exit 1; \ done ######### Customize Container Here ########### ENV HPLIP_DRIVER_INSTALLER=/tmp/hplip.tar.gz ENV HPLIP_TEMP_DIR=/tmp/hplip RUN mkdir -p ${HPLIP_TEMP_DIR} RUN \ curl -L -o ${HPLIP_DRIVER_INSTALLER} "http://prdownloads.sourceforge.net/hplip/hplip-3.22.6.tar.gz" && \ tar -xzf ${HPLIP_DRIVER_INSTALLER} -C ${HPLIP_TEMP_DIR} --strip-components=1 && \ rm ${HPLIP_DRIVER_INSTALLER} && \ chown -R ${KASM_USER}:${KASM_USER} ${HPLIP_TEMP_DIR} && \ apt-get update -y && \ apt-get install -y --assume-yes libcups2 cups libcups2-dev cups-bsd cups-client avahi-utils libavahi-client-dev libavahi-core-dev libavahi-common-dev libcupsimage2-dev libdbus-1-dev build-essential gtk2-engines-pixbuf ghostscript openssl libjpeg-dev libatk-adaptor libgail-common libsnmp-dev snmp-mibs-downloader libtool libtool-bin libusb-1.0-0-dev libusb-0.1-4 wget policykit-1 policykit-1-gnome automake1.11 python3-dbus.mainloop.pyqt5 python3-reportlab python3-notify2 python3-pyqt5 python3-dbus python3-gi python3-lxml python3-dev python3-pil python-is-python3 libsane libsane-dev sane-utils xsane && \ cd ${HPLIP_TEMP_DIR} && \ ./configure --with-hpppddir=/usr/share/ppd/HP --libdir=/usr/lib64 --prefix=/usr --enable-network-build --enable-scan-build --enable-fax-build --enable-dbus-build --disable-qt4 --enable-qt5 --disable-class-driver --enable-doc-build --disable-policykit --disable-libusb01_build --disable-udev_sysfs_rules --enable-hpcups-install --disable-hpijs-install --disable-foomatic-ppd-install --disable-foomatic-drv-install --disable-cups-ppd-install --enable-cups-drv-install --enable-apparmor_build --enable-hplip_testing_flag && \ chown -R ${KASM_USER}:${KASM_USER} ${HPLIP_TEMP_DIR} USER ${KASM_USER} RUN \ cd ${HPLIP_TEMP_DIR} && \ make USER ${ROOT_USER} RUN \ cd ${HPLIP_TEMP_DIR} && \ make install && \ usermod -a -G lp kasm-user ######### End Customizations ########### RUN \ $STARTUPDIR/set_user_permission.sh $HOME && \ rm -f /etc/X11/xinit/Xclients && \ chown 1000:0 $HOME && \ mkdir -p /home/kasm-user && \ chown -R 1000:0 /home/kasm-user && \ rm -Rf ${INST_DIR} # Userspace Runtime ENV HOME /home/kasm-user WORKDIR $HOME USER ${KASM_USER} CMD ["--tail-log"]
  9. Build the dockerfile.

    1. sudo docker build -t kasmweb/multiple-printers:1.17.0 -f dockerfile-kasm-multiple-printers .
    2. The image should successfully build without errors.

  10. Proceed to the steps to create a workspace in the Kasm Workspaces UI.

 

Create a workspace in the Kasm Workspaces UI

  1. Login to the Kasm UI

  2. Follow the normal steps for adding a docker workspace based on the instructions in the documentation.

    1. Reference the “Building Custom Images” documentation starting at the step where you login to the Kasm UI and add a workspace (at the creation of this KB article, start at step 3).

    2. Summary of steps to add a Workspace:

      1. Go to the “Workspaces” admin screen. (Admin > Infrastructure > Workspaces > Workspaces)

      2. Click the “Add workspaces” button.

      3. Provide all values for required fields including the field property values provided below:

        1. Workspace Type: Container

        2. Friendly Name: Multiple Printers

        3. Docker Image: kasmweb/multiple-printers:1.17.0

        4. If your docker image is not already present on the Kasm Docker Agent (such as when building images directly on the Kasm Agent), you will need to specify the correct Docker Image name and tag, Docker Registry, Docker Registry Username, and Docker Registry Password to allow the Kasm Docker Agents to pull the image from the remote registry.

      4. Click the Save button to save your changes.

  3. Add the workspace to a Kasm group that your test user belongs to. By default, new workspaces are automatically added to the “All Users” group.

  4. Go to the user dashboard.

  5. Get the “lp” module name for your printer.

    1. Open a terminal to run the following commands. NOTE - Opening a terminal in some Kasm workspaces may not be possible due to security controls. In this instances it is possible to build and run a full desktop version of the same workspace for testing purposes to retrieve the lp module names.

    2. Example getting the lp module name for an HP Deskjet 3600 printer.

      1. lpinfo -m | grep 'drv://' | grep hp-deskjet_3600 | cut -d' ' -f1
    3. Example listing all lp module names

      1. lpinfo -m | cut -d' ' -f1
  6. Add printers to the workspace using file mapping.

    1. Edit the workspace.

    2. Add a file mapping that runs as root when the workspace starts to register each of the print devices to the workspace as available printers.

      1. Type: Text

      2. Name: kasm_post_run_root

      3. Description: kasm_post_run_root

      4. Destination Path: /dockerstartup/kasm_post_run_root.sh

      5. Executable: true

      6. Writable: false

      7. Contents:

        1. #!/usr/bin/env bash set -ex ##Wait for the workspace to be ready /usr/bin/desktop_ready ## Add HP printers driver='drv:///hp/hpcups.drv/hp-deskjet_3600.ppd' lpadmin -p "Printer-01" -E -v socket://10.0.0.101:9100 -m "${driver}" -D "HP DesignJet XL 3600 01" lpadmin -p "Printer-02" -E -v socket://10.0.0.102:9100 -m "${driver}" -D "HP DesignJet XL 3600 02" lpadmin -p "Printer-03" -E -v socket://10.0.0.103:9100 -m "${driver}" -D "HP DesignJet XL 3600 03" ##Notify script is complete notify-send "Script Complete" "sudo is now installed"
      8. Example of the entire “kasm_post_run_root.sh“ file mapping.

      9. image-20250715-060323.png

         

      10. image-20250715-060303.png
  7. Test the workspace when complete.

 


 Instructions - Docker Images using only File Mapping

This instruction describes a method for allowing a docker workspace session to access multiple custom printer options by avoiding building a custom docker image with the required printer drivers. This method relies solely on file mapping. The downside to this method is the workspace will take longer to launch due to the time needed to complete all tasks related to installing the printer device driver at each session launch.

  1. Use the instructions for the “Custom Docker Image“ method with the following changes:

    1. Place the code that would have been added to the “Custom code” section of the dockerfile (ie: the non-interactive installation of the printer’s device drivers) in the root user startup script “kasm_post_run_root.sh“.

  2. Proceed with all other instructions.

  3. Test the workspace when complete.

 


 Instructions - Windows RDP Sessions

This instruction describes a method for allowing a Windows RDP workspace session to access multiple custom printer options by manually adding multiple drivers in advance of the session launch.

  1. Manually install the printer device drivers in advance of users accessing the server or use PowerShell to automate the installation of the device drivers as part of the auto-scale startup script.

  2. Use the Kasm UI to add the workspace as documented in the official Kasm Windows documentation.

  3. Test the workspace when complete.

 


 Instructions - Testing the workspace printing

  1. Login to the Kasm UI

  2. The group setting “allow_kasm_printing“ does not need to be enabled because the workspace will not use Kasm’s Print Redirection feature for this test.

  3. Test the workspace.

    1. Launch the workspace.

    2. If this is a full desktop workspace, open an application with print capabilities such as a web browser or a text editor.

    3. Use the application to select the print option.

    4. Browse the available printers.

    5. Select one of the custom printers.

    6. Complete the print operation.

    7. The document should print as expect to the target printer.

image-20250715-064251.png

 

 


Related Docs:

 Related articles