A setuid helper that creates mount namespaces for lxcfs, enabling applications like Chrome and Firefox to see their actual cgroup resource limits instead of the full host resources.
On shared multi-user systems (like ThinLinc terminal servers), you typically use systemd resource controls to limit per-user CPU and memory. However, applications read /proc/meminfo and /proc/cpuinfo directly, seeing the full host resources rather than their allocated limits.
This causes problems:
- Chrome/Chromium sizes its renderer processes and caches based on "available" memory
- Firefox does the same for content processes
- Java applications auto-configure heap sizes based on visible RAM
- Users see misleading values in
htop,free, etc.
A user limited to 8GB on a 256GB host will have Chrome try to use far more memory than allowed, leading to OOM kills and poor performance.
lxcfs is a FUSE filesystem that provides cgroup-aware versions of /proc files. lxcfs-ns creates a mount namespace where these virtual files replace the real /proc entries, making applications see accurate resource limits.
# Debian/Ubuntu
sudo apt install lxcfs
# RHEL/Rocky/Alma 8+
sudo dnf install epel-release
sudo dnf install lxcfs
# Verify it's running
systemctl status lxcfs
ls /var/lib/lxcfs/proc/Create a drop-in for user slices. Example for limiting all users:
# /etc/systemd/system/user-.slice.d/50-resource-limits.conf
[Slice]
MemoryMax=8G
MemoryHigh=7G
CPUQuota=400%
TasksMax=500Or per-user limits:
# /etc/systemd/system/user-1001.slice.d/50-limits.conf
[Slice]
MemoryMax=16G
CPUQuota=800%Apply changes:
sudo systemctl daemon-reload# Compile
gcc -o lxcfs-ns lxcfs-ns.c
# Install with setuid
sudo install -o root -g root -m 4755 lxcfs-ns /usr/local/bin/# Run any command with accurate resource visibility
lxcfs-ns free -h
lxcfs-ns htop
lxcfs-ns cat /proc/meminfo
# Start a shell with accurate limits
lxcfs-ns bash# Chrome/Chromium
lxcfs-ns google-chrome
lxcfs-ns chromium-browser
# Firefox
lxcfs-ns firefoxThinLinc is a remote desktop solution for multi-user Linux servers. Integrating lxcfs-ns ensures each user's desktop session sees accurate resource limits.
ThinLinc checks for ~/.thinlinc/xstartup before running the system default. Simply create this file:
mkdir -p ~/.thinlinc
cat > ~/.thinlinc/xstartup << 'EOF'
#!/bin/bash
# ~/.thinlinc/xstartup - session with memory-aware /proc via lxcfs
#
# All processes in this session will see cgroup memory limits
# instead of full system RAM in /proc/meminfo
#
# To disable: rename or delete this file
exec /usr/local/bin/lxcfs-ns /opt/thinlinc/etc/xstartup.default
EOF
chmod +x ~/.thinlinc/xstartupLog out and back in - your entire ThinLinc session now sees accurate resource limits.
For all users, add a script to /opt/thinlinc/etc/xstartup.d/:
# /opt/thinlinc/etc/xstartup.d/05-lxcfs-ns.sh
#!/bin/bash
# Re-exec under lxcfs-ns if not already in namespace
if [ -z "$LXCFS_NS_ACTIVE" ]; then
export LXCFS_NS_ACTIVE=1
exec /usr/local/bin/lxcfs-ns "$0" "$@"
fiIn /opt/thinlinc/etc/conf.d/vsmagent.hconf, you can configure a custom session wrapper:
# Create wrapper script firstCreate /usr/local/bin/thinlinc-session-wrapper:
#!/bin/bash
exec /usr/local/bin/lxcfs-ns /etc/X11/Xsessionsudo chmod +x /usr/local/bin/thinlinc-session-wrapperIf you only want browsers to see limits, create wrapper desktop files:
# /usr/local/share/applications/chrome-limited.desktop
[Desktop Entry]
Name=Google Chrome (Resource Limited)
Exec=/usr/local/bin/lxcfs-ns /usr/bin/google-chrome-stable %U
Type=Application
Icon=google-chrome
Categories=Network;WebBrowser;Add to /etc/profile.d/lxcfs-ns.sh:
# Automatically wrap interactive shells in lxcfs namespace
if [ -z "$LXCFS_NS_ACTIVE" ] && [ -x /usr/local/bin/lxcfs-ns ] && [ -d /var/lib/lxcfs/proc ]; then
export LXCFS_NS_ACTIVE=1
exec /usr/local/bin/lxcfs-ns "$SHELL" -l
fiAfter setup, verify the namespace is working:
# Outside namespace (shows full host RAM)
cat /proc/meminfo | grep MemTotal
# Inside namespace (shows cgroup limit)
lxcfs-ns cat /proc/meminfo | grep MemTotal
# Check if you're in the namespace
lxcfs-ns bash -c 'ls -la /proc/meminfo'
# Should show it's a regular file, not a symlink# 1. Install lxcfs
sudo apt install lxcfs
sudo systemctl enable --now lxcfs
# 2. Set up per-user memory limits (8GB per user)
sudo mkdir -p /etc/systemd/system/user-.slice.d
cat << 'EOF' | sudo tee /etc/systemd/system/user-.slice.d/50-resource-limits.conf
[Slice]
MemoryMax=8G
MemoryHigh=7G
CPUQuota=400%
EOF
sudo systemctl daemon-reload
# 3. Build and install lxcfs-ns
gcc -o lxcfs-ns lxcfs-ns.c
sudo install -o root -g root -m 4755 lxcfs-ns /usr/local/bin/
# 4. Test
lxcfs-ns free -h
# Should show ~8GB total instead of host RAM- lxcfs runs as a FUSE filesystem, providing virtual
/procfiles at/var/lib/lxcfs/proc/that read cgroup limits - lxcfs-ns is a setuid binary that:
- Creates a new mount namespace (requires root, hence setuid)
- Bind-mounts lxcfs files over real
/procentries - Drops privileges back to the calling user
- Executes the requested command
- Processes in this namespace see cgroup-accurate values in
/proc/meminfo,/proc/cpuinfo, etc.
- The binary is setuid root but immediately drops privileges after creating the namespace
- No user namespace is created, so setuid binaries (sudo, etc.) continue to work
- Podman/Docker work normally as they create their own namespaces
- Mount propagation is set to "slave" so host mount changes propagate in, but namespace changes don't leak out
lxcfs not available: Ensure lxcfs is installed and running:
sudo systemctl status lxcfs
ls /var/lib/lxcfs/proc/Permission denied: Ensure lxcfs-ns has setuid bit:
ls -la /usr/local/bin/lxcfs-ns
# Should show: -rwsr-xr-x root rootValues still show host resources: Check you're actually in the namespace:
cat /proc/self/mountinfo | grep lxcfsPublic Domain / CC0