|
#!/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}" |
This is great - thank you.
I do think you need to revert to the original instructions in the first part of step 1 from the revision on March 7.
10000 in the LXC will map correctly to 110000 in the PVE
(mapping 110000 in the LXC will incorrectly map on the PVE)
When I made this change it’s working great on my tteck Jellyfin container.