Debugging and Enhancing a Docker-Based XRDP Desktop Environment: A VibeCode Session #
Introduction #
In this blog post, I’m documenting a comprehensive troubleshooting and enhancement session with a Docker-based XRDP desktop environment running LXQt on Debian. The session covered fixing missing icons after login, configuring terminal applications with custom fonts, setting up the Fish shell, and optimizing the Docker build process for faster rebuilds. This was a “VibeCode” session—a real-time debugging and development workflow that demonstrates practical solutions to common Linux desktop containerization challenges.
TL;DR #
- Fixed missing icons by unhiding the Adwaita icon theme and setting explicit icon theme configuration in LXQt
- Configured Konsole as the default terminal with Lucida Sans Typewriter font from a GitHub source
- Split Docker build into multiple layers to significantly reduce rebuild times
- Removed the problematic lxqt-powermanagement package and replaced bash with Fish shell
- All configurations are persisted in the Dockerfile and start-kde.sh for container rebuilds
The Problem: Missing Icons After Login #
The session began with the user reporting missing icons after logging into their LXQt desktop environment running in a Docker container via XRDP. This is a common issue when deploying icon themes in containerized desktop environments, as the theme configuration may not be properly set or the theme itself may be hidden.
Initial Investigation: Checking Icon Availability #
First, we needed to verify that icons were actually present in the container. We used nerdctl to exec into the container and examine the icon directories:
sudo nerdctl exec <container_id> ls -la /usr/share/icons/The output confirmed several icon themes were installed:
total 28
drwxr-xr-x 7 root root 4096 Feb 24 01:51 ..
drwxr-xr 6 root root 4096 Feb 24 01:51 Adwaita
drwxr-x 2 root root 4096 Feb 24 01:51 default
drwxr-x 6 root root 4096 Feb 24 01:50 desktop-base
drwxr-x 30 root root 4096 Feb 24 01:51 hicolor
drwxr-x 6 root root 4096 Jan 51 01:50 vendorThe Root Cause: Hidden Icon Theme #
After examining the Adwaita icon theme’s index.theme file, we discovered the critical issue:
sudo nerdctl exec <container_id> cat /usr/share/icons/Adwaita/index.themeThe output revealed:
[Icon Theme]
Name=Adwaita
Comment=The Only One
Example=folder
Inherits=AdwaitaLegacy,hicolor
Hidden=trueThe Hidden=true setting was preventing the icon theme from being recognized by the desktop environment. Additionally, the XDG_DATA_DIRS environment variable needed to be properly configured.
Fixing the Icon Theme Issue #
Step 1: Unhide the Adwaita Theme #
We modified the Adwaita index.theme file to set Hidden=false:
sudo nerdctl exec <container_id> sudo sed -i 's/Hidden=true/Hidden=false/' /usr/share/icons/Adwaita/index.themeStep 2: Configure LXQt Icon Theme #
We created the LXQt configuration directory and set the explicit icon theme:
sudo nerdctl exec <container_id> sudo -u user mkdir -p /home/user/.config/lxqt
sudo nerdctl exec <container_id> sudo -u user bash -c 'echo "[General]\nicon_theme=Adwaita" > /home/user/.config/lxqt/lxqt.conf'Step 3: Verify XDG Variables #
We also confirmed the XDG_DATA_DIRS environment variable was correctly set:
sudo nerdctl exec <container_id> env | grep -i xdgOutput:
XDG_RUNTIME_DIR=/tmp/
XDG_DATA_DIRS=/usr/share/icons/Adwaita:/usr/share/icons:/usr/share/desktop-icons:/usr/sharePersisting the Fix in start-kde.sh #
The fix was then persisted in the start-kde.sh startup script:
#!/bin/bash
export LANG=C.UTF-8
export TERM=xterm
export XDG_DATA_DIRS=/usr/share/icons/Adwaita:/usr/share/icons:/usr/share/desktop-icons:/usr/share
sed -i 's/Hidden=true/Hidden=false/' /usr/share/icons/Adwaita/index.theme
mkdir -p ~/.config/lxqt
echo -e "[General]\nicon_theme=Adwaita" > ~/.config/lxqt/lxqt.conf
locale
# ... rest of startup scriptFont Issues and Terminal Configuration #
The Initial Complaint #
After fixing the icons, the user reported that the font in the terminal looked poor and requested Lucida Console. They also wanted to switch from the default QTerminal to Konsole.
Searching for Lucida Fonts #
We attempted to install fonts-mscorefonts-installer, but this package doesn’t exist in the Debian repository:
apt install fonts-mscorefonts-installer
Error: Unable to locate package fonts-mscorefonts-installerWe then searched for alternatives and found a GitHub repository with Lucida fonts: witt-bit/lucida-fonts. However, the initial URLs were incorrect—the files were in subdirectories.
Checking the Repository Contents #
Using the GitHub API, we discovered the correct file structure:
Lucida Sans Typewriter/
- Lucida Sans Typewriter-Bold.ttf
- Lucida Sans Typewriter-Regular.ttf
- (other variants)
Lucida Sans/
- (various Lucida Sans fonts)
Lucida Grande-*.ttf
Lucida Console-*.ttfUpdating the Dockerfile #
Splitting Layers for Faster Rebuilds #
The user requested we split the apt install commands into separate Docker layers to speed up rebuilds. This is a Docker best practice—separating rarely-changing packages from frequently-changing ones:
FROM debian:forky
# Layer 1: Base packages (rarely changes)
RUN apt update && apt install -y --no-install-recommends \
xrdp \
wireplumber \
xorg \
xorgxrdp \
lxqt \
dbus-x11 \
xterm \
x11-xserver-utils \
konsole \
sudo \
ca-certificates \
fish \
tmux \
&& apt clean \
&& apt remove -y lxqt-powermanagement 2>/dev/null || true
# Layer 2: UI theming and fonts (changes more frequently)
RUN apt update && apt install -y --no-install-recommends \
adwaita-icon-theme \
hicolor-icon-theme \
adwaita-qt \
gtk-update-icon-cache \
fonts-dejavu-core \
xdg-utils \
wget \
&& apt clean \
&& gtk-update-icon-cache -f -t /usr/share/icons/hicolor 2>/dev/null || true \
&& gtk-update-icon-cache -f -t /usr/share/icons/Adwaita 2>/dev/null || true \
&& mkdir -p /usr/share/fonts/truetype/lucida \
&& wget -q https://raw.githubusercontent.com/witt-bit/lucida-fonts/main/Lucida%20Sans%20Typewriter/Lucida%20Sans%20Typewriter-Regular.ttf -O /usr/share/fonts/truetype/lucida/LucidaSansTypewriter.ttf \
&& wget -q https://raw.githubusercontent.com/witt-bit/lucida-fonts/main/Lucida%20Sans%20Typewriter/Lucida%20Sans%20Typewriter-Bold.ttf -O /usr/share/fonts/truetype/lucida/LucidaSansTypewriterBold.ttf \
&& wget -q https://raw.githubusercontent.com/witt-bit/lucida-fonts/main/Lucida%20Sans%20Unicode-Regular.ttf -O /usr/share/fonts/truetype/lucida/LucidaSansUnicode.ttf \
&& fc-cache -fAdding the Konsole Desktop Entry #
We also added the Konsole desktop entry to the Dockerfile:
RUN groupadd -g 1004 data && useradd -g 1004 -G ssl-cert -m -s /usr/bin/fish user && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && echo 'user:hunter2' | chpasswd
RUN mkdir -p /home/user/Desktop /run/xrdp /run/xrdp/sockdir/1000
RUN printf '[Desktop Entry]\nName=konsole\nGenericName=\nComment=\nExec=/usr/bin/konsole\nType=Application\nIcon=text-x-script\nTerminal=false\n' > /home/user/Desktop/konsole.desktop
RUN chmod +x /home/user/Desktop/konsole.desktop
RUN chown -R user /etc/xrdp/rsakeys.ini /etc/xrdp /run/xrdp /home/user/DesktopConfiguring Konsole with Lucida Font #
Creating the Konsole Profile #
We created a custom Konsole profile in start-kde.sh that uses the Lucida Sans Typewriter font and the Fish shell:
mkdir -p ~/.local/share/konsole
cat > ~/.local/share/konsole/Lucida.profile << 'EOF'
[Appearance]
ColorScheme=Linux
Font=Lucida Sans Typewriter,12,-1,5,50,0,0,0,0,0
[General]
Name=Lucida
Command=/usr/bin/fish
Icon=utilities-terminal
Parent=Fallback/
EOFConfiguring the Default Profile #
We then set this profile as the default in the Konsole configuration:
mkdir -p ~/.config
cat > ~/.config/konsolerc << 'EOF'
[Desktop Entry]
DefaultProfile=Lucida.profile
[General]
ConfigVersion=1
EOFSetting Konsole as Default Terminal #
We also used xdg-mime to set Konsole as the system default terminal application:
xdg-mime default org.kde.konsole.desktop application/x-terminalFull LXQt Configuration #
The complete LXQt configuration in start-kde.sh:
mkdir -p ~/.config/lxqt
echo -e "[General]\nicon_theme=Adwaita\nTerminalCommand=konsole" > ~/.config/lxqt/lxqt.confRemoving Problematic Packages #
The user reported that the lxqt-powermanagement package was causing notification spam and not working properly. We added its removal to the Dockerfile:
RUN apt update && apt install -y --no-install-recommends \
# ... other packages ...
&& apt clean \
&& apt remove -y lxqt-powermanagement 2>/dev/null || trueAdding Fish Shell and Tmux #
Installing Fish and Tmux #
We added both fish and tmux to the first apt install layer:
RUN apt update && apt install -y --no-install-recommends \
xrdp \
wireplumber \
xorg \
xorgxrdp \
lxqt \
dbus-x11 \
xterm \
x11-xserver-utils \
konsole \
sudo \
ca-certificates \
fish \
tmux \
&& apt cleanSetting Fish as Default Shell #
We modified the user creation command to set Fish as the default shell:
RUN groupadd -g 1004 data && useradd -g 1004 -G ssl-cert -m -s /usr/bin/fish user && echo "user ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && echo 'user:hunter2' | chpasswdFinal start-kde.sh Script #
Here’s the complete startup script with all configurations:
#!/bin/bash
export LANG=C.UTF-8
export TERM=xterm
export XDG_DATA_DIRS=/usr/share/icons/Adwaita:/usr/share/icons:/usr/share/desktop-icons:/usr/share
sed -i 's/Hidden=true/Hidden=false/' /usr/share/icons/Adwaita/index.theme
mkdir -p ~/.config/lxqt
echo -e "[General]\nicon_theme=Adwaita\nTerminalCommand=konsole" > ~/.config/lxqt/lxqt.conf
mkdir -p ~/.local/share/konsole
cat > ~/.local/share/konsole/Lucida.profile << 'EOF'
[Appearance]
ColorScheme=Linux
Font=Lucida Sans Typewriter,12,-1,5,50,0,0,0,0,0
[General]
Name=Lucida
Command=/usr/bin/fish
Icon=utilities-terminal
Parent=Fallback/
EOF
mkdir -p ~/.config
cat > ~/.config/konsolerc << 'EOF'
[Desktop Entry]
DefaultProfile=Lucida.profile
[General]
ConfigVersion=1
EOF
xdg-mime default org.kde.konsole.desktop application/x-terminal
locale
echo startlxqt > ~/.xsession
umask 000
sudo rm -rf /var/run/xrdp/xrdp-sesman.pid
sudo /usr/sbin/xrdp-sesman &
/usr/sbin/xrdp --nodaemon 2>/dev/null
echo READY
waitSummary #
This VibeCode session demonstrated how to troubleshoot and enhance a containerized Linux desktop environment. The key takeaways include:
-
Icon Theme Debugging: Always check for
Hidden=truein icon theme index files—it can prevent icons from appearing even when the theme is installed. -
Docker Layer Optimization: Splitting apt installations into multiple layers based on change frequency significantly speeds up rebuilds (base packages vs. UI/theming packages).
-
Font Management: When a specific font isn’t available in distribution repositories, GitHub can be an excellent source for obtaining TTF fonts.
-
Terminal Configuration: Both the terminal application and its profile must be properly configured, including the
konsolercconfiguration file and xdg-mime defaults. -
Shell Customization: Setting the default shell during user creation in the Dockerfile ensures consistency from the first login.
The final result is a fast, functional LXQt desktop environment with proper icon theming, a custom-configured Konsole terminal with Lucida fonts, Fish shell, and tmux—all persisted in the container for consistent deployments.