---
title: Webmail using Roundcube
lastUpdated: 2025-08-25
slug: ispmail-trixie/webmail
sidebar:
  order: 170
---

import { Aside } from "@astrojs/starlight/components";

## Configure Apache

Now that the email has arrived, our valued user surely wants to read it. Most humans nowadays seem to prefer reading
their email in the web browser, because it's the simplest way. (Don't worry. Power users who prefer mail clients like
Thunderbird will also get what they want.) So let's prepare [Roundcube](https://roundcube.net/) for them.

<details class="collapsible">
  <summary>Click here to learn more about virtual hosts…</summary>

A web server like Apache has the job of answering HTTP or HTTPS requests from people’s browsers. Running just a single
website per server (or per IP address) would be both inefficient and limiting, so the idea of _virtual hosts_ was
introduced. With virtual hosts, one server can host many different websites. The browser helps by sending a
`Host: mail.example.org` header with each request, which tells the server which website it should serve. This works fine
for HTTP—though plain HTTP is rarely used anymore.

With HTTPS, things get trickier. Browsers expect the server to present a TLS certificate that matches the domain being
requested. If you try to open mail.example.org but the server responds with a certificate for shop.example.org, the
browser will block the connection. That means the server needs to know which domain the browser is asking for before the
encrypted connection is set up.

The solution is a feature called SNI (Server Name Indication). When establishing an HTTPS connection, the browser
includes the domain name it wants in the handshake. This allows the server to pick the correct TLS certificate right
from the start.

Fortunately you do not have to worry about it that much because Apache is doing the heavy lifting for you. A virtual
host configuration essentially looks like:

```
<VirtualHost *:443>
  ServerName mail.example.org
  SSLCertificateFile /etc/letsencrypt/live/mail.example.org/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/mail.example.org/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
```

There are two directories dealing with virtual hosts:

- /etc/apache2/sites-available
- /etc/apache2/sites-enabled

The actual file containing the configuration lives in _sites-available_. If that configuration should be active, then a
symbolic link (symlink) is added to the _sites-enabled_ directory pointing to the file in the _sites-available_
directory. That way you can switch sites on and off without deleting the actual configuration file. You can enable a
site using the `a2enconf` (apache2 enable config) command or disable it using `a2disconf`.

</details>

Since you ran `certbot` earlier to create a TLS certificate for your site, the default configuration files for HTTP and
HTTPS have been adapted already:

- **000-default.conf**: This is the virtual host configuration for HTTP requests. It uses a `RewriteRule` to redirect
  users to the HTTPS site. So if user accidentally forget to type `https://`, we will add it for them.
- **000-default-le-ssl.conf**: This is the HTTPS virtual host.

So to get Apache to serve the Roundcube application you need to edit the
`/etc/apache2/sites-available/000-default-le-ssl.conf` file.

<Aside type="danger" title="Important">

Please replace `mail.example.org` by the FQDN you chose.

</Aside>

Set this:

```
ServerName mail.example.org
DocumentRoot /var/lib/roundcube/public_html
Include /etc/roundcube/apache.conf
```

Meaning:

- `ServerName` sets the domain name that a user's browser will request.
- `DocumentRoot` points the entire web site to the directory where Roundcube is installed.
- `Include` loads additional security settings that the Roundcube package provides.

And as usual Apache needs to be restarted after the configuration change:

```
systemctl restart apache2
```

Check that Apache is running properly:

```
systemctl status apache2
```

In case of a problem run “`apache2ctl configtest`" to find the cause.

## Limit access to localhost

The main configuration file of Roundcube is located at `/etc/roundcube/config.inc.php`. Feel free to customize the file.
Fortunately nowadays the basic settings are already as we need them. However these two settings need to be changed by
you.

<Aside type="danger" title="Important">

Please replace `mail.example.org` by the FQDN you chose.

</Aside>

```
$config['imap_host'] = 'tls://mail.example.org:143';
$config['smtp_host'] = 'tls://mail.example.org:587';
```

So now when your users enter `https://webmail.example.org/` in their browser they should get the Roundcube login form:

Keep in mind that we are using the email address as the account name of the user. So when logging in please enter the
email address as the user name. E.g. `john@example.org` and password `summersun`.

TODO: show login dialog

TODO: on errors, check /var/log/roundcube/errors.log

## Plugins

Roundcube comes with various plugins that you can offer your users. I suggest that you enable at least the **password**
plugin so that your users can change their access password.

Again edit the `/etc/roundcube/config.inc.php` file and look for the _plugins_ configuration. To enable the recommended
plugins change it to:

```
$config['plugins'] = array(
     'password',
 );
```

Plugins are configured through files located in the `/etc/roundcube/plugins` directory. Let's quickly set up the
password plugin:

```sh title="Run this on your server"
cat > /etc/roundcube/plugins/password/config.inc.php << 'EOF'
<?php
$config['password_driver'] = 'sql';
$config['password_minimum_length'] = 12;
$config['password_force_save'] = true;
$config['password_algorithm'] = 'blowfish-crypt';
$config['password_algorithm_prefix'] = '{CRYPT}';
$config['password_db_dsn'] = 'mysql://mailadmin:MAILADMIN-PASSWORD-HERER@localhost/mailserver';
$config['password_query'] = "UPDATE virtual_users SET password=%P WHERE email=%u";
?>
EOF

chown root:www-data /etc/roundcube/plugins/password/config.inc.php
chmod u=rw,g=r,o= /etc/roundcube/plugins/password/config.inc.php
```

Let’s briefly cover the meaning of those lines:

- `$config['password_driver'] = 'sql';`\
  Use SQL as a backend.
- `$config['password_minimum_length'] = 12;`\
  New passwords must be at least 12 characters long.
- `$config['password_force_save'] = true;`\
  This will overwrite the password in the database even if it hasn’t changed. It helps us improve the strength of the password
  hash by re-encoding it with a better algorithm even if the user chooses to keep his old password.
- `$config['password_algorithm'] = 'blowfish-crypt';`\
  The cryptographic algorithm to encode the password. This one is considered very secure and supported by Dovecot.
- `$config['password_algorithm_prefix'] = '{CRYPT}';`\
  Prepend every password with this string so that Dovecot knows how we encrypted the password.
- `$config['password_db_dsn'] = 'mysql://mailadmin:MAILADMIN-PASSWORD-HERER@localhost/mailserver';`\
  Connection information for the local database. Use your own password for the _mailadmin_ (!) database user here. We cannot
  use the restricted _mailserver_ user because we have to write the new password to the database.
- `$config['password_query'] = "UPDATE virtual_users SET password=%P WHERE email=%u";`\
  The SQL query that is run to write the new password hash into the database. `%P` is a placeholder for the new password
  hash. `%u` is the logged-in user and conveniently matches the email address.

For a complete reference please see `/usr/share/roundcube/plugins/password/config.inc.php.dist`.

The last two lines make sure that this config file is only accessible to everyone.

Try it. Log into Roundcube as `john@example.org` with password ‘summersun’. Go to the _Settings_. Choose _Password_.
Enter a new password twice. You should get a success message at the bottom right. Now logout and login with the new
password. Does it work? Great.

<Aside type="tip" title="Important">

Before you get overly enthusiastic: you can't send emails from Roundcube yet. We will fix that now.

</Aside>
