This guide examines setting up chroot’ed SFTP-only user accounts under Virtualmin.
The Rationale:
SFTP is a secure alternative to FTP and FTPS that uses SSH. With this setup, no FTP server is needed, as the native sshd server is used instead, SSH does not require an SSL certificate (like FTPS), and is usually considered more secure.
However, one drawback is that FTP servers typically offer a simple config option to “restrict access to the user’s home directory”, whereas SFTP requires a chroot’ed setup to do this, which is more complex, and not supported natively by Virtualmin (or really any other CP).
Note: Giving users access to the full server is not as bad as it sounds. Users are limited by file permissions as to what they can actually see or do, and Virtualmin sets home directory permissions to 750 by default, so users can’t snoop around each other’s files. More importantly, restricting access to the user’s home directory only applies to FTP service. This is just a minor inconvenience for any competent hacker, as access to the full server is easily obtained via the web server (which is not chroot’ed), using any web-based file manager (many CMSs come with one built-in).
However, for the average user, there may still be some value in restricting just their FTP access so as to at least discourage them from snooping around.
There are some complications to overcome:
- The chroot directory must be root owned and world-readable (sshd checks this unconditionally for security reasons).
- The user’s home directory should be relative to this root because the server will attempt to go to the directory relative to the root when the user logs in.
- If you want to prevent users from being able to see even the list of other users on the server, then each user will need a separate chroot directory.
The typical solution involves a complex home directory path:
/home/chroot/domain/home/domain
Note that all directories in the path leading up to the final sub-directory should be root owned and world-readable.
Steps to follow:
1. Set the home directory template in Virtualmin accordingly:
Virtualmin -> System Settings -> Virtualmin Configuration -> Defaults for new domains -> Home directory base: /home/chroot/${DOM}/home
Virtualmin -> System Settings -> Virtualmin Configuration -> Defaults for new domains -> Home subdirectory: ${DOM}
Note that both settings are required, even if ${DOM} is the default, as Virtualmin will not correctly interpolate the directory unless a manual template is set.
2. Add a custom command to handle setting up and cleaning up the chroot:
Virtualmin -> System Settings -> Virtualmin Configuration ->Actions upon server and user creation -> Command to run before making changes to a server: /home/chroot/chroot.sh
Virtualmin -> System Settings -> Virtualmin Configuration ->Actions upon server and user creation -> Command to run after making changes to a server: /home/chroot/chroot.sh
3. Create the /home/chroot/chroot.sh as follows:
#!/bin/ksh
if [ ! “$VIRTUALSERVER_PARENT” ]
then
if [ “$VIRTUALSERVER_ACTION” == “CREATE_DOMAIN” ]
then
if [ ! “$VIRTUALSERVER_CREATED” ]
then
mkdir -p /home/chroot/$VIRTUALSERVER_DOM/home
else
echo “Setting up $VIRTUALSERVER_DOM to chroot’ed environment for sftp”
usermod -d /home/$VIRTUALSERVER_DOM $VIRTUALSERVER_USER
ln -s $VIRTUALSERVER_HOME /home
echo " … done"
fi
elif [ “$VIRTUALSERVER_ACTION” == “DELETE_DOMAIN” ]
then
if [ “$VIRTUALSERVER_CREATED” ]
then
echo “Cleaning up $VIRTUALSERVER_DOM’s chroot’ed environment”
rm -rf /home/chroot/$VIRTUALSERVER_DOM /home/$VIRTUALSERVER_DOM
echo " … done"
fi
fi
fi
And don’t forget to give it executable permissions.
This script:
- Creates the home directory’s parent directory as Virtualmin will not do this automatically, and fail without it.
- Changes the /etc/passwd home directory entry to be relative to the chroot (so it’s not the same as the real home directory!).
- Adds a symbolic link from this home directory location to the real directory for convenience so that things like ~domain still work.
4. Add Virtualmin users to a secondary group that sshd can identify for SFTP-only access:
Virtualmin -> System Settings -> Server Templates -> Default Settings -> Administration user -> Add domain owners to secondary group: sftponly
Be sure to create this group.
5. Update /etc/ssh/sshd_config to set SFTP-only access for members of this group:
Subsystem sftp internal-sftp
Match Group sftponly
ChrootDirectory /home/chroot/%u
ForceCommand internal-sftp
AllowTcpForwarding no
6. Reload sshd:
>systemctl reload sshd.service
7. Test the setup by creating a user, logging in via SFTP, and attempting to log in via SSH (hopefully unsuccessfully).