Skip to content disloops

Hosting Anonymous FTP

I wanted to create an FTP server to share some of the media that I've saved over the years. I like the old protocols and services and I plan to stand up more of them. Because each service has its own inherent security issues, the deployment process becomes an exercise in mitigating the risks. Check it out at

I used an Ubuntu Server 14.04 LTS instance for the FTP server and gave it an AWS Elastic IP (EIP). An entry must be added to the /etc/hosts file when deploying Ubuntu instances in AWS:  (hostname here)

Without specifying the hostname, using sudo creates an error message. Next I ran updates and changed SSH to a non-default port, then installed VSFTPD and backed up the config file:

sudo apt-get update
sudo apt-get dist-upgrade
sudo vi /etc/ssh/sshd_config
sudo apt-get install vsftpd
sudo cp /etc/vsftpd.conf /etc/vsftpd.conf.old

VSFTPD Configuration

I created an updated config file from the manual page: vsftpd.conf

That file has some specific settings enabled which you will have to customize for you own environment. Note that any whitespace between an option and its value will result in an error. Some of the more significant settings are described below.


In order to avoid exposing local accounts and their home directories, only anonymous connections are allowed. Two users are designated here – one that's used for all active connections, and another that's used internally for some unprivileged functions.


Anonymous users can upload files within the anon_ftp_user user's home directory. Files will be created with 600 permissions, meaning that only the root user can access them again. This prevents FTP users from creating executables or using the server to share their own files. Note: The anon_umask value is applied on top of these permissions, which is 077 by default.


This defines a range of ports to be used for passive connections. There should be at least as many available ports as max_clients specifies.


This prevents the server from providing its internal IP address in response to PASV requests. Note: This should work for you, but it didn't for me. A DNS lookup of my hostname within AWS still returns the internal IP address of the EC2 instance. I had to leave pasv_addr_resolve set to no and set pasv_address to the Elastic IP (EIP) that I associated with the server.


This enables "Explicit TLS" connections.

Server Configuration

Next we have to set up the users and directories:

sudo useradd -M -r -s /bin/false -d /srv/ftp/pub anon_ftp_user
sudo useradd -M -r -s /bin/false -d /dev/null nopriv_ftp_user

This creates the two users defined in the config file above. The -d option defines a home directory but -M ensures that it is not created automatically. The -r option designates an account as a "system user" which changes numerical range that the user ID (UID) and group ID (GID) are taken from. The -s option defines the user's shell. Because no one should log in using these accounts, we use /bin/false as the shell, which is just a binary that returns false and exits.

sudo mkdir -p /srv/ftp/pub/downloads

This recursively creates the directory structure we need. Anonymous connections will start in the /srv/ftp/pub directory, since it is the home directory for the anon_ftp_user account.

sudo mkdir /srv/ftp/pub/uploads
sudo chown -R ftp:ftp /srv/ftp
sudo chown anon_ftp_user:anon_ftp_user /srv/ftp/pub/uploads

This makes sure that only the /srv/ftp/pub/uploads directory can be written to. The /srv/ftp/pub/downloads directory is used to host all other files.

We still have to upload the certificates that are required for TLS connections. Create the CA bundle on a local machine, then move it to the server along with the private key:

cat STAR_disloops_com.crt COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt >> bundle.crt
scp -P [ssh_port] -i [ssh_key] bundle.crt ubuntu@[ip_addr]:/home/ubuntu/temp/
scp -P [ssh_port] -i [ssh_key] disloops_com.key ubuntu@[ip_addr]:/home/ubuntu/temp/

Log back into the server and give the certificate files the correct location and permissions:

sudo mv /home/ubuntu/temp/disloops_com.key /etc/ssl/private/
sudo mv /home/ubuntu/temp/bundle.crt /etc/ssl/certs/
sudo chown root:root /etc/ssl/certs/bundle.crt
sudo chmod 644 /etc/ssl/certs/bundle.crt
sudo chown root:root /etc/ssl/private/disloops_com.key
sudo chmod 600 /etc/ssl/private/disloops_com.key


Note: I used the following links for help with this section: [1] [2] [3]

The last step is to limit the amount of data that the anon_ftp_user can upload, in order to prevent the hard drive from being filled by malicious uploads. This can be accomplished with the quota package. First add the usrquota option entry to the /etc/fstab file, which controls the partitions. Mine now looks like this:

LABEL=cloudimg-rootfs / ext4 defaults,usrquota,discard 0 0

Remount the partition and install the quota package, then run quotacheck:

sudo shutdown -r now
sudo apt-get install quota
sudo quotacheck -vucfma

With the above options, the quotacheck program will create a new file called quota.user in the root of the filesystem to track disk usage. Use the setquota command to actually limit the amount of data that the anon_ftp_user can create:

sudo setquota -u anon_ftp_user 5000000 5000000 0 0 -a /

This sets a 5G limit on how much data the anonymous FTP user can upload.

Now quotas can be activated with the quotaon command. However, this creates an error by default in AWS. It turns out that quota support was removed from virtual kernels in recent version of Ubuntu. The following steps were required to add support:

sudo apt-get install linux-image-extra-virtual
sudo depmod -a
sudo modprobe quota_v1
sudo modprobe quota_v2

Then add the following lines to the /etc/modules file:


Now the quotaon command should work. You can use repquota to periodically check the disk usage statistics:

sudo quotaon -av
sudo repquota /

Note: Re-running quotacheck with the options listed above will overwrite any existing quota file, remove the defined quotas, and reset the disk usage statistics.


I wanted to monitor the logs on my EC2 instances, especially the public FTP server. AWS offers a monitoring service called CloudWatch for virtual resources. The following steps were required to send logs to CloudWatch from the Ubuntu instance. Note: This requires that your EC2 instance be launched with an IAM role that enables CloudWatch monitoring. Use the CloudWatch guide on log monitoring to set this up.

Download the installation script and run it:

cd /home/ubuntu/temp
sudo python ./ --region us-east-1

Use the default values during setup and feel free to add /var/log/syslog as instructed. If you launched the EC2 instance with the correct IAM role, it will not be necessary to enter the "Access Key ID" or the "Secret Access Key" (leave them blank).

The script will create a file at /var/awslogs/etc/awslogs.conf that controls what log information gets set to CloudWatch. You will have already added /var/log/syslog during the setup. Manually edit this file to add coverage for any other logs you want to monitor, including the VSFTPD log file:

datetime_format = %b %d %H:%M:%S
file = /var/log/vsftpd.log
buffer_duration = 5000
log_stream_name = {instance_id}
initial_position = start_of_file
log_group_name = /var/log/vsftpd.log

Note: On Amazon Linux instances, this file is located at: /etc/awslogs/awslogs.conf


The above steps should create a relatively safe FTP service that enables both uploads and anonymous connections. Visit mine at and let me know what you think.

Leave a Reply

Your email address will not be published. Required fields are marked *