chroot — Creating a Jailed FTP-Only User
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.
- 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-> Setnologinshell -> Configurevsftpd.conf-> Test FTP access.
Syntax & Configuration Rules
Unlike single commands, securing an FTP user involves modifying system files and configuration directives:
Key vsftpd Directives
| Directive | Description | Example Target | ⭐ Rating |
|---|---|---|---|
| : | : | : | : |
local_enable=YES | Allow local system users to log in | YES | ⭐⭐⭐⭐⭐ |
chroot_local_user=YES | Jail users inside their assigned local root | YES | ⭐⭐⭐⭐⭐ |
allow_writeable_chroot=YES | Prevent "500 OOPS: chroot" errors when root is writable | YES | ⭐⭐⭐⭐⭐ |
local_root=/path | Auto-assign root directory for the user | /home/$USER/public_html | ⭐⭐⭐⭐ |
user_sub_token=$USER | Allow dynamic user variables in config | $USER | ⭐⭐⭐ |
Shell Access Control
| File/Setting | Description | Action |
|---|---|---|
| : | : | : |
/usr/sbin/nologin | Prevents 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
Link Target Directory
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
| Problem | Cause | Fix |
|---|---|---|
| : | : | : |
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 folder | Incorrect local_root variable mapping. | Check local_root=/home/$USER/public_html. |
| The user can still connect via SSH | Shell is set to bash instead of nologin. | Run sudo usermod -s /usr/sbin/nologin designer. |
| Permission denied on upload | The user doesn't own the destination directory. | Run sudo chown -R designer:designer /home/designer. |
Best Practices
- Enforce TLS: Always configure
ssl_enable=YESinvsftpd.conffor production environments to prevent plaintext password sniffing. - Use
nologinoverfalse: Setting the shell to/usr/sbin/nologinprovides a clean rejection message for SSH attempts. - Minimize Shared Dependencies: If using a manual system
chrootinstead of built-in FTP jailing, copy only required libraries into the jail path. - Audit Logs: Monitor
/var/log/vsftpd.logorxferlogto track exactly what the restricted user uploads or manipulates.
Hands-On Practice
Task: Create a Jailed Contributor
- Install
vsftpdand configure it to lock local users into their homes withchroot_local_user=YES. - Create a user named
contractorwith/usr/sbin/nologinas their shell. - Establish a directory path
/home/contractor/data_dropand give them write access. - Challenge: Try to log in as
contractorviassh. Observe the rejection. Then log in via an FTP client and attempt to access/etc. Verify that you are trapped in the/home/contractordirectory.
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.