Dev.to Security 🔐 Cybersecurity 👁 0 📖 7 min read

Mounting a Local USB Drive to a Cloud VPS Securely with SSHFS and a Chroot Jail

Cloud VPS instances are great for compute, testing, and always-on development environments—until you start running low on disk space or want to work with large local files directly from your cloud workspace without uploa

Cloud VPS instances are great for compute, testing, and always-on development environments—until you start running low on disk space or want to work with large local files directly from your cloud workspace without uploading gigabytes over the internet every time.

Instead of paying for extra block storage, you can bridge an external USB drive plugged into your local Ubuntu-based workstation straight to any cloud VPS using a reverse SSH tunnel and SSHFS. Even better: with a few OpenSSH lockdown rules, you can ensure that even if your VPS were ever compromised, an attacker would be strictly trapped inside your USB drive with zero shell access, zero port forwarding, and zero visibility into your local home directory.

Here is a universal, step-by-step guide that works across Ubuntu (and Ubuntu-based desktops) and any Linux VPS provider, including seamless integration with VS Code Remote-SSH.

How the Architecture Works

Because your home computer sits behind a router/NAT, a cloud VPS cannot initiate a connection to it directly. We solve that cleanly without opening any ports on your home router:

  1. Reverse SSH Tunnel: When you connect from your local machine to your VPS (ssh my-vps), SSH opens a reverse tunnel on port 2222 of the VPS that points back to port 22 on your local machine.
  2. SSHFS Mount: Your VPS mounts your local USB drive over that encrypted localhost:2222 tunnel using sshfs, making it appear as a normal folder (~/usb_storage).
  3. OpenSSH Chroot & restrict Jail: On your local machine, OpenSSH forces any connection coming through that key into an SFTP-only chroot jail locked to /media/<local-user>, blocking interactive shells, directory traversal (cd ..), and network port forwarding.

Step 1: Prepare Your Local Ubuntu Machine

Plug in your external USB drive. On most Ubuntu-based desktops, it automatically mounts under /media/<local-user>/<drive-label>. Verify the exact mount path and label by running:

lsblk -o NAME,LABEL,MOUNTPOINTS

Take note of your local username (e.g., alex) and your drive's folder name (e.g., my_usb_drive), which gives a full path like /media/alex/my_usb_drive.

Next, make sure the OpenSSH server is installed and running locally so the reverse tunnel has an endpoint to connect to:

sudo apt update && sudo apt install -y openssh-server
sudo systemctl enable --now ssh

Verify it is active:

systemctl is-active ssh
# Output: active

Step 2: Configure the Reverse Tunnel in ~/.ssh/config

On your local machine, configure a host alias for your VPS in ~/.ssh/config so that every time you connect via terminal or VS Code Remote-SSH, port 2222 is automatically forwarded:

Host my-vps
    HostName YOUR_VPS_IP
    User YOUR_VPS_USER
    IdentityFile ~/.ssh/YOUR_VPS_KEY
    IdentitiesOnly yes
    RemoteForward 2222 localhost:22

(Replace YOUR_VPS_IP, YOUR_VPS_USER, and YOUR_VPS_KEY with your VPS details.)

From now on, running ssh my-vps (or connecting to my-vps in VS Code) establishes both your session and the reverse bridge automatically.

Step 3: Set Up Passwordless SSH Keys (VPS $\rightarrow$ Local)

For your VPS to mount the USB drive automatically without prompting for your local password every time, generate a dedicated SSH key pair on your VPS:

ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub

Copy the single line starting with ssh-ed25519 .... We will add it to your local machine's ~/.ssh/authorized_keys file in the next step—along with strict security restrictions.

Step 4: Lock Down Access to Only Your USB Drive

Giving a cloud server SSH access back into your personal workstation is a serious security risk if left unrestricted. We lock this down in two layers on your local Ubuntu machine.

Layer 1: Restrict the Public Key in ~/.ssh/authorized_keys

Ensure your ~/.ssh directory exists with strict permissions:

mkdir -p ~/.ssh && chmod 700 ~/.ssh

Add your VPS's public key to ~/.ssh/authorized_keys on one single line, prepended with OpenSSH's restrict and command options (replacing <drive-label> with your USB drive's folder name):

restrict,command="internal-sftp -d /<drive-label>" ssh-ed25519 AAAA_YOUR_VPS_PUBLIC_KEY_HERE user@your-vps

Then lock down the file permissions:

chmod 600 ~/.ssh/authorized_keys

  • restrict disables interactive shell access, port forwarding, X11 forwarding, and agent forwarding for this key.
  • command="internal-sftp -d /<drive-label>" forces the session directly into SFTP inside your USB drive folder.

Layer 2: Enforce a Kernel-Level Chroot Jail in /etc/ssh/sshd_config

To guarantee that nobody using SFTP can traverse up into /home/<local-user> or / on your local filesystem, add a Match User block to the bottom of /etc/ssh/sshd_config on your local machine (replacing <local-user> with your local Ubuntu username):

sudo tee -a /etc/ssh/sshd_config > /dev/null << 'EOF'

Match User <local-user>
    ForceCommand internal-sftp
    ChrootDirectory /media/<local-user>
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
EOF

Why /media/<local-user>? OpenSSH requires every directory in a ChrootDirectory path to be owned by root:root. Since /media/<local-user> is owned by root while your mounted USB drive /media/<local-user>/<drive-label> is owned by your user, setting the chroot root to /media/<local-user> satisfies OpenSSH's security requirements while keeping your drive writable. Inside SFTP, /media/<local-user>/<drive-label> simply appears as /<drive-label>.

Test the SSH configuration and reload the service:

sudo sshd -t && sudo systemctl reload ssh

Step 5: Install sshfs and Mount the Drive on Your VPS

Connect to your VPS (ssh my-vps), install sshfs, and create your mount point:

sudo apt update && sudo apt install -y sshfs
mkdir -p ~/usb_storage

Pro Tip: Protect Against Accidental Writes When Unmounted

Before mounting, set the empty ~/usb_storage directory on your VPS to read-only (chmod 555):

chmod 555 ~/usb_storage

When your USB drive is mounted on top of ~/usb_storage, your normal read/write permissions take over. If the drive ever disconnects or isn't mounted yet, chmod 555 ensures VS Code or scripts immediately throw a Permission denied error rather than silently writing gigabytes of files onto your VPS's internal SSD.

Now mount the USB drive over the reverse tunnel (replacing <local-user> and <drive-label>):

sshfs -p 2222 <local-user>@localhost:/<drive-label> ~/usb_storage -o reconnect,ServerAliveInterval=15

Verify that it mounted:

df -h ~/usb_storage && ls -la ~/usb_storage

You should see your full USB drive capacity and files (such as lost+found on an ext4 drive).

Step 6: Automate Mounting for Both Terminals and VS Code

1. Auto-Mount on SSH Login (~/.profile and ~/.bashrc)

Add a check to both ~/.profile and ~/.bashrc on your VPS so that whenever port 2222 is active and ~/usb_storage isn't already mounted, it connects automatically (replacing <local-user> and <drive-label>):

cat << 'EOF' | tee -a ~/.profile ~/.bashrc > /dev/null

# Auto-mount local USB drive when reverse tunnel (port 2222) is open
if ! mountpoint -q "$HOME/usb_storage" && ss -tln | grep -q ':2222 '; then
    sshfs -p 2222 <local-user>@localhost:/<drive-label> "$HOME/usb_storage" -o reconnect,ServerAliveInterval=15 2>/dev/null
fi
EOF

2. Auto-Mount When Opening VS Code Remote-SSH

VS Code's Remote-SSH extension connects using a background server that can skip interactive shell startup scripts. To make sure opening your project in VS Code always mounts the drive automatically, create a .vscode/tasks.json file inside ~/usb_storage:

mkdir -p ~/usb_storage/.vscode
cat << 'EOF' > ~/usb_storage/.vscode/tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Mount USB Storage",
      "type": "shell",
      "command": "mountpoint -q ~/usb_storage || sshfs -p 2222 <local-user>@localhost:/<drive-label> ~/usb_storage -o reconnect,ServerAliveInterval=15",
      "runOptions": {
        "runOn": "folderOpen"
      },
      "presentation": {
        "reveal": "silent"
      }
    }
  ]
}
EOF

When you open ~/usb_storage (or a project subfolder inside it) in VS Code, click Allow when prompted to permit automatic folder tasks. From then on, VS Code mounts the drive in the background every time you open your workspace.

(Tip: Open a specific project folder like ~/usb_storage/my-project rather than the root drive so VS Code's file watcher doesn't try to index your entire multi-terabyte drive over SSH.)

Step 7: Verify the Security Lockdown

From your VPS terminal, test that your local workstation is completely isolated:

  1. Test Shell Execution:
ssh -p 2222 <local-user>@localhost "ls -la /home/<local-user>"

Result: Immediately rejected with This service allows sftp connections only.

  1. Test Directory Traversal in SFTP:
sftp -P 2222 <local-user>@localhost << 'EOF'
pwd
cd ..
pwd
cd /home/<local-user>
EOF

Result: pwd stays locked at / (your /media/<local-user> chroot root), cd .. cannot escape /, and /home/<local-user> returns No such file.

  1. Test Port Forwarding:
ssh -f -N -L 9999:127.0.0.1:22 -p 2222 <local-user>@localhost && curl -v telnet://127.0.0.1:9999; pkill -f "9999:127.0.0.1"

Result: Blocked immediately (administratively prohibited), confirming the VPS cannot pivot into your local network.

Daily Workflow Summary

Once configured, your day-to-day workflow is effortless:

  1. Plug in your USB drive on your local Ubuntu machine.
  2. Connect to your VPS via ssh my-vps or VS Code Remote Explorer—the tunnel opens and ~/usb_storage mounts automatically.
  3. Before unplugging the USB drive or shutting down, run a clean unmount from your VPS terminal so FUSE doesn't leave a stale mount behind:
fusermount3 -u ~/usb_storage

(If a terminal or editor still has the folder open, use fusermount3 -uz ~/usb_storage for a clean lazy unmount.)

Want more Linux, self-hosting, and developer workflow guides? Check out more posts at techray.dev.

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.