Skip to content

Instantly share code, notes, and snippets.

@00xBAD
Created June 1, 2025 08:28
Show Gist options
  • Save 00xBAD/ab2975af90cdc70f1952c4a28c147df2 to your computer and use it in GitHub Desktop.
Save 00xBAD/ab2975af90cdc70f1952c4a28c147df2 to your computer and use it in GitHub Desktop.
Minimal and robust setup for auto-mounting USB devices on Ubuntu Server, sharing them via Samba, and safely unmounting with systemd + udev + CLI script. Headless-friendly. No GUI required.

🧰 USB Auto-Mount + Samba Share (Ubuntu Server Setup)

This guide documents a working setup for automatically mounting USB devices (sticks, SD cards, etc.), sharing them via Samba, and cleanly unmounting them via script or udev triggers, using systemd, udev, and CLI tools.


πŸ“‚ Files and Structure

/etc/samba/smb.conf                        # Samba config
/etc/systemd/system/[email protected]    # Mount handler unit (template)
/etc/systemd/system/[email protected]   # Unmount handler unit (template)
/etc/udev/rules.d/99-usb-mount.rules      # udev rules to trigger systemd units
/usr/local/bin/usb-mount-handler.sh       # Script to handle mounting
/usr/local/bin/usb-umount-handler.sh      # Script to handle unmounting and cleanup
~/safe-eject.sh                           # Manual safe eject script for the user

βš™οΈ Mount Logic via udev + systemd

/etc/udev/rules.d/99-usb-mount.rules

ACTION=="add",    KERNEL=="sd[b-z][0-9]", ENV{ID_FS_TYPE}!="", RUN+="/bin/systemctl start usb-mount@%k.service"
ACTION=="remove", KERNEL=="sd[b-z][0-9]",                   RUN+="/bin/systemctl start usb-umount@%k.service"

/etc/systemd/system/[email protected]

[Unit]
Description=Mount USB device %i
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/usb-mount-handler.sh %i
RemainAfterExit=true
StandardOutput=journal
StandardError=journal

/etc/systemd/system/[email protected]

[Unit]
Description=Unmount USB device %i
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/usb-umount-handler.sh %i
StandardOutput=journal
StandardError=journal

πŸ“œ Scripts

/usr/local/bin/usb-mount-handler.sh

#!/bin/bash

DEVICE="/dev/$1"
MOUNTPOINT="/media/usb-mount/usb-$1"
LOGGER="/usr/bin/logger"
BLKID="/usr/sbin/blkid"
MOUNT="/bin/mount"
MKDIR="/bin/mkdir"
CHMOD="/bin/chmod"
SLEEP="/bin/sleep"

$SLEEP 1
$MKDIR -p "$MOUNTPOINT"

FS=$($BLKID -o value -s TYPE "$DEVICE" 2>/dev/null)

$LOGGER "usb-mount: mounting $DEVICE (FS: $FS)"

case "$FS" in
  vfat|exfat|ntfs)
    $MOUNT -o uid=1000,gid=1000 "$DEVICE" "$MOUNTPOINT"
    ;;
  *)
    $MOUNT "$DEVICE" "$MOUNTPOINT"
    ;;
esac

$CHMOD -R 777 "$MOUNTPOINT"
$LOGGER "usb-mount: $DEVICE mounted at $MOUNTPOINT"

/usr/local/bin/usb-umount-handler.sh

#!/bin/bash

DEVICE="/dev/$1"
MOUNTPOINT="/media/usb-mount/usb-$1"
LOGGER="/usr/bin/logger"
UMOUNT="/bin/umount"
RM="/bin/rm"
MOUNTPOINT_BIN="/usr/bin/mountpoint"
SLEEP="/bin/sleep"

$SLEEP 1

if $MOUNTPOINT_BIN -q "$MOUNTPOINT"; then
    $UMOUNT "$MOUNTPOINT" && $LOGGER "usb-umount: $MOUNTPOINT unmounted"
else
    $LOGGER "usb-umount: device $DEVICE already removed, skipping umount"
fi

$RM -rf "$MOUNTPOINT"
$LOGGER "usb-umount: $MOUNTPOINT removed"

~/safe-eject.sh

#!/bin/bash

MOUNTBASE="/media/usb-mount"
LOGGER="/usr/bin/logger"

echo
echo "πŸ”Œ Devices mounted in $MOUNTBASE:"
echo

FOUND=0
for dir in "$MOUNTBASE"/usb-*; do
    [ -d "$dir" ] || continue
    dev=$(findmnt -n -o SOURCE --target "$dir")
    echo "πŸ”  $dev mounted on $dir"
    FOUND=1
done

if [ $FOUND -eq 0 ]; then
    echo "❌ No mounted devices found in $MOUNTBASE."
    exit 1
fi

echo
read -p "πŸ“¦ Enter the device name to eject (e.g., sdb1): " DEV

DEVPATH="/dev/$DEV"
BASENAME="/dev/${DEV%%[0-9]*}"  # e.g., sdb1 β†’ sdb

echo
echo "🚩 Unmounting $DEVPATH..."

udisksctl unmount -b "$DEVPATH"
UMOUNT_STATUS=$?

if [ $UMOUNT_STATUS -eq 0 ]; then
    echo "βœ… Successfully unmounted."
    echo "⚑ Powering off device ($BASENAME)..."
    udisksctl power-off -b "$BASENAME"
    echo "βœ… Device powered off and safe to remove!"
    $LOGGER "safe-eject: $DEVPATH unmounted and powered off successfully"
else
    echo "❌ Failed to unmount $DEVPATH"
    $LOGGER "safe-eject: ERROR while unmounting $DEVPATH"
fi

πŸ“‘ Samba Configuration

Relevant section from /etc/samba/smb.conf

[usb-share]
   path = /media/usb-mount
   browsable = yes
   writable = yes
   guest ok = yes
   force user = nobody
   create mask = 0777
   directory mask = 0777

This share allows browsing and full access (read/write) to all mounted USB folders under /media/usb-mount.


βœ… Result

  • πŸ”Œ Insert USB β†’ auto-mounted via systemd, exposed via Samba
  • ❌ Remove USB β†’ auto-unmounted via systemd, mount folder deleted
  • πŸ–οΈ Run ~/safe-eject.sh β†’ graceful unmount and power off via udisksctl

System is headless-friendly, persistent, modular, and clean.


πŸ“¦ Tips for Deployment

  • systemctl daemon-reload after modifying units
  • Ensure all scripts in /usr/local/bin are chmod +x
  • Adjust UID/GID in scripts if needed (default: 1000)
  • Monitor logs with: journalctl -u usb-mount@..., -u usb-umount@..., or udevadm monitor

Made with ❀️ for a reliable, DIY home server setup. Special thanks to GPT-4o πŸ€–.

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