A detail step to run desktop environment in container

Note: Desktop environment here is in broad sense. For me a desktop environment is a desktop environment if there is a X11 window manager or wayland compositor with other gui programs. Desktop environment in narrow sense is something like Gnome, Kde, Xfce, etc.

required:
a linux host can run container (lxd, incus, lxc, docker)
a working graphic card
a working sound card
a working network card

Warning: running DE in container is not perfect. You will encounter a lot of tech issues and bugs. Some of them cannot be solved or bypass.

Yes, I have write about it before:
https://discuss.linuxcontainers.org/t/containerlize-gui-apps-with-wayland/

but it surprised me after seeing this post:
https://discuss.linuxcontainers.org/t/is-it-possible-to-run-full-system-gui-container-in-incus/

I showed a way to run a wayland compositor in container, the rest thing need to do is installing wallpaper, file manager, web browser, test editor, video player and so on.

You will see this post 99% unrelated to container.
And I need a lot time to complete this post.

You may need to read extra information:
https://wiki.archlinux.org/title/Desktop_environment
https://wiki.archlinux.org/title/Wayland
https://wiki.archlinux.org/title/Window_manager
https://wiki.archlinux.org/title/Display_manager

Chapter I: personal experience

Container installed desktop environment is too long, letā€™s call it gui ct.

I run a gui ct for over half a year. I use it as HTPC. The biggest issues are containerā€™s wayland compositor will freeze when playing high rate 4K H265 10Bit SDR movie even my gpu can decode it, and host will freeze when CPU or RAM overloaded. Not big issues are canā€™t auto login because sway(wayland) donā€™t support display manager, host X11 will crush if X11 container exist, host X11 need xhost or xauthority or x cookie to let container use host X11 socket.

You donā€™t need to read my old post, I will write from scratch.

First you need something to hold gui ct like X11 window manager or wayland compositor. I think itā€™s possible we can skip it, but I donā€™t know what a container need to display in host DRM, it may involve creating a wayland compositor from scratch. I want to choose X11 window manager, but terrible user experience, you can try, I wonā€™t stop you. So I have to choose wayland compositor. For host, itā€™s ok to use tiling. For container, itā€™s better to use stacking, unless you are a geek, after testing there are only 2 suit for using: labwc and wayfire.

My host OS is debian, container manager is incus, wayland compositor is sway, you can use whatever you like. You donā€™t need to install xwayland in host.

Step for gui in host

In my opinion, xfce4-terminal is better than foot. You donā€™t have to install xfce4-terminal.

apt install sway xfce4-terminal -y

Letā€™s config sway, otherwize you will see a black screen.

mkdir -p ~/.config/sway
cp /etc/sway/config ~/.config/sway/
nano ~/.config/sway/config
  • * means for all display, if you want to change, you need to start sway, then you can see display name using swaymsg -t get_outputs.
  • sway should choose right resolution for you display, but if you need to change, this is template: resolution --custom 1920x1200@60Hz
  • background image path $HOME/background.jpg change to whatever you want.
  • fill will fill you screen with background image, there are others see: Home Ā· swaywm/sway Wiki Ā· GitHub
  • pos 0 0 will show frame from top left

output * resolution --custom 1920x1200@60Hz bg $HOME/background.jpg fill pos 0 0

  • set default terminal to xfce4-terminal
    set $term xfce4- xfce4-terminal

you need to change below contain to let container shows in fullscreen


#hide border
default_border none
default_floating_border none
font pango:monospace 0
titlebar_padding 1
titlebar_border_thickness 0
#bar {
#    position top
    # When the status_command prints a new line to stdout, swaybar updates.
    # The default just shows the current date and time.
#    status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done

#    colors {
#        statusline #ffffff
#        background #323232
#        inactive_workspace #32323200 #32323200 #5c5c5c
#    }
#}

Now you can start sway using sway in terminal. But if you using VM, WLR_NO_HARDWARE_CURSORS=1 sway.

Press Win+Enter to open terminal, I donā€™t what Win is in Mac, but I know is a button with icon. If you want sway auto open after login, add this to your .profile:

if [ "$(tty)" = "/dev/tty1" ] ; then
    exec sway
fi

Sound server is pipewire, I have problem playing sound using pulseaudio.

apt install pipewire-audio pavucontrol -y

running as user, not as root. Enable and start the new pipewire-pulse service with:

systemctl --user --now enable pipewire pipewire-pulse
systemctl --user --now enable wireplumber.service

Itā€™s time to check whether or not sound card working. Sometime you need to choose the right sound driver in pavucontrol.If you want to change volume, use pavucontrol in host.

That all gui part in host.

Itā€™s time to prepare for container. Since we can create gui ct, itā€™s better one user one container. And without display manager, itā€™s not convenient to switch user.

Step for gui in container

Use id to get your gid and uid, they will be 1000 if you are the only user, itā€™s fine to be other number just 1000 to your number.

Profile

Create a profile for hardware accelerate.

incus profile copy default hwac
incus profile edit hwac

config: {}
description: Hardware acceleration
devices:
  mygpu:
    type: gpu
    gid: '1000'
    uid: '1000'
name: hwac

Create a profile for wayland socket.

incus profile copy default wayland
incus profile edit wayland

config: {}
description: Let containers use host display
devices:
  waylandSocket:
    type: proxy
    bind: container
    connect: unix:/run/user/1000/wayland-1
    listen: unix:/mnt/wayland-1
    mode: '0770'
    security.gid: '1000'
    security.uid: '1000'
    gid: '1000'
    uid: '1000'
name: wayland

Create a profile for pipewire socket.

incus profile copy default pipewire
incus profile edit pipewire

config: {}
description: Let containers use host sound
devices:
  pipewireSocket:
    type: proxy
    bind: container
    connect: unix:/run/user/1000/pipewire-0
    listen: unix:/mnt/pipewire-0
    mode: '0770'
    security.gid: '1000'
    security.uid: '1000'
    gid: '1000'
    uid: '1000'
name: pipewire

Create a profile for autostart.

incus profile copy default autostart
incus profile edit autostart

config:
  boot.autostart: true
description: auto start and shutdown container
devices: {}
name: autostart

If using X11.

incus profile copy default x11
incus profile edit x11

config: 
  environment.DISPLAY: :0
description: x11
devices:
  x11:
    bind: container
    connect: unix:@/tmp/.X11-unix/X0
    listen: unix:@/tmp/.X11-unix/X0
    security.gid: '1000'
    security.uid: '1000'
    type: proxy
name: x11

Now we can create gui ct. Iā€™m using alpine for gui ct, you can use whatever you like.
incus launch images:alpine/3.19 htpc -p default -p wayland -p pipewire -p hwac -p autostart

Container basic step

Alpine default shell is ash.

incus exec htpc ash
apk update
apk upgrade

I like bash.

apk add bash nano bash-doc bash-completion
sed -i 's/ash/bash/g' /etc/passwd

doas is a replace for sudo.

apk add doas
echo "permit persist :wheel" >> /etc/doas.d/doas.conf

wlroots doesnā€™t like NVIDIA
Intel Video - Alpine Linux
Radeon Video - Alpine Linux

Install intel video driver.

apk add mesa-dri-gallium mesa-va-gallium linux-firmware-i915

If older than gen8:

apk add intel-media-driver

else:

apk add libva-intel-driver
Do you like me who is not a native English speaker, letā€™s modify alpine to suit us.

sed -i 's/#unicode="YES"/unicode="YES"/g' /etc/rc.conf

You should find font support your language. For example for east asia:

apk add musl-locales font-noto-cjk

Itā€™s container gui part.

apk add labwc font-dejavu font-awesome waybar dbus dbus-x11 swaybg nwg-launchers xfce4-terminal xdg-user-dirs thunar exo tumbler chromium mpv mousepad rhythmbox wayvnc copyq lxappearance wireplumber pipewire pipewire-pulse pipewire-zeroconf xarchiver openssh

If you are not a native English speaker, you need to install input method. Somehow ibus malfunction, we need to install fcitx5 in alpine edge repository. Edge - Alpine Linux

You need to install fcitx5 addons suit you language. For example fcitx5-chinese-addons.

apk add fcitx5 fcitx5-gtk3 fcitx5-configtool fcitx5-chinese-addons
LANG=zh_CN.UTF-8 apk add lang

Start service we need.

rc-update add dbus
rc-update add sshd
service sshd start

Create user. Letā€™s say user is lxc:

adduser -s /bin/bash -g "lxc" lxc

set you password now

adduser lxc wheel
adduser lxc video
adduser lxc input
adduser lxc audio

User lxc is now usable.

su -l lxc
LC_ALL=zh_CN.UTF-8 xdg-user-dirs-update

Donā€™t start labwc yet. Click Win+Enter open a xfce4-terminal. Push .bashrc and .profile to gui ct.

incus file push ~/.bashrc htpc/home/lxc/
incus file push ~/.profile htpc/home/lxc/

You can close xfce4-terminal using Win+Shift+q.

If you are not a native English speaker, add this to .bashrc in gui ct.

export LANG=zh_CN.UTF-8
export GTK_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export QT_IM_MODULE=fcitx

Alpine doesnā€™t provide XDG_RUNTIME_DIR, and wayland compositor(labwc) rely on it. So we need to create it every time we login. So we use .profile. Just add this:

if [ -z "$XDG_RUNTIME_DIR" ]; then
	XDG_RUNTIME_DIR="/tmp/$(id -u)-runtime-dir"
	mkdir -pm 0700 "$XDG_RUNTIME_DIR"
	export XDG_RUNTIME_DIR
fi

if [ -z "$XDG_CONFIG_HOME" ] ; then
    export XDG_CONFIG_HOME=$HOME/.config
fi

Now we have XDG_CONFIG_HOME, we can actually run labwc, donā€™t do it, else it will be a headless wayland session.

We are going to tell labwc to use host wayland socket. Just add this in .profile:

if ! [ -S "$XDG_RUNTIME_DIR/wayland-1" ] ; then
    ln -s /mnt/wayland-1 $XDG_RUNTIME_DIR/wayland-1
fi

if [ -z "$WAYLAND_DISPLAY" ] ; then
    export WAYLAND_DISPLAY=wayland-1
fi

Now we can actually run labwc:

source .bashrc
source .profile
labwc

If you see a black screen with a curse then you are succeed.
Letā€™s start custom it.

custom labwc

mkdir -p ~/config/labwc
nano ~/config/labwc/autostart

swaybg -i $HOME/Pictures/background.jpg -m fill >/dev/null 2>&1 &
copyq --start-server enable >/dev/null 2>&1 &
waybar >/dev/null 2>&1 &

nano ~/config/labwc/environment

# This allows xdg-desktop-portal-wlr to function (e.g. for screen-recording)
XDG_CURRENT_DESKTOP=wlroots
XDG_SESSION_DESKTOP=wlroots
XDG_SESSION_TYPE=wlroots
# Force firefox to use wayland backend
MOZ_ENABLE_WAYLAND=1
# Set cursor theme.
# Find icons themes with the command below or similar:
# find /usr/share/icons/ -type d -name "cursors"
# XCURSOR_THEME=breeze_cursors
# Disable hardware cursors. Most users wouldn't want to do this, but if you
# are experiencing issues with disappearing cursors, this might fix it.
WLR_NO_HARDWARE_CURSORS=1
# For Java applications such as JetBrains/Intellij Idea, set this variable
# to avoid menus with incorrect offset and blank windows
# See https://github.com/swaywm/sway/issues/595
_JAVA_AWT_WM_NONREPARENTING=1
QT_QPA_PLATFORM=wayland-egl
QT_WAYLAND_FORCE_DPI=physical
QT_WAYLAND_DISABLE_WINDOWDECORATION="1"
ELM_DISPLAY=wl
SDL_VIDEODRIVER=wayland
SAL_USE_VCLPLUGIN=gtk3
GTK_USE_PORTAL=0
MOZ_ENABLE_WAYLAND=1
MOZ_DBUS_REMOTE=1
XDG_SESSION_TYPE=wayland
intel_iommu=igfx_off
LIBVA_DRIVER_NAME=i965
WAYLAND_DISPLAY=wayland-0

nano ~/config/labwc/menu.xml

<?xml version="1.0" encoding="UTF-8"?>

<openbox_menu>

<menu id="client-menu">
  <item label="Minimize">
    <action name="Iconify" />
  </item>
  <item label="Maximize">
    <action name="ToggleMaximize" />
  </item>
  <item label="Fullscreen">
    <action name="ToggleFullscreen" />
  </item>
  <item label="Decorations">
    <action name="ToggleDecorations" />
  </item>
  <item label="AlwaysOnTop">
    <action name="ToggleAlwaysOnTop" />
  </item>
  <!--
    Any menu with the id "workspaces" will be hidden
    if there is only a single workspace available.
  -->
  <menu id="workspace" label="Workspace">
    <item label="Move to left workspace">
      <action name="SendToDesktop" to="left" />
    </item>
    <item label="Move to right workspace">
      <action name="SendToDesktop" to="right" />
    </item>
  </menu>
  <item label="Close">
    <action name="Close" />
  </item>
</menu>

<menu id="root-menu">
  <item label="App launcher">
    <action name="Execute" command="nwggrid" />
  </item>
    <item label="File browser">
    <action name="Execute" command="thunar" />
  </item>
  <item label="Web browser">
    <action name="Execute" command="chromium" />
  </item>
  <item label="Terminal">
    <action name="Execute" command="xfce4-terminal" />
  </item>
  <item label="Reconfigure">
    <action name="Reconfigure" />
  </item>
  <item label="Exit">
    <action name="Exit" />
  </item>
</menu>

</openbox_menu>

nano ~/config/labwc/rc.xml

<?xml version="1.0"?>

<labwc_config>

  <keyboard>
    <default />
    <!-- Use a different terminal emulator -->
    <keybind key="W-Return">
      <action name="Execute" command="foot" />
    </keybind>
    <!--
      Remove a previously defined keybind
      A shorter alternative is <keybind key="W-F4" />
    -->
    <keybind key="W-F4">
      <action name="None" />
    </keybind>
  </keyboard>

  <mouse>
    <default />
    <!-- Show a custom menu on desktop right click -->
    <context name="Root">
      <mousebind button="Right" action="Press">
        <action name="ShowMenu" menu="root-menu" />
      </mousebind>
    </context>
  </mouse>

<focus>
  <focusNew>no</focusNew>
  <focusLast>no</focusLast>
  <followMouse>no</followMouse>
  <focusDelay>200</focusDelay>
  <underMouse>no</underMouse>
  <raiseOnFocus>no</raiseOnFocus>
</focus>

</labwc_config>

Custom waybar now. waybar(5) ā€” Arch manual pages

Custom waybar

mkdir -p ~/config/waybar
all icon below will be something else because missing font-awesome.
nano ~/config/waybar/config

{
    "layer": "top", // Waybar at top layer
    // "position": "left", // Waybar position (top|bottom|left|right)
    // "height": 38, // Waybar height (to be removed for auto height)
    //"width": 1000, // Waybar width
    "spacing": 4, // Gaps between modules (4px)
    // Choose the order of the modules
    "modules-left": ["wlr/taskbar"],
    "modules-center": ["clock"],
    "modules-right": ["wireplumber", "tray", "cpu", "memory", "network",  "temperature"],
    // Modules configuration
    "clock": {
        "locale": "zh_CN.UTF-8",
	"format": "<span font='Noto Sans CJK SC'>{:%H:%M} </span>ļ€— ",
	"format-alt": "<span font='Noto Sans CJK SC'>{:%Y-%m-%d} </span>ļ³ ",
	"tooltip-format": "<span size='12pt' font='Noto Sans CJK SC'><big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt></span>",
	"calendar": {
		"mode" : "year",
		"mode-mon-col" : 3,
		"weeks-pos" : "right",
		"on-scroll" : 1,
		"on-click-right": "mode",
		"format": {
			"months": "<span color='#ffead3'><b>{}</b></span>",
			"days": "<span color='#ecc6d9'><b>{}</b></span>",
			"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
			"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
			"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
		}
	},
	"actions": {
		"on-click-right": "mode",
		"on-scroll-up": "shift_up",
		"on-scroll-down": "shift_down"
	}
},
    "cpu": {
        "format": "{usage}% ļ‹›",
        "tooltip": false
    },
    "memory": {
        "format": "{}% ļ‡¾"
    },
    "temperature": {
        // "thermal-zone": 2,
        // "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
        "critical-threshold": 80,
        // "format-critical": "{temperatureC}Ā°C {icon} ",
        "format": "{temperatureC}Ā°C {icon} ",
        "format-icons": ["ļ«", "ļ‹‰", "ļ©"]
    },
    "network": {
        // "interface": "wlp2*", // (Optional) To force the use of this interface
        "format-wifi": "{essid} ({signalStrength}%) ļ‡«",
        "format-ethernet": "{ifname} ļž– ",
        "tooltip-format": "{ifname} gateway {gwaddr} ļƒØ",
        "format-linked": "{ifname} (No IP) ļž–",
        "format-disconnected": "Disconnected āš ",
        "format-alt": "<span font='Noto Sans CJK SC'>{ifname}: {ipaddr} /{cidr}</span> ļž–"
    },
    "wlr/taskbar": {
        "format": "{icon} {name} ",
        "icon-size": 18,
        "tooltip-format": "{title}",
        "on-click": "minimize-raise"
    },
    "tray": {
	"icon-size": 20,
	"spacing": 5
    },
    "wireplumber": {
	"format": "{volume}% ļ€Ø",
	"format-muted": "ļ€¦",
	"max-volume": 1.0,
	"on-click": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle",
	"on-scroll-up": "wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 5%+",
	"on-scroll-down": "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
    }
}

nano ~/config/waybar/style.css

#waybar {
    font-family: "Noto Sans CJK SC";
    font-size: 18px;
}

#window {
    padding: 0 1px;
}

window#waybar {
    border: none;
    border-radius: 0;
    box-shadow: none;
    text-shadow: none;
    transition-duration: 0s;
    color: rgba(217, 216, 216, 1);
    background: rgba(180, 153, 255, 0.6);
}

window#waybar.solo {
    background: rgba(35, 31, 32, 0.5);
}

window#waybar.empty {
    /* display: none; */
}

/* Repeat style here to ensure properties are overwritten as there's no !important and button:hover above resets the colour */

#custom-powermenu {
    color:lightcoral;
}

#temperature {
    color: rgb(153,35,51);
}

#idle_inhibitor {
    color: powderblue;
}

#language {
        color: orchid;
}

#taskbar {
        background-color: lightyellow;
        border-radius: 8px;
}

#taskbar button.active {
        background-color: yellow;
        border-radius: 4px;
        padding: 2px;
        margin: 2px;
}

#taskbar button {
        background-color: transparent;
        border-radius: 4px;
        padding: 2px;
        margin: 2px;
}

#tray {
        background-color: transparent;
}

#wireplumber,
#wireplumber.muted,
#clock,
#taskbar,
#mode,
#battery,
#cpu,
#memory,
#network,
#idle_inhibitor,
#custom-media {
    color: rgb(157, 25, 6);
    margin: 0 2px;
}

#battery {
    color: lightgreen;
}

#battery.warning {
    color: rgba(255, 210, 4, 1);
}

#battery.critical {
    color: rgba(238, 46, 36, 1);
}

#battery.charging {
    color: rgba(217, 216, 216, 1);
}

#custom-storage.warning {
    color: rgba(255, 210, 4, 1);
}

#custom-storage.critical {
    color: rgba(238, 46, 36, 1);
}

@keyframes blink {
    to {
        background-color: #ffffff;
        color: black;
    }
}

Now you can restart labwc. And something like this will show. Yes, you need to find font-awesome icon.

Setting GTK theme

You can custom it the way gtk does using lxappearance. But something will not update well. Here is a sh script I copyed from somewhere to proper update:


#!/bin/sh

# usage: import-gsettings
config="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-3.0/settings.ini"
if [ ! -f "$config" ]; then exit 1; fi

gnome_schema="org.gnome.desktop.interface"
gtk_theme="$(grep 'gtk-theme-name' "$config" | sed 's/.*\s*=\s*//')"
icon_theme="$(grep 'gtk-icon-theme-name' "$config" | sed 's/.*\s*=\s*//')"
cursor_theme="$(grep 'gtk-cursor-theme-name' "$config" | sed 's/.*\s*=\s*//')"
font_name="$(grep 'gtk-font-name' "$config" | sed 's/.*\s*=\s*//')"
gsettings set "$gnome_schema" gtk-theme "$gtk_theme"
gsettings set "$gnome_schema" icon-theme "$icon_theme"
gsettings set "$gnome_schema" cursor-theme "$cursor_theme"
gsettings set "$gnome_schema" font-name "$font_name"

Now the most weird part.
We have to start pipewire manually.

/usr/libexec/pipewire-launcher >/dev/null 2>&1 &

Then remove itā€™s socket.

rm $XDG_RUNTIME_DIR/pipewire-0

Then swap with host pipewire socket.

ln -s /mnt/pipewire-0 $XDG_RUNTIME_DIR/pipewire-0

For waybar to display right volume, kill it and start it.

killall waybar
nohup waybar >/dev/null 2>&1 &

If you install fcitx5:

nohup fcitx5 -d >/dev/null 2>&1 &

Itā€™s too complex to do every time login container. So a sh script:

#/bin/sh
/usr/libexec/pipewire-launcher >/dev/null 2>&1 &
sleep 3s
rm $XDG_RUNTIME_DIR/pipewire-0
ln -s /mnt/pipewire-0 $XDG_RUNTIME_DIR/pipewire-0
killall waybar
nohup waybar >/dev/null 2>&1 &
nohup fcitx5 -d >/dev/null 2>&1 &

Thatā€™s it. Now you can use this gui ct as normal de.

Every time you need to run this gui ct, you only need to run:

incus exec htpc ā€“ su -l lxc

2 Likes

Chapter II: try and error

a nested gui container = a container using x11/Wayland protocol drawing images in host compositor
a headless gui container = a container installed x11 window manager/wayland compositor without drawing images in host compositor

In above, a nested stacking Wayland ct renders itself in host tilling Wayland compositor normally. Because Wayland compositor can draw in itself. So, no matter what host compositor is, every thing nested Wayland ct draws rendering in itself, unless you tell it to render in other place. What about nested x11 ct, things going in complete opposite direction, whatever nested x11 ct draws rendering in host window. Because whatever a x11 app need to draw, it needs to tell window manager to draw for it, and there can be only one active window manager in x11, and a window manager only has one compositor. Yes, compositor is the one rendering images in your screen.

conclusion:
nested wayland is isolated from host display environment.
nested x11 is mixed with host display environment.

nested stacking x11 ct

So, itā€™s what you will see if a nested stacking x11 ct showing in tilling xwayland compositor.

host os: debian 12
host Wayland compositor: sway
host app: xfce4-terminal
container os: debian 12
container x11: mate
container app: caja


From left to right, hostā€™s xfce4-terminal, mate top panel, mate caja, mate bottom panel. Very tilling taste.

letā€™s nest a stacking x11 in a stacking xwayland compositor.
I installed labwc in host(Iā€™m too lazy to start a new vm, so just change debian source to testing). Another gui ct called xfce but installed xfce and mate. So, what will happen when we start mate? labwc crushed. i tried wayfire too, crushed. I donā€™t know why but labwc and wayfire canā€™t open x11 app with xwayland, even they are installed in host. But there is an old buddy weston who is not very suit for daily use but very suit for testing. Yes, I forgot about it until viewing arch wiki. Can we start x11 app in weston? Yes, in ~/.config/weston.ini, add this:

[core]
xwayland=true

Letā€™s try again. Start mate-session in ct.


wait, what is that?
Killed mate and start with nohup mate-session >/dev/null 2>&1 &
Same thing, but a panel missing. But we can start app in terminal now. Try xeyes. Haha, work.

Well, it seems like we can open more than one mate-session.

And panel is usable, cool.


Nested x11 apps work in stacking way, great.

What about xfce.


Better, but xfce panel blocked by weston panel and xfce dock.

Chapter III:

Last year, I was updating my server, and decided to pass-through gpu to vm to isolate gui environment from host to reduce possible risks that something I do in gui might destroy host. I did, but there is no audio output from vm even with an audio card pass-throughed. Most people are fine with that, but not me, a htpc is not a htpc without audio output. So I started searching for alternative. I decided to nest x11 in container after seeing this 2 post:

Due to my short years in Linux desktop environment, I failed, kde wonā€™t let me using x11 or xwayland socket in container, because of xauthority. Itā€™s time to revenge.

Letā€™s see some necessary file in Gnome.

Launch a container.
incus launch images:debian/12 x -p default -p x11 -p hwac
Got to push xauth file to container. But xauth file in gnome changes name every time restarted. But you can see this post solved the problem: https://discuss.linuxcontainers.org/t/incus-lxd-profile-for-gui-apps-wayland-x11-and-pulseaudio/.
incus file push /run/user/1000/.mutter-* x/mnt/xauth

incus exec x bash

apt install xfce4
export XAUTHORITY=/mnt/xauth
startxfce4

But shows a warn.


But whoā€™s dbus-launch? Containerā€™s.

apt install dbus-x11
Start again. Well, itā€™s quite easy. I remember I was pulling my hair off with no idea what to do last year.

But this nested x11 is not usable, at least thatā€™s what I think. To make it work, we need to jump out of box. We canā€™t open x11 in a window like wayland, but we can mix ct x11 with host.

As I said in last chapter, whatever a x11 app need to draw, it needs to tell window manager to draw for it. So, we donā€™t need to start a full desktop environment(Gnome) in host, a window manager is enough. Letā€™s try fluxbox which Iā€™ve never used before.
In host:
apt install fluxbox -y
Now you can select fluxbox using display manager.


Letā€™s see some necessary file in fluxbox.

Letā€™s run startxfce4 in ct.

Thatā€™s way better than gnome. And way smooth than mate in weston. Wait, I forgot to push xauth file to ct, it opened anyway, I should have tried it earlier.
But what will happen after killed xfce? Fluxbox background was destroyed.

conclusion:

  • Nesting x11 is way more easier but less secure than wayland.
  • Nested x11 ct have more bugs, you can see a lot warnings in terminal.
  • I recommend nest wayland in wayland, x11 in x11.

Thatā€™s all, you have learnt how to run desktop envirement in container.

1 Like