How to share a folder between a host and a container in Incus

Incus is a manager for virtual machines and system containers.

A system container (therein container) is an instance of an operating system that also runs on a computer, along with the main operating system. A system container uses, instead, security primitives of the Linux kernel for the separation from the main operating system. You can think of system containers as software virtual machines.

In this post we are going to see how to conveniently share a folder between the host and an Incus container. The common use-case is that you want to share directly files between the host and a container and you want the file ownership to be handled well. Note that in a container the UID and GID do not correspond to the same values as on the host.

Therefore, we are looking on how to share storage between the host and one or more Incus containers. The other case that we look into earlier, is to share storage between containers that has been allocated on the Incus storage pool.

Quick answer

incus config device add mycontainer mysharedfolder disk source=/home/myusername/SHARED path=/SHARED shift=true

Table of Contents

Background

On a Linux system the User ID (UID) and Group ID (GID) values are generally in the range of 0 (for root) to 65534 (for nobody). You can verify this by having a look at your /etc/passwd file on your system. In this file, each line is a different account; either a system account or a user account. Such a sample line is the following. There are several fields, separated by a colon character (:). The first field is the user name (here, root). The third field is the numeric user ID (UID) with the value of 0. The fourth field is the numeric group ID (GID) with the value of 0 as well. This is the root account.

root:x:0:0:root:/root:/bin/bash

Let’s do another one. The default user account in Debian and Debian-derived Linux distributions. The username in this Linux installation is myusername, the UID is 1000 and the GID is 1000 as well. This value of 1000 is quite common between Linux distributions.

myusername:x:1000:1000:User,,,:/home/user:/bin/bash

And now this one is the last one we will do. This is a special account with username nobody, and UID/GID at 65534. The purpose of this account is to be used for resources that somehow do not have a valid ID, or for processes and services that are expected to have the least privileges. In an Incus container you will see nobody and nogroup if you shared a folder and the translation of the IDs between the host and the container did not work well or did not happen at all.

nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin

Somewhat sharing folders between the host and Incus containers

To share a directory from the host to your Incus container(s), you add a disk device using incus config device. Here, mycontainer is the name of the container. And mysharedfolder is the name of the share which is only visible in Incus. You specify the source (an existing folder on the host) and the path (a folder in the container). However, there’s one big issue here. There’s no translation between the UID and GID of the files and directories in that folder.

incus config device add mycontainer mysharedfolder disk source=/home/myusername/SHARED path=/SHARED

Here’s on the host and in the container and then again on the host. In the last command it shows an empty folder. I think it’s possible to view the contents of SHARED in the container from the viewpoint of the host. It would require a smart use of the nsenter command to enter the proper namespace which I am not sure yet how to do for ZFS storage pools. If it worked, it would show that UID of myusername in the container from the viewpoint of the host, it would be something like 1001000 (Base ID 100000 plus 1000 for the first non-root account). That is, if the container has files with UID/GID outside of its range of 100000 – 165535, those files are not accessible from within the container.

$ ls -l SHARED/
total 0
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 one
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 two
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 three
$ incus exec mycontainer -- ls -l /SHARED/
total 0
-rw-rw-r-- 1 nobody nogroup 0 Jul 30 16:26 one
-rw-rw-r-- 1 nobody nogroup 0 Jul 30 16:26 three
-rw-rw-r-- 1 nobody nogroup 0 Jul 30 16:26 two
$ sudo ls -l /var/lib/incus/containers/mycontainer/rootfs/SHARED
total 0
$ 

This was a good exercise to show the common mistake in sharing a folder from the host to the container. You can now remove the disk device and do it again properly.

$ incus config device remove mycontainer mysharedfolder
Device mysharedfolder removed from mycontainer
$ 

How to properly share a folder between a host and a container in Incus

The shared folder requires some sort of automated UID/GID shifting so that from the point of view of the container, it has valid (within range) values for the UID/GID. This is achieved with the parameter shift=true when we create the Incus disk device.

Let’s see a full example. We create a container and then create a folder on the host, which we call SHARED. Then, in that folder we create three empty files using the touch command. We are being fancy here. Then, we create the Incus disk device to share the folder into the container, and enable shift=true.

$ incus launch images:ubuntu/24.04/cloud mycontainer
Launching mycontainer
$ mkdir SHARED
$ touch SHARED/one SHARED/two SHARED/there
$ incus config device add mycontainer mysharedfolder disk source=/home/myusername/SHARED path=/SHARED shift=true
Device mysharedfolder added to mycontainer
$ 

where

  • incus config device, the Incus command to configure devices.
  • add, we add a device.
  • mycontainer, the name of the container.
  • mysharedfolder, the name of the shared folder. This is only visible from the host, and it’s just any name. We need a name so that we can specify the device when we want to perform further management.
  • disk, this is a disk device. Currently, Incus supports 12 types of devices.
  • source=/home/myusername/SHARED, the absolute path to the source folder. We type source= and then source folder, no spaces in between. The source folder (which is on the host) must already exist.
  • path=/SHARED, the absolute path to the folder in the container.
  • shift=true, the setting that automagically performs the necessary UID/GID translation.

In some cases, for example when your Linux kernel on the Incus host is old, the shift=true setting may not work. Or, some filesystems may not support it. I leave it to you to report back any cases where this did not work. In the comments below.

Let’s verify that everything work OK. First we see the files on the host. In my case, both the user myusername and group myusername have UID and GID 1000. In the container (which was images:ubuntu/24.04/cloud) they also have the same UID/GID of 1000, but for this Ubuntu runtime the default username with UID 1000 is ubuntu, and the default group with GID 1000 is lxd. These are just names and are not important. If you are still unsure, then use ls with the added parameter --numeric-uid-gid to show the numeric IDs. In both cases below, the UID and GID are 1000.

$ ls -l SHARED/
total 0
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 one
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 two
-rw-rw-r-- 1 myusername myusername 0 Ιουλ 30 19:26 three
$ incus exec mycontainer -- ls -l /SHARED/
total 0
-rw-rw-r-- 1 ubuntu lxd 0 Jul 30 16:26 one
-rw-rw-r-- 1 ubuntu lxd 0 Jul 30 16:26 two
-rw-rw-r-- 1 ubuntu lxd 0 Jul 30 16:26 three
$ 

If we had created an images:debian/12/cloud container, here is how the files would look like. The username with UID 1000 is debian, and the group with GID 1000 is netdev.

$ incus exec mycontainer -- ls -l /SHARED/
total 0
-rw-rw-r-- 1 debian netdev 0 Jul 30 16:26 one
-rw-rw-r-- 1 debian netdev 0 Jul 30 16:26 three
-rw-rw-r-- 1 debian netdev 0 Jul 30 16:26 two
$ 

You can create files and subfolders in the shared folder, either on the host or in the container. You can also share it between more containers.

Incus config device commads

Let’s have a look at the incus config device commands.

$ incus config device 
Usage:
  incus config device [flags]
  incus config device [command]

Available Commands:
  add         Add instance devices
  get         Get values for device configuration keys
  list        List instance devices
  override    Copy profile inherited devices and override configuration keys
  remove      Remove instance devices
  set         Set device configuration keys
  show        Show full device configuration
  unset       Unset device configuration keys

Global Flags:
      --debug          Show all debug messages
      --force-local    Force using the local unix socket
  -h, --help           Print help
      --project        Override the source project
  -q, --quiet          Don't show progress information
      --sub-commands   Use with help or --help to view sub-commands
  -v, --verbose        Show all information messages
      --version        Print version number

Use "incus config device [command] --help" for more information about a command.
$ 

We are going to use some of those commands. First, we list the disk devices. There’s currently only one disk device, mysharedfolder. We then show the disk device. We get the list of parameters, which we can get individually and even set them to different values. We then get the value of the path parameter. Finally, we remove the disk device. We have not shown how to override, set and unset.

$ incus config device list mycontainer
mysharedfolder
$ incus config device show mycontainer
mysharedfolder:
  path: /SHARED
  shift: "true"
  source: /home/myusername/SHARED
  type: disk
$ incus config device get mycontainer mysharedfolder path
/SHARED
$ incus config device remove mycontainer mysharedfolder 
Device mysharedfolder removed from mycontainer
$ 

Conclusion

We have seen how to create disk devices on Incus containers in order to share a folder from the host to one or more containers. Using shift=true we can take care of the translation of the UIDs and GIDs. I am interested in corner cases where these do not work. It would help me fix this post, and eventually move it to the official documentation of Incus.

Permanent link to this article: https://blog.simos.info/how-to-share-a-folder-between-a-host-and-a-container-in-incus/

3 comments

    • Axel on November 14, 2024 at 18:11
    • Reply

    Hello, Thanks a lot for this blog post.

    Do you know if it is possible to do this in a profile for automatically add a shared disk when creating an instance ?

    Thanks

  1. I get “Error: Failed to start device “macmini”: Required idmapping abilities not available” on Mac OS as host with Debian as guest container.

    • Richard on April 4, 2025 at 17:24
    • Reply

    I wish to map into a container directory on a cifs share. I’ve found out that one cannot install cifs-utils and use fstab within the container to access the share directly so I have mounted the cifs share on the host and made a drive mapping similar to above. I cannot make shift=true work with such a cifs share mapping. I have got it to work by making the mapping without the ‘shift = true’ and then making an id-mapping: $ incus config set iqBt raw.idmap “both 110000 110000” and I can see what that has done in the container YAML. I have also added ‘root:110000:1’ to both /etc/subgid and /etc/subuid on the host but not really sure if that is correct and necessary?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.