Pure-FTPd
Overview
Pure-FTPd is a small, fast, security-focused open source FTP daemon. This SecureAnyCloud image runs it as an FTPS-only file transfer server, already configured and hardened, so you can start moving files securely within minutes of launch.
Explicit FTP over TLS is required for both authentication and data transfer, so credentials and file contents never travel in the clear. Anonymous access is disabled. The image ships with no shared credentials: on first boot, every VM generates its own TLS certificate and its own FTP user and password.
What you get:
- Pure-FTPd from Ubuntu 24.04 (noble main), FTPS only with explicit TLS required
- Virtual users held in a PureDB database rather than real Linux login accounts, each locked into its own home directory under
/srv/ftpwith a chroot jail - A dedicated, independently resizable 50 GiB Azure data disk at
/srv/ftp(ext4), separate from the OS disk and provisioned with every VM - A self-signed TLS certificate and an FTP user named SecureAnyCloud with a strong random password, both unique to each VM and created by a one-shot service at first boot
- Per-VM credentials recorded in the root-only file
/root/pure-ftpd-credentials.txt - Anonymous FTP disabled, and a fixed passive port range (30000-30009) for firewall-friendly transfers
- Management tools in
/usr/local/sbin:pureftpd-adduserandpureftpd-listusers, which wrap the underlyingpure-pwutility for day-to-day administration - 24/7 SecureAnyCloud support
Prerequisites
Before you deploy, make sure you have:
- An active Microsoft Azure subscription where you can create virtual machines
- An SSH key pair for administrator access to the VM
- A virtual network and subnet in the target region, with a network security group (NSG) that allows inbound port 22 (SSH) from your admin network, plus inbound port 21 (FTP control) and the passive data port range 30000-30009 from the networks your FTP users connect from
- The Azure CLI installed locally if you plan to deploy from the command line
- An FTPS-capable client to connect as a user: the
lftpcommand-line tool, FileZilla, WinSCP or Cyberduck
Standard_B2s (2 vCPU / 4 GiB RAM) is a balanced default. Size the VM to the number of users and the transfer volume you expect.
Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, and search the Marketplace for Pure-FTPd by SecureAnyCloud. Select the listing, then choose Create.
On the Basics tab, pick your subscription, resource group, region and a VM size (Standard_B2s or larger). Under Administrator account, select SSH public key, set the username and paste your public key. Under Inbound port rules, allow SSH (22).
Review the dedicated data disk on the Disks tab. It is included in the image and holds your FTP users' home directories. Select Review + create, then Create. First-boot initialization (the TLS certificate and the per-VM FTP user) completes within a few seconds of the VM reaching the Running state.
When the VM is running, add inbound NSG rules for FTP control (21) and the passive range (30000-30009) from the networks your FTP users connect from (see Step 8).
Deploy from the Azure CLI
Run the following commands to create a VM from the SecureAnyCloud Pure-FTPd image in an existing VNet and subnet. Replace the angle-bracket values with your own. The dedicated /srv/ftp data disk is part of the image and is attached automatically.
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:pure-ftpd-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name pure-ftpd \
--image sac1647283583153:pure-ftpd-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
# Open the FTP control port and the passive data range
az vm open-port --resource-group <your-rg> --name pure-ftpd --port 21 --priority 1001
az vm open-port --resource-group <your-rg> --name pure-ftpd --port 30000-30009 --priority 1002Connect as the Administrator over SSH
Connect to the VM over SSH as the administrator user you set at deploy time (azureuser by default on Ubuntu). The administrator account accepts SSH keys only.
ssh azureuser@<vm-public-ip>Read the Per-VM FTP Credentials
On first boot, the server creates an FTP user named SecureAnyCloud with a password unique to your VM. It writes the details to a root-only file. Read that file with sudo:
sudo cat /root/pure-ftpd-credentials.txtThe file lists the per-VM user, password and connection details. The password shown here is an example, and yours will differ:
ftp.user=sac ftp.password=p27vGj3Cm1vGusRyXxbn ftp.host=10.0.0.21 ftp.tls=explicit-required ftp.passive_ports=30000-30009Confirm the Service and the Data Disk
Check that Pure-FTPd is active and that the dedicated data disk is mounted at /srv/ftp.
systemctl is-active pure-ftpd findmnt -no SOURCE,TARGET,FSTYPE,SIZE /srv/ftpList the FTP users held in the PureDB database.
sudo pureftpd-listusersThe first-boot user appears with its chroot home directory:
sac /srv/ftp/sac/./Verify FTPS Works Locally
Test an encrypted round trip directly on the VM with the bundled lftp client. The commands read the per-VM password from the credentials file, connect over explicit FTPS, upload a file and download it again.
The local test uses active mode (passive-mode false), so it works over the loopback address regardless of the ForcePassiveIP setting that external clients use.
FTP_USER=$(sudo awk -F= '/^ftp.user=/{print $2; exit}' /root/pure-ftpd-credentials.txt)
FTP_PW=$(sudo awk -F= '/^ftp.password=/{print $2; exit}' /root/pure-ftpd-credentials.txt)
echo "hello from sac" > /tmp/hello.txt lftp -u "$FTP_USER","$FTP_PW" \
-e "set ssl:verify-certificate no; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode false; put /tmp/hello.txt -o hello.txt; ls; get hello.txt -o /tmp/hello.dl; bye" \
127.0.0.1 cat /tmp/hello.dlThe listing shows the uploaded file, and the downloaded copy is byte-identical:
-rw-r--r-- 1 999 ftpvirtual 20 Jul 19 05:23 hello.txt hello from sacAdd Your Own FTP Users
Create additional FTP users with pureftpd-adduser. Each user is jailed in a chroot to its own home directory under /srv/ftp. Omit the password and the tool generates a strong one for you.
sudo pureftpd-adduser project-uploads
sudo pureftpd-listusersThe tool prints the generated password and confirms the chroot home.
FTPS virtual user "project-uploads" ready. chroot home : /srv/ftp/project-uploads TLS : required (explicit FTPS) GENERATED PASSWORD for project-uploads: cECwfzp4AqhgFVClA5UtTo set a specific password instead, run sudo pureftpd-adduser project-uploads --password 'YourStrongPassword'. For advanced operations such as changing a password, quotas or bandwidth limits, use the underlying pure-pw tool, for example sudo pure-pw passwd project-uploads -m.
Connect from Your Workstation
Connect from any FTPS-capable client. The server requires explicit FTP over TLS and rejects plain FTP.
With the lftp command-line client, replace the host with your VM's public IP:
lftp -u sac,'<your-password>' \
-e "set ftp:ssl-force true; set ftp:ssl-protect-data true; set ssl:verify-certificate no; ls; bye" \
<vm-public-ip>In FileZilla, set Protocol to FTP - File Transfer Protocol, Encryption to Require explicit FTP over TLS, Host to your VM's public IP and Port to 21. Enter the user and password, and accept the self-signed certificate on first connect.
Passive mode and the NSG. FTP uses a second connection for data transfer. The image uses a fixed passive port range (30000-30009) and sets ForcePassiveIP to your VM's public IP on first boot, so passive-mode clients work through NAT. Open TCP 21 and TCP 30000-30009 in your Azure NSG for the networks your users connect from.
Where Things Live
- FTP user home directories (chroot roots):
/srv/ftp/<user>on the dedicated data disk - Virtual user database:
/etc/pure-ftpd/pureftpd.pdb, managed withpure-pwandpureftpd-adduser - Configuration, one file per directive:
/etc/pure-ftpd/conf/ - Per-VM self-signed TLS certificate:
/etc/ssl/private/pure-ftpd.pem - Per-VM credentials:
/root/pure-ftpd-credentials.txt - Transfer and connection log:
sudo journalctl -u pure-ftpd
Support
SecureAnyCloud maintains this image with security patching and 24/7 support. For help, contact sales@secureanycloud.com. For the underlying software, see the Pure-FTPd documentation.
Deploy on Azure
Launch Pure-FTPd 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
Pure-FTPd is a small, fast, security-focused FTP server. This SecureAnyCloud AWS Marketplace AMI runs it in an FTPS-first configuration: explicit TLS is required on both the control channel and the data channel, so credentials and file contents are never sent in the clear.
Pure-FTPd is installed from the official Ubuntu 24.04 apt archive and runs under systemd as pure-ftpd.service. It listens for the FTP control channel on tcp port 21 and uses the passive data port range 30000 to 30009. There is no web interface. The files under /etc/pure-ftpd/conf are the whole configuration.
The image is secure by default and has no known bootstrap credential. On first boot, a one-shot service creates a unique virtual FTP user with a strong random password, generates a unique self-signed TLS certificate for the instance, sets ForcePassiveIP to the instance address, and writes the user, password and host to a root-owned credentials file.
What you get:
- Pure-FTPd from the Ubuntu 24.04 apt archive, run under systemd as
pure-ftpd.service - FTPS (explicit TLS) required on the control and data channels (
TLS 2), so a plaintext FTP login is refused - A unique virtual FTP user and password and a unique self-signed TLS certificate for each instance, generated on first boot and written to
/root/pure-ftpd-credentials.txt(mode 0600) - Logins served from a compact PureDB virtual-user database mapped to a single unprivileged system account, so no real system account is reachable over FTP
- Every virtual user chrooted to its own home directory under
/srv/ftp, so an account sees only its own files - No anonymous access (
NoAnonymous yes) and PureDB-only authentication (UnixAuthentication no) - A defined passive port range (30000 to 30009) and a ForcePassiveIP value set to the instance address, for passive mode behind network address translation
- The file store on a dedicated data volume mounted at
/srv/ftp, plus the helper toolspureftpd-adduserandpureftpd-listusers
Connecting to your instance
Connect over SSH with your EC2 key pair, as the default login user for the AMI variant you launched.
AMI variant SSH login user
Pure-FTPd on Ubuntu 24.04 ubuntu
For example: ssh -i your-key.pem ubuntu@YOUR_INSTANCE_IP. The administrator account uses SSH key authentication with the EC2 key pair you selected at launch.
Prerequisites
- An EC2 instance launched from this SecureAnyCloud Pure-FTPd AMI
- An EC2 Security Group that allows inbound tcp 21 (FTP control) and tcp 30000 to 30009 (FTPS passive data), scoped to your client addresses only. Do not expose FTP to the whole internet.
- SSH access to the instance as
ubuntu
FTPS uses one connection for control and a separate connection for each transfer, so port 21 and the passive range must both be open to your clients.
The passive range is small by design. If you expect many concurrent transfers, widen it in /etc/pure-ftpd/conf/PassivePortRange and in the Security Group, then restart the service.
Verify the FTPS server is running
Connect over SSH as ubuntu. Confirm that pure-ftpd.service is active, check the installed version, and confirm that the server is listening on port 21.
sudo systemctl is-active pure-ftpd pure-ftpd --help 2>&1 | head -1 sudo ss -tlnH | grep ':21 'The output shows active, the Pure-FTPd version banner, and a listener bound to *:21 for the FTP control channel.
Retrieve the per instance credentials and test a secure transfer
On first boot, your instance generated a unique virtual FTP user, a unique password and a unique TLS certificate. The user, password and host are stored in the root-owned credentials file as ftp.user, ftp.password and ftp.host. Read it with sudo:
sudo cat /root/pure-ftpd-credentials.txtTest a secure transfer end to end with lftp, which is preinstalled. The commands below read the generated user and password from that file without printing the password. They force explicit TLS, upload a file, download it again and confirm that the contents match.
Passive mode is turned off for this loopback self-test. Real clients use passive mode over the 30000 to 30009 range.
U=$(sudo awk -F= '/^ftp\.user=/{print $2; exit}' /root/pure-ftpd-credentials.txt)
P=$(sudo awk -F= '/^ftp\.password=/{print $2; exit}' /root/pure-ftpd-credentials.txt) rm -f /tmp/guide-up.txt /tmp/guide-dl.txt echo "sac FTPS round trip $(date -u '+%Y-%m-%d %H:%M UTC')" > /tmp/guide-up.txt lftp -u "$U","$P" -e 'set xfer:clobber on; set ssl:verify-certificate no; set ftp:ssl-force true; set ftp:ssl-protect-data true; set ftp:passive-mode false; put /tmp/guide-up.txt -o report.txt; ls; get report.txt -o /tmp/guide-dl.txt; rm report.txt; bye' 127.0.0.1 cmp -s /tmp/guide-up.txt /tmp/guide-dl.txt && echo "FTPS round trip OK: download is byte-identical to the upload over required TLS"Both the upload and the download succeed over explicit TLS, and the downloaded contents match the upload. This confirms that the FTPS pipeline works end to end: TLS negotiation, the per-instance user and password, and the chrooted home directory.
Confirm plaintext and anonymous access are refused
A secure FTP server must refuse anything less than TLS. This image requires explicit TLS, refuses anonymous logins and chroots each user to its home directory.
The commands below test the first two behaviors. A plaintext (no TLS) login and an anonymous login should each fail.
U=$(sudo awk -F= '/^ftp\.user=/{print $2; exit}' /root/pure-ftpd-credentials.txt)
P=$(sudo awk -F= '/^ftp\.password=/{print $2; exit}' /root/pure-ftpd-credentials.txt)
PT=$(lftp -u "$U","$P" -e 'set ftp:ssl-force false; set ftp:ssl-allow false; set net:timeout 8; set net:max-retries 1; ls; bye' 127.0.0.1 2>&1 || true) case "$PT" in *530*|*"Login failed"*) echo "plaintext FTP login refused (explicit TLS is required)";; *) echo "unexpected: $PT";; esac
AN=$(lftp -u anonymous,anon@example.com -e 'set ssl:verify-certificate no; set ftp:ssl-force true; set net:timeout 8; set net:max-retries 1; ls; bye' 127.0.0.1 2>&1 || true) case "$AN" in *530*|*"Login failed"*|*"authentication failed"*) echo "anonymous login refused (NoAnonymous is on)";; *) echo "unexpected: $AN";; esacBoth attempts are rejected. The plaintext login fails because explicit TLS is required, and the anonymous login fails because anonymous access is disabled.
Because every virtual user is chrooted to its own home under /srv/ftp, an account cannot browse the rest of the server.
Review the hardening configuration
All of the hardening lives in the Pure-FTPd conf directory, one file per directive, and is applied by pure-ftpd-wrapper. Print the key settings:
cd /etc/pure-ftpd/conf grep -H '' NoAnonymous TLS ChrootEveryone UnixAuthentication PassivePortRange PureDBThe configuration enforces:
NoAnonymous yes: no anonymous FTPTLS 2: explicit FTPS required on control and dataChrootEveryone yes: every user is jailed to its home directoryUnixAuthentication no: PureDB virtual users only, never real system accountsPassivePortRange 30000 30009: the fixed passive port range
The per-instance passive address is written to /etc/pure-ftpd/conf/ForcePassiveIP on first boot. After you edit any file, apply the change with sudo systemctl restart pure-ftpd.
Connect from an FTPS client
From your workstation, connect with any FTPS-capable client using explicit TLS, also called FTP over TLS or AUTH TLS. Use the ftp.user, ftp.password and ftp.host values from the credentials file, port 21, and enable explicit TLS with passive mode.
The certificate is self-signed, so accept it on first connection or replace it with your own. For example, connect with lftp or curl:
# Replace the host and password with the values from /root/pure-ftpd-credentials.txt.
# lftp (explicit FTPS, passive mode over the 30000-30009 range): lftp -u sac,YOUR_PASSWORD -e 'set ftp:ssl-force true; set ftp:ssl-protect-data true; set ssl:verify-certificate no; put report.pdf; ls; bye' YOUR_INSTANCE_IP
# curl (explicit FTPS):
curl --ssl-reqd --insecure -u sac:YOUR_PASSWORD -T report.pdf ftp://YOUR_INSTANCE_IP/report.pdfGraphical clients such as FileZilla and WinSCP work the same way. Choose the protocol FTP with Require explicit FTP over TLS, set the host to your instance address and the port to 21, and use passive mode.
Make sure your EC2 Security Group allows inbound tcp 21 and tcp 30000 to 30009 from your client address.
Add more users and replace the certificate
Each FTP account is a PureDB virtual user chrooted to its own home under /srv/ftp, all backed by one unprivileged system account. To add another isolated account, use the helper tool. It generates a strong password and creates the chrooted home.
# Create a new virtual FTP user with a generated password:
sudo pureftpd-adduser alice
# List the virtual FTP users:
sudo pureftpd-listusersTo use a certificate signed by a certificate authority instead of the per-instance self-signed one, replace /etc/ssl/private/pure-ftpd.pem (the key and certificate concatenated) and restart the service.
The standard pure-pw tool remains available for per-user quotas, bandwidth limits and virtual user management in the PureDB database.
Support
SecureAnyCloud provides 24/7 technical support for this Pure-FTPd image by email (sales@secureanycloud.com) and live chat. We help with:
- Connecting FTPS clients
- Managing virtual users and the PureDB backend
- Configuring chroot and quotas
- Opening the control port and passive range in your Security Group
- Setting the passive mode address behind network address translation
- TLS certificate management, version upgrades and troubleshooting
Critical issues receive a one-hour average response time.
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
Deploy on AWS
Launch Pure-FTPd with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com