Skip to content

Instantly share code, notes, and snippets.

@ryanilano
Forked from NorkzYT/README.md
Created August 7, 2025 19:31
Show Gist options
  • Select an option

  • Save ryanilano/4af2357a877764fc3f99cf5bebb5e7d8 to your computer and use it in GitHub Desktop.

Select an option

Save ryanilano/4af2357a877764fc3f99cf5bebb5e7d8 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 one or more unprivileged LXC containers in one pass.
It automates:

  1. Creating a host-side mountpoint under /mnt/lxc_shares/<folder>.
  2. Writing a properly-tuned /etc/fstab entry (systemd.automount, uid/gid mapping, etc.).
  3. Mounting the share immediately.
  4. Injecting the bind-mount (mpX:) into the live LXC configuration with pct set.
  5. Stopping and restarting each container to apply the mount.

Note: target containers must be running when you start the script. It will stop and restart them briefly.


Usage

proxmox-lxc-cifs-share.sh [OPTIONS]

OPTIONS

  • --config FILE Read all parameters from FILE (no prompts).

  • --add Skip host-side mount; only bind the existing share into containers.

  • --containers IDS Comma-separated LXC IDs (e.g. 105,106).

  • --users NAMES Comma-separated container usernames (must match the count and order of --containers).

  • --noserverino Disable the CIFS serverino option (fixes “Stale file handle” on some NAS).

  • --help Show usage and exit.


Quick-start

# 1. Download and make executable
curl -fsSL -o proxmox-lxc-cifs-share.sh \
  https://…/proxmox-lxc-cifs-share.sh
chmod +x proxmox-lxc-cifs-share.sh

# 2a. Interactive setup (prompts for all values)
sudo ./proxmox-lxc-cifs-share.sh

# 2b. Bind into two containers without touching /etc/fstab
sudo ./proxmox-lxc-cifs-share.sh \
  --add \
  --containers 105,106 \
  --users ubuntu,svcuser

# 2c. From a config file, bind into one container
sudo ./proxmox-lxc-cifs-share.sh \
  --config myshare.conf \
  --add

Config-file format

Save your settings in myshare.conf:

folder_name=nas_rwx
cifs_host=10.0.0.2
share_name=media
smb_username=myuser
smb_password=mypass
containers=105,106
users=ubuntu,svcuser

Then run:

sudo ./proxmox-lxc-cifs-share.sh --config myshare.conf --add

Prerequisites

Item Notes
Proxmox VE node Tested on Proxmox VE 7–8 (Debian 12+). Run on the host.
Unprivileged LXC container(s) Must exist and be running.
CIFS/SMB share Hostname/IP, share name, valid credentials.
Root privileges Use sudo or run as root.
cifs-utils Install with apt update && apt install cifs-utils.

Once complete, verify inside each container:

pct exec <ID> -- ls -ld /mnt/<folder_name>

1) Initial interactive run

root@proxmox-node:/opt# chmod +x proxmox-lxc-cifs-share.sh
root@proxmox-node:/opt# ./proxmox-lxc-cifs-share.sh
=== Share Settings ===
Folder under /mnt/lxc_shares (e.g. nas_rwx): appdata
CIFS host (IP/DNS): 10.0.0.2
Share name: appdata
SMB username: xxx
SMB password: xxx

Available LXC IDs:
102
103
104
105
106
107
108
109
110
111
LXC IDs (comma-separated): 103

Usernames in 103:
root
daemon
bin
sys
sync
games
man
lp
mail
news
uucp
proxy
www-data
backup
list
irc
gnats
nobody
messagebus
syslog
postfix
_apt
sshd
systemd-network
systemd-resolve
systemd-timesync
uuidd
tcpdump
systemd-coredump
ubuntu
root
nobody
Usernames (comma-separated): ubuntu

Generate config file? [y/N]: y
Config path [./share.conf]: ./
ERROR: './' is a directory; please specify a file name.
Config path [./share.conf]: ./share.conf
Config saved to ./share.conf
Host mount exists; skip host-side work? [Y/n]: y
Stopping LXC 103…
Binding into 103 → /mnt/appdata
Starting LXC 103…

Verification:
  ↳ 103: OK

✅  All done.

2) Interactive “add” mode

root@proxmox-node:/opt# ./proxmox-lxc-cifs-share.sh \
  --add \
  --containers 103 \
  --users ubuntu
=== Share Settings ===
Folder under /mnt/lxc_shares (e.g. nas_rwx): appdata
CIFS host (IP/DNS): 10.0.0.2
Share name: appdata
SMB username: xxx
SMB password: xxx

Generate config file? [y/N]: n
Stopping LXC 103…
Binding into 103 → /mnt/appdata
Starting LXC 103…

Verification:
  ↳ 103: OK

✅  All done.

3) Config-file + “add” mode

root@proxmox-node:/opt# ./proxmox-lxc-cifs-share.sh \
  --config share.conf \
  --add

Stopping LXC 103…
Binding into 103 → /mnt/appdata
Starting LXC 103…

Verification:
  ↳ 103: OK

✅  All done.
#!/usr/bin/env bash
# proxmox-lxc-cifs-share.sh
#
# Mount a CIFS/SMB share on a Proxmox VE host and bind-mount it into
# one or more unprivileged LXC containers with dynamic UID/GID mapping.
#
# Usage:
# proxmox-lxc-cifs-share.sh [--config FILE] [--add]
# [--containers IDS] [--users NAMES] [--noserverino] [--help]
#
# Compatible with Proxmox VE 7–8 on Debian 12+.
set -euo pipefail
# ──────────────────────────────────────────────────────────────────────────────
# Helpers
# ──────────────────────────────────────────────────────────────────────────────
error_exit() {
echo "ERROR: $1" >&2
exit 1
}
show_help() {
cat <<EOF
Usage: $0 [OPTIONS]
Options:
--config FILE Read all parameters from FILE.
--add Only bind into containers; skip host mount.
--containers IDS Comma-separated LXC IDs (e.g. 105,106).
--users NAMES Comma-separated usernames matching each ID.
--noserverino Disable CIFS “serverino” option.
--help Show this help and exit.
Examples:
# Interactive:
sudo $0
# Bind into two containers:
sudo $0 --add --containers 105,106 --users ubuntu,svcuser
# From config file:
sudo $0 --config myshare.conf --add
EOF
exit 0
}
list_lxc_ids() {
pct list | awk 'NR>1 {print $1}'
}
list_usernames() {
local id=$1
pct status "$id" &>/dev/null || error_exit "LXC $id not found"
pct exec "$id" -- getent passwd | cut -d: -f1
}
validate_prerequisites() {
(( EUID == 0 )) || error_exit "Run as root or via sudo"
command -v pct >/dev/null 2>&1 || error_exit "'pct' not found"
command -v mount.cifs >/dev/null 2>&1 || error_exit "Install cifs-utils"
command -v systemd-escape \
>/dev/null 2>&1 || error_exit "Install systemd"
}
load_config() {
[[ -f $config_file ]] || error_exit "Config file '$config_file' missing"
source "$config_file"
}
prompt_share_settings() {
echo "=== Share Settings ==="
read -rp "Folder under /mnt/lxc_shares (e.g. nas_rwx): " folder_name
read -rp "CIFS host (IP/DNS): " cifs_host
read -rp "Share name: " share_name
read -rp "SMB username: " smb_username
read -rs -p "SMB password: " smb_password
echo
}
prompt_containers_and_users() {
echo "Available LXC IDs:"
list_lxc_ids
read -rp "LXC IDs (comma-separated): " containers
echo
echo "Usernames in ${containers%%,*}:"
list_usernames "${containers%%,*}"
read -rp "Usernames (comma-separated): " users
echo
}
prompt_generate_config() {
read -rp "Generate config file? [y/N]: " gen
if [[ $gen =~ ^[Yy]$ ]]; then
while true; do
read -rp "Config path [./share.conf]: " cfg
cfg=${cfg:-./share.conf}
if [[ -d $cfg ]]; then
echo "ERROR: '$cfg' is a directory; please specify a file name."
continue
fi
break
done
{
echo "folder_name=$folder_name"
echo "cifs_host=$cifs_host"
echo "share_name=$share_name"
echo "smb_username=$smb_username"
echo "smb_password=$smb_password"
echo "containers=$containers"
echo "users=$users"
} >"$cfg"
echo "Config saved to $cfg"
fi
}
parse_flags() {
NOSERVERINO=0
ADD_MODE=0
config_file=""
containers=""
users=""
while [[ $# -gt 0 ]]; do
case $1 in
--noserverino) NOSERVERINO=1; shift ;;
--add) ADD_MODE=1; shift ;;
--config) config_file=$2; shift 2 ;;
--containers) containers=$2; shift 2 ;;
--users) users=$2; shift 2 ;;
--help) show_help ;;
*) error_exit "Unknown option: $1" ;;
esac
done
}
parse_lists() {
IFS=, read -ra CTIDS <<<"$containers"
IFS=, read -ra USERS <<<"$users"
(( ${#CTIDS[@]} == ${#USERS[@]} )) \
|| error_exit "Count of containers != count of users"
}
# ──────────────────────────────────────────────────────────────────────────────
# Main
# ──────────────────────────────────────────────────────────────────────────────
validate_prerequisites
parse_flags "$@"
if [[ -n $config_file ]]; then
load_config
else
prompt_share_settings
[[ -n $containers && -n $users ]] \
|| prompt_containers_and_users
prompt_generate_config
fi
parse_lists
# Primary container for UID/GID mapping
primary_id="${CTIDS[0]}"
primary_user="${USERS[0]}"
pct status "$primary_id" &>/dev/null || error_exit "LXC $primary_id not found"
container_uid=$(pct exec "$primary_id" -- id -u "$primary_user" 2>/dev/null) \
|| error_exit "User $primary_user not in $primary_id"
container_gid=$(pct exec "$primary_id" -- id -g "$primary_user")
idmap_offset=$(pct config "$primary_id" | awk '/^lxc.idmap: u 0 /{print $4; exit}')
idmap_offset=${idmap_offset:-100000}
host_uid=$(( idmap_offset + container_uid ))
host_gid=$(( idmap_offset + container_gid ))
mnt_root="/mnt/lxc_shares/${folder_name}"
if (( ADD_MODE == 0 )); then
ensure_mount() {
mkdir -p "$mnt_root"
opts="_netdev,x-systemd.automount,noatime,nobrl"
opts+=",uid=${host_uid},gid=${host_gid},dir_mode=0770,file_mode=0770"
opts+=",username=${smb_username},password=${smb_password},iocharset=utf8"
(( NOSERVERINO )) && opts+=",noserverino"
entry="//${cifs_host}/${share_name} ${mnt_root} cifs ${opts} 0 0"
grep -q "^//${cifs_host}/${share_name} ${mnt_root} " /etc/fstab \
&& sed -i "\|^//${cifs_host}/${share_name} ${mnt_root} .*|d" /etc/fstab
echo "$entry" >>/etc/fstab
systemctl daemon-reload
base=$(systemd-escape --path "$mnt_root")
systemctl stop "${base}.automount" "${base}.mount" >/dev/null 2>&1 || true
mount "$mnt_root"
}
if grep -q "^//${cifs_host}/${share_name} ${mnt_root} " /etc/fstab; then
read -rp "Host mount exists; skip host-side work? [Y/n]: " yn
[[ $yn =~ ^[Nn]$ ]] && ensure_mount
else
ensure_mount
fi
fi
for i in "${!CTIDS[@]}"; do
id=${CTIDS[i]}
echo "Stopping LXC $id…"
pct stop "$id"
while [[ $(pct status "$id") != "status: stopped" ]]; do sleep 1; done
echo "Binding into $id → /mnt/$folder_name"
pct set "$id" --mp0 "${mnt_root},mp=/mnt/${folder_name},backup=0"
echo "Starting LXC $id…"
pct start "$id"
done
echo
echo "Verification:"
for id in "${CTIDS[@]}"; do
if pct exec "$id" -- test -d "/mnt/${folder_name}"; then
echo " ↳ $id: OK"
else
echo " ↳ $id: FAILED"
fi
done
echo
echo "✅ All done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment