Wayland and waydroid in privileged LXC

Hello everybody, it’s me doing weird thing again.
Privileged LXC wayland direct display is only the bait, main dish is waydroid. It’s the same recipe as Container can direct display wayland in host now. Not surprise, I can’t find anyone convert it to LXC, at least not using duckduckgo. I can’t run it in unprivileged LXC now, because I just learn LXC in 3 days, and haven’t touched unprivileged LXC yet, but it’s just a permission problem, I trust anyone with unprivileged LXC experience can solve it.

Host OS is ubuntu server 26.04. If you are using other OS, remember the device major:minor might be different, use ls -al to find out.
First, create a privileged LXC, any OS you like, I’m using debian 13. Edit the CT’s config:

## tty devices
lxc.tty.dir = 
lxc.tty.max = 0
lxc.cgroup2.devices.allow = c 4:0 rwm
lxc.cgroup2.devices.allow = c 4:7 rwm

lxc.mount.entry = /dev/tty0 dev/tty0 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/tty7 dev/tty7 none bind,optional,create=file 0 0

## DRM devices
lxc.cgroup2.devices.allow = c 226:* rwm

lxc.mount.entry = /dev/dri/card0 dev/dri/card0 none bind,create=file,optional 0 0
lxc.mount.entry = /dev/dri/renderD128 dev/dri/renderD128 none bind,create=file,optional 0 0

## udev runtime directory
lxc.mount.entry = /run/udev mnt/udev none bind,create=dir,optional 0 0

## Input devices
lxc.cgroup2.devices.allow = c 13:* rwm

lxc.mount.entry = /dev/input dev/input none bind,create=dir,optional 0 0

## sound devices
lxc.cgroup2.devices.allow = c 116:* rwm

lxc.mount.entry = /dev/snd dev/snd none bind,create=dir,optional 0 0

Start the CT, then lxc-attach or lxc-console whatever you like, we are going to mount /mnt/udev at /run/udev. I’m using systemd, but if you are using other init service, you know how to do it.

cat > /etc/systemd/system/run-udev.mount << EOF
[Unit]
Description=Bind mount /mnt/udev over /run/udev
After=systemd-udevd.service
RequiresMountsFor=/run/udev/data

[Mount]
What=/mnt/udev
Where=/run/udev
Type=bind
Options=bind

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl --now enable run-udev.mount

Then install wayland compositor and audio control service, I’m using labwc and pulseaudio. Then create a user in gorup:

  • audio
  • video
  • render
  • tty
  • input

I recommand add sudo group, too.
useradd -m -G audio,video,sudo,input,render,tty -s /bin/bash username
I recommand set user password now.
Before change to the user, you need to know ubuntu ttys’ default permission is 600, if your user is not in sudo group, you need to change tty0 and tty7’s permission to 660 now.
After change to user, if you are testing in VM with wlroots wayland compositor like me, if you want to see the cursor:
WLR_NO_HARDWARE_CURSORS=1 labwc
Else you know how to start the compositor.
And you need to change to tty7, or else you can’t start it due to permission error.

Now, is waydroid part. You should know the core of waydroid is waydroid’s LXC, which is a LXC container, so you don’t need to put waydroid in container. And I can firmly tell you only need LXC and binder and (memfd|ashmem) and psi=1 to start waydroid’s LXC.

Step 1

So, before you try, you need to know whether your kernel support binder.
For ubuntu:
grep -i -e android -e memfd -e ashmem "/boot/config-$(uname -r)"
You will see:

CONFIG_LIVEUPDATE_MEMFD=y
CONFIG_KVM_GUEST_MEMFD=y
CONFIG_MEMFD_CREATE=y
CONFIG_X86_ANDROID_TABLETS=m
# Android
CONFIG_ANDROID_BINDER_IPC=m
# CONFIG_ANDROID_BINDER_IPC_RUST is not set
CONFIG_ANDROID_BINDERFS=m
CONFIG_ANDROID_BINDER_DEVICES=""
# end of Android

For arch linux:
zgrep -i -e android -e memfd -e ashmem /proc/config.gz
You will see:

CONFIG_LIVEUPDATE_MEMFD=y
CONFIG_KVM_GUEST_MEMFD=y
CONFIG_MEMFD_CREATE=y
CONFIG_X86_ANDROID_TABLETS=m
# Android
# CONFIG_ANDROID_BINDER_IPC is not set
CONFIG_ANDROID_BINDER_IPC_RUST=y
CONFIG_ANDROID_BINDER_DEVICES=""
# end of Android

From archwiki: The modules can either be compiled into the kernel (y), into modules (m), or not at all (n).
So for ubuntu, it has memfd compiled into the kernel and binder compiled into modules. For arch linux, it has memfd and binder compiled into the kernel. Debian’s binder is not at all, please tell me if you know how to compile binder into module.

Step 2

Install LXC, and we are good to go.

Now I’m going to give you 2 choices, choose one you like.
Q: where do you want to runwaydroid LXC?

A: Run waydroid LXC in host without install waydroid

First part is prepare binary and script and folder and config files.

Install wayland compositor and audio control service you like, I’m using labwc and pulseaudio. And start them.
As user not root: mkdir -p ~/.local/share/waydroid/data
And download waydroid image zips and unzip to /etc/waydroid-extra/images. You should know system image has 2 kinds, one with VANILLA can’t use google, one with GAPPS can use google. I’m using VANILLA.

Now switch to root.
mkdir -p /var/lib/waydroid/lxc/waydroid/
For create binder devices I copyed a part of python3 script from waydroid/tools/helpers/drivers.py at main · waydroid/waydroid · GitHub line 43 to line 65. And add a line to call the function:
allocBinderNodes("", ["anbox-binder", "anbox-hwbinder", "anbox-vndbinder"])
I put the python3 script in /var/lib/waydroid/binder.py. And chmod +x /var/lib/waydroid/binder.py.
I’m not pasting the script just to avoid license problem.

If running in real host, I guess ro.hardware.gralloc=gbm and ro.hardware.egl=mesa should work with intel GPU. DO remember to change waydroid.host.user and waydroid.host.uid and waydroid.host.gid and waydroid.host_data_path to fit your environment. Normally waydroid.wayland_display is wayland-0, you can check with ls $XDG_RUNTIME_DIR

/var/lib/waydroid/waydroid.prop
sys.use_memfd=true
ro.adb.secure=1
ro.debuggable=0
gralloc.gbm.device=/dev/dri/renderD128
debug.stagefright.ccodec=0
ro.hardware.camera=v4l2
ro.opengles.version=196610
waydroid.updater.disabled=true
waydroid.tools_version=1.6.3
ro.vndk.lite=true
ro.hardware.gralloc=default
ro.hardware.egl=swiftshader
waydroid.host.user=USERNAME
waydroid.host.uid=1000
waydroid.host.gid=1000
waydroid.host_data_path=/home/USERNAME/.local/share/waydroid/data
waydroid.background_start=false
waydroid.xdg_runtime_dir=/run/xdg
waydroid.pulse_runtime_path=/run/xdg/pulse
waydroid.wayland_display=wayland-0
waydroid.stub_sensors_hal=1

Because after ubuntu installed lxc, it create a lxcbr0, so lxc.net.0.link = lxcbr0.

/var/lib/waydroid/lxc/waydroid/config
# Waydroid LXC Config

lxc.rootfs.path = /var/lib/waydroid/rootfs
lxc.arch = x86_64
lxc.autodev = 0
# lxc.autodev.tmpfs.size = 25000000

lxc.cap.keep = audit_control sys_nice wake_alarm setpcap setgid setuid sys_ptrace sys_admin wake_alarm block_suspend sys_time net_admin net_raw net_bind_service kill dac_override dac_read_search fsetid mknod syslog chown sys_resource fowner ipc_lock sys_chroot

lxc.mount.auto = cgroup:ro sys:ro proc

lxc.console.path = none

lxc.include = /var/lib/waydroid/lxc/waydroid/config_nodes
lxc.include = /var/lib/waydroid/lxc/waydroid/config_session

# lxc.hook.post-stop = /dev/null

lxc.uts.name = waydroid

lxc.apparmor.profile = unconfined
lxc.seccomp.profile = /var/lib/waydroid/lxc/waydroid/waydroid.seccomp

lxc.no_new_privs = 1

lxc.init.cmd = /init

lxc.net.0.type = veth
lxc.net.0.flags = up
lxc.net.0.link = lxcbr0
lxc.net.0.name = eth0
lxc.net.0.hwaddr = 00:16:3e:f9:d3:03
lxc.net.0.mtu = 1500

lxc.pty.max = 10
lxc.seccomp.allow_nesting = 1
/var/lib/waydroid/lxc/waydroid/config_nodes
lxc.mount.entry = tmpfs dev tmpfs nosuid 0 0
lxc.mount.entry = /dev/zero dev/zero none bind,create=file,optional 0 0
lxc.mount.entry = /dev/null dev/null none bind,create=file,optional 0 0
lxc.mount.entry = /dev/full dev/full none bind,create=file,optional 0 0
lxc.mount.entry = /dev/fuse dev/fuse none bind,create=file,optional 0 0
lxc.mount.entry = /dev/tty dev/tty none bind,create=file,optional 0 0
lxc.mount.entry = /dev/char dev/char none bind,create=dir,optional 0 0
lxc.mount.entry = /dev/dri/renderD128 dev/dri/renderD128 none bind,create=file,optional 0 0
lxc.mount.entry = /dev/fb0 dev/fb0 none bind,create=file,optional 0 0
lxc.mount.entry = /dev/dma_heap/system dev/dma_heap/system none bind,create=file,optional 0 0
lxc.mount.entry = /dev/anbox-binder dev/binder none bind,create=file,optional 0 0
lxc.mount.entry = /dev/anbox-vndbinder dev/vndbinder none bind,create=file,optional 0 0
lxc.mount.entry = /dev/anbox-hwbinder dev/hwbinder none bind,create=file,optional 0 0
lxc.mount.entry = none dev/pts devpts defaults,mode=644,ptmxmode=666,create=dir 0 0
lxc.mount.entry = /dev/uhid dev/uhid none bind,create=file,optional 0 0
lxc.mount.entry = /dev/net/tun dev/tun none bind,create=file,optional 0 0
lxc.mount.entry = /var/lib/waydroid/host-permissions vendor/etc/host-permissions none bind,optional 0 0
lxc.mount.entry = /sys/kernel/debug sys/kernel/debug none rbind,create=dir,optional 0 0
lxc.mount.entry = tmpfs mnt_extra tmpfs nodev 0 0
lxc.mount.entry = tmpfs tmp tmpfs nodev 0 0
lxc.mount.entry = tmpfs var tmpfs nodev 0 0
lxc.mount.entry = tmpfs run tmpfs nodev 0 0

DO check user id and name and compositor name.

/var/lib/waydroid/lxc/waydroid/config_session
lxc.mount.entry = tmpfs /run/xdg none create=dir 0 0
lxc.mount.entry = /run/user/1000/wayland-0 run/xdg/wayland-0 none rbind,create=file 0 0
lxc.mount.entry = /run/user/1000/pulse/native run/xdg/pulse/native none rbind,create=file 0 0
lxc.mount.entry = /home/USERNAME/.local/share/waydroid/data data none rbind 0 0
/var/lib/waydroid/lxc/waydroid/waydroid.seccomp
2
blacklist
init_module
finit_module
delete_module
_sysctl
kexec_file_load
kexec_load
reboot
open_by_handle_at errno 38
adjtimex errno 0
clock_adjtime errno 0
clock_adjtime64 errno 0
clock_settime errno 0
clock_settime64 errno 0
settimeofday errno 0
stime errno 0
add_key errno 0
keyctl errno 0
request_key errno 0
swapoff errno 0
swapon errno 0

Create this folders and preparation will be done.

mkdir -p /var/lib/waydroid/host-permissions
mkdir -p /var/lib/waydroid/overlay/vendor
mkdir -p /var/lib/waydroid/overlay_rw/system
mkdir -p /var/lib/waydroid/overlay_rw/vendor
mkdir -p /var/lib/waydroid/overlay_work/system/index
mkdir -p /var/lib/waydroid/overlay_work/system/work
mkdir -p /var/lib/waydroid/overlay_work/vendor/index
mkdir -p /var/lib/waydroid/overlay_work/vendor/work
mkdir -p /var/lib/waydroid/rootfs

Second part is run waydroid.

Make sure user has started wayland compositor and audio control service.

As root run below commands:

mkdir -p /dev/binderfs

modprobe binder_linux

mount -t binder binder /dev/binderfs

/var/lib/waydroid/binder.py

chmod 666 -R /dev/binderfs/anbox-binder

chmod 666 -R /dev/binderfs/anbox-vndbinder

chmod 666 -R /dev/binderfs/anbox-hwbinder

ln -s /dev/binderfs/anbox-hwbinder /dev/binderfs/anbox-vndbinder /dev/binderfs/anbox-binder /dev/binderfs/features /dev/binderfs/binder-control /dev/

chmod 777 -R /dev/dri/renderD128

chmod 777 -R /dev/fb0

chmod 777 -R /dev/dma_heap/system

mount -o ro /etc/waydroid-extra/images/system.img /var/lib/waydroid/rootfs

mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay:/var/lib/waydroid/rootfs,upperdir=/var/lib/waydroid/overlay_rw/system,workdir=/var/lib/waydroid/overlay_work/system,xino=off overlay /var/lib/waydroid/rootfs

mount -o ro /etc/waydroid-extra/images/vendor.img /var/lib/waydroid/rootfs/vendor

mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay/vendor:/var/lib/waydroid/rootfs/vendor,upperdir=/var/lib/waydroid/overlay_rw/vendor,workdir=/var/lib/waydroid/overlay_work/vendor,xino=off overlay /var/lib/waydroid/rootfs/vendor

mount -o bind /var/lib/waydroid/waydroid.prop /var/lib/waydroid/rootfs/vendor/waydroid.prop

lxc-start -P /var/lib/waydroid/lxc -n waydroid -- /init

Wait a few seconds, waydroid will show in your screen.
To verify the CT status: lxc-info -P /var/lib/waydroid/lxc -n waydroid -sH
To stop the CT with cli: lxc-stop -P /var/lib/waydroid/lxc -n waydroid -k

B: Run waydroid LXC in privileged LXC CT

Well, I’m just going to continue use CT in previous session to use wayland and pulseaudio’s socket.

Part loop:

Ubuntu has already 7 loop exist, and used 3.
Because I failed to mount img file in host then mount the folder in incus container, i only tried mount in CT.
Add this to the CT’s config:

lxc.cgroup2.devices.allow = c 10:237 rwm
lxc.cgroup2.devices.allow = b 7:4 rwm
lxc.cgroup2.devices.allow = b 7:5 rwm
lxc.cgroup2.devices.allow = b 7:6 rwm
lxc.cgroup2.devices.allow = b 7:7 rwm
lxc.mount.entry = /dev/loop-control dev/loop-control none bind,create=file 0 0
lxc.mount.entry = /dev/loop0 dev/loop0 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop1 dev/loop1 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop2 dev/loop2 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop3 dev/loop3 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop4 dev/loop4 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop5 dev/loop5 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop6 dev/loop6 none bind,optional,create=file 0 0
lxc.mount.entry = /dev/loop7 dev/loop7 none bind,optional,create=file 0 0
lxc.mount.entry = /etc/waydroid-extra/images etc/waydroid-extra/images none bind,create=dir,optional 0 0

Part waydroid need devices and folders

Add this to the CT’s config:

## waydroid devices
lxc.cgroup2.devices.allow = c 29:0 rwm
lxc.cgroup2.devices.allow = c 10:239 rwm
lxc.cgroup2.devices.allow = c 10:200 rwm

lxc.mount.entry = /dev/fb0 dev/fb0 none bind,create=file 0 0
lxc.mount.entry = /dev/uhid dev/uhid none bind,create=file 0 0
lxc.mount.entry = /dev/net/tun dev/net/tun none bind,create=file 0 0
lxc.mount.entry = /dev/fuse dev/fuse none bind,create=file 0 0
lxc.mount.entry = /dev/dma_heap dev/dma_heap none bind,create=dir,optional 0 0
lxc.mount.entry = /dev/char dev/char none bind,create=dir,optional 0 0

Part binder:

I can still give you 2 choices, where do you want /dev/binderfs created? I recommand in CT.

A: in CT:

Add this to the CT’s config:

## binder 
lxc.cgroup2.devices.allow = c 239:0 rwm
lxc.cgroup2.devices.allow = c 239:1 rwm
lxc.cgroup2.devices.allow = c 239:2 rwm
lxc.cgroup2.devices.allow = c 239:3 rwm

/dev/binderfs cannot exist in host, in host run:
modprobe binder_linux

B: in host:

Add this to the CT’s config:

## binder 
lxc.cgroup2.devices.allow = c 239:0 rwm
lxc.cgroup2.devices.allow = c 239:1 rwm
lxc.cgroup2.devices.allow = c 239:2 rwm
lxc.cgroup2.devices.allow = c 239:3 rwm
lxc.mount.entry = /dev/binderfs dev/binderfs none bind,create=dir,optional 0 0

/var/lib/waydroid/binder.py is a part of python3 script from waydroid/tools/helpers/drivers.py at main · waydroid/waydroid · GitHub line 43 to line 65. And add a line to call the function:
allocBinderNodes("", ["anbox-binder", "anbox-hwbinder", "anbox-vndbinder"])

In host run:

modprobe binder_linux

mkdir -p /dev/binderfs

mount -t binder binder /dev/binderfs

/var/lib/waydroid/binder.py

chmod 666 -R /dev/binderfs/anbox-binder

chmod 666 -R /dev/binderfs/anbox-vndbinder

chmod 666 -R /dev/binderfs/anbox-hwbinder

In CT run:

ln -s /dev/binderfs/anbox-hwbinder /dev/binderfs/anbox-vndbinder /dev/binderfs/anbox-binder /dev/binderfs/features /dev/binderfs/binder-control /dev/

Now everything waydroid depends on exist in the CT.

Part prepare script and folder and config files

Do what’s in “Run waydroid LXC in host without install waydroid” in the CT, except /var/lib/waydroid/lxc/waydroid/config, delete every thing start with lxc.net.0. And as user in CT create ~/.local/share/waydroid/data.

Part run waydroid LXC in CT

the full command line after a host boot then start waydroid in LXC If you choose /dev/binderfs in CT should be:
chvt 7
sudo su
modprobe binder_linux
chmod 777 -R /dev/dri/renderD128
chmod 777 -R /dev/fb0
chmod 777 -R /dev/dma_heap/system
# my LXC CT name is debian13
lxc-start --name debian13
lxc-attach --name debian13 --clear-env
mkdir -p /dev/binderfs
mount -t binder binder /dev/binderfs
/var/lib/waydroid/binder.py
chmod 666 -R /dev/binderfs/anbox-binder
chmod 666 -R /dev/binderfs/anbox-vndbinder
chmod 666 -R /dev/binderfs/anbox-hwbinder
chmod 660 /dev/tty0
chmod 660 /dev/tty7
ln -s /dev/binderfs/anbox-hwbinder /dev/binderfs/anbox-vndbinder /dev/binderfs/anbox-binder /dev/binderfs/features /dev/binderfs/binder-control /dev/
mount -o ro /etc/waydroid-extra/images/system.img /var/lib/waydroid/rootfs
mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay:/var/lib/waydroid/rootfs,upperdir=/var/lib/waydroid/overlay_rw/system,workdir=/var/lib/waydroid/overlay_work/system,xino=off overlay /var/lib/waydroid/rootfs
mount -o ro /etc/waydroid-extra/images/vendor.img /var/lib/waydroid/rootfs/vendor
mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay/vendor:/var/lib/waydroid/rootfs/vendor,upperdir=/var/lib/waydroid/overlay_rw/vendor,workdir=/var/lib/waydroid/overlay_work/vendor,xino=off overlay /var/lib/waydroid/rootfs/vendor
mount -o bind /var/lib/waydroid/waydroid.prop /var/lib/waydroid/rootfs/vendor/waydroid.prop
# my username in LXC CT is test
su -l test
WLR_NO_HARDWARE_CURSORS=1 labwc >/dev/null 2>&1 &

sudo lxc-start -P /var/lib/waydroid/lxc -n waydroid -- /init
the full command line after a host boot then start waydroid in LXC If you choose /dev/binderfs in host should be:
chvt 7
sudo su
modprobe binder_linux
chmod 777 -R /dev/dri/renderD128
chmod 777 -R /dev/fb0
chmod 777 -R /dev/dma_heap/system
mkdir -p /dev/binderfs
mount -t binder binder /dev/binderfs
/var/lib/waydroid/binder.py
chmod 666 -R /dev/binderfs/anbox-binder
chmod 666 -R /dev/binderfs/anbox-vndbinder
chmod 666 -R /dev/binderfs/anbox-hwbinder
lxc-start --name debian13
lxc-attach --name debian13 --clear-env
chmod 660 /dev/tty0
chmod 660 /dev/tty7
ln -s /dev/binderfs/anbox-hwbinder /dev/binderfs/anbox-vndbinder /dev/binderfs/anbox-binder /dev/binderfs/features /dev/binderfs/binder-control /dev/
mount -o ro /etc/waydroid-extra/images/system.img /var/lib/waydroid/rootfs
mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay:/var/lib/waydroid/rootfs,upperdir=/var/lib/waydroid/overlay_rw/system,workdir=/var/lib/waydroid/overlay_work/system,xino=off overlay /var/lib/waydroid/rootfs
mount -o ro /etc/waydroid-extra/images/vendor.img /var/lib/waydroid/rootfs/vendor
mount -t overlay -o ro,lowerdir=/var/lib/waydroid/overlay/vendor:/var/lib/waydroid/rootfs/vendor,upperdir=/var/lib/waydroid/overlay_rw/vendor,workdir=/var/lib/waydroid/overlay_work/vendor,xino=off overlay /var/lib/waydroid/rootfs/vendor
mount -o bind /var/lib/waydroid/waydroid.prop /var/lib/waydroid/rootfs/vendor/waydroid.prop
su -l test
WLR_NO_HARDWARE_CURSORS=1 labwc >/dev/null 2>&1 &

sudo lxc-start -P /var/lib/waydroid/lxc -n waydroid -- /init

I’m sorry for this part I shouldn’t make assumption waydroid will work in CT.

This will not work, I make this work in below reply

Guess what I’m going to do.

apt install curl ca-certificates -y
curl -s https://repo.waydro.id | bash
apt update
apt install waydroid -y
waydroid init -f

cat >> /var/lib/waydroid/waydroid.cfg << EOF
ro.hardware.gralloc=default
ro.hardware.egl=swiftshader
EOF

waydroid upgrade -o
systemctl restart waydroid-container.service

Restart the host.
You should run:

modprobe binder_linux
chmod 777 -R /dev/dri/renderD128
chmod 777 -R /dev/fb0
chmod 777 -R /dev/dma_heap/system

If you choose /dev/binderfs in CT, you only need to get in the CT, switch to user and start wayland compositor and audio control service and run waydroid, that all.
If you choose /dev/binderfs in host, you run binderfs create commands. Get in the CT, switch to user and start wayland compositor and audio control service and run waydroid, that all.

Thank to this, even though my first language is Chinese, I can only understand half of what he said:

If you find something is wrong, please reply.

Solved waydroid won’t start in CT.
In host:

sudo modprobe ip_tables
sudo modprobe binder_linux

In CT:
Edit /usr/lib/waydroid/tools/helpers/drivers.py

Turn this fuction:

def probeAshmemDriver(args):
    if not os.path.exists("/dev/ashmem"):
        command = ["modprobe", "-q", "ashmem_linux"]
        tools.helpers.run.user(args, command, check=False)

    if not os.path.exists("/dev/ashmem"):
        return -1

    return 0

into:

def probeAshmemDriver(args):
        return -1

Then as root:

waydroid init -f

cat >> /var/lib/waydroid/waydroid.cfg << EOF
ro.hardware.gralloc=default
ro.hardware.egl=swiftshader
EOF

waydroid upgrade -o
systemctl restart waydroid-container.service

Then as user:
waydroid

What a coincidence, I have been trying to do that for the last two days.
In my case the OS are inverted: host is Proxmox 9 (Debian 13) and LXC container OS is Ubuntu 26.04.

Unfortunately you loose me as I’m not able to follow your explanations scattered across your three messages.
Do you think you could tidy the whole thing a bit ?
Thank you!

I don’t think pve 9 support binder. You can verify with: grep -i -e android -e memfd -e ashmem "/boot/config-$(uname -r)"

root@pve4:~# grep -i -e android -e memfd -e ashmem "/boot/config-$(uname -r)"
CONFIG_LIVEUPDATE_MEMFD=y
CONFIG_KVM_GUEST_MEMFD=y
CONFIG_MEMFD_CREATE=y
CONFIG_X86_ANDROID_TABLETS=m
# Android
CONFIG_ANDROID_BINDER_IPC=m
# CONFIG_ANDROID_BINDER_IPC_RUST is not set
CONFIG_ANDROID_BINDERFS=m
CONFIG_ANDROID_BINDER_DEVICES=""
# end of Android

Great, pve 9 does support binder. If you want to put waydroid in LXC, then it’s depend to you where the wayland compositor and audio manage service run. Although I have only run them in LXC with waydroid. But you know, waydroid mounts external wayland socket and pulseaudio socket, so can you.
The easiest way to do is you run wayland compositor and audio manage service and waydroid run in same LXC. First do what in post 1 to install wayland compositor and audio manage service, then do post 2 step 2 answer B Part loop and Part waydroid need devices and folders and Part binder A, then do post 3.

For someone has to use debian 13 and also want waydroid working, use proxmox 9’s kernel will work. Here is the step:

wget https://enterprise.proxmox.com/debian/proxmox-release-trixie.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg

cat >/etc/apt/sources.list.d/pve-no-subscription.sources <<'EOF'
Types: deb
URIs: https://download.proxmox.com/debian/pve
Suites: trixie
Components: pve-no-subscription
Signed-By: /etc/apt/trusted.gpg.d/proxmox-release-trixie.gpg
EOF

apt update

apt install proxmox-default-kernel -y

update-initramfs -u -k all

update-grub

reboot

After reboot.

$ grep -i -e android -e memfd -e ashmem "/boot/config-$(uname -r)"
CONFIG_LIVEUPDATE_MEMFD=y
CONFIG_KVM_GUEST_MEMFD=y
CONFIG_MEMFD_CREATE=y
CONFIG_X86_ANDROID_TABLETS=m
# Android
CONFIG_ANDROID_BINDER_IPC=m
# CONFIG_ANDROID_BINDER_IPC_RUST is not set
CONFIG_ANDROID_BINDERFS=m
CONFIG_ANDROID_BINDER_DEVICES=""
# end of Android

I don’t know how it may affect system stability, but I guess it won’t break very often, I can run pve 9 for mouths without trouble.