SFTP server
Videos
Overview: SFTP Server on Ubuntu 24.04 LTS on Azure: overview (watch on YouTube)
Launch and log in: SFTP Server on Ubuntu 24.04 LTS on Azure: launch and log in (watch on YouTube)
Deep Dive: SFTP Server on Ubuntu 24.04 LTS on Azure: deep dive (watch on YouTube)
Overview
This guide covers deploying and using SFTP Server 9.6 on Ubuntu 24.04 LTS from SecureAnyCloud on Microsoft Azure.
SFTP (the SSH File Transfer Protocol) moves files over an encrypted SSH connection on port 22. Every operating system has a client (sftp, WinSCP, FileZilla, Cyberduck) and so do most backup, ETL and B2B tools. This image is a plain, well-understood SFTP server: the OpenSSH server that ships with Ubuntu, set up so that you can hand accounts to partners and systems safely.
What you get:
- SFTP users are jailed. Every member of the
sftpusersgroup is locked (chrooted) into its own directory,/srv/sftp/<user>, on a dedicated 50 GiB Azure data disk. The jail is owned by root. The only place a user can write is itsuploaddirectory. SFTP users get no shell, no terminal and no port, agent, X11 or socket forwarding, so an SFTP account can move files and nothing else. - SFTP users are key-only by default. You can switch on password logins for SFTP users only with one command. The administrator account signs in the way you chose when you deployed the VM (SSH key or password), and root never logs in.
- Passwords never go on a command line. The account tools either generate a password and show it once, or read it from standard input. A password typed as a command argument would end up in your shell history and in sudo's log, so the tools refuse that form.
- Unique per VM. The image contains no SSH host key, no user and no key. On first boot each VM gets its own SSH host keys and a demo SFTP user,
sftpdemo, with its own ed25519 key. The host key fingerprints are written to a root-only file, so you can check the very first connection. - Closed if anything goes wrong. First boot proves a full SFTP round trip, the jail and every refusal, and that no key leaked into a log, before it finishes. If any check fails, the demo user and its key are removed again.
- Per-user quotas and an audit log that work. Quotas are enforced on the data disk at every boot, and a deleted user's limit is cleared so it never passes to a new account. Every SFTP session and file operation (open, read, write, rename, remove) is written to the system journal with the client's address. OpenSSH cannot log from inside a jail on its own, so the image places the journal's socket inside each jail for you.
- Hardened service. fail2ban bans addresses that keep failing to log in. sshd, fail2ban and the boot preparation cannot reach the Azure Instance Metadata Service (169.254.169.254) or the Azure WireServer (168.63.129.16). The Azure Linux agent on the VM keeps working as normal.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
- OpenSSH 9.6p1 from Ubuntu 24.04's own package (
openssh-server 1:9.6p1-3ubuntu13), installed from the Ubuntu archive (noble-security), so Ubuntu keeps patching it and unattended-upgrades applies its fixes. "9.6" is the upstream release Ubuntu 24.04 maintains. This build carries every Ubuntu OpenSSH security update to date, including USN-6859-1 (CVE-2024-6387, "regreSSHion"), USN-6887-1 (CVE-2024-39894), USN-7270-1 (CVE-2025-26465, CVE-2025-26466), USN-7457-1 (CVE-2025-32728), USN-8090-1, USN-8222-1, USN-8533-1, USN-8721-1 and USN-8928-1 (October 2026). The exact package version is in Step 13. - fail2ban, the quota tools, Ubuntu 24.04 LTS, cloud-init and the Azure Linux agent. The SFTP account tools are in
/usr/local/sbin(Step 8).
Default user: azureuser (or the administrator name you choose). Architecture: x64. Recommended size: Standard_B2s.
Prerequisites
Before you deploy this image, make sure you have:
- An Azure subscription, an SSH key pair (or a password, if you choose password authentication for the administrator in the portal) and a virtual network in the target region.
- A network security group that allows TCP 22 from your administrators' and your SFTP users' networks only. SFTP and administration share port 22. No other port is needed.
- An SFTP client: the
sftpcommand, WinSCP, FileZilla or Cyberduck.
Deploy the VM
In the Azure portal, choose Create a resource, search for SFTP Server on Ubuntu 24.04 LTS by SecureAnyCloud, and select Create.
Pick your subscription, resource group and region. Choose the Standard_B2s size (SFTP needs little CPU, so size for your users and transfer volume). Choose the administrator account, and use an SSH public key if you can.
Under Networking, allow inbound 22 only from the networks your users and administrators connect from.
The image brings its own 50 GiB data disk for /srv/sftp. You can enlarge it on the Disks tab, and first boot grows the file system to fill it.
To deploy with the Azure CLI, replace the values in angle brackets. The last command limits port 22 to one network:
az group create --name sftp-rg --location <region>
az vm image terms accept --urn sac1647283583153:sftp-server-ubuntu-24-04:default:latest
az vm create --resource-group sftp-rg --name sftp-server \
--image sac1647283583153:sftp-server-ubuntu-24-04:default:latest \
--size Standard_B2s --admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub --public-ip-sku Standard
az network nsg rule update --resource-group sftp-rg --nsg-name sftp-serverNSG \
--name default-allow-ssh --source-address-prefixes <your-client-cidr>Connect to your VM
ssh azureuser@<vm-public-ip>The administrator account works like any Ubuntu VM on Azure. Sign in over SSH with the key (or password) you chose at deployment, and use sudo for administration.
Check the services
First boot creates the demo user and proves an SFTP round trip before it finishes (a few seconds after SSH answers):
systemctl is-active ssh fail2ban sftp-prepare sftp-server-firstboot
sudo test -f /var/lib/sac/data/sftp-server-firstboot.done && echo FIRSTBOOT_DONEactive active active active FIRSTBOOT_DONEsftp-server-firstboot runs once. After a later reboot it reports inactive, which is expected because the marker file stays in place.
Only sshd listens on a public address, on port 22:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0' | sort0.0.0.0:22 users:(("sshd",...)) [::]:22 users:(("sshd",...))Connection details and host key fingerprints
sudo grep -vE '^(#|$)' /root/sftp-server-info.txtThe file is readable by root only:
SFTP_HOST=<vm-public-ip> SFTP_PORT=22 SFTP_DEMO_USER=sftpdemo SFTP_DEMO_KEY=/root/sftp-demo-key SFTP_DEMO_KEY_FINGERPRINT=SHA256:<demo-key-fingerprint> SFTP_DEMO_JAIL=/srv/sftp/sftpdemo SFTP_PASSWORD_AUTH=off SFTP_ADMIN_USER=azureuser HOST_KEY_ED25519_SHA256=SHA256:<this-VM's-ed25519-host-key> HOST_KEY_ECDSA_SHA256=SHA256:<this-VM's-ecdsa-host-key> HOST_KEY_RSA_SHA256=SHA256:<this-VM's-rsa-host-key>SFTP_HOST is the VM's public IP address from Azure instance metadata (the private address when the VM has no public IP). To print a DNS name there instead, put it in /etc/sac/sftp-hostname before first boot. First boot is the only part of the image that reads instance metadata, and it cannot reach the WireServer.
The first time any client connects, it shows the server's host key fingerprint and asks whether to trust it. It must equal one of the HOST_KEY_* values. If it does not, do not connect. You can print the fingerprints at any time:
for t in ed25519 ecdsa rsa; do ssh-keygen -l -E sha256 -f /etc/ssh/ssh_host_${t}_key.pub; doneTry the demo user
The demo user sftpdemo exists so you can try the server straight away. Its private key, unique to your VM, is /root/sftp-demo-key. Copy it to your own computer over your administrator SSH session, then connect:
ssh azureuser@<vm-public-ip> 'sudo cat /root/sftp-demo-key' > sftp-demo-key chmod 600 sftp-demo-key sftp -i sftp-demo-key sftpdemo@<vm-public-ip> sftp> cd upload sftp> put report.csv sftp> ls -l sftp> byeThe built-in check runs the same kind of session on the VM itself: an upload and a byte-for-byte download, the audit log entries, the jail, and the refusals (no shell, no terminal, no forwarding, no root login, no password while passwords are off):
sudo sftp-verify.sh | tail -7ok TCP forwarding (-W 169.254.169.254:80) refused: administratively prohibited ok remote forwarding (-R) refused by the server (rc 255) ok root login refused (Permission denied) ok the demo key does not open the administrator account (azureuser) ok password authentication not offered to sftpdemo (key only: 'Permission denied (publickey)') SFTP_ROUNDTRIP_OK target 10.0.0.4Once your own users exist, remove the demo user and its key with sudo sftp-deluser sftpdemo --yes && sudo shred -u /root/sftp-demo-key /root/sftp-demo-key.pub. After that, sftp-verify.sh has no account to test with.
Add a user with an SSH key (recommended)
Ask the user for their public key (the .pub file) and add it with --ssh-key @<file> (or paste the key line in quotes). --quota caps the user's storage. This example makes a key pair on the VM only to show the whole flow. In practice, the user keeps the private key and sends you the public one:
[ -f /tmp/bob_key ] || ssh-keygen -q -t ed25519 -N '' -C bob -f /tmp/bob_key
sudo sftp-adduser bob --ssh-key @/tmp/bob_key.pub --quota 10GSFTP user "bob" ready. jail (chroot) : /srv/sftp/bob writable: /srv/sftp/bob/upload ssh key : added to /etc/ssh/authorized_keys.d/bob quota : 10GThe key is stored in /etc/ssh/authorized_keys.d/bob, owned by root and outside the jail, with OpenSSH's restrict option. A private key is refused if it is passed by mistake. Bob can now upload and download:
printf 'put /etc/hostname upload/hello.txt\nls -l upload\n' > /tmp/bob.batch sftp -i /tmp/bob_key -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=/tmp/bob_known_hosts -b /tmp/bob.batch bob@127.0.0.1sftp> put /etc/hostname upload/hello.txt sftp> ls -l upload -rw-r----- ? 1001 1001 12 Oct 25 10:10 upload/hello.txtNew files are created with mode 0640 (owner read-write, group read).
Password logins for SFTP users (optional)
Passwords are off for SFTP users on a fresh VM. Creating a user with --password generate switches password logins on for the sftpusers group only and prints a new 24-character password once, so store it straight away:
sudo sftp-adduser alice --password generate --quota 5G Note: SFTP password authentication is now ON for the sftpusers group (the administrator account is unaffected). SFTP user "alice" ready. jail (chroot) : /srv/sftp/alice writable: /srv/sftp/alice/upload quota : 5G GENERATED PASSWORD for alice (shown once, store it now): <24-character password>To choose the password yourself, pass it on standard input and never on the command line. A command line ends up in your shell history and in sudo's log, so the tools refuse --password <value>:
read -rs PW && printf '%s\n' "$PW" | sudo sftp-adduser carol --password-stdin; unset PWCheck or change the setting at any time:
sudo sftp-password-auth statusSFTP password authentication: OFF (key only)sudo sftp-password-auth on writes /etc/ssh/sshd_config.d/64-sac-sftp-password.conf (a Match Group sftpusers block with PasswordAuthentication yes). sudo sftp-password-auth off removes it. It never changes how the administrator signs in.
Moving a password user to keys: add their public key with sudo sftp-adduser <user> --ssh-key @<user>.pub, lock the password with sudo sftp-passwd <user> --lock (no password hash is kept), and once no one uses passwords, run sudo sftp-password-auth off.
fail2ban bans an address after 5 failed logins in 10 minutes (1 hour at first, growing to a week for repeat offenders).
Manage users
sudo sftp-listusersUSER PASSWORD KEYS QUOTA USED JAIL bob no 1 10240M 4.0K /srv/sftp/bob sftpdemo no 1 5120M 4.0K /srv/sftp/sftpdemoCommand Purpose
sftp-adduser <user> [--ssh-key @<file>] [--password generate \| --password-stdin] [--quota 10G] Create a user, or add a key, password or quota to one
sftp-passwd <user> generate \| --password-stdin \| --lock New password (printed once or read from standard input), or lock it
sftp-deluser <user> [--yes \| --keep-data] Remove a user and clear its quota limit; --yes also deletes /srv/sftp/<user>
sftp-listusers [--json] Users, password set, number of keys, quota, usage
sftp-password-auth on \| off \| status SFTP password logins for the sftpusers group
sftp-verify.sh, sftp-healthcheck The built-in end-to-end check and a quick health check
All of them need sudo. They refuse to touch an account that is not an SFTP user.
How the jail works
sudo ls -la /srv/sftp/bobdrwxr-xr-x 4 root root 4096 Oct 25 10:10 . drwxr-xr-x 5 root root 4096 Oct 25 10:10 .. drwxr-xr-x 2 root root 4096 Oct 25 10:10 dev drwxr-x--- 2 bob sftpusers 4096 Oct 25 10:10 uploadThe jail root belongs to root (OpenSSH requires this), so the user cannot change it. upload is the user's own directory. dev holds only the socket that carries the audit log to the journal (Step 10). From the user's side, / is the jail, .. leads nowhere and system files do not exist:
printf 'pwd\ncd ..\npwd\nls /\n' > /tmp/bob.batch2 sftp -i /tmp/bob_key -o UserKnownHostsFile=/tmp/bob_known_hosts -b /tmp/bob.batch2 bob@127.0.0.1sftp> pwd Remote working directory: / sftp> cd .. sftp> pwd Remote working directory: / sftp> ls / /dev /uploadAn SFTP account cannot run commands either:
ssh -i /tmp/bob_key -o BatchMode=yes -o UserKnownHostsFile=/tmp/bob_known_hosts bob@127.0.0.1 id || trueThis service allows sftp connections only.The effective sshd settings for an SFTP user and for the administrator show the difference (replace azureuser with your administrator name if you chose another):
sudo sshd -T -C user=bob,host=client,addr=198.51.100.7 | grep -E '^(forcecommand|chrootdirectory|allowtcpforwarding|disableforwarding|permittty|authorizedkeysfile|passwordauthentication) '
sudo sshd -T -C user=azureuser,host=client,addr=198.51.100.7 | grep -E '^(permitrootlogin|forcecommand|chrootdirectory) 'passwordauthentication no permittty no allowtcpforwarding no disableforwarding yes forcecommand internal-sftp -u 0027 -l INFO chrootdirectory /srv/sftp/%u authorizedkeysfile /etc/ssh/authorized_keys.d/%u permitrootlogin no forcecommand none chrootdirectory noneThe SFTP settings live in /etc/ssh/sshd_config.d/65-sac-sftp.conf and apply to members of the sftpusers group only. They keep SFTP users key-only even if you chose password sign-in for the administrator.
/etc/ssh/sshd_config.d/00-sac.conf refuses root logins, empty passwords and X11 forwarding for everyone. The administrator's password setting is the one you picked in the portal, and cloud-init writes it to 50-cloud-init.conf.
The transfer audit log
Every SFTP session and file operation is in the journal, with the client's address taken from the connection:
sudo journalctl -t internal-sftp --no-pager -n 8 -o catsession opened for local user bob from [127.0.0.1] open "/upload/hello.txt" flags WRITE,CREATE,TRUNCATE mode 0644 close "/upload/hello.txt" bytes read 0 written 12 opendir "/upload/" closedir "/upload/" session closed for local user bob from [127.0.0.1]A removal shows as remove name "/upload/<file>". OpenSSH writes these lines from inside the jail, where there is normally no log socket, so they would be lost. The image binds the journal's socket into each jail as dev/log at every boot (sftp-prepare.service) and whenever sftp-adduser creates a user. Logins and refusals are in sshd's own log: sudo journalctl -u ssh.
Security checks
fail2ban watches sshd's log and bans an address after repeated failed logins:
sudo fail2ban-client status sshdStatus for the jail: sshd |- Filter | |- Currently failed: 0 | |- Total failed: 0 | `- Journal matches: _SYSTEMD_UNIT=ssh.service + _COMM=sshd `- Actions |- Currently banned: 0 |- Total banned: 0 `- Banned IP list:To lift a ban, run sudo fail2ban-client set sshd unbanip <address>.
The image points fail2ban at ssh.service, the unit that sshd actually runs as. Ubuntu's stock filter watches sshd.service and would never ban anything.
sshd, fail2ban and the boot preparation are blocked from the Azure instance metadata service and the WireServer. First boot may read instance metadata (for the host address and the administrator name) but not the WireServer. SFTP users cannot reach either, because they cannot run commands or forward connections.
systemctl show -p IPAddressDeny ssh fail2ban sftp-prepare sftp-server-firstbootIPAddressDeny=169.254.169.254/32 168.63.129.16/32 IPAddressDeny=169.254.169.254/32 168.63.129.16/32 IPAddressDeny=169.254.169.254/32 168.63.129.16/32 IPAddressDeny=168.63.129.16/32Each blocked unit checks this from the inside every time it starts:
sudo journalctl -u ssh -u fail2ban -u sftp-prepare -b -o cat --no-pager | grep -E '^METADATA_' | sort | uniq -c3 METADATA_BLOCKED 168.63.129.16 3 METADATA_BLOCKED 169.254.169.254The data disk and quotas
df -h /srv/sftp findmnt -no OPTIONS /srv/sftpFilesystem Size Used Avail Use% Mounted on /dev/sdc 49G 60K 47G 1% /srv/sftp rw,nosuid,nodev,noexec,relatime,quota,usrquota,grpquota/srv/sftp is its own Azure data disk (ext4, mounted by UUID with nodev,nosuid,noexec), so you can snapshot, resize or move it on its own.
To grow it, resize the disk in Azure. At the next boot, sftp-prepare.service grows the file system. Or run sudo resize2fs $(findmnt -no SOURCE /srv/sftp) straight away.
Quotas are enforced by the usrquota,grpquota mount options at every mount, so they survive reboots. An upload that would exceed a user's quota is refused with "Disk quota exceeded". Removing a user clears its limit, so a new account that later gets the same user ID starts without one.
To see each user's usage and limit (in KiB), run:
sudo repquota -u /srv/sftp | sed -n '1,3p;/bob\|sftpdemo/p'The ext4 quota format needs the kernel's quota_v2 module. On the current Azure kernel it is part of the kernel's own modules package, which every kernel update installs together with the new kernel. On older Azure kernels, which kept it in linux-modules-extra, the image installs the matching metapackage instead. The file below records which applies to your VM:
modinfo -F filename quota_v2 cat /etc/sac/sftp-quota-kernel-metaUpdates
OpenSSH is Ubuntu's package, so apt and unattended-upgrades keep it patched along with the rest of the system. The installed version and where it came from:
dpkg-query -W openssh-server cat /usr/local/share/doc/sac-sftp/SOURCE.txtAfter an OpenSSH update, sudo systemctl restart ssh makes the running server use it (open SFTP sessions are not interrupted).
Server components
Component Version Path
OpenSSH server (sshd, internal-sftp) 9.6p1, Ubuntu 1:9.6p1-3ubuntu13 (updated by apt) /usr/sbin/sshd
fail2ban Ubuntu 24.04 package /etc/fail2ban/jail.d/sac-sshd.conf
Ubuntu 24.04 LTS
Path Purpose
/etc/ssh/sshd_config.d/00-sac.conf No root login, no empty passwords, no X11 forwarding (for everyone)
/etc/ssh/sshd_config.d/64-sac-sftp-password.conf Present only while SFTP password logins are on
/etc/ssh/sshd_config.d/65-sac-sftp.conf The SFTP jail for the sftpusers group (key only by default)
/etc/ssh/authorized_keys.d/<user> SFTP users' public keys
/srv/sftp/<user> Each user's jail; upload/ is writable
/root/sftp-server-info.txt Connection details and host key fingerprints (mode 0600)
/root/sftp-demo-key The demo user's private key (mode 0600)
/usr/local/sbin/sftp-* Account tools, checks, the metadata probe and the per-boot preparation
/usr/local/share/doc/sac-sftp/SOURCE.txt Version and source notes
Troubleshooting
- "Permission denied (publickey)" for an SFTP user. The key is not in
/etc/ssh/authorized_keys.d/<user>, or the user is using the wrong private key. Add the public key withsftp-adduser <user> --ssh-key @<file>. Password users needsftp-password-auth on(Step 7). - "Connection refused" or a timeout after several failed logins. fail2ban has banned the address. Check
sudo fail2ban-client status sshdand unban it (Step 11). Also check that the network security group allows TCP 22 from that address. - "Couldn't write to remote file ... Permission denied". The user tried to write outside
upload/. The jail root is read-only by design. - "Disk quota exceeded". Raise the quota with
sudo sftp-adduser <user> --quota <size>or remove files. - The client warns that the host key changed. A new VM always has new host keys. Compare the fingerprint with
/root/sftp-server-info.txtbefore accepting it. - Nothing works after deployment. Check
systemctl status sftp-server-firstbootandjournalctl -u sftp-server-firstboot.
Security recommendations
- Allow TCP 22 in the network security group only from the networks your users and administrators use.
- Prefer SSH keys. If you turn passwords on, use the generated passwords, and turn them off again when you no longer need them.
- Remove the demo user and its key once your own users exist (Step 5).
- Keep unattended upgrades on, and restart sshd after OpenSSH updates.
- Send the journal (
journalctl -t internal-sftp,journalctl -u ssh) to your log service, for example Azure Monitor, if you need to keep an audit trail beyond the VM.
Support and licensing
SecureAnyCloud provides support for this image by email and chat, around the clock. OpenSSH is free software under the OpenSSH license (the original author's free-use grant, with parts under the BSD and ISC licenses). The full terms are in /usr/share/doc/openssh-server/copyright.
OpenSSH is a trademark of the OpenBSD project. SecureAnyCloud is not affiliated with, endorsed by or sponsored by the OpenBSD or OpenSSH projects; the name only identifies the open source software in this image.
Deploy on Azure
Launch SFTP Server on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This image runs a production-ready SFTP file transfer server built on OpenSSH, the open source secure shell suite. The SFTP service is fully configured and security hardened, so you can onboard users and move files securely within minutes of launch without hand-editing the SSH daemon configuration.
Every SFTP user is locked into their own home directory with an OpenSSH chroot jail. A user can only see and write inside their own space, never the rest of the filesystem, and is given no interactive shell. User home directories live on a dedicated, independently resizable storage volume mounted at /srv/sftp, kept separate from the operating system disk.
The image ships key-only, which is the secure default and a requirement of the AWS Marketplace image scan. SFTP users authenticate with an SSH key out of the box. You can enable password authentication for SFTP users with a single command, and it is also turned on automatically the first time you create a password user. The administrator account always stays key-only.
A small set of management tools, sftp-adduser, sftp-deluser, sftp-listusers, sftp-passwd and sftp-password-auth, is the primary interface to the server. The image is hardened by default with fail2ban brute-force protection, per-user disk quotas, and transfer audit logging that records every upload, download and delete to the system journal.
On the first boot of every deployed instance, a one-shot service creates a demo SFTP user named sftpdemo with a fresh SSH key unique to that instance. It records the details in a root-only file, so you can confirm the server works immediately and then remove the demo user once your own users exist.
What you get:
- An OpenSSH SFTP server with every user locked into a chroot jail on a dedicated volume mounted at /srv/sftp
- Key-only authentication by default, with one command to enable passwords for SFTP users
- Management tools for adding, listing, changing and removing users
- fail2ban brute-force protection and per-user disk quotas
- Transfer audit logging of every upload, download and delete to the system journal
- A demo SFTP user created on first boot with a key unique to your instance
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for administrator SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from the networks your SFTP users and administrators connect from
- The AWS CLI version 2 installed locally if you plan to deploy from the command line, and an SFTP client (the
sftpcommand line tool, FileZilla, Cyberduck or WinSCP) to connect as a user
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for SFTP Server. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger as a balanced default. Size the instance to the number of users and the transfer volume you expect. Choose your EC2 key pair under Key pair (login) for administrator access. Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from the networks your SFTP users connect from. SFTP rides on the SSH port, so only port 22 is required.
Select Launch instance. First-boot initialization takes only a few seconds after the instance state becomes Running and the status checks pass.
Launch the Instance from the AWS CLI
The following block launches an instance from the SecureAnyCloud SFTP Server Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens port 22 from the networks your users connect from.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}' \
--metadata-options 'HttpTokens=required,HttpEndpoint=enabled' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=sftp-server}]'The image attaches a dedicated 50 GiB SFTP storage volume automatically, mounted at /srv/sftp, where every user's chroot home directory lives. To start with more storage, enlarge that volume on the Storage step in the console, or add a second block device mapping on the CLI.
Connect as the Administrator over SSH
Connect to the instance with SSH as the default login user for the operating system variant you launched. The administrator account is key-only. The login user differs by variant:
Operating system variant SSH login user
Ubuntu 26.04 ubuntu
Replace <key-file> with the path to your private key file and <instance-public-ip> with the public IP address or DNS name of the instance.
ssh -i <key-file> ubuntu@<instance-public-ip>All of the user management commands below are run as the administrator with sudo.
The Built-In Demo User
On first boot the server creates a demo SFTP user named sftpdemo with a fresh SSH key unique to your instance. Read its details and the path to its private key from the root-only information file:
sudo cat /root/sftp-server-info.txtThe demo user's private key is written to /root/sftp-demo-key. Copy it to your client to connect as the demo user and confirm the server works (see Step 8). The demo user is confined to its own home directory, exactly like any user you create. Once your own users exist, remove the demo user:
sudo sftp-deluser sftpdemo --yesAuthentication Model
The image ships key-only. Password authentication is disabled by default, which is the secure baseline and is required to pass the AWS Marketplace image scan. SSH key users work immediately. To allow password logins for SFTP users, enable them with one command. The administrator account always remains key-only:
sudo sftp-password-auth onCheck or turn the setting off at any time with sudo sftp-password-auth status and sudo sftp-password-auth off. Creating a password-based user (next step) turns this on for you automatically.
Create a Password-Based SFTP User
Create a user who authenticates with a password. The --password generate option creates a strong random password and prints it once; give it to the user over a secure channel. To set a specific password instead, use --password '<value>'. The first time you create a password user, SFTP password authentication is enabled automatically.
sudo sftp-adduser alice --password generateThe tool creates the account with no shell, adds it to the sftpusers group, and builds the chroot home directory at /srv/sftp/alice with a single user-writable subdirectory, upload. The user connects on port 22 and lands directly in their home directory.
Create an SSH Key-Based SFTP User
Create a user who authenticates with an SSH key. Pass the user's public key with --ssh-key, either inline or, as shown here, from a file with the @ prefix. This example generates a demonstration key pair first; in practice the user supplies their own public key.
ssh-keygen -t ed25519 -f /tmp/bob_key -N '' -q sudo sftp-adduser bob --ssh-key @/tmp/bob_key.pubThe public key is stored in the central, root-owned location /etc/ssh/authorized_keys.d/bob, outside the user's jail, so the key cannot be tampered with by the user and the chroot ownership rules are always satisfied. A key-based user created without a password cannot log in with a password at all. You can give a user both a password and a key by passing both options.
Per-User Disk Quotas
Cap how much storage a user can consume with --quota. This protects the shared volume so that no single user can fill the disk. The size accepts a G, M or K suffix.
sudo sftp-adduser carol --password generate --quota 10GYou can review every user's state, including the number of keys and current upload directory usage, at any time:
sudo sftp-listusersConnecting as an SFTP User
SFTP users connect on port 22 and are dropped straight into their home directory; their only writable area is the upload directory. From the sftp command-line client, a password user connects like this (they are prompted for the password):
sftp alice@<instance-public-ip>A key-based user connects with their private key:
sftp -i bob_key bob@<instance-public-ip>Once connected, a user can upload and download files inside the upload directory:
sftp> cd upload sftp> put localfile.txt sftp> get remotefile.txt sftp> byeThe server works with any standard SFTP client. In a graphical client, use these settings:
Setting Value
Protocol SFTP (SSH File Transfer Protocol)
Host the instance public IP or DNS name
Port 22
Username the SFTP user name, for example alice
Password or key the generated password, or the user's private key
How the Home Directory Lock Works
Every SFTP user is confined to their own directory by an OpenSSH chroot jail. The jail root, the user's home directory, is owned by root and is not writable by the user; this is an OpenSSH requirement and is what makes the lock secure. Inside it, a single upload directory is owned by the user and is where they read and write files.
sudo ls -la /srv/sftp/aliceA locked user cannot leave their home directory, cannot see other users' files, and cannot reach the rest of the operating system. Listing the root of their session shows only the upload directory, and attempts to retrieve a system file such as /etc/passwd fail because that path does not exist inside the jail.
Transfer Audit Logging
Every SFTP session and every file operation, upload, download, rename and delete, is recorded to the system journal for compliance and troubleshooting. Review the audit trail with:
sudo journalctl -t internal-sftp --no-pager --since today | tail -20Each entry records the user, the operation and the path, so you have a complete record of who transferred what and when.
Managing Users
Reset or lock a user's password at any time. Locking the password leaves any SSH key the user has in place:
sudo sftp-passwd alice generateRemove a user when they no longer need access. By default the account is removed and you are reminded that the data remains; add --yes to delete the user's files as well, or --keep-data to keep them deliberately:
sudo sftp-deluser bob --yesThe full set of management tools is:
Command Purpose
sftp-adduser <name> [--password generate\|<value>] [--ssh-key @file\|"key"] [--quota <size>] Create or update an SFTP user
sftp-passwd <name> [--password <value>\|generate\|--lock] Set, generate or lock a user's password
sftp-listusers [--json] List users with auth method, key count and usage
sftp-deluser <name> [--keep-data] [--yes] Remove a user, optionally with their data
Hardening Notes
The image is hardened out of the box, and you can tighten it further:
- Brute-force protection. fail2ban watches for repeated failed logins on port 22 and bans offending addresses with an increasing ban time. Check the jail and currently banned addresses with
sudo fail2ban-client status sshd. - Network exposure. Restrict the inbound port 22 rule in the instance's security group to the specific networks your users and administrators connect from, rather than leaving it open to the whole internet.
- Administrator access. The administrator account accepts SSH keys only. Password authentication is disabled for it, so only SFTP users in the
sftpusersgroup can use passwords. - Dedicated volume. Snapshot and resize the
/srv/sftpvolume independently of the operating system disk to back up or grow user storage on its own schedule.
Support
This image is supported 24/7 by SecureAnyCloud. We can help with SFTP user onboarding, SSH key management, chroot configuration, disk quotas, transfer auditing and secure file transfer architecture. Contact details and your support entitlement are provided with your AWS Marketplace subscription.
Deploy on AWS
Launch SFTP Server on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com