Transparently fix Steam Proton compatibility issues on NTFS partitions using bind mounts
Français | English
Running Steam games with Proton on NTFS partitions under Linux causes several issues:
- Symlinks not supported - Proton requires symlink support for Wine prefix management
- Case sensitivity - NTFS is case-insensitive while many Linux games expect case-sensitive filesystems
- Permission issues - NTFS doesn't handle Linux file permissions properly
- Performance degradation - FUSE-based NTFS drivers (ntfs-3g) can be slower for intensive I/O
This commonly manifests as:
- Games failing to launch
- Crashes during gameplay
- Missing or corrupted save files
- Poor performance in shader compilation
This script creates a transparent bind mount that redirects Steam's Proton compatibility data (compatdata) from your NTFS partition to your Linux native filesystem (ext4/btrfs/etc.), while keeping Steam pointing to the original location.
Before:
Steam → /mnt/GamingDisk/steamapps/compatdata (NTFS - problematic)
After:
Steam → /mnt/GamingDisk/steamapps/compatdata (bind mount)
↓
~/.local/share/Steam-Compat/GamingDisk_compatdata (ext4 - works perfectly)
Steam continues to see compatdata on your external disk, but the actual data lives on your Linux filesystem where Proton works flawlessly.
The compatdata folder contains Proton's Wine prefixes. Each game has its own simulated Windows environment. On NTFS, these issues arise:
- Symbolic links: Proton creates symlinks to manage Windows DLLs. NTFS doesn't support them natively (requires special privileges on Windows).
- POSIX permissions: Wine configuration scripts require executable permissions (
chmod +x). NTFS doesn't preserve them correctly. - Case-sensitivity: Some games check for files with specific casing. NTFS treats
Config.iniandconfig.inias identical.
The problem: Modern games compile shaders on-the-fly. Vulkan and DirectX create cache files to speed up subsequent launches.
On NTFS:
- NTFS transactions via FUSE are slow and can corrupt
- Temporary files with generated names (e.g.,
shader_XYZ.tmp) cause name conflicts - File locking doesn't work correctly → crashes during compilation
Real example: Ace Combat 7 compiles ~10,000 shaders at startup. On NTFS, it crashes at 30%. On ext4, smooth compilation.
Context: Proton/Wine creates .lock files to synchronize access to shared resources (Wine registry, config files).
Why it's critical:
Game starts → Creates compatdata/123456/pfx/system.reg.lock
Game crashes → Process dies BEFORE removing the .lock
Relaunch → Proton sees .lock → "Resource already in use" → Refuses to startNTFS makes it worse because file handles don't close cleanly via FUSE. The script automatically cleans these orphaned files before each mount.
UNIX sockets (-type s) and FIFOs (-type p) are special Linux files for inter-process communication.
- On ext4: They auto-delete when the process dies
- On NTFS via bind mount: If a crash leaves residues, they can block the next execution
- Example: A Wine audio server might create
/tmp/.wine-1000-audioas a socket. If the game crashes, the socket remains and blocks restart.
Preventive cleanup avoids these edge cases.
mount --bind /home/user/.local/share/Steam-Compat/compatdata /mnt/disk/steamapps/compatdataThis command tells the Linux kernel: "When a process accesses /mnt/disk/steamapps/compatdata, redirect it to the real folder on ext4".
Benefits:
- ✅ Steam doesn't know files are elsewhere (no config modification needed)
- ✅ System-level transparency (works with all games)
- ✅ Native ext4 performance (no FUSE layer)
- ✅ No impact on other Steam folders (like
common/which contains game binaries)
- Linux (any distribution)
- Bash 4.0+
- Root privileges (sudo)
- Steam installed
- An NTFS partition with Steam library
gum- Enhanced interactive prompts (recommended)fzf- Alternative interactive selectionrsync- Faster data copying with progress (falls back tocp)
Install optional tools on Debian/Ubuntu:
sudo apt install rsync gum fzf# Download the script
curl -O https://raw.githubusercontent.com/Ikkitsuna/steam-ntfs-compat/main/gamingdisk_compat_helper.sh
# Make it executable
chmod +x gamingdisk_compat_helper.sh
# Move to system path (optional)
sudo mv gamingdisk_compat_helper.sh /usr/local/bin/steam-ntfs-compat- Clone this repository:
git clone https://github.com/Ikkitsuna/steam-ntfs-compat.git
cd steam-ntfs-compat- Make the script executable:
chmod +x gamingdisk_compat_helper.shMount compatdata to ext4:
sudo ./gamingdisk_compat_helper.shUnmount when done:
sudo ./gamingdisk_compat_helper.sh --unmount# List all available disks with labels and filesystems (no root needed)
./gamingdisk_compat_helper.sh --list
# Use custom disk label
sudo ./gamingdisk_compat_helper.sh --label MyGameDisk
# Start fresh without copying existing compatdata
sudo ./gamingdisk_compat_helper.sh --no-copy
# Preview what will happen (no root needed)
./gamingdisk_compat_helper.sh --dry-run
# Show help
./gamingdisk_compat_helper.sh --helpOptions:
-l, --label LABEL Disk label to search for (default: GamingDisk)
-u, --unmount Unmount the bind mount
-d, --dry-run Show what would be done without executing
--list List all available disks with their labels and filesystems
--no-copy Skip copying existing compatdata (start fresh)
-h, --help Display help message
Examples:
./gamingdisk_compat_helper.sh --list # List available disks (no sudo)
sudo ./gamingdisk_compat_helper.sh # Mount using default label
sudo ./gamingdisk_compat_helper.sh -l MyDisk # Mount using custom label
sudo ./gamingdisk_compat_helper.sh --no-copy # Mount without copying data
sudo ./gamingdisk_compat_helper.sh --unmount # Unmount bind mount
./gamingdisk_compat_helper.sh --dry-run # Preview (no sudo)
# 1. List available disks to find your disk label
./gamingdisk_compat_helper.sh --list
# 2. Close Steam if running
# (the script will prompt you)
# 3. Run the script
sudo ./gamingdisk_compat_helper.sh
# 4. Launch Steam and play!
steam
# 5. When done gaming, unmount (optional)
sudo ./gamingdisk_compat_helper.sh --unmountThe bind mount is temporary and disappears on reboot. To make it automatic:
Create /etc/systemd/system/steam-ntfs-compat@.service:
[Unit]
Description=Steam NTFS Compatibility Helper for %i
After=local-fs.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/steam-ntfs-compat --label %i
ExecStop=/usr/local/bin/steam-ntfs-compat --label %i --unmount
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl enable --now steam-ntfs-compat@GamingDisk.serviceCreate /etc/udev/rules.d/99-steam-ntfs-compat.rules:
ACTION=="add", ENV{ID_FS_LABEL}=="GamingDisk", RUN+="/usr/local/bin/steam-ntfs-compat --label GamingDisk"
Reload udev rules:
sudo udevadm control --reload-rulesList all available disks with the --list option:
./gamingdisk_compat_helper.sh --listOr check manually:
lsblk -o LABEL,MOUNTPOINTEnsure your disk is mounted and use the correct label:
sudo ./gamingdisk_compat_helper.sh --label YOUR_ACTUAL_LABEL- Verify the bind mount is active:
mount | grep compatdata- Check file ownership:
ls -la ~/.local/share/Steam-Compat/- Check logs:
cat ~/.local/share/gamingdisk_compat.logEnsure you're running with sudo:
sudo ./gamingdisk_compat_helper.shThe script requires Steam to be closed to prevent data corruption. Close Steam before running.
| Aspect | NTFS (Before) | Bind Mount (After) |
|---|---|---|
| Symlinks | ❌ Not supported | ✅ Full support |
| Case sensitivity | ❌ Case-insensitive | ✅ Case-sensitive |
| Permissions | ❌ Limited | ✅ Full Linux ACL |
| Performance | ✅ Native filesystem | |
| Proton compatibility | ❌ Frequent issues | ✅ Works perfectly |
| Shaders | ❌ Crashes on load | ✅ Smooth compilation on ext4 |
| Locks (.lock) | ❌ Blocking files | ✅ Auto-cleanup on mount |
- Steam detection - Automatically detects and offers to close Steam
- Data preservation - Copies existing compatdata before mounting
- Dry-run mode - Preview actions without making changes
- NTFS verification - Warns if target isn't NTFS
- Logging - Tracks all operations in
~/.local/share/gamingdisk_compat.log
You can use different labels for multiple gaming disks:
sudo ./gamingdisk_compat_helper.sh --label GamingDisk1
sudo ./gamingdisk_compat_helper.sh --label GamingDisk2Each disk gets its own isolated compatdata directory.
Q: Will this affect my game files?
A: No, only Proton's compatibility data (compatdata) is redirected. Your actual game files remain on NTFS.
Q: What happens if I reboot? A: The bind mount disappears. Re-run the script or set up a systemd service for automatic mounting.
Q: Can I use this with multiple Steam libraries?
A: Yes, the script auto-detects steamapps folders and supports multiple libraries on the same disk.
Q: Does this work with Steam Deck? A: Yes, but Steam Deck uses ext4 by default. This is mainly for desktop Linux users with NTFS partitions.
Q: What if I want to remove everything?
A: Unmount with --unmount, then optionally delete ~/.local/share/Steam-Compat/.
Q: Is this safe? A: Yes, your original data is preserved. The script copies existing compatdata before creating the bind mount.
Q: How do I find my disk label?
A: Use ./gamingdisk_compat_helper.sh --list to see all available disks with their labels and filesystems. No sudo required!
Q: When should I use --no-copy?
A: Use --no-copy if you want to start with a fresh Proton prefix, or if your existing compatdata is corrupted. This skips copying the old data and creates an empty compatdata directory. Note: Your games will need to re-download shaders and recreate Wine prefixes.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Steam and Proton developers for making gaming on Linux possible
- The Linux community for filesystem expertise
- Everyone who tested and provided feedback
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ for the Linux gaming community
If this helped you, consider giving it a ⭐ on GitHub!