Ever wondered how to set up a more secure FTP server?
I did. And the first thing that came to my mind was getting those username/password things encrypted.
Who did invent a plaintext login mechanism!?

So, let's get started.
This howto will tell you how to set up an Proftpd based FTP server with TLS encryption for data&control channels.

Firstly, I assume that you have a working proftpd installation.
You can get it simply by:

apt-get install proftpd

So, you should be able to login to the server and sniff your credentials using i.e. tcpdump or tcpick.
Anyway, now we want to go into TLS stuff.
Firstly, let's set up a plain TLS configuration.
Edit your /etc/proftpd/proftpd.conf, and add the following section:

TLSEngine on
TLSProtocol TLSv1
TLSRequired off
TLSRSACertificateFile ftpcert.pem
TLSRSACertificateKeyFile ftpcert.pem
TLSCACertificateFile cacert.pem
TLSVerifyClient off
TLSRenegotiate required off

Of course, you have to set proper paths to your Certificate and Key files (and CA certificate file as well).
Now. You can force all clients to use TLS encryption, with TLSRequired option. However, be sure that all clients are aware of it, because otherwise, they will be unable to log in (with most of the FTP clients).
For instance, Total Commander now supports FTP w/TLS (since version 7.02 I think), but you have to add openssl.dll to it's installation dir.
Furthermore, decide if you want to use any Verification mechanism for your certificate (TLSVerifyClient directive).
TLSRenegotiate is used to keep some buggy clients happy, as they break during renegotiation session.

Now, do a restart and providing that you've enabled the mod_tls module, you have TLS working.
You can be happy now, but read further as you will probably encounter some problems later.

All seems quite well when you test your installation without NAT.
The problems start to show up when NAT goes into action.
Probably you will encounter the 'hanging listing' problem? :)

So, there is a number of issues here to check.

  • If you are not able to get your FTP listing even without TLS, check if you have appriopriate modules loaded into kernel:
host:~# lsmod | grep ftp
ip_nat_ftp              3200  0
ip_nat                 16172  3 ip_nat_ftp,ipt_MASQUERADE,iptable_nat
ip_conntrack_ftp        7280  1 ip_nat_ftp
ip_conntrack           46644  6 ip_nat_ftp,ipt_MASQUERADE,xt_state,iptable_nat,ip_nat,ip_conntrack_ftp
  • if your listing works ok with NAT wo/TLS, but it doesn't w/TLS, then you got to the point that I struggled. So I will explain a bit. While using NAT, you start to use Passive Mode (PASV). In this mode, the FTP server, is starting to communicate via some high-ranged ports mapped accordingly to the established connection (source,destination) on the stateful firewall (iptables). In a non-TLS scenario that firewall's nat_ftp module is aware of the ports that FTP server is using for the PASV mode (as it looks up the PASV commands inside the packets traversed). The problem appears when you start using TLS mode. Then, the firewall is unable to see the ports anymore, because the packets and control channel is encrypted. And we have a problem. Solution? Here it is:

I'm assuming that you are using iptables, that your policy is DROP on the INPUT chain, and that you have permitted RELATED,ESTABLISHED and all traffic to port 20,21 (standard ftp ports). Now. Add the following line to you protftpd.conf:

PassivePorts 50000 51000

What does it do? It tells the server to use this explicit range of ports when establishing FTP PASV connection. This way we know which ports it will use.
Now the only thing you can do to get it working is opening those ports on firewall:

iptables -I INPUT -m state --state NEW -j ACCEPT -p tcp -m multiport --ports 50000:51000

Voila! It should work now!

One more thing. If you have a lot of FTP clients/traffic, consider widening this range, as you may run out of the ports that can be assigned to users (when many of them are connecting simultaneously).