VSFTPD Variable Expansion Issue: $USER Not Interpreting in local_root Configuration


2 views

When configuring vsftpd with dynamic directory paths using environment variables like $USER, you might encounter the error:

500 OOPS: cannot change directory:/home/$USER/public_html

Despite $USER working correctly in shell environments, it fails to expand within the vsftpd configuration file.

This occurs because vsftpd doesn't perform shell-style variable expansion in its configuration file by default. The local_root directive treats $USER as literal text rather than substituting it with the actual username.

Verification steps:

  • Command line: echo $USER returns correct username
  • vsftpd config: local_root=/var/www/sites/$USER remains unexpanded

Option 1: Use Per-User Configuration

Create individual config files in /etc/vsftpd_user_conf/:

# In /etc/vsftpd.conf
user_config_dir=/etc/vsftpd_user_conf

Then create user-specific files:

# /etc/vsftpd_user_conf/johndoe
local_root=/var/www/sites/johndoe

Option 2: Use Template Expansion

For dynamic environments, generate the config file during user login:

#!/bin/bash
# /etc/vsftpd.conf.dynamic
cat <<EOF > /etc/vsftpd.conf.dynamic
$(sed "s/\$USER/$USER/g" /etc/vsftpd.conf.template)
EOF

Option 3: PAM Module Solution

For recent vsftpd versions (2.3.5+), use PAM to set environment variables:

# /etc/pam.d/vsftpd
session required pam_mkhomedir.so skel=/etc/skel/ umask=0022
session required pam_env.so

The original issue was reported on:

  • vsftpd 2.2.2
  • Ubuntu 10.04.1 LTS (Lucid)

Newer versions (3.0.0+) support more sophisticated variable expansion through different mechanisms.

Enable verbose logging to understand the exact failure point:

# /etc/vsftpd.conf
debug_ssl=YES
log_ftp_protocol=YES
xferlog_std_format=NO

Check logs with:

tail -f /var/log/vsftpd.log

While configuring vsftpd on Ubuntu 10.04 (Lucid Lynx), I encountered an issue where the $USER variable in local_root=/var/www/sites/$USER wasn't being interpreted. The server returned:

500 OOPS: cannot change directory:/home/$USER/public_html

Interestingly, when testing with echo $USER in the shell, it correctly displays the username. The issue only occurs within the vsftpd configuration.

In vsftpd 2.2.2 (the version shipped with Ubuntu 10.04), environment variable interpolation in the config file isn't supported. The $USER is treated literally rather than being expanded to the actual username.

This behavior differs from shell scripts where $VAR notation automatically expands variables.

Here are several approaches to solve this:

1. Use vsftpd's user_config_dir Feature

Create per-user configuration files that contain their specific paths:

# In /etc/vsftpd.conf
user_config_dir=/etc/vsftpd_user_conf

Then create individual files in that directory:

# /etc/vsftpd_user_conf/john
local_root=/var/www/sites/john

# /etc/vsftpd_user_conf/mary  
local_root=/var/www/sites/mary

2. Script-Based Configuration Generation

Create a script to generate vsftpd.conf with expanded variables:

#!/bin/bash
# generate_vsftpd_conf.sh
USER_PATH="/var/www/sites/$(whoami)"
echo "local_root=$USER_PATH" > /etc/vsftpd.conf
# Add other vsftpd settings...

Run this script whenever users change or the configuration needs updating.

3. Upgrade vsftpd

Newer versions of vsftpd (3.0.0+) support better variable handling. Consider upgrading:

sudo apt-get install ppa-purge
sudo add-apt-repository ppa:thefrontiergroup/vsftpd
sudo apt-get update
sudo apt-get install vsftpd

After implementing any solution, test with:

sudo service vsftpd restart
ftp localhost

Check that you can properly access user-specific directories without the $USER interpolation error.

For simpler setups, consider creating symlinks:

sudo mkdir -p /var/www/sites
for user in $(ls /home); do
  sudo ln -s /home/$user/public_html /var/www/sites/$user
done

Then use a static path in vsftpd.conf:

local_root=/var/www/sites