SFTP chroot

Related articles
SSHFS
OpenSSH
4.9+ includes a built-in chroot for SFTP, but requires a few tweaks to the normal install.
Installation
Install
and configure
OpenSSH
. Once running, make sure
sftp-server
has been set correctly:
/etc/ssh/sshd_config
Subsystem sftp /usr/lib/ssh/sftp-server
Access files with
sftp
or
SSHFS
. Many standard
FTP clients
should work as well.
Configuration
Setup the filesystem
Note
Readers may select a file access scheme on their own.  For example, optionally create a subdirectory for an incoming (writable) space and/or a read-only space.  This need not be done directly under
/srv/ssh/jail
- it can be accomplished on the live partition which will be mounted via a bind mount as well.
It is also possible chrooting into
/home
directory thus skipping the usage of bind, however the desired user home directory should be owned by root:
# chown root:root /home/<username>
# chmod 0755 /home/<username>
Bind mount the live
filesystem
to be shared to this directory. In this example,
/mnt/data/share
is to be used, owned by
user
root
and has octal
permissions
of
755
:
# chown root:root /mnt/data/share
# chmod 755 /mnt/data/share
# mkdir -p /srv/ssh/jail
# mount -o bind /mnt/data/share /srv/ssh/jail
Add entries to
fstab
to make the bind mount survive on a reboot:
/etc/fstab
/mnt/data/share /srv/ssh/jail  none   bind   0   0
Create an unprivileged user
Note
You do not need to create a group, it is possible to use
Match User
instead of
Match Group
.
Create the
sftponly
user group
:
# groupadd sftponly
Create a
user
who is a member of the
sftponly
group and has
shell
login access denied:
# useradd -G sftponly -s /usr/bin/nologin -d
/srv/ssh/jail
username
Note
SSH authentication by password (not recommended) only works if users have access to a login shell (i.e.
-s /usr/bin/nologin
not set).
Set a (complex) password to prevent
account is locked
error (may appear even with key authentication):
# passwd
username
Configure OpenSSH
Note
You may want to use
Match User
instead of
Match Group
as been given in the previous step.
/etc/ssh/sshd_config
Subsystem sftp /usr/lib/ssh/sftp-server

Match Group sftponly
  ChrootDirectory %h
  ForceCommand internal-sftp
  AllowTcpForwarding no
  X11Forwarding no
  PasswordAuthentication no
Restart
sshd.service
to confirm the changes.
Fixing path for authorized_keys
Tip
Use the
debug mode
of OpenSSH on the client and server in case of
(pre)auth
error(s).
With the standard path of
AuthorizedKeysFile
, the
SSH keys
authentication will fail for chrooted-users. To fix this,
append
a root-owned directory on
AuthorizedKeysFile
to
/etc/ssh/sshd_config
e.g.
/etc/ssh/authorized_keys
, as example:
/etc/ssh/sshd_config
AuthorizedKeysFile
/etc/ssh/authorized_keys/%u
.ssh/authorized_keys
PermitRootLogin no
PasswordAuthentication no
PermitEmptyPasswords no
Subsystem sftp /usr/lib/ssh/sftp-server
Create
authorized_keys
folder, generate a
SSH-key
on the client,
copy
the contents of the key to
/etc/ssh/authorized_keys
(or any other preferred method) of the server and
set correct permissions
:
# mkdir /etc/ssh/authorized_keys
# chown root:root /etc/ssh/authorized_keys
# chmod 755 /etc/ssh/authorized_keys
# echo 'ssh-rsa <key> <username@host>' >>
/etc/ssh/authorized_keys/username
# chmod 644 /etc/ssh/authorized_keys/
username
Restart
sshd.service
.
Tips and tricks
Write permissions
The
bind
path needs to be fully owned by
root
, however files and/or subdirectories do not have to be.
In the following example the
user
www-demo
uses
/srv/ssh/www/demo
as the jail-directory:
# mkdir /srv/ssh/www/demo/public_html
# chown www-demo:sftponly /srv/ssh/www/demo/public_html
# chmod 755 /srv/ssh/www/demo/public_html
The user should now be able to create files/subdirectories inside this directory. See
File permissions and attributes
for more information.
Allow upload only
To allow only uploading files via sftp and deny downloading files, change the
ForceCommand internal-sftp
line:
/etc/ssh/sshd_config
Match Group sftponly
  ForceCommand internal-sftp -u 0666 -p realpath,open,write,close,lstat
Logging
The user will not be able to access
/dev/log
. This can be seen by running
strace
on the process once the user connects and attempts to download a file.
Create sub directory
Create the sub-directory
dev
in the
ChrootDirectory
, for example:
# mkdir /usr/local/chroot/user/dev
# chmod 755 /usr/local/chroot/user/dev
Now you should create socket at
/usr/local/chroot/user/dev/log
which will be used by openssh. You may directly bind this socket to
/dev/log
(or
/run/systemd/journal/dev-log
in case you are using journald) or create using
syslog-ng
/
rsyslog
.
Bind to journald
# touch /usr/local/chroot/user/dev/log
# mount --bind /run/systemd/journal/dev-log /usr/local/chroot/user/dev/log
To make it permanent, add an entry to
fstab
:
/etc/fstab
/run/systemd/journal/dev-log /usr/local/chroot/user/dev/log none bind,nofail,x-systemd.requires=sshd.service
Syslog-ng configuration
Add to
/etc/syslog-ng/syslog-ng.conf
a new source for the log and add the configuration, for example change the section:
source src {
  unix-dgram("/dev/log");
  internal();
  file("/proc/kmsg");
};
to:
source src {
  unix-dgram("/dev/log");
  internal();
  file("/proc/kmsg");
  unix-dgram("/usr/local/chroot/theuser/dev/log");
};
and append:
#sftp configuration
destination sftp { file("/var/log/sftp.log"); };
filter f_sftp { program("internal-sftp"); };
log { source(src); filter(f_sftp); destination(sftp); };
(Optional) If you would like to similarly log SSH messages to its own file:
#sshd configuration
destination ssh { file("/var/log/ssh.log"); };
filter f_ssh { program("sshd"); };
log { source(src); filter(f_ssh); destination(ssh); };
(From
Syslog-ng#Move log to another file
)
OpenSSH configuration
Edit
/etc/ssh/sshd_config
to replace all instances of
internal-sftp
with
internal-sftp -f AUTH -l VERBOSE
.
Restart service
Restart
service
syslog-ng
and
sshd
.
/usr/local/chroot/theuser/dev/log
should now exist.
Alternatives to SFTP
Secure copy protocol (SCP)
Installing
openssh
provides the
scp
command to transfer files. SCP may be faster than using SFTP
[1]
.
Install
rssh
AUR
or
scponly
as alternative shell solutions.
Scponly
install
scponly
.
For existing users, simply set the user's shell to scponly:
# usermod -s /usr/bin/scponly
username
See
the Scponly Wiki
for more details.
Adding a chroot jail
The package comes with a script to create a chroot. To use it, run:
# /usr/share/doc/scponly/setup_chroot.sh
Provide answers.
Check that
/path/to/chroot
has
root:root
owner and
r-x
for others.
Change the shell for selected user to
/usr/bin/scponlyc
.
sftp-server may require some libnss modules such as libnss_files. Copy them to chroot's
/lib
path.
See also
https://www.minstrel.org.uk/papers/sftp/
sshd_config(5)