Chroot jails are a surprisingly blunt instrument for achieving FTP user isolation, often leading to more complexity than expected if you’re not careful.
Let’s see what this looks like in practice. Imagine you have a user, ftpuser1, who should only be able to access /home/ftpuser1/files. We’ll use vsftpd for this example, as it’s common and has straightforward chroot support.
First, ensure vsftpd is installed and running. On many Linux systems, this is as simple as:
sudo apt update && sudo apt install vsftpd
sudo systemctl start vsftpd
sudo systemctl enable vsftpd
Now, let’s set up our user and their directory.
sudo adduser ftpuser1
sudo mkdir -p /home/ftpuser1/files
sudo chown ftpuser1:ftpuser1 /home/ftpuser1/files
sudo chmod 755 /home/ftpuser1/files
The critical part is configuring vsftpd to enforce the chroot. Edit /etc/vsftpd.conf:
# Enable local user chroot
local_enable=YES
# Chroot all local users
chroot_local_user=YES
# This is crucial for security and functionality
allow_writeable_chroot=YES
# Specify a banner (optional but good practice)
ftpd_banner=Welcome to our FTP service!
# Anonymity disabled
anonymous_enable=NO
# Allow uploads
write_enable=YES
# Set userlist to control who can log in
userlist_enable=YES
userlist_file=/etc/vsftpd.userlist
userlist_deny=NO
Create the userlist file /etc/vsftpd.userlist and add ftpuser1 to it:
ftpuser1
Now, restart vsftpd for the changes to take effect:
sudo systemctl restart vsftpd
If ftpuser1 tries to log in now, they will be "jailed" to their home directory /home/ftpuser1. However, they will not be able to upload files or create new directories if allow_writeable_chroot=YES is not set. This is a security feature: by default, the chroot directory itself cannot be writable by the user. Setting allow_writeable_chroot=YES overrides this, allowing the user to write within their jailed directory.
The mental model here is that chroot fundamentally changes the root directory (/) for a process. When vsftpd starts a session for ftpuser1, it effectively makes /home/ftpuser1 appear as / to that user’s FTP process. Any cd command they issue, like cd files, will be relative to this new root. So, cd files becomes /files from the perspective of the jailed process, which maps to /home/ftpuser1/files on the actual filesystem.
The problem allow_writeable_chroot=YES solves is that the user’s actual home directory (e.g., /home/ftpuser1) is usually created as writable by the user. Without allow_writeable_chroot=YES, vsftpd would refuse to start the chroot jail if the jail root itself is writable, because it’s a security risk. By setting it to YES, we tell vsftpd to proceed even if the jail root is writable, trusting that the user will only be able to write inside their home directory, not above it.
The most surprising thing most people miss is that the chroot directory itself must exist and be owned by root (or a user that the FTP daemon process doesn’t run as) if allow_writeable_chroot is not set. If allow_writeable_chroot=NO (the default and more secure setting), vsftpd will refuse to start a chroot session if the jailed directory is writable by the user. This often leads to users being jailed but unable to upload, or worse, the FTP service failing to start entirely if the home directory is misconfigured. The common workaround is allow_writeable_chroot=YES, but it requires careful permission management within the jail.
The next hurdle you’ll likely face is managing multiple users with different directory structures, which often involves symbolic links or more complex directory layouts to make the jailed environment feel natural.