Skip to content

Instantly share code, notes, and snippets.

@NorkzYT
Last active July 1, 2025 18:26
Show Gist options
  • Save NorkzYT/14449b247dae9ac81ba4664564669299 to your computer and use it in GitHub Desktop.
Save NorkzYT/14449b247dae9ac81ba4664564669299 to your computer and use it in GitHub Desktop.
Proxmox CIFS Share Mount Wizard Script

Proxmox LXC ⇆ CIFS Mount Wizard

proxmox-lxc-cifs-share.sh is an interactive helper that mounts a network CIFS/SMB share on a Proxmox VE node and bind-mounts it into an unprivileged LXC container in one pass.
It automates:

  1. Creating a host-side mountpoint under /mnt/lxc_shares/<folder>.
  2. Writing a properly-tuned /etc/fstab entry (persistent, systemd.automount, uid/gid mapping, etc.).
  3. Mounting the share immediately.
  4. Creating/ensuring a lxc_shares group inside the container (GID 10000) and adding your target user.
  5. Injecting the bind-mount (mpX:) into the live LXC configuration with pct set.
  6. Restarting the container and handing you a ready-to-use path at /mnt/<folder>.

Note: the script assumes the target LXC is currently running. It will stop and restart that container briefly as part of its process.


Features

  • Idempotent — safe to re-run; existing fstab lines, groups or mp-entries are skipped.
  • Snapshot-safe — uses pct set, thus bind-mounts are applied to the active config, not stale snapshots.
  • Clean dependency checks — aborts if pct or mount.cifs are missing or you are not on a Proxmox host.
  • Diagnostic output — numbered steps tell you exactly what happens and where (mp0, mp1, …).
  • Optional --noserverino flag to fix “Stale file handle” errors on Synology/TrueNAS shares.

Prerequisites

Item Notes
Proxmox VE node Tested on Proxmox VE 8 / Debian 12 host. Run on the node, not inside a container.
Unprivileged LXC container Must already exist. The script stops and restarts it briefly.
CIFS/SMB share Hostname/IP, share name, and valid credentials.
Root privileges Use sudo or run as root.
cifs-utils package apt update && apt install cifs-utils (usually present on Proxmox).

Quick-start

# 1. Get the script
curl -o proxmox-lxc-cifs-share.sh https://gist.githubusercontent.com/NorkzYT/14449b247dae9ac81ba4664564669299/raw/66b73972f7054a13fb5fb2a7646f7bb004827763/proxmox-lxc-cifs-share.sh
chmod +x proxmox-lxc-cifs-share.sh

# 2. Run it (on the Proxmox node)
sudo ./proxmox-lxc-cifs-share.sh
root@proxmox-node:/opt# chmod +x proxmox-lxc-cifs-share.sh
root@proxmox-node:/opt# ./proxmox-lxc-cifs-share.sh 
=== Proxmox CIFS Share Mount Wizard ===
1) Folder name under /mnt/lxc_shares (e.g. nas_rwx): appdata
2) CIFS host (IP/DNS, e.g. 10.0.0.2): 10.0.0.2
3) Share name (e.g. media): appdata
4) SMB username: xxx
5) SMB password: xxx
6) LXC numeric ID (e.g. 105): 103
7) Container username (e.g. ubuntu): ubuntu

Validating container 103...
Retrieving UID/GID for 'ubuntu' inside LXC 103...
  ↳ container UID=1000, GID=1000
Parsing idmap offset from container config...
  ↳ Warning: idmap offset not found; defaulting to 100000
  ↳ host idmap offset=100000
  ↳ will mount with host UID=101000, GID=101000
Stopping LXC 103...
Ensuring host mount point exists at /mnt/lxc_shares/appdata...
Building fstab entry...
  ↳ Removing old /etc/fstab entry...
  ↳ Adding new /etc/fstab entry...
Reloading systemd daemon...
Stopping potential systemd units mnt-lxc_shares-appdata.automount & mnt-lxc_shares-appdata.mount...
Mounting //10.0.0.2/appdata → /mnt/lxc_shares/appdata...
Configuring bind-mount into LXC (no backups)...
  ↳ Bind-mount set as mp0 → /mnt/appdata
Starting LXC 103...

✅  Configuration complete!
Inspect inside the container with:
    ls -ld /mnt/appdata
#!/usr/bin/env bash
# proxmox-lxc-cifs-share.sh
# https://gist.github.com/NorkzYT/14449b247dae9ac81ba4664564669299
#
# Mount a CIFS/SMB share on a Proxmox VE host and bind-mount it into
# an unprivileged LXC container as any container user, by dynamically
# mapping UIDs/GIDs.
#
# ---------------------------------------------------------------
# Compatible with Proxmox VE 7-8. Tested on Debian 12 host.
# ---------------------------------------------------------------
set -euo pipefail
#
#----------------------#
#----- Preconditions --#
#----------------------#
#
# Must be root
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Please run as root." >&2
exit 1
fi
# Helper for error + exit
error_exit() {
echo "ERROR: $1" >&2
exit 1
}
# Ensure required commands exist
command -v bash >/dev/null 2>&1 || error_exit "Please run with bash: bash $0"
command -v pct >/dev/null 2>&1 || error_exit "'pct' command not found. Run this on the Proxmox host."
command -v mount.cifs >/dev/null 2>&1 || error_exit "cifs-utils missing. Install: apt update && apt install cifs-utils"
command -v systemd-escape >/dev/null 2>&1 || error_exit "systemd-escape missing. Required for systemd unit management."
#
#----------------------#
#----- Parse Flags ----#
#----------------------#
#
NOSERVERINO=0
if [[ "${1:-}" == "--noserverino" ]]; then
NOSERVERINO=1
shift
fi
#
#----------------------#
#----- User Input -----#
#----------------------#
#
echo "=== Proxmox CIFS Share Mount Wizard ==="
read -r -p "1) Folder name under /mnt/lxc_shares (e.g. nas_rwx): " folder_name
read -r -p "2) CIFS host (IP/DNS, e.g. 10.0.0.2): " cifs_host
read -r -p "3) Share name (e.g. media): " share_name
read -r -p "4) SMB username: " smb_username
read -s -p "5) SMB password: " smb_password && echo
read -r -p "6) LXC numeric ID (e.g. 105): " lxc_id
read -r -p "7) Container username (e.g. ubuntu): " lxc_username
echo
#
#----------------------#
#----- Validation -----#
#----------------------#
#
echo "Validating container ${lxc_id}..."
pct status "$lxc_id" &>/dev/null \
|| error_exit "LXC ${lxc_id} does not exist."
echo "Retrieving UID/GID for '${lxc_username}' inside LXC ${lxc_id}..."
if ! container_uid=$(pct exec "$lxc_id" -- id -u "$lxc_username" 2>/dev/null); then
error_exit "User '${lxc_username}' not found in container ${lxc_id}."
fi
container_gid=$(pct exec "$lxc_id" -- id -g "$lxc_username")
echo " ↳ container UID=${container_uid}, GID=${container_gid}"
echo "Parsing idmap offset from container config..."
idmap_offset=$(pct config "$lxc_id" \
| awk '/^lxc.idmap: u 0 /{print $4; exit}')
if [[ -z "$idmap_offset" ]]; then
echo " ↳ Warning: idmap offset not found; defaulting to 100000"
idmap_offset=100000
fi
echo " ↳ host idmap offset=${idmap_offset}"
host_uid=$(( idmap_offset + container_uid ))
host_gid=$(( idmap_offset + container_gid ))
echo " ↳ will mount with host UID=${host_uid}, GID=${host_gid}"
#
#----------------------#
#--- Stop Container ----#
#----------------------#
#
echo "Stopping LXC ${lxc_id}..."
pct stop "$lxc_id"
while [[ "$(pct status "$lxc_id")" != "status: stopped" ]]; do
sleep 1
done
#
#----------------------#
#--- Host-side Mount --#
#----------------------#
#
mnt_root="/mnt/lxc_shares/${folder_name}"
echo "Ensuring host mount point exists at ${mnt_root}..."
mkdir -p "$mnt_root"
echo "Building fstab entry..."
options="_netdev,x-systemd.automount,noatime,nobrl"
options+=",uid=${host_uid},gid=${host_gid},dir_mode=0770,file_mode=0770"
options+=",username=${smb_username},password=${smb_password}"
(( NOSERVERINO )) && options+=",noserverino"
fstab_entry="//${cifs_host}/${share_name} ${mnt_root} cifs ${options} 0 0"
# Remove any stale entry
if grep -Eqs "^//${cifs_host}/${share_name}[[:space:]]+${mnt_root}[[:space:]]+cifs" /etc/fstab; then
echo " ↳ Removing old /etc/fstab entry..."
sed -i "\|^//${cifs_host}/${share_name} ${mnt_root} .*|d" /etc/fstab
fi
echo " ↳ Adding new /etc/fstab entry..."
echo "$fstab_entry" >> /etc/fstab
echo "Reloading systemd daemon..."
systemctl daemon-reload
unit_base=$(systemd-escape --path "$mnt_root")
echo "Stopping potential systemd units ${unit_base}.automount & ${unit_base}.mount..."
systemctl stop "${unit_base}.automount" "${unit_base}.mount" >/dev/null 2>&1 || true
if mountpoint -q "$mnt_root"; then
echo " ↳ Unmounting existing mount..."
umount -l "$mnt_root"
fi
echo "Mounting //${cifs_host}/${share_name}${mnt_root}..."
mount "$mnt_root"
#
#----------------------#
#--- Container Bind ----#
#----------------------#
#
echo "Configuring bind-mount into LXC (no backups)..."
pct set "$lxc_id" \
--mp0 "${mnt_root},mp=/mnt/${folder_name},backup=0"
echo " ↳ Bind-mount set as mp0 → /mnt/${folder_name}"
echo "Starting LXC ${lxc_id}..."
pct start "$lxc_id"
#
#----------------------#
#----- Completion ------#
#----------------------#
#
echo -e "\n✅ Configuration complete!"
echo "Inspect inside the container with:"
echo " ls -ld /mnt/${folder_name}"
@NorkzYT
Copy link
Author

NorkzYT commented Jul 1, 2025

@rfResearch @neil-bh

Thank you for all the information. I will revise the script with your recommendations this weekend.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment