Adding the same disk to multiple containers and resultant permissions

Hi,

Perhaps the answer to this is staring me in the face; I just can’t see it.

I am running Incus on a very vanilla Debian 13, this has ZFS datasets similar to the following table:

NAME MOUNTPOINT
tank/nasdisk/files /mnt/files
tank/nasdisk/files/ftp /mnt/files/ftp
tank/nasdisk/media/photos /mnt/media/photos
tank/nasdisk/media/tunes /mnt/media/tunes
tank/websites /mnt/websites

I have an Incus container called nas. I use this machine to provide basic file-sharing on my LAN. I added disk devices to this container with Incus, using the following syntax:
incus config device add nas files disk source=/mnt/files path=/mnt/files shift=true etc…
The owner and group for these are stephen and samba

I have another container called ftp. I added a disk device to this container using:
incus config device add ftp ftpdisk disk source=/mnt/files/ftp path=/mnt/ftp shift=true
The owner and group for this is 1001 and ftpuser. I am not sure why user is 1001
This container has a vsftpd daemon and the user ftpuser can upload files to /mnt/ftp/

If I ls -l /mnt/files on nas I see that the folder /mnt/files/ftp has owner and group nobody and nogroup and is therefore inaccessible from other locations on my LAN.

So my question is, what is the best way to share multiple folders to multiple containers with a variety of users? Would I be better off using fstab and smb, rather than adding the location as disk devices? Adding disk devices seems more elegant to me, but I just can’t grasp the best way to do so.

What do the actual permission in /mnt on the host look like?

Hi Stéphane,

ls -l /mnt on the Incus host

drwxrws— incus-sysadmin stephen files
drwxr-xr-x root root media
drwxr-sr-x incus-sysadmin www-data websites

incus-sysadmin is a member of incus-admin
The group www-data exists on the host, however it is for Apache in a container called lamp. I can’t remember why that group exists on the host. I was having trouble with permissions for web development too (note also the setuid bit).

EDIT: no-one is in the group www-data on the host.
The mnt/files/ftp directory also appears empty to the user stephen from a LAN client (I can see the folder contents using an FTP client from the LAN client with the username ftpuser)

I can see the contents from the container ftp so can confirm that uploads are being made.

I guess what’s really not clicking for me is how permissions propagate up and down

Can you show:

  • incus config show --expanded nas
  • incus config show --expanded ftp
  • stat /mnt/files
  • stat /mnt/files/ftp
  • incus exec nas -- stat /mnt/files
  • incus exec nas -- stat /mnt/files/ftp
  • incus exec ftp -- stat /mnt/ftp

incus config show --expanded nas

architecture: x86_64
config:
  environment.TZ: Europe/London
  image.architecture: amd64
  image.description: Debian bookworm amd64 (20240613_05:24)
  image.os: Debian
  image.release: bookworm
  image.serial: '20240613_05:24'
  image.type: squashfs
  image.variant: default
  volatile.base_image: 0b892fb5e94a45dad6d76f413ba7ac471691cb67bf425e060eb336bf1be81880
  volatile.cloud-init.instance-id: 5fcee70b-59c7-4605-89b2-bfa191a5eaf2
  volatile.eth0.host_name: mac45b66d58
  volatile.eth0.hwaddr: 00:16:3e:fe:18:3e
  volatile.eth0.last_state.created: "false"
  volatile.eth0.name: eth0
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: RUNNING
  volatile.uuid: a1e06318-b4cc-46ca-8699-8a6df4301d28
  volatile.uuid.generation: a1e06318-b4cc-46ca-8699-8a6df4301d28
devices:
  captures:
    path: /mnt/media/captures
    shift: "true"
    source: /mnt/media/captures
    type: disk
  documents:
    path: /mnt/media/documents
    shift: "true"
    source: /mnt/media/documents
    type: disk
  eth0:
    nictype: macvlan
    parent: eno1.31
    type: nic
  files:
    path: /mnt/files
    shift: "true"
    source: /mnt/files
    type: disk
  ftp:
    path: /mnt/ftp
    shift: "true"
    source: /mnt/files/ftp
    type: disk
  literature:
    path: /mnt/media/literature
    shift: "true"
    source: /mnt/media/literature
    type: disk
  movies:
    path: /mnt/media/movies
    shift: "true"
    source: /mnt/media/movies
    type: disk
  photos:
    path: /mnt/media/photos
    shift: "true"
    source: /mnt/media/photos
    type: disk
  root:
    path: /
    pool: default
    type: disk
  series:
    path: /mnt/media/series
    shift: "true"
    source: /mnt/media/series
    type: disk
  tunes:
    path: /mnt/media/tunes
    shift: "true"
    source: /mnt/media/tunes
    type: disk
  websites:
    path: /mnt/websites
    shift: "true"
    source: /mnt/websites
    type: disk
ephemeral: false
profiles:
  - infravlan
stateful: false
description: ""

incus config show --expanded ftp

architecture: x86_64
config:
  environment.TZ: Europe/London
  image.architecture: amd64
  image.description: Alpine 3.24 amd64 (20260727_13:15)
  image.os: Alpine
  image.release: "3.24"
  image.requirements.secureboot: "false"
  image.serial: '20260727_13:15'
  image.type: squashfs
  image.variant: default
  volatile.base_image: 82bd433982f98b730c998e912643b1a93d7bc19fb90fc4c0c4cb2a1ffa01beb3
  volatile.cloud-init.instance-id: a52cf487-91c3-4794-9279-91bb1e2a868a
  volatile.eth0.host_name: mac58c7fbad
  volatile.eth0.hwaddr: 10:66:6a:2b:d4:09
  volatile.eth0.last_state.created: "false"
  volatile.eth0.name: eth0
  volatile.idmap.base: "0"
  volatile.idmap.current: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.idmap.next: '[{"Isuid":true,"Isgid":false,"Hostid":1000000,"Nsid":0,"Maprange":1000000000},{"Isuid":false,"Isgid":true,"Hostid":1000000,"Nsid":0,"Maprange":1000000000}]'
  volatile.last_state.idmap: '[]'
  volatile.last_state.power: RUNNING
  volatile.uuid: c2d7ca60-2908-4ef9-abe6-77c29bc36840
  volatile.uuid.generation: c2d7ca60-2908-4ef9-abe6-77c29bc36840
devices:
  eth0:
    nictype: macvlan
    parent: eno1.31
    type: nic
  ftpdisk:
    path: /mnt/ftp
    shift: "true"
    source: /mnt/files/ftp
    type: disk
  root:
    path: /
    pool: default
    type: disk
ephemeral: false
profiles:
  - infravlan
stateful: false
description: ""

stat /mnt/files

  File: /mnt/files
  Size: 21              Blocks: 49         IO Block: 16384  directory
Device: 0,50    Inode: 34          Links: 18
Access: (2770/drwxrws---)  Uid: ( 1001/incus-sysadmin)   Gid: ( 1000/ stephen)
Access: 2026-07-29 16:10:56.046829454 +0100
Modify: 2026-07-28 15:30:17.549716416 +0100
Change: 2026-07-28 15:30:17.549716416 +0100
 Birth: 2024-06-15 11:38:33.437672554 +0100

stat /mnt/files/ftp

  File: /mnt/files/ftp
  Size: 3               Blocks: 1          IO Block: 512    directory
Device: 0,61    Inode: 34          Links: 3
Access: (2770/drwxrws---)  Uid: ( 1001/incus-sysadmin)   Gid: ( 1000/ stephen)
Access: 2026-07-28 15:51:46.297885407 +0100
Modify: 2026-07-28 15:49:34.878294610 +0100
Change: 2026-07-28 15:49:34.878294610 +0100
 Birth: 2026-07-28 15:30:17.421716830 +0100

incus exec nas – stat /mnt/files

  File: /mnt/files
  Size: 21              Blocks: 49         IO Block: 16384  directory
Device: 0,50    Inode: 34          Links: 18
Access: (2770/drwxrws---)  Uid: ( 1001/ stephen)   Gid: ( 1000/   samba)
Access: 2026-07-29 16:10:56.046829454 +0100
Modify: 2026-07-28 15:30:17.549716416 +0100
Change: 2026-07-28 15:30:17.549716416 +0100
 Birth: 2024-06-15 11:38:33.437672554 +0100

incus exec nas – stat /mnt/files/ftp

  File: /mnt/files/ftp
  Size: 2               Blocks: 1          IO Block: 512    directory
Device: 0,50    Inode: 266842      Links: 2
Access: (2755/drwxr-sr-x)  Uid: ( 1001/ stephen)   Gid: ( 1000/   samba)
Access: 2026-07-29 13:59:41.476998957 +0100
Modify: 2026-07-28 15:30:17.549716416 +0100
Change: 2026-07-29 13:59:39.933000557 +0100
 Birth: 2026-07-28 15:30:17.549716416 +0100

incus exec ftp – stat /mnt/ftp

  File: /mnt/ftp
  Size: 3               Blocks: 1          IO Block: 512    directory
Device: 3dh/61d Inode: 34          Links: 3
Access: (2770/drwxrws---)  Uid: ( 1001/ UNKNOWN)   Gid: ( 1000/ ftpuser)
Access: 2026-07-28 14:51:46.297885407 +0000
Modify: 2026-07-28 14:49:34.878294610 +0000
Change: 2026-07-28 14:49:34.878294610 +0000

Maybe you need rbind @stgraber ?

Also when working with multiple users needing the resources I found posix ACL’s the best.

Like setfacl -m 'u:jochumdev:rwx,d:u:jochumdev:rwx' /home/r3j0

Okay, so there are actually no problems at all. We see the same uid/gid in all cases, everything is working as intended.

The only problem you have is about the user and group name as in one container you do have a user and group from it (per /etc/passwd, /etc/group) and in the other one you do not, leading to it reporting an unknown value.

User and group names are purely a userspace concept implemented through NSS (/etc/passwd, /etc/group, …), the Linux kernel (and by extension here, Incus and LXC) only work with uid/gid and those we can see are correct across the board.

So do I need to create each user/group on both host and container? Or just the host?

If I ls -l /mnt/files/ftp on nas it appears empty
If I ls -l /mnt/ftp on ftp I see subdirectories and files
If I ls -l /mnt/files/ftp on the server I see subdirectories and files

How would all this be different if I was using LDAP?

You need to create them all in all containers and if the host needs them too, then on the host too.
LDAP if configured in all containers and on the host would also work.

So if I add a directory that is root:root on the host, by default it will be root:root in the container (withshift=true)?
Then if I change permissions in the nas container to be stephen:samba, the permissions on the host will stay root:root?
If I now use SMB to share that, users on other machines would need an account on nas that was either stephen or was in the samba group?

However, if I now added the same disk device to another container, say ftp, it would have permissions root:root (from the host). In this scenario, if I changed to permissions on ftp to ftpuser:ftp, permissions would still be root:root on the host and I would have to add the ftpuser to any other machine that wanted access to it?

Stop thinking about user and group names, those are meaningless and the source of your confusion.

With shift=true, the uids and gids match between the host and the container.

If a file is owned by root/root (0/0), it will show up as root/root (0/0) in the container.
If the file is owned by 1000/1000, it will show up as 1000/1000 in both host and container.

The reported user name and group name completely depends on whatever you have listed for user 1000 and group 1000 in /etc/passwd and /etc/group. If the host has foo set for 1000 in both and the container has bar set for 1000 in both, then you’ll see foo/foo on the host and bar/bar in the container.

So think purely in terms of UID/GID

1000/1000 on Server can be root:root
1000/1000 on ftp can be ftpuser:ftp
1000/1000 on nas can be stephen:samba
1000/1000 on lamp can be stephen:www-data

Any changes to permissions in a container will not affect the permissions on the host.
But a user in a container will only have permissions if they have a UID/GID that is mapped to the host?

root/root is 0/0, so that can’t really be true, no.

Change of permissions will absolutely affect the host. If you chown 2000:2000 foo, foo will show as being owned by 2000/2000 on the host too.

The user in the container will have access to the file if the file mode allows access for either their uid or for a group they’re a member of, same as all file accesses always work on all UNIX systems.

A nice solution for this is nss-extrausers.

On the host, create these files with userids > 1000 (I start at 2000 to avoid clashing with locally-created accounts in the container’s own passwd file):

# ls /var/lib/extrausers/
group  passwd  shadow
# cat /var/lib/extrausers/group
brian:x:2000:
... etc
# cat /var/lib/extrausers/passwd
brian:x:2000:2000::/home/brian:/bin/bash
... etc
# cat /var/lib/extrausers/shadow
brian:!:18401:0:99999:7:::
... etc

Mount this directory into each container, by adding it as a disk device:

incus config device add `<container>` extrausers disk source=/var/lib/extrausers/ path=/var/lib/extrausers/

or do this in a profile:

devices:
  extrausers:
    path: /var/lib/extrausers/
    source: /var/lib/extrausers/
    type: disk

Then install package libnss-extrausers in each container, and configure it in /etc/nsswitch.conf:

passwd:         files extrausers systemd
group:          files extrausers systemd
shadow:         files extrausers

Now all containers can resolve all the uid/gids in /var/lib/extrausers