Setup Email Server From Scratch On FreeBSD - 07 RoundCube WebMail
06 SPF DMARC And DKIM <- Intro -> 08 Create Virtual Domains
This tutorial is partially complete 2025-05-14
Postfix, Dovecot, & PostfixAdmin work with MySQL and virtual accounts
can be created with PostfixAdmin and used with an email client. SPF, OpenDKIM,
and DMARC milters, Roundcube with sieve filters and password plugins all work.
Roundcube kolab calendar works (2025-05-20)
######################################
# Setup RoundCube Webmail On FreeBSD #
######################################
Getting Roundcube setup and installing the modules could be a tutorial by itself. There are many ways to
get and install Roundcube so if you're up for experimentation try a few different options and see which
works best.
Initially I tried installing Roundcube from the git repo but it had some dependencies which were taking too long to resolve, so
I tried to install both from pkg and ports which installed most of the dependencies. The next problem was getting it to connect
to MariaDB which was solved by adding the socket lines to php.ini.
Initially enabling calendar broke the email reading pane in roundcube. Install sabre/dav to fix the issue, and then reinstall
the package version of calendar which includes the css to make it work right (FreeBSD doesn't seem to have lessc to compile the
css but the pkg version has the css).
If you download roundcube from the git source there are installation instructions and an installer script
for doing upgrades. The way I have installed calendar here works but generates invisible errors in the
logs which may be fixed by using the latest git source. You may need to use lessc and the Python version
might work (I haven't tried it yet).
# Install Python version of lessc
pkg install py311-lesscpy
# run with lesscpy ... I have not tried this
# Apache module compiled against more recent version of openssl. reinstall openssl
pkg install openssl
# Edit MariaDB configuration
nano /usr/local/etc/mysql/conf.d/server.cnf
# ---
# Options specific to all server programs
[server]
lower_case_table_names=1
character-set-server = utf8mb4
collation_server = utf8mb4_unicode_520_ci
innodb_large_prefix=1
innodb_file_per_table=1
innodb_file_format=Barracuda
# Options specific to MariaDB server programs
[server-mariadb]
lower_case_table_names=1
character-set-server = utf8mb4
collation_server = utf8mb4_unicode_520_ci
innodb_large_prefix=1
innodb_file_per_table=1
innodb_file_format=Barracuda
# ---
service mysql-server restart
# Create Roundcube Database
mysql -u root
> create database roundcubemail;
CREATE USER roundcube@localhost IDENTIFIED BY 'super_secret_password';
GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost;
grant all privileges on roundcubemail.* to 'roundcube'@'localhost';
flush privileges;
exit;
# Test the mysql login
mysql -u roundcube -psuper_secret_password roundcubemail
> exit;
# Configure PHP and add php modules
# Get your timezone for adding to php.ini
# Update the zoneinfo and find your timezone for php.
pkg install zoneinfo-2025.a
ls /usr/share/zoneinfo/*
# Add PHP Modules - these may or may not be neeeded
pkg install php83-pear-DB_ldap2 php83-pecl-imagick php83-pecl-redis php83-mysqli
pkg install php83-imap php83-curl php83-zip php83-mbstring php83-bz2 php83-intl php83-gmp php83-gd
pkg install php83-gettext
pkg install php83-phar
# Add roundcube packages - I installed every package that matched roundcube which may or may not be needed.
pkg install roundcube-automatic_addressbook-php83 roundcube-calendar-kolab-php83
pkg install roundcube-carddav-php83 roundcube-classic-php83 roundcube-contextmenu-php83
pkg install roundcube-gravatar-php83 roundcube-html5_notifier-php83
pkg install roundcube-identity_smtp-php83 roundcube-larry-php83 roundcube-login_info-php83
pkg install roundcube-php83 roundcube-sauserprefs-php83 roundcube-thunderbird_labels-php83
pkg install roundcube-tls_icon-php83 roundcube-twofactor_gauthenticator-php83
pkg install roundcube-veximaccountadmin-php83 roundcube-yubikey_auth-php83
# Copy php.ini if not done already.
ls -l /usr/local/etc/php.ini
# If it doesn't exist use one of the following
cp /usr/local/etc/php.ini-development /usr/local/etc/php.ini
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# Configure PHP
# Not all of these may be needed ... but here are some resonable settings
# Please note that allowing uploads of 500MB might cause a problem with heavily
# loaded servers and typical mail servers only accept mails 10 - 30MB. These
# settings work nicely between 2 mail servers that are configured to accept larger
# email sizes. I set these larger than roundcube where if you set 200M in roundcube
# the displayed allowed size is 150M.
# SEE THE MYSQL SOCKET LINES!!!
nano /usr/local/etc/php.ini
# ---
max_input_time = 300
max_execution_time = 300
max_input_vars = 3000
memory_limit = 256M
post_max_size = 200M
upload_max_filesize = 200M
# These were necessary!!!
pdo_mysql.default_socket = /var/run/mysql/mysql.sock
mysqli.default_socket = /var/run/mysql/mysql.sock
# Not sure which of these were needed but these are the ones I enabled. During
# install on FreeBSD these are enabled in an include directory, so if you run
# php from commandline and get a bunch of module double loading errors, comment
# out the ones with errors.
;extension=bz2
;extension=curl
;extension=fileinfo
;extension=gd
;extension=gettext
;extension=gmp
;extension=intl
;extension=imap
;extension=mbstring
;extension=exif ; Must be after mbstring as it depends on it
;extension=mysqli
;extension=openssl
;extension=pdo_mysql
;extension=zip
date.timezone = US/Pacific
# ---
# Setup Apache Roundcube Directory
nano /usr/local/etc/apache24/Includes/10-mx.okbsd-le-ssl.conf
# ---
Alias /webmail "/usr/local/www/roundcube"
<Directory /usr/local/www/roundcube/>
Options FollowSymLinks MultiViews
AllowOverride All
Require all denied
Require ip 10.10.200.0/24 IP2 IP3 IP4 NET2 IPV6_NETWORK
</Directory>
# ---
apachectl restart
# Move Default Roundcube
# This version of roundcube didn't work perfectly so I moved it to the side and
# installed from scratch. The benefit is that the needed libraries were
# installed by pkg.
cd /usr/local/www
mv roundcube roundcube_default
# Reinstall The Lateset Roundcube
cd /usr/local/www
https://github.com/roundcube/roundcubemail/releases/download/1.6.10/roundcubemail-1.6.10.tar.gz
tar xfzv roundcubemail-1.6.10-complete.tar.gz
mv roundcubemail-1.6.10 roundcube
cd /usr/local/www/roundcube
chown -R www:www temp logs
cd /usr/local/www/roundcube/SQL
mysql -u roundcube -psuper_secret_password roundcubemail < mysql.initial.sql
# Automatic Addressbook
cd /usr/local/www/roundcube
git clone https://github.com/sblaisot/automatic_addressbook.git
mv automatic_addressbook roundcube/plugins/
cd /usr/local/www/roundcube/plugins/automatic_addressbook/SQL
mysql -u roundcube -psuper_secret_password roundcubemail < mysql.initial.sql
cd /usr/local/www/roundcube/plugins/automatic_addressbook/config
cp config.inc.php.dist config.inc.php
# Kolab Calendar
# Calendar won't work right and we'll reinstall this by pkg later
# git clone https://git.kolab.org/diffusion/RPK/roundcubemail-plugins-kolab.git
# cd /usr/local/www/roundcubemail-plugins-kolab/plugins
# cp -R calendar libkolab libcalendaring /usr/local/www/roundcube/plugins
# cd /usr/local/www/roundcube/plugins/libkolab/SQL
# mysql -u roundcube -psuper_secret_password roundcubemail < mysql.initial.sql
# cd /usr/local/www/roundcube/plugins/calendar
# cp config.inc.php.dist config.inc.php
# cd ../..
# bin/initdb.sh --dir=plugins/calendar/drivers/database/SQL
# Manage Sieve
cd /usr/local/www/roundcube/plugins/managesieve
cp config.inc.php.dist config.inc.php
# Configure Roundcube
cd /usr/local/www/roundcube/config
cp config.inc.php.sample config.inc.php
# Please change the DES Key to a random 24 char string and make it exactly 24 chars and set your
# super_secret_password the same as you provided when creating the roundcube database. Please count the
# chars in your key, base 64 defaults to 32 so remove 8 chars.
openssl rand -base64 24
nano /usr/local/www/roundcube/config/config.inc.php
# ---
$config['db_dsnw'] = 'mysql://roundcube:super_secret_password@localhost/roundcubemail';
$config['imap_host'] = 'tls://mx.okbsd.com:143';
$config['smtp_host'] = 'tls://mx.okbsd.com:587';
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['support_url'] = '';
$config['product_name'] = 'OkBSD Webmail';
$config['des_key'] = '123456789012345678901234';
// 'filesystem_attachments', // conflicts with another attachment plugin
$config['plugins'] = ['acl', 'additional_message_headers', 'archive',
'attachment_reminder', 'autologon', 'debug_logger', 'emoticons', 'enigma',
'help', 'hide_blockquote', 'http_authentication', 'identicon',
'identity_select', 'jqueryui', 'krb_authentication', 'managesieve',
'markasjunk', 'new_user_dialog', 'new_user_identity', 'newmail_notifier',
'password', 'reconnect', 'redundant_attachments', 'show_additional_headers',
'squirrelmail_usercopy', 'subscriptions_option', 'userinfo',
'vcard_attachments', 'virtuser_file', 'virtuser_query', 'zipdownload',
'automatic_addressbook'];
// ,'calendar', 'twofactor_gauthenticator', 'html5_notifier']; // setup later
$config['enable_spellcheck'] = true;
// skin name: folder from skins/
$config['skin'] = 'elastic';
$config['max_pagesize'] = 1000;
// $config['url_base'] = '/mail-login/';
$config['enable_installer'] = true;
# ---
nano /usr/local/www/roundcube/config/defaults.inc.php
# ---
$config['max_message_size'] = '200M'; // RC will display max 150M
# ---
# Go to the roundcube installer
# If you have problems getting roundcube to connect to and write to mysql, the
# solution was to enable the socket path in php.ini and apachectl restart.
# For the smtp test use the mail name without the domain and password.
# For the imap test the full senders email and full 'To' email.
# For connection problems double check the tls://<hostname>:587 and 143 lines,
# using localhost won't work for tls.
https://mx.okbsd.com/webmail/installer
# Once configured and all checks are ok remove the install folder and comment out
# the enable_installer line.
rm -rf /usr/local/www/roundcube/installer
nano /usr/local/www/roundcube/config/config.inc.php
# ---
// $config['enable_installer'] = true;
# ---
# note: vexiadmin allows users to manage spam filtering
# Sieve Install and Configure - seive is provided by dovecot-pideonhole
cd /usr/ports/mail/dovecot-pideonhole
make
X DOCS
X EXAMPLES
X LDAP
X MANAGESIEVE
X GSSAPI_NONE
make install
nano /usr/local/etc/dovecot/dovecot.conf
# ---
protocols = imap lmtp sieve
service managesieve-login {
inet_listener sieve {
port = 4190
}
inet_listener sieve_deprecated {
port = 2000
}
service_count = 1
process_min_avail = 0
vsz_limit = 64M
}
service managesieve {
process_limit = 1024
}
protocol sieve {
managesieve_max_line_length = 65536
managesieve_implementation_string = dovecot
log_path = /var/log/dovecot-sieve-errors.log
info_log_path = /var/log/dovecot-sieve.log
}
# ---
nano /usr/local/etc/dovecot/conf.d/10-master.conf
# ---
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
}
# ---
nano /usr/local/etc/postfix/main.cf
# ---
mailbox_transport = lmtp:unix:private/dovecot-lmtp
smtputf8_enable = no
# ---
nano /usr/local/etc/dovecot/conf.d/15-lda.conf
# ---
protocol lda {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins sieve
}
# ---
nano /usr/local/etc/dovecot/conf.d/20-lmtp.conf
# ---
protocol lmtp {
# Space separated list of plugins to load (default is global mail_plugins).
mail_plugins = $mail_plugins quota sieve
}
# ---
nano /usr/local/etc/dovecot/conf.d/10-mail.conf
# ---
mail_location = maildir:~/Maildir
mail_home = /var/vmail/%d/%n
# ---
mkdir -p /usr/local/etc/dovecot/sieve/global
nano /usr/local/etc/dovecot/sieve/before-global.sieve
# ---
require "fileinto";
if header :contains "X-Spam-Flag" "YES"
{
fileinto "Junk";
stop;
}
# ---
sievec /usr/local/etc/dovecot/sieve/before-global.sieve
nano /etc/dovecot/conf.d/90-plugin.conf
# ---
plugin {
#setting_name = value
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_default = /usr/local/etc/dovecot/sieve/default.sieve
sieve_global = /usr/local/etc/dovecot/sieve/global/
sieve_before = /usr/local/etc/dovecot/sieve/before-global.sieve
}
# ---
service postfix restart
service dovecot restart
# Configure managesieve
cd /usr/local/www/roundcube/plugins/managesieve
cp config.inc.php.dist config.inc.php
# Change the following values in plugins/managesieve/config.inc.php
nano /usr/local/www/roundcube/plugins/managesieve/config.inc.php
# --- add or change
// $config['managesieve_host'] = 'localhost';
$config['managesieve_host'] = 'tls://mx.okbsd.com';
$config['managesieve_default'] = '/usr/local/etc/dovecot/sieve/global';
$config['managesieve_debug'] = true;
$config['managesieve_usetls'] = true;
# ---
apachectl restart
# Remove Roundcube Header
nano /etc/postfix/smtp_header_checks
# --- create or add
/^User-Agent.*Roundcube Webmail/ IGNORE
# ---
nano /etc/postfix/main.cf
# --- append to end of file
smtp_header_checks = regexp:/etc/postfix/smtp_header_checks
# ---
postmap /etc/postfix/smtp_header_checks
service postfix restart
# Configure RoundCube Password Plugin
cd /usr/local/www/roundcube/plugins/password
cp config.inc.php.dist cp config.inc.php
nano config.inc.php
# ---
$config['password_algorithm'] = 'dovecot';
$config['password_dovecotpw'] = '/usr/local/bin/doveadm pw -r 5';
$config['password_dovecotpw_method'] = 'ARGON2I';
$config['password_dovecotpw_with_method'] = true;
$config['password_db_dsn'] = 'mysql://postfixadmin:postfix_admin_password@127.0.0.1/postfixadmin';
$config['password_query'] = 'UPDATE mailbox SET password=%P,modified=NOW() WHERE username=%u';
$config['password_strength_driver'] = null;
$config['password_minimum_length'] = 8;
$config['password_minimum_score'] = 0;
# ---
chown www:www config.inc.php
chmod 600 config.inc.php
# Double check ARGON2I
/usr/local/bin/doveadm pw -l SHA1 SSHA512 SCRAM-SHA-256 BLF-CRYPT PLAIN HMAC-MD5
OTP SHA512 SHA DES-CRYPT CRYPT SSHA MD5-CRYPT PLAIN-MD4 PLAIN-MD5 SCRAM-SHA-1
SHA512-CRYPT CLEAR CLEARTEXT ARGON2I ARGON2ID SSHA256 MD5 PBKDF2 SHA256 CRAM-MD5
PLAIN-TRUNC SHA256-CRYPT SMD5 DIGEST-MD5 LDAP-MD5
# Check that changing password works in roundcube
# Fix the Calendar
# Adding sabre/dav makes the mail pane readable again but calendars aren't listed
# in the calendar pane. This is probably a css issue and lessc is not available on
# FreeBSD, so reinstall the FreeBSD calendar package with sabre/dav.
# We should also invesitate how to enable CalDav CardDav
https://wiki.archlinux.org/title/Roundcube#Sabre%5CVObject%5CProperty%5CText_Not_Found
https://std.rocks/gnulinux_roundcube.html
curl -sS https://getcomposer.org/installer | php
php composer.phar update
php composer require sabre/dav ~3.1.3
ls /usr/local/www/roundcube/vendor/sabre
# Remove the calendar plugin directories
cd /usr/local/www/roundcube/plugins
rm -rf calendar libkolab libcalendaring
pkg remove roundcube-calendar-kolab-php83
# Reinstall the plugins from pkg
pkg install roundcube-calendar-kolab-php83
cd /usr/local/www/roundcube/plugins/libkolab/SQL
mysql -u roundcube -psuper_secret_password roundcubemail < mysql.initial.sql
cd /usr/local/www/roundcube/plugins/calendar
cp config.inc.php.dist config.inc.php
cd ../..
bin/initdb.sh --dir=plugins/calendar/drivers/database/SQL
# I downloaded new versions of kolab plugins and overwrote the working
# directories, leaving any css files from the pkg in place, everything still worked.
cd /usr/local/www
git clone https://git.kolab.org/diffusion/RPK/roundcubemail-plugins-kolab.git
cd /usr/local/www/roundcubemail-plugins-kolab/plugins
cp -R calendar libkolab libcalendaring /usr/local/www/roundcube/plugins
# Update roundcube config to include calendar
nano /usr/local/www/roundcube/config/config.inc.php
# --- add to plugins
'calendar',
# ---
# Add some more plugins
pkg remove roundcube-html5_notifier-php83
pkg install roundcube-html5_notifier-php83
cd /usr/local/www/roundcube/plugins/html5_notifier/config
cp config.inc.php.dist config.inc.php
# Setting identity in roundcube errors ... fix enigma home directory
cd /usr/local/www/roundcube/plugins/enigma
cp config.inc.php.dist config.inc.php
nano /usr/local/www/roundcube/plugins/enigma/config.inc.php
# ---
$config['enigma_pgp_homedir'] = "/usr/local/www/roundcube/plugins/enigma/home";
# ---
mkdir /usr/local/www/roundcube/plugins/enigma/home
chown www:www /usr/local/www/roundcube/plugins/enigma/home
chmod 750 /usr/local/www/roundcube/plugins/enigma/home
pkg install gnupg
# Removed 'twofactor_gauthenticator', wasn't working right more research needed on this to get it to work
# // ,'twofactor_gauthenticator'
# pkg remove roundcube-twofactor_gauthenticator-php83
# pkg install roundcube-twofactor_gauthenticator-php83
# cd /usr/local/www/roundcube/plugins/twofactor_gauthenticator/config
# cp config.inc.php.dist config.inc.php
nano /usr/local/www/roundcube/config/config.inc.php
# --- add to plugins
'automatic_addressbook', 'calendar', 'html5_notifier'];
# ---
# Test that everything works as expected
# Roundcube has an extensive set of plugins which are beyond the scope of
# this setup tutorial. It would be interesting to set this up properly with caldav cardav
# Next - Multiple "Virtual" Mail Domains