Skip to main content

chroot — Creating a Jailed FTP-Only User

Learning Focus

By the end of this lesson, you will be able to lock a specific user into a restricted directory using vsftpd and chroot, preventing them from accessing the wider filesystem or logging in via SSH.

Overview​

A chroot "jail" isolates a user by changing the apparent root directory for that user's session. In this context, rather than using the complex standalone chroot command for a full shell environment, we use the built-in chroot functionality of an FTP server (vsftpd) to safely confine a user (e.g., a designer editing WordPress themes) to a specific directory.

Capability Snapshot
  • Core Function: Isolate user to a specific directory (chroot).
  • Primary Benefit: Restricts access to sensitive system files and prevents SSH shell access.
  • Where to Use: Giving third-party developers, designers, or content editors limited access to a site root or specific folder.
  • Workflow: Install vsftpd -> Set nologin shell -> Configure vsftpd.conf -> Test FTP access.

Syntax & Configuration Rules​

Unlike single commands, securing an FTP user involves modifying system files and configuration directives:

Key vsftpd Directives​

DirectiveDescriptionExample Target⭐ Rating
::::
local_enable=YESAllow local system users to log inYES⭐⭐⭐⭐⭐
chroot_local_user=YESJail users inside their assigned local rootYES⭐⭐⭐⭐⭐
allow_writeable_chroot=YESPrevent "500 OOPS: chroot" errors when root is writableYES⭐⭐⭐⭐⭐
local_root=/pathAuto-assign root directory for the user/home/$USER/public_html⭐⭐⭐⭐
user_sub_token=$USERAllow dynamic user variables in config$USER⭐⭐⭐

Shell Access Control​

File/SettingDescriptionAction
:::
/usr/sbin/nologinPrevents the user from opening an SSH shell.Assign as user's shell in /etc/passwd.

Step-by-Step Examples​

This section walks through the process of jailing a designer to a WordPress theme directory.

Environment Preparation​

Assume your WordPress site root is /home/wpstrategist/public_html/. We want to jail the designer to /home/wpstrategist/public_html/wp-content/themes/.

Install FTP Service (vsftpd)​

sudo apt update
sudo apt install vsftpd -y
sudo systemctl enable --now vsftpd

Configure vsftpd for Chroot​

Backup the default configuration and create a secure one:

sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.backup
sudo nano /etc/vsftpd.conf

Minimal working secure configuration:

# Basic Settings
listen=YES
listen_ipv6=NO
anonymous_enable=NO
local_enable=YES
write_enable=YES
chroot_local_user=YES

# Security Jailing
allow_writeable_chroot=YES
user_sub_token=$USER
local_root=/home/$USER/public_html
pam_service_name=vsftpd
ssl_enable=NO # Set to YES in production for TLS

# Logging
xferlog_enable=YES
xferlog_std_format=YES

Restart the service:

sudo systemctl restart vsftpd

Create the Restricted User​

Create a user without SSH access by setting their shell to nologin:

sudo adduser designer --home /home/designer --shell /usr/sbin/nologin

Verify the restriction:

grep designer /etc/passwd
# Expected output ends in /usr/sbin/nologin

Create the folder structure and symlink the actual theme directory so edits instantly reflect on the site:

sudo mkdir -p /home/designer/public_html/wp-content/themes
sudo chown -R designer:designer /home/designer
sudo chmod -R 755 /home/designer
sudo ln -s /home/wpstrategist/public_html/wp-content/themes /home/designer/public_html/wp-content/themes

Apply Selective Chroot (Optional)​

If you only want specific users jailed (instead of all local users):

# In /etc/vsftpd.conf:
chroot_local_user=NO
chroot_list_enable=YES
chroot_list_file=/etc/vsftpd.chroot_list

Add the user to the list:

echo "designer" | sudo tee -a /etc/vsftpd.chroot_list
sudo systemctl restart vsftpd

Practical Use Cases​

WordPress Theme Designer​

Limit a designer to only the wp-content/themes directory using an FTP client like FileZilla or Cyberduck. They cannot access system configuration or other users' sites.

Shared Hosting Environment​

Confine multiple clients to their respective /var/www/domain.com directories without giving them access to the root filesystem or each other's files.

Log Reviewer​

Create a read-only FTP user jailed to /var/log for external auditors or log parsing tools.

Common Mistakes & Troubleshooting​

ProblemCauseFix
:::
500 OOPS: vsftpd: refusing to run with writable root inside chroot()The chroot jail directory is fully writable.Set allow_writeable_chroot=YES in vsftpd.conf.
Login fails with "530 Login incorrect"Wrong password, or shell is blocked by PAM.Ensure /usr/sbin/nologin is listed in /etc/shells.
Connects successfully but shows an empty folderIncorrect local_root variable mapping.Check local_root=/home/$USER/public_html.
The user can still connect via SSHShell is set to bash instead of nologin.Run sudo usermod -s /usr/sbin/nologin designer.
Permission denied on uploadThe user doesn't own the destination directory.Run sudo chown -R designer:designer /home/designer.

Best Practices​

  • Enforce TLS: Always configure ssl_enable=YES in vsftpd.conf for production environments to prevent plaintext password sniffing.
  • Use nologin over false: Setting the shell to /usr/sbin/nologin provides a clean rejection message for SSH attempts.
  • Minimize Shared Dependencies: If using a manual system chroot instead of built-in FTP jailing, copy only required libraries into the jail path.
  • Audit Logs: Monitor /var/log/vsftpd.log or xferlog to track exactly what the restricted user uploads or manipulates.

Hands-On Practice​

Task: Create a Jailed Contributor​

  1. Install vsftpd and configure it to lock local users into their homes with chroot_local_user=YES.
  2. Create a user named contractor with /usr/sbin/nologin as their shell.
  3. Establish a directory path /home/contractor/data_drop and give them write access.
  4. Challenge: Try to log in as contractor via ssh. Observe the rejection. Then log in via an FTP client and attempt to access /etc. Verify that you are trapped in the /home/contractor directory.

Connection to Other Concepts​

  • Groups and Permissions: Use Linux groups alongside chroot to manage teams of jailed users efficiently.
  • OpenSSH ChrootDirectory: For an SFTP alternative that doesn't require a separate FTP server, SSH can be configured to jail users securely using ChrootDirectory.

Visual Learning Diagram​

Command Execution Examples​

Here are 10 practical command examples with expected inputs and outputs related to managing a chrooted FTP user.

Install FTP Service​

sudo apt install vsftpd

Expected output:

Reading package lists... Done
Building dependency tree...
Setting up vsftpd (3.0.5-0ubuntu1) ...

Explanation: Installs the vsftpd (Very Secure FTP Daemon) package on Ubuntu/Debian systems.

Check FTP Service Status​

sudo systemctl status vsftpd

Expected output:

● vsftpd.service - vsftpd FTP server
Loaded: loaded (/lib/systemd/system/vsftpd.service; enabled)
Active: active (running)

Explanation: Verifies that the vsftpd service is actively running and enabled to start on system boot.

Create a User with No Shell​

sudo adduser designer --shell /usr/sbin/nologin

Expected output:

Adding user `designer' ...
Adding new group `designer' (1001) ...
Adding new user `designer' (1001) ...
Creating home directory `/home/designer' ...

Explanation: Creates a new user named designer whose shell is restricted, preventing terminal/SSH logins.

Verify User Shell Restriction​

grep designer /etc/passwd

Expected output:

designer:x:1001:1001:,,,:/home/designer:/usr/sbin/nologin

Explanation: Confirms that the user's shell is properly set to /usr/sbin/nologin in the system's password file.

Create the Jailed Directory​

sudo mkdir -p /home/designer/public_html

Expected output: (No output) Explanation: Creates the public_html directory inside the user's home where they will be jailed and can upload files.

Assign Directory Ownership​

sudo chown -R designer:designer /home/designer

Expected output: (No output) Explanation: Recursively grants the designer user ownership of their home directory, allowing them to read and write files.

Enable Chroot in vsftpd.conf​

echo "chroot_local_user=YES" | sudo tee -a /etc/vsftpd.conf

Expected output:

chroot_local_user=YES

Explanation: Appends the chroot_local_user directive to the configuration file, enforcing the jail for all local users.

Restart FTP Service​

sudo systemctl restart vsftpd

Expected output: (No output) Explanation: Restarts the vsftpd daemon to apply the new configuration changes.

Test SSH Rejection​

ssh designer@localhost

Expected output:

designer@localhost's password:
This account is currently not available.
Connection to localhost closed.

Explanation: Proves that the user is securely blocked from accessing an SSH shell.

Audit FTP Activity Logs​

sudo tail /var/log/vsftpd.log

Expected output:

Mon Oct 23 10:15:00 2023 [pid 1234] [designer] OK LOGIN: Client "192.168.1.100"
Mon Oct 23 10:15:05 2023 [pid 1234] [designer] OK UPLOAD: Client "192.168.1.100", "/home/designer/public_html/style.css", 1024 bytes

Explanation: Displays the last few lines of the FTP transfer log, showing successful logins and file uploads by the jailed user.

What's Next: Proceed to explore sudo Configuration to understand the opposite of restriction: delegating root privileges safely.