What is SFTP:
SFTP, or Secure File Transfer Protocol, is a secure file transfer protocol that uses secure shell (SSH) encryption to provide a higher level of security for sending and receiving file transfers. SFTP transfers files using SSH and encrypted FTP commands (hence SFTP) to avoid password sniffing and exposing sensitive information in plain text.
Overview:
In this article, we will go over a simple and quick way to setup an SFTP server on Ubuntu Server 22.04 LTS. There are a few installation and just overall day-to-day gotchas that I have overcome that are not mentioned in the other articles and I wanted to share this information so that anyone just getting into SFTP doesn’t have to go through the same pain I had to.
This installation will use mostly default settings with some basic resources requirements. Adjust the resources to what fits best for your workflows.
- 4vCPU
- 4GB RAM
- 100GB OS
- 100GB Data
apt-get update && apt-get upgrade -y
fdisk -l
gdisk /dev/sdb
n for a new partition
Accept the defaults
w to write the changes
fdisk -l
mkfs.ext4 /dev/sdb1
mkdir /data
blkid
Note the UUID for the data disk
vim /etc/fstab
UUID=12345-6789-12345-12345 /data ext4 defaults 0 0
mount -a
df -h
reboot
addgroup sftp
useradd ftpuser
passwd ftpuser
usermod -a -G sftp ftpuser
grep sftp /etc/group
mkdir /data/FTP
chown root:root /data
chmod 755 /data
chown -R ftpuser:sftp /data/FTP
chmod -R 770 /data/FTP
chmod -R g+s /data/FTP
vim /etc/ssh/sshd_config
#Allow older keys if needed
#HostKeyAlgorithms +ssh-rsa,ssh-dss
#KexAlgorithms +diffie-hellman-group1-sha1
#Custom mgmt settings
PermitRootLogin no
#DenyUsers ANY-OTHER-USERS
MaxSessions 100
MaxStartups 80:50:100
#SFTP data settings
Match group sftp
ChrootDirectory /data
ForceCommand internal-sftp
PermitTTY no
X11Forwarding no
AllowTcpForwarding no
systemctl restart ssh
crontab -e
#Delete files older than 30 days from /data/FTP
0 0 * * * /usr/bin/find /data/FTP -type f -mtime +30 -delete
#Delete empty folders older than 30 days from /data/FTP
0 0 * * * /usr/bin/find /data/FTP/ -mindepth 1 -type d -empty -mtime +90 -delete
Prerequisites:
- Note: All commands are done via an SSH connection in this guide.
To start you will need to open an SSH session to your Ubuntu machine, if you are on windows you can use putty or even PowerShell to achieve this.
Update the Ubuntu server to get the latest version of OpenSSH and any other packages .
apt-get update && apt-get upgrade -y
- Command Block #01
- apt-get update && apt-get upgrade -y
- && means to run command 1 only after command 2 succeeds
- apt-get update && apt-get upgrade -y
Format & Mount the Data drive:
After installing updating the server we will now get the extra data drive ready to store our SFTP files later on.
Find and create a partition on the data drive. Please note your drive path may be different than the “/dev/sdb” I have listed below. Review the fdisk output and adjust accordingly.
fdisk -l
gdisk /dev/sdb
n for a new partition
Accept the defaults
w to write the changes
Now that the disk has a new blank partition we need to format the partition and set the drive to auto mounts on reboot. In the example below I create a directory called /data in the root directory but you can switch this to any directory that you would prefer.
fdisk -l
mkfs.ext4 /dev/sdb1
mkdir /data
blkid
Note the UUID for the data disk
vim /etc/fstab
UUID=12345-6789-12345-12345 /data ext4 defaults 0 0
mount -a
df -h
reboot
- Command Block #01
- fdisk -l
- fdisk is a dialog-driven program for the creation and manipulation of partition tables. It understands GPT, MBR, Sun, SGI, and BSD partition tables
- -l, –list
- List the partition tables for the specified devices and then exit.
- gdisk /dev/sdb
- GPT fdisk (aka gdisk) is a text-mode menu-driven program for the creation and manipulation of partition tables.
- fdisk -l
- Command Block #02
- mkfs.ext4
- mkfs is used to build a Linux filesystem
- ext4 is the file system type
- blkid
- blkid helps determine exta attributes for a device\drive. In this case, we use it to get the UUID of the data drive.
- /etc/fstab
- A Linux file containing mount information for a Linux file system.
- The order of records here is important as data is read sequentially when mounting/unmounting,…etc
- mkfs.ext4
SFTP Group & Users
Now that the data drive is mount on reboots we can setup an SFTP group and user(s) to use later when we configured the SFTP settings. The group name and user(s) can be anything you want so please adjust accordingly.
addgroup sftp
useradd ftpuser
passwd ftpuser
usermod -a -G sftp ftpuser
grep sftp /etc/group
- Command Block #01
- addgroup <groupname>
- Creates a new group
- useradd <username>
- Creates a new user
- usermod -a -G sftp ftpuser
- usermod modifies user accounts
- -a is to append
- -G is to define the Group
- In short, we are adding the “ftpuser” to the “sftp” group,
- grep sftp /etc/group
- We are querying the sftp group to make sure the “ftpuser” is actually apart of the “sftp” group.
- addgroup <groupname>
SFTP Configuration:
That we have the data drive, group, user and everything else prestage we can jump into configuring the SFTP service.
We will create a default directory called “FTP” in the /data drive to store any SFTP data. This directory will be locked down as we will be using a method called “Chroot jail” to help better secure the server.
Something to note when using the “Chroot jail” method is that only root can have write access to the main directory which in this case is /data. The group and other permissions cannot have write access. If they do you will receive permission denied later on.
mkdir /data/FTP
chown root:root /data
chmod 755 /data
With the Chroot jail setup we will grant the sftp group & ftpuser we created earlier access to the /data/FTP folder. Adjust permissions how you see fit but for right now I am giving the owner and group full control of the /data/FTP directory.
chown -R ftpuser:sftp /data/FTP
chmod -R 770 /data/FTP
chmod -R g+s /data/FTP
With permissions in place we will now configured various settings in the “/etc/ssh/sshd_config” file. This file is the configuration file for the SSH\SFTP service that allows us to customize a lot of different options.
For some more information on sshd_config you can reference this link: sshd_config
vim /etc/ssh/sshd_config
#Allow older keys if needed
#HostKeyAlgorithms +ssh-rsa,ssh-dss
#KexAlgorithms +diffie-hellman-group1-sha1
#Custom mgmt settings
PermitRootLogin no
#DenyUsers ANY-OTHER-USERS
MaxSessions 100
MaxStartups 80:50:100
#SFTP data settings
Match group sftp
ChrootDirectory /data
ForceCommand internal-sftp
PermitTTY no
X11Forwarding no
AllowTcpForwarding no
Reboot the ssh service to apply the changes
systemctl restart ssh
- Command Block #01
- chown root:root /data
- chown is used to change the ownership of a directory or file
- root:root is the user and group that we are setting ownership to
- /data is the directory we give the root user and group ownership over.
- chmod 755 /data
- chmod is used to change permissions for a directory or file
- 755 is read as Owner:Group:Other
- 7 = Read,Write,Execute
- 5 = Read & Execute
- This is how part of how we set up the chroot jail.
- chown root:root /data
- Command Block #02
- chown -R ftpuser:sftp /data/FTP
- -R is used to recursively set ownership
- ftpuser:sftp is the user and group that we are setting ownership to
- /data/FTP is the directory we give the ftpuser user and sftp group ownership over.
- chmod 755 /data
- chmod is used to change permissions for a directory or file
- 770 is read as Owner:Group:Other
- 7 = Read,Write,Execute
- 0 = Nothing
- chmod -R g+s /data/FTP
- This means that all new files and subdirectories created within the current directory inherit the group ID of the directory, rather than the primary group ID of the user who created the file.
- chown -R ftpuser:sftp /data/FTP
- Command Block #03
- HostKeyAlgorithms +ssh-rsa,ssh-dss
- KexAlgorithms +diffie-hellman-group1-sha1
- The following are commented out but when it comes to older systems that support SFTP they might not support the newer ciphers & key exchanges and instead only support the only less secure options.
- Uncommenting these lines will allow the SFTP server to work with some older systems.
- The + before the lines means their ciphers & keys are appended to the default allowed listed rather than replace the existing ones. This helps the SFTP server still trying to use the most secure option if it can.
- PermitRootLogin no
- DenyUsers ANY-OTHER-USERS
- Block the ability for root to SSH into the system.
- Block any other users on the system from using SSH.
- I block any other users present on the system from using SSH and will only uncomment this line when its needed. As most other operations I can do from the console of the system.
- MaxSessions 100
- MaxStartups 80:50:100
- Allow more than the default of 10 active sessions to connect to the SFTP server.
- I use this as sometimes I might have many clients connecting and sending data to the SFTP server when running bulk reports.
- 80:50:100 allows us to control what happens when we start reaching the max number of sessions.
- In this config when active SFTP sessions reach 80 we will start dropping 50% of the incoming connections and when the active sessions reach 100 we drop all incoming sessions.
- Match group sftp
- Apply settings to any user apart of the SFTP group
- ChrootDirectory /data
- Chroot jail method
- ForceCommand internal-sftp
- PermitTTY no
- X11Forwarding no
- AllowTcpForwarding no
- All the items listed above help increase the security of the SFTP server by either forcing only sftp connections to reducing various attack surfaces.
Testing
Once the sshd_config has been edited and ssh service has been restarted you can use filezile, powerhsell or any other sftp client to connect to your new SFTP server.
Auto cleanup old data
A little bonus option that I like to put in place for most systems is to have a simple automatic cleanup system in place to avoid bloated and stale storage.
For my purposes this SFTP server is only a temp storage aggregation point for various data reports and not its long term storage.
In the example below I am auto deleting files older then 30 days and also deleting any empty folders that are over 90 days old. This cron jobs run every day at midnight. When deleting the empty folders its important to user the “-mindepth 1” option or you can also delete the parent folder as well.
crontab -e
#Delete files older than 30 days from /data/FTP
0 0 * * * /usr/bin/find /data/FTP -type f -mtime +30 -delete
#Delete empty folders older than 30 days from /data/FTP
0 0 * * * /usr/bin/find /data/FTP/ -mindepth 1 -type d -empty -mtime +90 -delete