rss logo

How to Secure Roundcube Webmail with Fail2ban, 2FA and HTTPS

Rouncube Logo

This article focuses on improving Roundcube webmail security. It explains how to configure Fail2ban to protect against brute-force attacks, and how to integrate a 2FA (Two-Factor Authentication) plugin, developed by alexandregz, to strengthen user authentication.

Although HTTPS configuration in Roundcube has already been covered here, this guide also reviews the required steps to enable HTTPS and add an extra layer of transport security.

Enable Fail2ban Protection

Fail2ban is a powerful security tool designed to monitor authentication errors in log files and temporarily block IP addresses responsible for repeated failed attempts. It can be used to protect various services such as sshd, Apache, and Dovecot against brute-force attacks.

Install and Configure Fail2ban

  • Install fail2ban:
root@host:~# apt update && apt install fail2ban
  • Start and enable the nftables service:
root@host:~# systemctl start nftables
root@host:~# systemctl enable nftables
  • Edit the /etc/fail2ban/jail.conf file:
banaction = nftables-multiport
banaction_allports = nftables-allports
  • Edit the /etc/fail2ban/jail.d/defaults-debian.conf file:
[DEFAULT]
banaction = nftables
banaction_allports = nftables[type=allports]
maxretry = 10
findtime = 60m
bantime  = 5m
# Optional: enable email reporting
#destemail = fail2ban@std.rocks
#sender    = fail2ban@std.rocks
#mta       = sendmail
#action = %(action_mwl)s

[sshd]
enabled = true
backend = systemd

[roundcube-auth]
enabled = true
logpath = /var/log/roundcube/errors.log
  • Restart the fail2ban service to take the changes into account:
root@host:~# systemctl restart fail2ban
  • Check the status of the roundcube-auth jail:
root@host:~# fail2ban-client status roundcube-auth
Status for the jail: roundcube-auth
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	0
|  `- File list:	/var/log/roundcube/errors.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	0
   `- Banned IP list:	

Unblock an IP Address in Fail2ban

  • List blocked IP addresses:
root@host:~# nft -a list ruleset
table inet filter { # handle 1
        chain input { # handle 1
                type filter hook input priority filter; policy accept;
        }

        chain forward { # handle 2
                type filter hook forward priority filter; policy accept;
        }

        chain output { # handle 3
                type filter hook output priority filter; policy accept;
        }
}
table inet f2b-table { # handle 2
        set addr-set-roundcube-auth { # handle 2
                type ipv4_addr
                elements = { 192.168.10.36 }
        }

        chain f2b-chain { # handle 1
                type filter hook input priority filter - 1; policy accept;
                tcp dport { 80, 443 } ip saddr @addr-set-roundcube-auth reject with icmp port-unreachable # handle 6
        }
}
  • If necessary, temporarily unblock a blocked IP address:
root@host:~# fail2ban-client set roundcube-auth unbanip 192.168.10.36
  • To permanently whitelist IP addresses, edit /etc/fail2ban/jail.conf:
ignoreip = 127.0.0.1/8 ::1 192.168.10.36
  • Restart the fail2ban service to apply the changes:
root@host:~# systemctl restart fail2ban

Add a Two-Factor Authentication (2FA) Plugin to Roundcube

A smartphone application compatible with Google Authenticator is required to generate one-time passwords. I personally use FreeOTP. It is an open-source authentication application developed by Red Hat.

The official GitHub repository for the twofactor_gauthenticator plugin is available here: https://github.com/alexandregz/twofactor_gauthenticator

Enable the 2FA Plugin in Roundcube

  • Install Git and download the 2FA plugin:
root@host:~# apt update && apt install git
root@host:~# git clone https://github.com/alexandregz/twofactor_gauthenticator.git
  • Move the twofactor_gauthenticator directory to the Roundcube plugins directory (/var/lib/roundcube/plugins):
root@host:~# mv twofactor_gauthenticator /var/lib/roundcube/plugins/
  • Edit /etc/roundcube/config.inc.php to activate the 2FA plugin:
$config['plugins'] = [
        'twofactor_gauthenticator',
];
  • From the Roundcube web interface, navigate to Settings > 2-Factor Authentication:
Rouncube web interface settings menu with 2-factor authentication entry
  • Enable the Activate option and click Fill all fields:
Rouncube web interface settings for the 2-factor authentication plugin
  • A pop-up window appears; click OK to continue:
2FA roundcube plugin warning window for QR code scanning
  • Write down the secret and recovery codes in case you lose your 2FA device, then scan the QR code using your 2FA application on your smartphone:
Roundcube interface 2FA plugin with QR Code and recovery codes
  • From your smartphone, retrieve the current one-time password, enter it in the input field, then click Check code to verify the configuration:
2FA roundcube plugin check code code validation window
  • Finally, click Save to apply the settings:
2FA roundcube plugin check code
  • At the next login, the 2FA authentication prompt should appear:
2FA roundcube login page

Reset 2FA Authentication for a User

If you have lost your 2FA device, you will no longer be able to log in to Roundcube. To recover a user’s 2FA recovery codes or disable 2FA authentication, several actions must be performed directly on the Roundcube server. This procedure applies to installations using a SQLite database.

  • Connect to the SQLite database:
root@host:~# sqlite3 /var/lib/dbconfig-common/sqlite3/roundcube/roundcube
  • Identify the user account to reset and retrieve the 2FA recovery codes:
SELECT * FROM users ;
1|john@std.rocks|std.rocks||2024-02-09 15:02:30|2024-02-24 12:31:00|2024-02-24 11:43:03|1|en_US|a:2:{s:11:"client_hash";s:16:"Tzl9oKiP5cifLfVO";s:24:"twofactor_gauthenticator";a:3:{s:6:"secret";s:16:"VTAPZI2PZVUIR45Q";s:8:"activate";b:1;s:14:"recovery_codes";a:4:{i:0;s:10:"B2FDEYC5J7";i:1;s:10:"A6TY7H5XD6";i:2;s:10:"CYYNSZ22UB";i:3;s:10:"SWISSDWBZ7N";}}}
  • Alternatively, reset 2FA settings by setting preferences to NULL:
UPDATE users SET preferences = NULL WHERE user_id = 1;

Whitelist IPs for 2FA Bypass

You may not want to enable 2FA authentication when connecting from trusted networks, such as your local network or specific public IP addresses. It is possible to add these IPs to /var/lib/roundcube/plugins/twofactor_gauthenticator/config.inc.php. For example, the following configuration disables 2FA authentication for the 192.168.1.0/24 network and the 203.0.113.1 IP address.

  • Edit /var/lib/roundcube/plugins/twofactor_gauthenticator/config.inc.php and add the IP addresses you want to exclude:
// A Whitelist of IPs which are allowed to bypass the 2FA, CIDR format available.
// NOTE: We need to use .0 IP to define LAN because the class CIDR have a issue about that (we can't use 129.168.1.2/24, for example)
// NOTE2: To create a empty whitelist, make sure it looks like this: `$rcmail_config['whitelist'] = array();` <- There are NO QUOTES inside the parentheses.
$rcmail_config['whitelist'] = array('192.168.1.0/24','203.0.113.1');

Enable HTTPS for Roundcube

For security reasons, enabling HTTPS for the Roundcube web interface is strongly recommended. This can be achieved using Let’s Encrypt certificates or self-signed certificates. The following sections describe how to implement both solutions.

  • First, enable the Apache SSL module:
root@host:~# a2enmod ssl

Let's Encrypt

A Let’s Encrypt certificate can be requested to secure the connection. Its main advantage is that it is trusted by web browsers and does not trigger any security warning when accessing the service.

  • Install the certbot utility:
root@host:~# apt update && apt install certbot
  • Stop the Apache service:
root@host:~# systemctl stop apache2
  • Run the certbot tool. Ports 80 and 443 must be accessible on the Roundcube server, and the DNS record roundcube.std.rocks must point to this server:
root@host:~# certbot certonly --email letsencrypt@std.rocks --standalone -d roundcube.std.rocks
  • Modify the configuration file /etc/apache2/sites-available/default-ssl.conf and add:
SSLCertificateFile /etc/letsencrypt/roundcube.std.rocks/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/roundcube.std.rocks/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/roundcube.std.rocks/chain.pem
  • Enable the SSL site and restart the Apache service:
root@host:~# a2ensite default-ssl
root@host:~# systemctl start apache2

Self-Signed Certificates

  • Alternatively, create a self-signed certificate:
root@host:~# mkdir /etc/apache2/ssl/
root@host:~# openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout /etc/apache2/ssl/selfsigned.key -out /etc/apache2/ssl/selsigned.crt
-----
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]:FR
State or Province Name (full name) [Some-State]:STD
Locality Name (eg, city) []:stdcity
Organization Name (eg, company) [Internet Widgits Pty Ltd]:std
Organizational Unit Name (eg, section) []:std
Common Name (e.g. server FQDN or YOUR name) []:roundcube.std.rocks
Email Address []:email@std.rocks
root@host:~# cat /etc/apache2/ssl/selfsigned.key /etc/apache2/ssl/selsigned.crt > /etc/apache2/ssl/cert.pem
  • Edit the /etc/apache2/sites-available/default-ssl.conf file:
DocumentRoot /var/lib/roundcube/public_html/
#AUTOGENERATE CERTIFICATES
SSLCertificateFile    /etc/apache2/ssl/cert.pem
SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key
  • Edit the /etc/apache2/ports.conf file and disable HTTP:
#Listen 80
  • Enable the SSL site and restart the Apache service:
root@host:~# a2ensite default-ssl
root@host:~# systemctl restart apache2