Better way to idmap and control devices permissions in LCX

Tecnolobo

New Member
Jul 20, 2026
4
2
3
Hi everyone.

I've been using Proxmox for about 30 days, and I came up with a different way to make `idmap` work more transparently.

Most of the posts I found explain how to customize `idmap` so that the host users and groups match those inside the container, allowing the container to access host devices.

This usually results in a configuration like this:

lxc.idmap: u 0 100000 65536
lxc.idmap: g 0 100000 44
lxc.idmap: g 44 44 1
lxc.idmap: g 45 100045 62
lxc.idmap: g 107 104 1
lxc.idmap: g 108 100108 65428

If you need to add another user or group, you often have to adjust multiple lines to keep the mapping consistent.

In my opinion, this approach forces the container to adapt to the host permissions. It is difficult to read, harder to maintain, more error-prone, and also depends on the Linux template's users and groups never changing.

I looked for a different solution and remembered that POSIX ACLs allow multiple permissions to be assigned to the same device.

So here's the idea: instead of changing the ID mapping to fit the permissions, change the permissions to fit a simple ID mapping.

For my container (ID 200), I map every user and group into the range `<container-id>00000`, except for root:

lxc.idmap: u 0 100000 1
lxc.idmap: g 0 100000 1
lxc.idmap: u 1 20000001 65535
lxc.idmap: g 1 20000001 65535

Then I use `lxc.hook.pre-start` to automatically update the configuration and apply the required ACLs when the container starts.

Add the container UID range to `/etc/subuid`:
lxc.hook.pre-start: /bin/bash -c 'file="/etc/subuid"; find_string="root:${LXC_NAME}00000:65536"; grep -xFq "${find_string}" ${file} || echo "${find_string}" >> ${file}'
Add the container GID range to `/etc/subgid`:
lxc.hook.pre-start: /bin/bash -c 'file="/etc/subgid"; find_string="root:${LXC_NAME}00000:65536"; grep -xFq "${find_string}" ${file} || echo "${find_string}" >> ${file}'
Grant the `input` group inside the container access to the input devices:
lxc.hook.pre-start: /bin/bash -c 'setfacl -R -m u:100000:rw,g:${LXC_NAME}00101:rw /dev/input/*'
Grant the `audio` group inside the container access to the sound devices:
lxc.hook.pre-start: /bin/bash -c 'setfacl -R -m u:100000:rw,g:${LXC_NAME}00029:rw /dev/snd/*'

This results in a much cleaner and easier-to-maintain configuration. On the host, you only need to install the ACL package:
sudo apt update && sudo apt install acl


Using this approach, I finally have a container running a full desktop environment using the host GPU for display output, with LightDM, the MATE desktop, Steam, and emulators. Xorg automatically detects the keyboard and mouse. Still working on joystick support.

The only issue I still have is that keyboards input occasionally leaks to the host virtual terminal. I'm still investigating that.

Important !!!!!!!!!

When you first create the container, all users and groups are mapped into the default `100000` range. Before switching to this mapping scheme, stop the container and update the ownership of the files inside the container filesystem.

To list all UIDs and GIDs currently in use:

TARGET_DIR="<YOUR_CONTAINER_DIR>"; sudo find "$TARGET_DIR" -printf "%u\n" 2>/dev/null | sort -u | awk '$1 >= 100001' > uids.txt
TARGET_DIR="<YOUR_CONTAINER_DIR>"; sudo find "$TARGET_DIR" -printf "%g\n" 2>/dev/null | sort -u | awk '$1 >= 100001' > gids.txt

After checking the generated lists, convert the ownerships:

TARGET_DIR="<YOUR_CONTAINER_DIR>"; CONTAINER=<CONTAINER_ID>; while read -r id; do [ -n "$id" ] && echo "UID: $id -> $((id-100000+${CONTAINER}00000))" && sudo find "$TARGET_DIR" -uid "$id" -exec chown "$((id-100000+${CONTAINER}00000))" {} +; done < uids.txt
TARGET_DIR="<YOUR_CONTAINER_DIR>"; CONTAINER=<CONTAINER_ID>; while read -r id; do [ -n "$id" ] && echo "GID: $id -> $((id-100000+${CONTAINER}00000))" && sudo find "$TARGET_DIR" -gid "$id" -exec chgrp "$((id-100000+${CONTAINER}00000))" {} +; done < gids.txt


Don't forget to adjust the container ID and directory paths to match your own setup.

This approach has worked well for me so far, and I find it much easier to understand and maintain than a complex `idmap` configuration.

I'd be interested to hear if anyone sees any drawbacks to this approach or has suggestions for improving it.
 
Using the device passthrough feature should be easier. Find it in the web UI under "Add" -> "Device Passthrough". In the "Advanced" section you can configure the permissions and ownership.
 
Using the device passthrough feature should be easier. Find it in the web UI under "Add" -> "Device Passthrough". In the "Advanced" section you can configure the permissions and ownership.
I have tried to pass the /dev/input and the /dev/input/* and don't work, probably I have made some error, or these way don't allow to pass a full directory.

Can you explain better how I can do it?

Thanks.
 
Your issue is that GRUB (even the downgraded 2.06) isn't properly handling your mdadm RAID1 setup for /boot and EFI after the Proxmox 9 upgrade. It worked fine in PVE 8, but the upgrade messed up the automatic detection/config.

The manual boot with set root=(md/2) works because you're forcing it to the right RAID device. Device numbers can shift, which is why it doesn't stick on reboot.

Quick Fix (once you boot manually):​

  1. Boot with your usual manual commands.
  2. Run these as root:
    Code:
    apt update
    apt install --reinstall mdadm
    
    # Update mdadm config
    mdadm --detail --scan >> /etc/mdadm/mdadm.conf
    
    # Rebuild initramfs
    update-initramfs -u -k all
    
    # Reinstall GRUB on both disks
    grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=proxmox --recheck /dev/sda
    grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=proxmox --recheck /dev/sdb
    
    update-grub
Reboot and see if it works.

If it still drops to GRUB:​

Check /etc/default/grub and make sure the kernel line has the right root device (e.g. root=/dev/md125 or better, use the UUID).
Then run update-grub again.
Some people with mdadm /boot also create a custom GRUB snippet in /etc/grub.d/ to force the set root=(md/...) or mduuid.


Tips​

  • Proxmox doesn't really like mdadm for boot stuff anymore (they prefer ZFS). If you can, migrating to ZFS mirror later would be cleaner.
  • Keep GRUB pinned so it doesn't auto-upgrade and break again.
  • Sync your EFI partitions manually if they ever get out of sync.
If it still doesn't boot automatically after this, paste the output of these commands (after manual boot):
Code:
lsblk -f
cat /proc/mdstat
efibootmgr -v



Systems Thinker. Builder of Proximo - The Proxmox MCP you can hand the keys — VE + Backup Server + Mail Gateway + Datacenter Manager on one audited trust core (plan · prove · undo · diagnose). MCP + A2A + API

Hi. I think you reply at wrong post.
 
I have tried to pass the /dev/input and the /dev/input/* and don't work, probably I have made some error, or these way don't allow to pass a full directory.

Can you explain better how I can do it?
You cannot pass a directory through with the Device Passthrough feature. It only accepts individual device nodes. You would need to add each device node individually (e.g. /dev/input/event0, /dev/input/event1, ...).

If you only need a few specific devices, it is a good idea to create persistently named symlinks with udev rules, since the /dev/input/event<n> numbering can change between reboots or when devices are reconnected.

If your goal is to expose all input devices to the container, your approach is fine aswell.
 
  • Like
Reactions: Johannes S
You cannot pass a directory through with the Device Passthrough feature. It only accepts individual device nodes. You would need to add each device node individually (e.g. /dev/input/event0, /dev/input/event1, ...).

If you only need a few specific devices, it is a good idea to create persistently named symlinks with udev rules, since the /dev/input/event<n> numbering can change between reboots or when devices are reconnected.

If your goal is to expose all input devices to the container, your approach is fine aswell.
How these aprouch will work with devices connected after the container has started.

Like I said, I am trying to run a full desktop inside a LXC in the proxmox.

Still have a problem with keys leaking to the host terminal, but resolve it with the mask, stop the Getty service on container start-up and restore after container stop.

And cannot make the polkit security run.

Sound working. Need check if is possible pass a full usb port to inside container for use of usb devices inside container.