Proxmox LXC Containers with Audio and Giocoso
1.0 Introduction
I've recently moved to using Proxmox as my virtualisation platform: it is based on Debian and thus uses Linux's native KVM hypervisor capabilities (the previous virtualisation technology I was using), so it's generally quite straightforward, but with a nice web UI making things very point-and-click. A refinement of this, however, was a technology that I'd never actually used before: LXC Containers. These are incredibly lightweight, minimal virtualised environments, rather than the full-fat virtual machines that I've used for about 26 years now!
When I'm testing new builds of Giocoso, Semplice or Niente, it helps to be able to knock together a slim environment in which to check I haven't badly broken anything: LXC Containers are much speedier to deploy than 'proper' virtual machines, so this was definitely a technology I wanted to crack.
The “problem” with containers is that they really are minimal: they come with no GUI, no audio, no nothing that would allow a music-playing program like Giocoso to operate effectively… which rather seems to defeat their intended purpose! Fortunately, it's fixable and with a bit of command line shenanigans, you get to have the simplicity of a container with all the graphical and audible tools needed to be useful.
However: the “shenanigans” involved are really quite elaborate and complex shenanigans and this is definitely not for the faint-hearted! Each distro has its own quirks and peculiarities. I'll document those for Arch, Fedora, Ubuntu and Linux Mint: the same principles then apply to any other distro, but the specifics will need to be worked out by yourself according to what otherwise breaks or works!
I'll begin by discussing two ways of adding shared, on-the-network storage to your Proxmox environment: managed storage and un-managed storage. This is something you'll do once-only to your Proxmox host and all your containers will benefit from it thereafter, so it's as well to get this out of the way up-front before tackling distro-specific container issues.
2.0 Adding Managed NFS Storage to the Proxmox Host
NFS storage is added to a Proxmox environment in two distinct ways, depending on whether you want Proxmox to manage them or whether you just want Proxmox to access them (perhaps even in read-only mode).
Managed network storage is created via the Proxmox web interface; unmanaged storage has to be created using the command line. Managed storage is what you want when you need to back up your containers and virtual machines: it's storage that Proxmox will create a number of folders in and keep an eye on automatically once it's been created. This is not, therefore, how you get NFS storage visible to containers and virtual machines: it's only network storage that the Proxmox host itself will be able to see and use.
So, with all that out of the way, we start with this situation:
That's a fresh Proxmox installation with local storage only. To add a storage location on the NAS which Proxmox will manage (and create a bunch of subfolders in), it's sufficient to click on the Datacenter → Storage options, click [Add], then select NFS from the drop-down. Fill in the details of the server and the share, like so:
The 'Content' field is the important bit: it defines what Proxmox can store on the share and what it expects to find there (and what sub-folders it will create there). If you say content is 'backup', for example, it will create a 'dump' folder and your backups of containers and VMs will be stored there. If you want to upload an ISO to the NAS, that would require you to select the ISO Image content type, and so on.
In my case, I actually only want this mechanism to allow containers to be backed up, so I select only the Backup content type. Click [OK] to submit the selection and I end up with this sort of thing:
My 'Copland' host is allowed to see the NAS for backups and restores -and that's it.
3.0 Adding an unmanaged NAS Share to the Proxmox Host
So, now click on the Proxmox host item in the Web Gui (i.e., the one directly under 'datacenter': in my case, that's “Copland”):
Visit the Shell item in the middle pane and you'll see a command line interface on the right, with you logged in as root. You now create a mount point on the host, as follows:
mkdir -p /mnt/nas_music
(The specific name of the mount point doesn't really matter, but “nas_music” is good enough here).
You then issue a variant of this command:
echo "192.168.137.1:/bulkdata/music/ /mnt/nas_music nfs rw,hard,intr,rsize=131072,wsize=131072,timeo=14 0 0" >> /etc/fstab
That's assuming your NAS has IP 192.168.137.1, and that it's exporting the music collection at /bulkdata/music. This entry in the fstab file says 'mount that share on that NAS at the local mount point /mnt/nas_music, which I just created'. The long list of options (such as “rw,hard” and so on) are there to make fetching data across the network between the NAS and Proxmox as efficient as possible.
To actually mount the share, you then issue the command:
mount /mnt/nas_music
You will probably be told that “ount: (hint) your fstab has been modified, but systemd still uses the old version; use 'systemctl daemon-reload' to reload.” If you see that message, just issue these commands:
systemctl daemon-reload mount /mnt/nas_music
You can then check that the Proxmox host now “sees” the music folder structure you're expecting it to see:
Once the Proxmox host can see the music collection, we can make containers see it to.
4.0 Making a Bind Mount
I created an Ubuntu 25.04 container, using a downloaded template. I built it as a privileged container: the default is to be unprivileged, so you have to actively uncheck that option on the first screen of the container builder wizard. That also disables nested virtualization by default (running virtual machines inside the container). The GUI doesn't let you have Nesting if you've unchecked the Unprivileged container option, though you can re-enable Nesting after the container is built if you feel you need to.
Once the container is built, go back to the Proxmox host's shell (that's Copland on my setup, then click Shell in the middle pane) and issue the command:
pct set 100 -mp0 /mnt/nas_music,mp=/mnt/music
That “100” is the ID of the freshly-built container, so change it to match whatever ID is assigned to your new container. The rest of the command says that the hosts mount point of /mnt/nas_music should become the mountpoint /mnt/music within the container. This isn't being managed by the usual /etc/fstab mechanism: this is Proxmox forcing a mount into the container. This arrangement is called a bind mount.
Bind mounts can be created with the container running, but they don't take effect until the container has then bounced down and back up. I created mine with the container closed down anyway, so I can now just start mine up.
Once it has started, I can click on the container's Console option and see this:
Specific notes for Ubuntu 25.04:
- The container came up but to a blank, black screen. This is fixed by clicking the container, going to Options, and setting “console mode” to /dev/console. It defaults to tty, which is wrong for this OS.
- The container then came up with text visible on the console, but the text was a nightmare of errors. This is fixed by clicking the container, going to Options, clicking Features and switching “Nesting” on. Reboot the container again and this time you'll see a standard login prompt.
Once networking is OK:
apt update && apt upgrade useradd -m -s /bin/bash hjr passwd hjr apt install wget nano alsa-utils openssh-server pulseaudio
On both the Proxmox host and within your container, issue the command:
getent group audio
You want the container and the host to agree on the group number. In my case, the command returned number 29 both times, so they already agreed. Had they not done so, a groupmod -g 29 audio would have made the container's group number match the hosts'.
Whether they agree or not, you also need to issue this command:
usermod -aG audio hjr
Finish off with:
systemctl enable ssh systemctl start ssh export EDITOR=nano visudo
Find the line where root is mentioned as having “ALL (ALL:ALL) ALL” privileges and, immediately under that, add your new unprivileged user to the file. My line ended up as:
hjr ALL=(ALL:ALL) ALL
Save the file, then reboot the container. When it comes back up, you can now log in to it from your usual PC and using the unprivileged user account. Having done so, type the command:
aplay -l
At this point, no audio devices were present: that's pretty unique to Ubuntu, to be honest.
The fix is to switch back to the Proxmox host's shell and type:
ls -l /dev/snd
My output was:
root@copland:~# ls -l /dev/snd total 0 drwxr-xr-x 2 root root 60 Feb 28 17:07 by-path crw-rw---- 1 root audio 116, 9 Feb 28 17:07 controlC0 crw-rw---- 1 root audio 116, 7 Feb 28 17:07 hwC0D0 crw-rw---- 1 root audio 116, 8 Feb 28 17:07 hwC0D2 crw-rw---- 1 root audio 116, 3 Feb 28 17:07 pcmC0D0c crw-rw---- 1 root audio 116, 2 Feb 28 17:07 pcmC0D0p crw-rw---- 1 root audio 116, 4 Feb 28 17:07 pcmC0D3p crw-rw---- 1 root audio 116, 5 Feb 28 17:07 pcmC0D7p crw-rw---- 1 root audio 116, 6 Feb 28 17:07 pcmC0D8p crw-rw---- 1 root audio 116, 1 Feb 28 17:07 seq crw-rw---- 1 root audio 116, 33 Feb 28 17:07 timer
Based on these devices, I then issued the command at the Proxmox host's shell:
pct set 100 -dev0 /dev/snd/controlC0 pct set 100 -dev1 /dev/snd/pcmC0D0p pct set 100 -dev2 /dev/snd/timer
(The “100” is again my container's ID number).
If you immediately do:
aplay -l
…back in the container, you'll probably still see the 'no soundcards found' error. Do a sudo aplay -l, however, and you'll likely see very different results:
hjr@ubuntulxc:~$ aplay -l aplay: device_list:279: no soundcards found... hjr@ubuntulxc:~$ sudo aplay -l **** List of PLAYBACK Hardware Devices **** card 0: PCH [HDA Intel PCH], device 0: ALC293 Analog [ALC293 Analog] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 7: HDMI 1 [HDMI 1] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 8: HDMI 2 [HDMI 2] Subdevices: 1/1 Subdevice #0: subdevice #0
So, the audio devices are accessible to root: to allow non-root users to use them, you need to go to the Proxmox Host shell once more and type:
nano /etc/pve/lxc/100.conf
…and add the entries:
lxc.mount.entry: /dev/snd/controlC0 dev/snd/controlC0 none bind,optional,create=file,gid=29,mode=0660 lxc.mount.entry: /dev/snd/pcmC0D0p dev/snd/pcmC0D0p none bind,optional,create=file,gid=29,mode=0660 lxc.mount.entry: /dev/snd/timer dev/snd/timer none bind,optional,create=file,gid=29,mode=0660 lxc.apparmor.profile: unconfined lxc.cgroup2.devices.allow: c 116:* rwm
Be warned: the GUI may acquire some of these resources in the container's Resources tab: delete them from the GUI if so. The only source of the lines should be the configuration file.
Restart the container and log back on:
hjr@ubuntuct:~$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: PCH [HDA Intel PCH], device 0: ALC293 Analog [ALC293 Analog] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 3: HDMI 0 [HDMI 0] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 7: HDMI 1 [HDMI 1] Subdevices: 1/1 Subdevice #0: subdevice #0 card 0: PCH [HDA Intel PCH], device 8: HDMI 2 [HDMI 2] Subdevices: 1/1 Subdevice #0: subdevice #0
That means the non-root user can see (and use!) audio devices. It also means that plughw:0,0 should be the device we tell Giocoso to use. Now, as the non-root user, issue the command:
echo "export PULSE_SERVER=192.168.137.13" >> ~/.bashrc
Now install Giocoso.
wget software.bbritten.com/gioinst bash gioinst giocoso
In the configuration options, specify plughw:0,0 as the audio device and also say yes to force the use of pulse audio
2.0
0. For the Proxmox Host, click Shell, then as root, edit /etc/fstab:
192.168.137.1:/bulkdata/music/classical /mnt/netmusic nfs rw,hard,intr,rsize=131072,wsize=131072,timeo=14 0 0
This means your host now knows of a /mnt/netmusic folder, which points to a network share of music files. VMs and containers you subsequently create can then be given access to this host-bound mount point.
1. build a Fedora 43 Container
It needs to be privileged, because we're going to get it to mount my music via NFS After it's built, but before you start it, issue the command:
pct set 100 -mp0 /mnt/netmusic,mp=/netmusic
…from the Host shell (not the container's shell) and with the container stopped. That's creating a mountpoint within the container called /netmusic to which the host's /mnt/netmusic is mapped. When you restart the container, it will have access to the entire music collection.
Once it's built:
useradd -m hjr passwd hjr
3. Networking doesn't work out of the box. Type this:
cat <<EOF > /etc/systemd/network/20-wired.network [Match] Name=eth0 [Network] DHCP=yes EOF
Then:
sudo systemctl enable --now systemd-networkd sudo systemctl enable --now systemd-resolved
dnf update dnf install wget ncurses nano alsa-utils pipewire-utils openssh-server export EDITOR=nano visudo
## ## Allow root to run any commands anywhere root ALL=(ALL) ALL hjr ALL=(ALL) ALL #<====Add this line!
Then:
systemctl start sshd systemctl enable sshd
You now need to enable audio. On the Proxmox host, find the group number of the audio group:
getent group audio
You'll likely get a group number of “29”. The same command run inside the Fedora container will probably be “63”. They need to be identical, so back in the Fedora container:
groupmod -g 29 audio usermod -aG audio hjr
The last command there puts you into the audio group. Finish off with:
reboot
When the container comes back up, log in as yourself, not root, and then issue the command:
aplay -l
…which will tell you the audio devices that the container can see. Now you are ready to install Giocoso, best done over an ssh link using a local terminal that you know supports sixel graphics (such as iTerm2 on macOS):
wget software.bbritten.com/gioinst bash gioinst
When it's running, configure (1) force the use of pulseaudio and (2) the use of an appropriate hardware device for audio (such as “plughw:1,0”). Exit Giocoso.
For audio to be piped over the network to your local PC from the Fedora Container, you need two things: 1) Pulseaudio running on your local PC and 2) an environment variable on the Fedora Container which tells it which pulseaudio server to pipe music to.
On macOS, therefore: brew install pulseaudio to get PulseAudio installed. On most Linux distros, it's probably already present. Then, on macOS:
nano /opt/homebrew/etc/pulse/default.pa
Find the line which reads load-module module-native-protocol-tcp and make sure it ends up reading:
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.137.0/24 auth-anonymous=1
That lets any host on my local 192.168.137.x network pipe audio to my iMac, and without having to authenticate. So that's my iMac client ready to receive audio.
In the Fedora container:
echo "export PULSE_SERVER=192.168.137.13" >> ~/.bashrc
That tells the bashrc file to say that my iMac at 192.168.137.13 is where audio should be directed. Close the terminal then re-launch a new ssh session to the container (thus ensuring that the new environment variable is picked up and applied). Giocoso in the Fedora container should now be able to play music and have it sound out on your iMac.
3.0 Mint
Visit https://images.linuxcontainers.org/images/mint/. Navigate to the latest version and image you want. I went for x86_64 Wilma, dated to February 2026: find the URL for the root.tar.xz file (mine ended up being https://images.linuxcontainers.org/images/mint/wilma/amd64/default/20260227_08%3A51/rootfs.tar.xz) Copy that URL/Link. In the Proxmox interface, click on local storage device → CT Templates → Download from URL → paste in the URL. Once the template is downloaded, you can create a new CT container and point it to the root.tar.xz template.
Note that Mint has networking working by default.
apt install wget ncurses-bin nano alsa-utils pipewire openssh-server
useradd -m -s /bin/bash hjr passwd hjr
export EDITOR=nano visudo
Add the line
hjr ALL=(ALL:ALL) ALL
reboot log in as hjr
wget software.bbritten.com/gioinst bash gioinst
Set the pipewire redirect:
echo “export PULSE_SERVER=192.168.137.13” » ~/.bashrc
Mint gets its user IDs confused.
id hjr shows 1001, id ubuntu shows 1000. That's wrong for me: my NFS server has hjr as user 1000. We need to swap them around. So log out of the container, completely. From the Proxmox host, open a shell and type:
pct enter 1xx
…to gain direct access to the container. Then:
usermod -u 2000 ubuntu groupmod -g 2000 ubuntu
usermod -u 1000 hjr groupmod -g 1000 hjr
chown -R hjr:hjr /home/hjr
Reboot the container. Ownership of the NFS mount should now be correct.
Disconnect and re-connect to have the new setting applied. Configure Giocoso to use PulseAudio.
You'll also need to do this:
sudo apt install file
This is an unusual one: file is a standard part of full-fat desktop Mint, but it's missing from the container template. Without it, Giocoso cannot detect FLACs in a folder. You'll get 'invalid or missing FLAC' error messages if it's not present on the system. Manually installing it makes Mint play music over the network to the iMac perfectly, however.
Arch
The template is obtainable from https://images.linuxcontainers.org/images/archlinux/current/amd64/default/20260228_04%3A18/
pick the rootfs.tar.xz one. Copy the path to that link, then in Proxmox do a download from URL.
After building the Arch container, networking will work out of the box (ping google.com will respond correctly, for example), but a pacman -Syu will fail with complaints about “error: restricting filesystem access failed because Landlock is not supported by the kernel!”
The fix is to nano -c /etc/pacman.conf and around line 39 and 40, uncomment the lines about 'DisableSandboxFilesystem' and 'DisableSandboxSyscalls'. When both are uncommented, save the file and pacman will work.
pacman -S wget nano alsa-utils openssh pulseaudio





