{"id":500,"date":"2020-10-17T17:06:01","date_gmt":"2020-10-17T17:06:01","guid":{"rendered":"https:\/\/dft.wiki\/?p=500"},"modified":"2026-04-21T13:35:39","modified_gmt":"2026-04-21T17:35:39","slug":"vsftpd-tls-on-ubuntu-20-04","status":"publish","type":"post","link":"https:\/\/dft.wiki\/?p=500","title":{"rendered":"VSFTPD + TLS + Fail2Ban on Ubuntu"},"content":{"rendered":"<p>Assuming you already have an SSL\/TLS key that you may have created for your HTTP server [<a href=\"https:\/\/dft.wiki\/?p=233\">Read It<\/a>], we will use it for the VSFTPD.<\/p>\n<pre>sudo apt update\r\nsudo apt install vsftpd\r\nsudo service vsftpd status\r\nsudo ufw allow from <strong>200.200.200.200<\/strong> to any<\/pre>\n<p>For now, you should allow your public IP (replace <strong>200.200.200.200<\/strong> with yours) to have full access to your server to avoid any problem with the open ports on your firewall. Later we will remove this line and apply the precise ports.<\/p>\n<p>Test connecting to your FTP server with FileZilla (for example). You might be successful. Now edit the configuration file:<\/p>\n<pre>sudo cp \/etc\/vsftpd.{conf,bkp}\r\nsudo nano \/etc\/vsftpd.conf<\/pre>\n<p>Look for all of these configurations and make them look the same:<\/p>\n<pre>listen=NO\r\nlisten_ipv6=YES\r\nanonymous_enable=NO\r\nlocal_enable=YES\r\nwrite_enable=YES\r\nlocal_umask=022\r\ndirmessage_enable=YES\r\nuse_localtime=YES\r\nxferlog_enable=YES\r\nconnect_from_port_20=YES\r\nsecure_chroot_dir=\/var\/run\/vsftpd\/empty\r\npam_service_name=vsftpd\r\nutf8_filesystem=YES<\/pre>\n<p>For the SSL\/TLS the configurations are (just add them at the end):<\/p>\n<pre>rsa_cert_file=\/etc\/apache2\/md\/domains\/<strong>domain.com<\/strong>\/pubcert.pem\r\nrsa_private_key_file=\/etc\/apache2\/md\/domains\/<strong>domain.com<\/strong>\/privkey.pem\r\nssl_enable=YES\r\nallow_anon_ssl=NO\r\nforce_local_data_ssl=YES\r\nforce_local_logins_ssl=YES\r\nssl_tlsv1=YES\r\nssl_sslv2=NO\r\nssl_sslv3=NO\r\nrequire_ssl_reuse=NO\r\nssl_ciphers=HIGH<\/pre>\n<p><strong>Note:<\/strong> for this tutorial we assumed the server already has the certificate issued by Let&#8217;s Encrypt using the module MD of Apache. If it was generated in another way, search for these files in your system or purchase them. If this is your case, they might located as described above and probably only the domain name needs to be changed.<\/p>\n<p>You should also enable &#8220;Passive Mode&#8221; (recommended):<\/p>\n<pre>pasv_enable=Yes\r\npasv_max_port=40000\r\npasv_min_port=50000<\/pre>\n<p>Restart the service and check it is running, and also test connecting to it from FileZilla:<\/p>\n<pre>sudo systemctl restart vsftpd\r\nsudo systemctl status vsftpd<\/pre>\n<p>Let&#8217;s remove that odd permission from your firewall and make it precise to your situation:<\/p>\n<pre>sudo ufw status numbered | grep <strong>200.200.200.200<\/strong><\/pre>\n<p>Remember that <strong>200.200.200.200<\/strong> is your own client public IP, not the server IP.<\/p>\n<pre><strong>[ 7]<\/strong> Anywhere\u00a0 \u00a0 ALLOW IN\u00a0 \u00a0 200.200.200.200<\/pre>\n<p>What we are looking for is the rile number to be deleted [7], in my case. Now, delete it (confirm when asked for):<\/p>\n<pre>sudo ufw delete <strong>7<\/strong><\/pre>\n<p>Add the new rules:<\/p>\n<pre>sudo ufw allow 20:21\/tcp comment \"FTP\"\r\nsudo ufw allow <strong>40000:50000<\/strong>\/tcp comment \"FTP Passive Mode\"<\/pre>\n<p>The second line is for the case where you activated &#8220;passive mode&#8221;, and the range of ports (<strong>40000:50000<\/strong>) must match precisely between the VSFTP configuration file and the Firewall.<\/p>\n<p>How wide should be the range? It is up to you!<\/p>\n<p>In my case, I only use 50 because I don&#8217;t expect many multiple transfers. It depends on your server expected demand.<\/p>\n<p>Let&#8217;s make the Fail2Ban monitor and protect this server. I am assuming you already have this service running [<a href=\"https:\/\/dft.wiki\/?p=401\">Read It<\/a>], and you just need to include the VSFTP in the configuration:<\/p>\n<pre>sudo nano \/etc\/fail2ban\/jail.local<\/pre>\n<p>Search for <strong>vsftpd <\/strong>(Ctrl+W), and it must look like this:<\/p>\n<pre>[<strong>vsftpd<\/strong>]\r\nenabled = true\r\nport = ftp,ftp-data,ftps,ftps-data\r\nlogpath = %(vsftpd_log)s<\/pre>\n<p>Then go to the filter file:<\/p>\n<pre>sudo nano \/etc\/fail2ban\/filter.d\/vsftpd.conf<\/pre>\n<p>This is how it looks like, if different, just copy and paste to replace:<\/p>\n<pre>[INCLUDES]\r\nbefore = common.conf\r\n[Definition]\r\n__pam_re=\\(?%(__pam_auth)s(?:\\(\\S+\\))?\\)?:?\r\n_daemon = vsftpd\r\nfailregex = ^%(__prefix_line)s%(__pam_re)s\\s+authentication failure; logname=\\S* uid=\\S* euid=\\S* tty=(ftp)? ruser=\\S* rhost=&lt;HOST&gt;(?:\\s+user=.*)?\\s*$\r\n^ \\[pid \\d+\\] \\[[^\\]]+\\] FAIL LOGIN: Client \"&lt;HOST&gt;\"(?:\\s*$|,)\r\n^ \\[pid \\d+\\] \\[root\\] FAIL LOGIN: Client \"&lt;HOST&gt;\"(?:\\s*$|,)\r\nignoreregex =<\/pre>\n<p>Restart the Fail2Ban, check the status of the new Jail, and make one fail to attempt to log in to see if it captures the event.<\/p>\n<pre>sudo systemctl restart fail2ban\r\nsudo fail2ban-client status vsftpd<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-509 size-full\" src=\"https:\/\/dft.wiki\/wp-content\/uploads\/sites\/15\/2020\/10\/Screenshot-from-2020-10-17-13-18-32.png\" alt=\"\" width=\"246\" height=\"160\" \/><\/p>\n<p>After the fail attempt, &#8220;<strong>Total failed<\/strong>&#8221; will start counting.<\/p>\n<p>Just in case you ban yourself, issue the following command with <strong>your IP address<\/strong> in it:<\/p>\n<pre>sudo fail2ban-client unban <strong>200.200.200.200<\/strong><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Assuming you already have an SSL\/TLS key that you may have created for your HTTP [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-500","post","type-post","status-publish","format-standard","hentry","category-linux"],"_links":{"self":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/500","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=500"}],"version-history":[{"count":11,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/500\/revisions"}],"predecessor-version":[{"id":5494,"href":"https:\/\/dft.wiki\/index.php?rest_route=\/wp\/v2\/posts\/500\/revisions\/5494"}],"wp:attachment":[{"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=500"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=500"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dft.wiki\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=500"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}