This functionality now comes standard in OpenSSH using the ChrootDirectory and the ForceCommand keyword in sshd_config! Hurray!
The Match keyword also allows you to specify which users are affected. This means that rssh and the setup outlined in this howto are no longer necessary. From the sshd_config man page:
Specifies a path to chroot(2) to after authentication. This
path, and all its components, must be root-owned directories that
are not writable by any other user or group.
The path may contain the following tokens that are expanded at
runtime once the connecting user has been authenticated: %% is
replaced by a literal '%', %h is replaced by the home directory
of the user being authenticated, and %u is replaced by the user‐
name of that user.
The ChrootDirectory must contain the necessary files and directo‐
ries to support the users' session. For an interactive session
this requires at least a shell, typically sh(1), and basic /dev
nodes such as null(4), zero(4), stdin(4), stdout(4), stderr(4),
arandom(4) and tty(4) devices. For file transfer sessions using
“sftp”, no additional configuration of the environment is neces‐
sary if the in-process sftp server is used (see Subsystem for
The default is not to chroot(2).
Forces the execution of the command specified by ForceCommand,
ignoring any command supplied by the client and ~/.ssh/rc if
present. The command is invoked by using the user's login shell
with the -c option. This applies to shell, command, or subsystem
execution. It is most useful inside a Match block. The command
originally supplied by the client is available in the
SSH_ORIGINAL_COMMAND environment variable. Specifying a command
of “internal-sftp” will force the use of an in-process sftp
server that requires no support files when used with
You should probably use the functionality built into OpenSSH instead, but just in case you don't want to do so, below is the tutorial as it was, which was last edited on February 5th, 2008 at 08:10 PM.
Match Introduces a conditional block. If all of the criteria on the
Match line are satisfied, the keywords on the following lines
override those set in the global section of the config file,
until either another Match line or the end of the file.
The arguments to Match are one or more criteria-pattern pairs.
The available criteria are User, Group, Host, and Address. The
match patterns may consist of single entries or comma-separated
lists and may use the wildcard and negation operators described
in the PATTERNS section of ssh_config(5).
The patterns in an Address criteria may additionally contain
addresses to match in CIDR address/masklen format, e.g.
“192.0.2.0/24” or “3ffe:ffff::/32”. Note that the mask length
provided must be consistent with the address - it is an error to
specify a mask length that is too long for the address or one
with bits set in this host portion of the address. For example,
“192.0.2.0/33” and “192.0.2.0/8” respectively.
Only a subset of keywords may be used on the lines following a
Match keyword. Available keywords are AllowAgentForwarding,
AllowTcpForwarding, Banner, ChrootDirectory, ForceCommand,
GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication,
MaxAuthTries, MaxSessions, PasswordAuthentication,
PermitEmptyPasswords, PermitOpen, PermitRootLogin,
RhostsRSAAuthentication, RSAAuthentication, X11DisplayOffset,
X11Forwarding and X11UseLocalHost.
Howto create chrooted Openssh SFTP without shell access through rssh.
I noticed many people wanted to set up a secure way (non cleartext and authentication required) to transfer files but wanted to limit their users from accessing a shell or browsing the entire file system. For the past week, I have been searching for a way to do this myself.
However, most of the solutions posted to these requests didn't suit me: chrootssh (http://chrootssh.sourceforge.net/), which I found difficult to set up since it involved compiling from source instead of installing from a package; set up another ftp server (like vsftpd), since I already had sshd running, I didn't want to manage another server and I was having difficulty getting this to work securely; setting the user's shell to the sftp-server, which still allowed to user to get out of their directories (but limited the user to sftp).
I also tried rssh unsuccessfully once before finding a HOWTO from the gentoo-wiki website <http://www.gentoo-wiki.com/index.php?title=HOWTO_SFTP_Server_(chrooted%2C_wit hout_shell)&redirect=no>. (Many thanks to them). I adapted their HOWTO slightly to work for Ubuntu.
It took me a week to finally set it up and get it working since I started trying. I hope this HOWTO will help anyone else who wants to do this, but since I am writing this HOWTO after I set it up, I may accidentally forget a step. In addition, my system may differ from your's (FYI, Ubuntu Breezy with i686 kernel; but even if you have the same, your configs may differ). I make no guarantees that this will work on your system. I am just writing this in hopes that it will help. Feel free to post any suggestions/comments/questions/corrections. NOTE: I only tested my setup for SFTP.
First, you need the "openssh-server" package. (I assume you already have that installed, updated, and configured. If not, it is pretty easy to do so & there are other tutorials available. You can get it through Synaptic Package Manager.)
Then get the "rssh" package through Synaptic or through apt-get.
Once that is ready, you can configure rssh by editing the file "/etc/rssh.conf". (You probably want to make a backup copy of that file by typing the command:
The command I used to edit /etc/rssh.conf was :
sudo cp /etc/rssh.conf /etc/rssh.orig.conf
Note: you need the nano text editor to do this. replace "nano" with "gedit" or another text editor if you want.
sudo nano /etc/rssh.conf
The file should already be mostly filled out. Just uncomment (by removing the '#') the lines "#allowsftp" to allow sftp and if you want, uncomment the line "#allowscp". I left "#allowscp" commented since I only wanted sftp.
There should be a line in "/etc/rssh.conf" that currently reads:
change it to:
#chrootpath = "/usr/local/chroot dir"
(uncomment the line and change the path to "/home/chroot". The path is personal preference, but I decided "/home/chroot".) Doing this tells rssh to chroot jail everyone using rssh to the directory "/home/chroot".
chrootpath = "/home/chroot"
At this point, your rssh.conf file should have the following uncommented lines:
Now to make sure OpenSSH does not weaken rssh (gunzip and read "/usr/share/doc/rssh/SECURITY" for more information), make sure you have the latest package for openssh-server and run the following command:
logfacility = LOG_USER
umask = 022
chrootpath = "/home/chroot"
If you see the line beginning with "PermitUserEnvironment", use your text editor to either remove the line from "/etc/ssh/sshd_config" or to change the line to
cat /etc/ssh/sshd_config | grep "PermitUserEnvironment"
Now to build the chrooted directory. There should be a zipped script at "/usr/share/doc/rssh/examples/mkchroot.sh.gz". Unzip the file, make a copy and edit the copy. You can do so using the following series of commands
If you scroll through the file, you will find the lines:
sudo gunzip /usr/share/doc/rssh/examples/mkchroot.sh.gz
sudo cp /usr/share/doc/rssh/examples/mkchroot.sh ~/mkchroot.sh
sudo nano ~/mkchroot
Make sure these paths match the ones given when you type the following command:
If they do not match, change your script so the paths match.
If your setup is like mine, your sftp server will actually be located in "/usr/lib/openssh/sftp-server" instead of "/usr/lib/sftp-server", which is where rssh thinks the sftp-server is. If this is your case, change
Save the script and exit the editor.
Then make the script executable with the following command:
sudo chmod u+x ~/mkchroot.sh
Now remember how you made
in "/etc/rssh"? Well, now you actually make the chroot directory by running the following commands:
chrootpath = "/home/chroot"
While running that command, don't worry if you get the error saying that it cannot copy "linux-gate.so.1". It isn't a real file. However, you will probably need to copy the file "ld-linux.so.2" if it appears when you type the command:
sudo ./mkchroot.sh /home/chroot
but is not in the path "/home/chroot/lib/ld-linux.so.2". You can copy the file with the following commands:
ldd /usr/bin/scp | grep "ld-linux.so.2"
Just to play it safe, make sure you have "libnss_compat.so.2" in the directory "/home/chroot/lib". If not, put it there with the following command:
sudo cp /lib/ld-linux.so.2 lib/
Now make rssh a valid shell by running the command:
sudo cp /lib/libnss_compat.so.2 /home/chroot/lib/
Now create a new user (I called mine "sft" for secure file transfer). Make the shell for the new user "/usr/bin/rssh". Make sure the home directory path is inside the chroot jail. For me, I made the home directory "/home/chroot/home/sft". If you don't know how to add a user, there is a GUI under System -> Administration -> Users and Groups.
Now to apply the finishing touches and tie up loose ends:
For logging to work properly, you need to tell sysklogd to listen to "/home/chroot/dev/log". You can do this by editing "/etc/init.d/sysklogd".
WARNING: You can seriously mess up your system logging if you mess up here. BE CAREFUL!
(you can replace nano with your text editor of choice). Run the following to edit "/etc/init.d/sysklogd":
You should find a line that starts with:
sudo nano /etc/init.d/sysklogd
Simply add the following in the appropriate space on the line:
If your config is like mine, the original line will read:
The new line will read:
You will need to tell sysklogd to restart to get the new config; use the following command:
SYSLOGD="-a /home/chroot/dev/log -u syslog"
From what I read online, some programs may need /etc/passwd in order to run properly (I think scp). To play it safe, place a copy of /etc/passwd in the chroot directory using the following command:
sudo /etc/init.d/sysklogd restart
For security reasons, you will probably want to remove all irrelevant lines from the passwd file in "/home/chroot/etc/". So for my passwd file, since the name of the account that will use this chrooted directory, I only have the line:
sudo cp /etc/passwd /home/chroot/etc/
WARNING: Please edit only the chroot copy of the passwd file, not the real one in /etc/passwd.
sft:x:1001:1001:Secure File Transfer Account,,,:/home/sft:/usr/bin/rssh
You can use nano or another text editor to remove the other lines. (I also changed the home directory in the chroot passwd file from "/home/chroot/home/sft" to "/home/sft". I'm not sure if this is necessary, but I did this because I felt this will be better.)
In order for the chrooting process to work, "/usr/lib/rssh/rssh_chroot_helper" has to be setuid root. (Note: this path is relative to real root, not chroot root.) To setuid root, run the command:
sudo chmod u+s /usr/lib/rssh/rssh_chroot_helper
Now remember how rssh thinks that the sftp subsystem is located at "/usr/lib/sftp-server" but it is actually located in "/usr/lib/openssh/sftp-server"? If not, you can run the command:
to figure it out. (Note: if this is not the case on your system, since our configs may differ, you should not follow this step and you should not follow one of the previous steps where you changed sftp_server_path="/usr/lib/sftp-server" to sftp_server_path="/usr/lib/openssh/sftp-server".)
If however, your sftp-server is located in "/usr/lib/openssh/" and rssh thinks that it is located in "/usr/lib/" and your sshd (ssh server) thinks that the sftp subsystem is located at "/usr/lib/openssh/", make the following changes. (Note: you can check where sshd thinks the sftp subsystem is by the following command:
First, create a link to "/usr/lib/openssh/sftp-server" at "/usr/lib/". (Note: I already found a symbolic link to sftp-server in my "/usr/lib", so I kept it as a symbolic link. However, a hard link seems more reasonable to me. I'll let you decide which one you want. If you don't know the difference between a symbolic link and a hard link, feel free to look it up; if you know how to explain the difference properly, please post an explanation.)
cat /etc/ssh/sshd_config | grep "Subsystem sftp "
To create the symbolic link, use the command:
To create the hard link, use the command:
sudo ln -s /usr/lib/openssh/sftp-server /usr/lib/
Now that the sftp-server exists in "/usr/lib", you can change the config file for your sshd. Use your text editor to edit "/etc/ssh/sshd_config". For me, the command was:
sudo ln /usr/lib/openssh/sftp-server /usr/lib/
Then find the line:
sudo nano /etc/ssh/sshd_config
and replace it with:
Subsystem sftp /usr/lib/openssh/sftp-server
Save and exit the text editor when done. In order for the new config to take effect, you need to tell sshd to reload the config using the following command:
Subsystem sftp /usr/lib/sftp-server
Now you have to fix your chroot directory setup (you need to be able to run "/usr/lib/sftp-server" even when chrooted). To do this, create a hard link between for "/home/chroot/usr/lib/openssh/sftp-server" at "/home/chroot/usr/lib/" using the following command:
sudo /etc/init.d/ssh reload
Finally, there may be some files in the rsshed account's home directory like ".bashrc". If these are not needed, you can just delete them using the command "rm".
sudo ln /home/chroot/usr/lib/openssh/sftp-server /home/chroot/usr/lib/
At this point, your setup should be done (unless you or I missed a step).
Fire up your favorite SFTP client and test the new setup. Hopefully it will work. Now try to ssh in using the rsshed account. A message should appear, and then rssh should exit, closing the connection.
If you get a "connection closed" error and you have followed all the steps, adding null to your chrooted dev directory may help. You can do this with the command
where /home/chroot is the chroot directory.
mknod -m 666 /home/chroot/dev/null c 1 3
Side note: If the user with the chrooted rsshed account manages to get to the server & get to the graphical login, they can login like a normal user (without chroot restrictions & without protection provided by rssh since the rssh shell is not the login shell).
I have discovered that this setup will still allow people to use the port forwarding feature of SSH if it is enabled on the server. See the blue section below for the fix.
Update on AllowTcpForwarding:
You can use "Match" in your sshd_config to allow/disallow certain groups/users the ability to forward TCP connections. Thanks to oojah for this information. (He placed the rssh users into a group called "chroot" in this example.)