How to Grant a Linux User Access to Just One Specific Directory

We’ve all been there. You hire a freelance developer to patch a legacy PHP app, or an external data scientist needs to upload CSVs to your server. They ask for SSH access. Your heart drops. You know perfectly well that if you just create a standard user account, they can roam around your server. Even as an unprivileged user, they can peek into /etc, read system configurations, list running processes, and browse the /home directories of your engineering team.

In the world of Linux Security and System Administration, the principle of least privilege is law. You want to know exactly how to give a user permission to one folder linux without exposing your entire file system. You don’t want them poking around your Python scripts, your Nginx configs, or your PostgreSQL Linux database credentials.

I’ve spent over a decade doing Linux Administration, managing everything from bare-metal Debian Linux boxes to complex Kubernetes Linux clusters in AWS and Azure. I’ve seen junior admins make the catastrophic mistake of granting excessive permissions—or worse, using chmod 777—just to get a contractor off their back. Today, I’m going to show you the right way to lock a user down to a single directory. We will cover soft restrictions using Access Control Lists (ACLs), and hard restrictions using SSH Chroot Jails.

Why Basic File Permissions Aren’t Enough

Before we build our jail, we need to understand why standard Linux Permissions fail us in this specific scenario. The Linux File System is designed to be open by default for reading. If you create a new user on Ubuntu, CentOS, or Fedora Linux, that user gets a home directory. But nothing stops them from typing cd / and running the ls command.

Sure, they can’t modify files in /etc or /var without root access, but they can read a lot of them. They can read /etc/passwd. If you have poorly secured backup scripts or AWS Linux credentials sitting in another user’s directory, a snooping contractor can read those too. Even if you use strict File Permissions, the default Linux environment allows horizontal visibility.

If you want to isolate a user completely, you have two main approaches depending on your exact requirements:

  1. The ACL Approach: Good if you trust the user slightly, but just want to restrict their write/read access to a specific web directory (like an Apache or Nginx document root).
  2. The Chroot Jail Approach: The bulletproof method. The user logs in, and the system literally tricks them into thinking the target folder is the root / of the entire hard drive.

Method 1: Using ACLs for “Soft” Directory Confinement

Let’s say you have a web application located at /var/www/html/project-x. You want your user, dev_contractor, to be able to read and write to this directory, but nowhere else. Standard chown and chmod commands get messy here, especially if your Linux Web Server (like Apache or Nginx) also needs ownership of those files.

This is where Access Control Lists (ACLs) come in. ACLs allow you to apply granular Linux Permissions to specific users without changing the base owner or group of the file.

Step 1: Install ACL Utilities

Most modern Linux Distributions (Ubuntu, Red Hat Linux, Arch Linux) support ACLs out of the box, but you might need to install the tools.

# On Debian/Ubuntu Tutorial systems:
sudo apt-get update
sudo apt-get install acl

# On Red Hat/CentOS/Fedora systems:
sudo dnf install acl

Step 2: Create the User and Restrict Their Home

First, create the user without a standard bash shell if they don’t need to execute scripts, or give them a restricted shell. We will also lock down their home directory.

sudo useradd -m -s /bin/bash dev_contractor
sudo passwd dev_contractor
sudo chmod 700 /home/dev_contractor

Step 3: Grant Access to the Target Folder

Now, we use setfacl. We want to give dev_contractor read, write, and execute permissions on /var/www/html/project-x. Note: the “execute” bit on a directory in Linux means the ability to “enter” or cd into it.

sudo setfacl -R -m u:dev_contractor:rwx /var/www/html/project-x
sudo setfacl -R -d -m u:dev_contractor:rwx /var/www/html/project-x

Pro-tip from the Linux Terminal: The -d flag sets the default ACL. This means any new files created in this directory in the future will automatically inherit these permissions. This saves you from getting paged at 3 AM because the contractor uploaded a new PHP file and the web server can’t read it.

Step 4: The Path Execution Problem

Here is where many sysadmins get stuck. If you tell someone how to give a user permission to one folder linux using ACLs, you must remind them about the parent directories. For dev_contractor to cd into /var/www/html/project-x, they must have execute (traverse) permissions on /var, /var/www, and /var/www/html.

sudo setfacl -m u:dev_contractor:x /var
sudo setfacl -m u:dev_contractor:x /var/www
sudo setfacl -m u:dev_contractor:x /var/www/html

This method works great for collaborative environments. However, dev_contractor can still run cd /tmp or look around the system. If you want absolute containment, we must build a Chroot Jail.

server rack data center - Data Center Server Rack Size: A Beginner's Guide

Method 2: The Bulletproof SSH Chroot Jail (SFTP Only)

If the user only needs to upload and download files (which is true 90% of the time for web developers), the most secure method is an SFTP-only Chroot Jail. A “chroot” (change root) operation changes the apparent root directory for the current running process. When they log in via Linux SSH, they are trapped. They cannot go up a level because, to them, their directory is /.

Step 1: Create the Target Directory and User

Let’s create a directory specifically for this purpose. We’ll call it /sftp_jail/contractor_data.

sudo mkdir -p /sftp_jail/contractor_data
sudo useradd -M -d /sftp_jail/contractor_data -s /usr/sbin/nologin jail_user
sudo passwd jail_user

Notice we used -s /usr/sbin/nologin. We are explicitly denying them Linux Terminal access. They cannot SSH in and get a bash prompt. They can only use SFTP.

Step 2: Configure Directory Permissions (Crucial Step)

Chroot jails have extremely strict ownership requirements. The OpenSSH daemon will flat-out refuse to let the user log in if the permissions are wrong. The directory that acts as the jail (the chroot root) must be owned by root and must not be writable by any other user or group.

# The jail root MUST be owned by root:root
sudo chown root:root /sftp_jail
sudo chmod 755 /sftp_jail

# Create a sub-directory where the user can actually write files
sudo mkdir /sftp_jail/contractor_data/uploads
sudo chown jail_user:jail_user /sftp_jail/contractor_data/uploads
sudo chmod 700 /sftp_jail/contractor_data/uploads

Step 3: Modify the SSH Daemon Configuration

Now we need to tell our Linux Server to trap this user upon login. Open your SSH configuration file using your favorite Vim Editor or Nano.

sudo vim /etc/ssh/sshd_config

Scroll to the very bottom of the file (Match blocks must always go at the end) and add the following lines:

Match User jail_user
    ChrootDirectory /sftp_jail/contractor_data
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no
    PasswordAuthentication yes

Let’s break down these Linux Commands and directives:

  • Match User: Applies these rules only to jail_user.
  • ChrootDirectory: Sets their root / to this specific path.
  • ForceCommand internal-sftp: Forces the SSH server to use its built-in SFTP server, overriding any shell requests.
  • AllowTcpForwarding no: Prevents the user from using SSH tunneling to bypass firewalls or access internal Linux Databases like MySQL Linux.

Step 4: Restart SSH and Test

Before restarting SSH, always validate your configuration to avoid locking yourself out of your own Linux Server!

sudo sshd -t
sudo systemctl restart sshd

Now, test the connection from another terminal or use an SFTP client like FileZilla:

sftp jail_user@your_server_ip

If you run ls, you will only see the uploads folder. If you run cd .., nothing happens. You are successfully trapped! This is the definitive answer to how to give a user permission to one folder linux securely.

Method 3: The Interactive Shell Chroot Jail (Advanced)

Sometimes, an SFTP-only connection isn’t enough. What if the user needs to execute a Python Scripting task, compile C Programming Linux code with GCC, or run Bash Scripting tools inside that directory? Giving them an interactive shell inside a chroot jail is significantly harder because a chroot is entirely empty. It has no /bin/bash, no /bin/ls, and none of the shared libraries required to run those commands.

We have to manually copy the required binaries and their dependencies into the jail.

Step 1: Prepare the Jail Environment

Let’s set up a jail at /var/jail.

sudo mkdir -p /var/jail/{dev,etc,lib,lib64,usr,bin}
sudo mkdir -p /var/jail/usr/bin
sudo chown root:root /var/jail

Step 2: Copy Binaries and Dependencies

If we want the user to be able to use bash and ls, we need to copy them into the jail’s /bin directory. But Linux Tools rely on shared C libraries. We can find these dependencies using the ldd command.

ldd /bin/bash

This will output something like:

linux-vdso.so.1 (0x00007ffc8e7e1000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f3e8c1a0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3e8bf78000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3e8c33f000)

You must copy every single one of those files into the exact same directory structure within your jail. Because doing this manually is a nightmare, I wrote a quick Shell Scripting utility you can use to automate this. Create a file called jail_builder.sh:

#!/bin/bash
# A simple script to copy a binary and its dependencies into a chroot jail

JAIL="/var/jail"
APPS="/bin/bash /bin/ls /bin/cat /usr/bin/vim"

for app in $APPS; do
    # Copy the binary
    sudo cp -v --parents "$app" "$JAIL"
    
    # Copy the dependencies
    ldd "$app" | awk '{ print $3 }' | grep '^/' | xargs -I '{}' sudo cp -v --parents '{}' "$JAIL"
    
    # Handle the special ld-linux linker
    ldd "$app" | grep 'ld-linux' | awk '{ print $1 }' | xargs -I '{}' sudo cp -v --parents '{}' "$JAIL"
done

Run the script. It will populate your jail with bash, ls, cat, and the vim editor.

Step 3: Configure SSH for the Shell Jail

Update your /etc/ssh/sshd_config file just like we did for SFTP, but this time, allow terminal access.

Match User shell_prisoner
    ChrootDirectory /var/jail
    AllowTcpForwarding no
    X11Forwarding no

Restart SSH. When shell_prisoner logs in, they will drop into a bash prompt, but they will be completely confined to /var/jail. They won’t have access to system monitoring tools like htop or the top command because the /proc filesystem isn’t mounted in their jail. This is excellent for Linux Automation environments where you want to isolate a specific Python System Admin script.

Method 4: The Bind Mount Trick (For Existing Directories)

There is a massive caveat to the SSH Chroot method: The ChrootDirectory must be owned by root. But what if the folder you want to share is /var/www/html/app, and that folder MUST be owned by the www-data user for your web server to function? SSH will refuse to chroot into a directory owned by www-data.

The solution is a Linux Administration technique called a “Bind Mount.” A bind mount takes an existing directory tree and replicates it under a different point.

First, set up your standard SFTP jail as described in Method 2, with strict root ownership:

sudo mkdir -p /sftp_jail/bind_user
sudo chown root:root /sftp_jail/bind_user

Next, create a mount point inside the jail:

sudo mkdir /sftp_jail/bind_user/app_files

Now, bind mount the real web directory into the jail directory:

sudo mount --bind /var/www/html/app /sftp_jail/bind_user/app_files

To make this persist across reboots, add it to your Linux Disk Management file, /etc/fstab:

/var/www/html/app    /sftp_jail/bind_user/app_files    none    bind    0 0

Now, your user is chrooted into /sftp_jail/bind_user (which is safely owned by root), but they can seamlessly edit the files inside the app_files folder, which maps directly to your live web directory. This is the ultimate, production-grade answer to how to give a user permission to one folder linux without breaking your application’s existing permissions.

DevOps Approach: Automating Jails with Ansible

If you are managing dozens of servers, doing this by hand via the Linux Terminal is inefficient. In modern Linux DevOps environments, we use tools like Ansible to enforce infrastructure as code. Here is a quick Ansible playbook snippet to automate the SFTP jail creation. This ensures consistency across your AWS Linux or Container Linux fleet.

---
- name: Setup SFTP Jail for Contractor
  hosts: webservers
  become: yes
  tasks:
    - name: Create sftp-only group
      group:
        name: sftponly
        state: present

    - name: Create the restricted user
      user:
        name: contractor
        group: sftponly
        shell: /usr/sbin/nologin
        home: /var/sftp/contractor

    - name: Ensure jail root is owned by root
      file:
        path: /var/sftp/contractor
        state: directory
        owner: root
        group: root
        mode: '0755'

    - name: Create writable upload directory
      file:
        path: /var/sftp/contractor/uploads
        state: directory
        owner: contractor
        group: sftponly
        mode: '0700'

    - name: Configure sshd_config
      blockinfile:
        path: /etc/ssh/sshd_config
        block: |
          Match Group sftponly
              ChrootDirectory %h
              ForceCommand internal-sftp
              AllowTcpForwarding no
              X11Forwarding no
      notify: Restart SSH

Troubleshooting Common Pitfalls

Setting up jails and strict file permissions rarely works perfectly on the first try. If you are tearing your hair out, check these common culprits:

Can Not Find Kubeconfig File