Not a real step-by-step guide, but more like notes for future references.
Revision history (dd/mm/yy):
09/09/2014 – minor changes to proftpd.conf
.
17/10/2014 – removed SSLv3 from tls.conf
.
Software
Software used in this article:
- Debian Wheezy
- ProFTPD 1.3.4a
- OpenSSL 1.0.1e
Pre-Installation Notes
NOTE 1: our server is behind NAT, therefore we’ll use a passive FTP mode to connect from outside. Mikrotik router’s NAT configuration (SSH method) is provided.
NOTE 2: we’ll be using mod_auth_file for FTP authentication.
NOTE 3: we’ll use “DefaultServer on” with no additional VirtualHosts.
Installation
Install openssl and proftpd (choose standalone version):
# apt-get update && apt-get install proftpd openssl [...] Run proftpd: standalone [...]
Configuration
We will create a new directory for FTP uploads. We will also prevent other users from removing or renaming a file in the directory unless they own the file or the directory:
# mkdir -m 1777 /ftp
Double-check permissions:
# ls -ld /ftp drwxrwxrwt 2 root root 4096 Jan 25 21:36 /ftp/
Navigate to the proftpd installation directory:
# cd /etc/proftpd
Backup the default configuration files first:
# cp ./proftpd.conf ./proftpd.conf.$(date +%F) # cp ./tls.conf ./tls.conf.$(date +%F) # cp ./virtuals.conf ./virtuals.conf.$(date +%F)
Create a new folder to store an FTP authentication file as well as prevent world from accessing it:
# mkdir -m 0770 ./auth # chown proftpd ./auth
Check permissions:
# ls -ld ./auth drwxrwx--- 2 proftpd root 4096 Jan 26 18:14 ./auth/
List the five biggest UIDs that are already in use:
# cat /etc/passwd | cut -d: -f3 | sort -n | tail -n 5 1001 1002 1003 1004 65534
Create a new FTP user for sandy with UID of 1100 (not in use):
# ftpasswd --passwd --file=/etc/proftpd/auth/users.passwd --name=sandy --home=/ftp \ --shell=/bin/false --uid=1100 --gid=1100
Consult the man page of ftpasswd for more info if required.
Let’s see the auth file’s content:
# cat ./auth/users.passwd sandy:$1$a3lD4ThisIsNotARealPassword6m5Z2:1100:1100::/ftp:/bin/false
Make file readable for proftpd user:
# chown proftpd /etc/proftpd/auth/users.passwd
Create a new folder to store SSL certificates:
# mkdir /etc/proftpd/ssl
Generate an SSL certificate for FTPS:
# openssl req -new -x509 -days 1825 -sha256 -nodes -out ./ssl/server.crt \ -keyout ./ssl/server.key Generating a 2048 bit RSA private key ...........+++ .................................................................................+++ writing new private key to './server.key' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:GB State or Province Name (full name) [Some-State]:Outer Space Locality Name (eg, city) []:Nibiru Organization Name (eg, company) [Internet Widgits Pty Ltd]:ftp.example.com Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:ftp.example.com Email Address []:[email protected]
Make SSL certificates non world-readable:
# chmod 0440 ./ssl/*
proftpd.conf
Here’s our proftpd.conf
configuration:
# cat ./proftpd.conf #/etc/profptd/proftpd.conf ####################################################################### # Server Config # ####################################################################### Include /etc/proftpd/modules.conf Include /etc/proftpd/tls.conf ServerName "Private FTP Server" ServerType standalone ServerAdmin [email protected] DefaultServer on AccessGrantMsg "User %u logged in." # keep the required auth module only AuthOrder mod_auth_file.c UseReverseDNS off RequireValidShell off # we want the main server instance to listen on a specific IP DefaultAddress localhost Port 21 PassivePorts 64000 65000 # never ever run as root User proftpd Group nogroup # pid file ScoreboardFile /var/run/proftpd.score # for DOS prevention, only works in standalone mode MaxInstances 20 # for passive FTP mode MasqueradeAddress 54.X.Y.Z MultilineRFC2228 on ShowSymlinks off UseIPv6 off DefaultTransferMode binary # DebugLevel only applies to SystemLog files DebugLevel 0 TransferLog /var/log/proftpd/xferlog SystemLog /var/log/proftpd/proftpd.log WtmpLog off ####################################################################### # Global Config # ####################################################################### <Global> RootLogin off AuthPAM off AuthUserFile /etc/proftpd/auth/users.passwd # jailing DefaultRoot /ftp #DefaultChdir /ftp/shared # give out minimal information ServerIdent on "Private FTP Server" IdentLookups off # no welcome message until user has authenticated DeferWelcome off DisplayLogin /etc/proftpd/welcome.msg DisplayConnect /etc/issue.net TimeoutLogin 120 TimeoutNoTransfer 300 TimeoutStalled 3600 TimeoutIdle 600 MaxClients 5 "Sorry, ftp server has reached its maximum user limit (%m)" MaxClientsPerUser 5 "Sorry, no more than %m connections per user." # restrict sandy's uploads to 1 gigabyte per file MaxStoreFileSize 1 Gb user sandy # allow unlimited upload and download size for everyone else MaxStoreFileSize * MaxRetrieveFileSize * MaxLoginAttempts 3 DenyFilter \*.*/ Umask 022 AllowOverwrite on AllowOverride off # allow to resume not only the downloads, but the uploads too AllowRetrieveRestart on AllowStoreRestart on RequireValidShell off </Global> # Delay engine reduces impact of the so-called Timing Attack <IfModule mod_delay.c> DelayEngine on </IfModule> <Limit SITE_CHMOD> DenyAll </Limit> ####################################################################### # VirtualHosts # ####################################################################### # for future use Include /etc/proftpd/virtuals.conf
tls.conf
Here’s our tls.conf
configuration:
# cat ./tls.conf <IfModule mod_tls.c> TLSEngine on TLSRequired on TLSProtocol TLSv1 TLSRSACertificateFile /etc/proftpd/ssl/server.crt TLSRSACertificateKeyFile /etc/proftpd/ssl/server.key TLSVerifyClient off TLSOptions AllowClientRenegotiations NoSessionReuseRequired TLSLog /var/log/proftpd/tls.log </IfModule>
virtuals.conf
The virtuals.conf
file contains no virtual hosts:
# cat ./virtuals.conf # this file is empty
welcome.msg
Here’s our welcome.msg
configuration:
# cat ./welcome.msg Welcome %U from %R. You are user number %N of %M allowed. This is a private FTP system - no anonymous logins. You will be disconnected after 10 minutes of inactivity.
Restart ProFTPD Daemon
# service proftpd restart [ ok ] Stopping ftp server: proftpd. [....] Starting ftp server: proftpdlocal proftpd[5395] 127.0.0.1: 127.0.0.1:21 masquerading as 54.X.Y.Z . ok
Configure NAT on Mikrotik RouterOS
TCP ports 21 and 64000-65000 need to be forwarded on Mikrotik router (as well as opened on iptables firewall) for public access. Do via SSH:
[sandy@mikrotik] > ip firewall nat
[sandy@mikrotik] /ip firewall nat> add chain=dstnat dst-address=54.X.Y.Z protocol=tcp dst-port=21 action=dst-nat to-addresses=10.X.Y.Z to-ports=21
[sandy@mikrotik] /ip firewall nat> add chain=dstnat dst-address=54.X.Y.Z protocol=tcp dst-port=64000-65000 action=dst-nat to-addresses=10.X.Y.Z to-ports=64000-65000
Connect with FileZilla Client from a Public Network
Connection details:
Host: ftpes://ftp.example.com
Username: sandy
Passwd: **********
Port: 21
We’ll be asked to accept the self-signed SSL certificate:
FileZilla client log:
Status: Resolving address of ftp.example.com Status: Connecting to 54.X.Y.Z:21... Status: Connection established, waiting for welcome message... Response: 220 Private FTP Server Command: AUTH TLS Response: 234 AUTH TLS successful Status: Initializing TLS... Status: Verifying certificate... Command: USER sandy Status: TLS/SSL connection established. Response: 331 Password required for sandy Command: PASS ************ Response: 230-Welcome sandy from 91.X.Y.Z. Response: 230-You are user number 1 of 10 allowed. Response: 230-This is a private FTP system - no anonymous logins. Response: 230-You will be disconnected after 10 minutes of inactivity. Response: 230 User sandy logged in. Command: OPTS UTF8 ON Response: 200 UTF8 set to on Command: PBSZ 0 Response: 200 PBSZ 0 successful Command: PROT P Response: 200 Protection set to Private Status: Connected Status: Retrieving directory listing... Command: PWD Response: 257 "/" is the current directory Status: Directory listing successful
Bugs
When installing ProFTPD on Ubuntu 14.04, you may notice the service being killed when cron runs logrotate:
ProFTPD killed (signal 15) ProFTPD 1.3.5rc3 standalone mode SHUTDOWN
The workaround is to open the /etc/init.d/proftpd
file and change the following line:
start-stop-daemon --stop --signal $SIGNAL --quiet --pidfile "$PIDFILE"
to:
start-stop-daemon --stop --signal $SIGNAL --retry 1 --quiet --pidfile "$PIDFILE"
You can test if ProFTPD is working after logrotate by running:
# logrotate -vf /etc/logrotate.conf
which parameter specifies ftpEs?
e.g. for vsftpd it is: implicit_ssl=NO
this configuration above seems like a configuration for ftpS.
Thanks for your input. As the article name implies, this configuration is for explicit FTPS (aka FTPES).
I’m not aware of any ProFTPD parameter that particularly specifies FTPES, but if you want to use an implicit FTPS mode, you need to specify “UseImplicitSSL” under TLSOptions and probably use the standard implicit FTPS port 990.
The best How-To I’ve found about a ftp server. After hours of read and search, you made my ftp server operate. Thanks for your tutorial!
You’re welcome!
I have followed the guide, im on a Debian 8.6. and i cannot get it working. Im almost there i think. When i try to login via filezilla i always get :
USER forensik
Svar: 331 Password required for forensik
Kommando: PASS **********
Svar: 530 Login incorrect.
Fel: Critical error, could not connect to server.
The TLS fase is just going fine, i even tried to reinstall my proftpd and install a new one. Anyone know whats going on? I have tried both locally and from the internet, with the same result
Where is the FTP auth file located, and what are the permissions set on the file? Can you post the content of the file, removing any password hashes?