Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: November 4, 2024
SFTP (Secure File Transfer Protocol) is a popular method for transferring files securely over a network. It uses SSH (Secure Shell) to encrypt communications.
In this tutorial, we’ll see the process of configuring a Linux server to permit SFTP connections while disallowing SSH connections.
Secure File Transfer Protocol (SFTP) is a secure method for network file transfer. It’s built on the top of SSH and provides a similar level of security. However, unlike SSH, SFTP doesn’t provide full shell access. Consequently, this makes it a more secure option for scenarios where only file transfers are necessary.
In other words, such a configuration is beneficial when we want secure file transfer without compromising the security of a system by allowing full shell access. In these cases, administrators can allow users to upload and download files but prevent them from running commands on the server.
Several situations may require limiting SSH access while allowing SFTP:
Thus, restricting SSH access enhances security. It minimizes potential attack surfaces while still allowing file transfers to occur securely.
Effectively, we can allow SFTP but disallow SSH access by configuring the SSH daemon to use the SFTP server. In addition, this involves setting up a limited user environment, restricting their access to only SFTP.
Let’s see how to configure restricted SSH access.
First, we create a dedicated group for SFTP users:
$ sudo groupadd sftpusers
The users in the new group have only file transfer access to the server. For this, we later modify the sshd_config file. Of course, we can either assign existing users or add new users to this group.
In this case, let’s add a new user, baeldung, to the above group:
$ sudo useradd -m -d /home/baeldung -g sftpusers baeldung
Notably, the options -m and -d set the home directory for the user as /home/baeldung.
Next, we add a password for the new user:
$ sudo passwd baeldung
Alternatively, we can also add an existing user to the sftpusers group.
A chroot environment confines users to a part of the system, isolating them from the rest.
To begin with, let’s create a new directory for the SFTP users to control their access:
$ sudo mkdir /home/baeldung/uploads
The new directory, uploads, belongs to the currently logged-in user. So, we now assign ownership of the chroot directory and its parent directories to the root:
$ sudo chown root:root /home/baeldung/
$ sudo chown root:root /home/baeldung/uploads/
The above ownership rights match the OpenSSH server directive for ChrootDirectory configuration.
Next, we set access permissions for the files inside the uploads directory. In general, root has full access, while others have only read and execute access:
$ sudo chmod 755 /home/baeldung/uploads/
As a result, baeldung can only upload files to the uploads directory.
Next, we modify the sshd_config configuration file. In this file, we use the internal-sftp parameter set against the Subsystem directive:
$ cat /etc/ssh/sshd_config
...
Subsystem sftp internal-sftp
...
Thus, the above setup enables SFTP with the internal-sftp server. Alternatively, we can use the sftp-server binary for implementing the subsystem.
Furthermore, at the end of the file, we specify a group of users with restricted SFTP access:
$ cat /etc/ssh/sshd_config
...
Match Group sftpusers
ChrootDirectory /home/baeldung/uploads
ForceCommand internal-sftp
AllowTcpForwarding no
X11Forwarding no
...
Let’s see a breakdown of the above parameters:
After saving the configuration file, we restart the SSH service to apply the changes:
$ sudo systemctl restart sshd
Finally, we can test our setup.
Let’s open a terminal on the client and try to access the uploads directory on the server:
$ sftp [email protected]
...
[email protected]'s password:
Connected to 192.168.29.22.
sftp>
As a result, we can log in as baeldung.
Additionally, we can check the chroot environment on the remote machine. To do this, we list the current working directory:
sftp> pwd
Remote working directory: /
Then, we move a level up in the directory and again see the current directory:
sftp> cd ..
sftp> pwd
Remote working directory: /
Similarly, we try logging in via ssh:
$ ssh [email protected]
[email protected]'s password:
This service allows sftp connections only.
Connection to 192.168.29.22 closed.
Thus, the setup seems to be working properly and doesn’t allow SSH access.
Another method to disallow SSH access while enabling SFTP is to assign users a non-functional shell.
There are two popular binaries for this purpose:
While both function the same way for our purposes, we use /bin/false for this demonstration.
First, we add a new user, baeldung1, in the sftpusers group:
$ sudo useradd -m -G sftpusers baeldung1
Next, we set a password for the new user:
$ sudo passwd baeldung1
Of course, we assign the /bin/false shell:
$ sudo usermod -s /bin/false baeldung1
Again, we create a directory for a chroot environment:
$ sudo mkdir /home/baeldung1/uploads
Next, we change the directory permissions:
$ sudo chown root:root /home/baeldung1/
Similarly, we set the ownership for the uploads directory:
$ sudo chown root:root /home/baeldung1/uploads/
Finally, we set the permissions for root and others:
$ sudo chmod 755 /home/baeldung1/uploads/
As a result, the root has all the accesses and others have only read and execute accesses.
To verify the setup, let’s try to log in from another machine:
$ sftp [email protected]
[email protected]'s password:
Connected to 192.168.29.22.
sftp>
Further, we check the current directory on the remote server:
sftp> pwd
Remote working directory: /
Also, we can try navigating outside of the chrooted directory:
sftp> cd ..
sftp> pwd
Remote working directory: /
As a result, we see we can’t leave the chroot environment.
Let’s also try to log in via ssh:
$ ssh [email protected]
[email protected]'s password:
This service allows sftp connections only.
Connection to 192.168.29.22 closed.
As a result, ssh connection isn’t allowed.
In the same way, we can use the /bin/nologin shell.
Another useful method to restrict SSH access is by using the scponly utility. This utility restricts users to file transfer operations without allowing SSH shell access.
scponly is currently available on GitHub. Moreover, it has not been updated for a long time. Thus, some features such as the chroot setup might not work.
Let’s install scponly from the source code.
First, we update the package list on the system:
$ sudo apt update
Next, we install the essential tools for building software from source code. This includes the GNU Compiler Collection (GCC), make, and other tools:
$ sudo apt install build-essential
Since /opt is a common location for manually installed software, let’s move there:
$ cd /opt
Next, we download the scponly source code using the wget command:
$ sudo wget http://sourceforge.net/projects/scponly/files/scponly-snapshots/scponly-20110526.tgz
Next, we extract the downloaded .tbz file:
$ sudo tar -zxvf scponly-20110526.tgz
Moving on, we navigate to the extracted directory:
$ cd /opt/scponly-20110526
Now, we run the configuration script, specifying the path to the sftp-server binary:
$ sudo ./configure --with-sftp-server=/usr/lib/openssh/sftp-server
The above script checks for all the required dependencies for the build and install process.
Further, we use the make command to compile the source code:
$ sudo make
To install the compiled scponly binary, we leverage the install subcommand:
$ sudo make install
As a result, the files are installed in their proper directories.
Next, we add the scponly shell to the system’s list of valid shells (/etc/shells):
$ sudo sh -c "echo "/usr/local/bin/scponly" >> /etc/shells"
As a result, users should now be able to use the scponly shell.
Finally, to test the setup, we create a user, scponly:
$ sudo useradd -d /home/scponly -s /usr/local/bin/scponly scponly
The above user has a home directory of /home/scponly. Also, the shell is set as /usr/local/bin/scponly, which restricts the user to file transfers only.
Naturally, we set a password for the user:
$ sudo passwd scponly
Let’s test the result.
To test the user with scponly, we try to log in from another machine with that user:
$ sftp [email protected]
[email protected]'s password:
Connected to 192.168.29.22.
sftp>
Thus, we’ve successfully connected to the remote machine over SFTP.
Let’s again try by logging in via ssh:
$ ssh [email protected]
[email protected]'s password:
Welcome to Ubuntu
...
Could not chdir to home directory /home/scponly: No such file or directory
Connection to 192.168.29.22 closed.
Thus, the connection is automatically closed.
In this article, we’ve seen how we can allow SFTP connections while denying SSH login. We employed several methods for this purpose:
Effectively, the above approaches provide a secure and controlled way to transfer files without compromising our system security.