Setup Email Server From Scratch On FreeBSD - 02 FAMP Install
01 Server Setup <- Intro -> 03 Postfix SMTPD
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. Incoming SPF
milter and outgoing OpenDKIM milter signing tested and working.
##############
# FAMP Setup #
##############
FAMP and LAMP stands for FreeBSD Apache MySQL PHP or Linux ... and are used to
provide dynamic website services with a database backend. They are required for
the mail stack and are used to run various suites like wordpress, phpmyadmin,
postfixadmin, and roundcube webmail. We'll set this up first before starting
on the actual mail stack installation.
pkg search mariadb
pkg install mariadb106-server mariadb106-client
mysql --version
mysql Ver 15.1 Distrib 10.6.21-MariaDB, for FreeBSD14.2 (amd64)
sysrc mysql_enable="YES"
service mysql-server start
mysql
root@localhost [(none)]>
exit
# You can leave the mysql root password blank if you are concerned it might be
# forgotten but then the database is only as secure as the root account. In
# this case it is a good idea to use unix socket and disallow root remotely.
mysql_secure_installation
<enter>
Switch to unix_socket authentication [Y/n] Y
Change the root password? [Y/n] n
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y
# Setup a separate admin user
mysql
GRANT ALL ON *.* TO 'admin'@'localhost' IDENTIFIED BY 'secretpassword' WITH GRANT OPTION;
FLUSH PRIVILEGES;
exit
nano /usr/local/etc/mysql/conf.d/server.cnf
[server]
lower_case_table_names=1
character-set-server = utf8mb4
collation_server = utf8mb4_unicode_520_ci
..... farther down
# collation-server = utf8mb4_general_ci
collation-server = utf8mb4_unicode_520_ci
... farther ...
[mariadb]
lower_case_table_names=1
character-set-server = utf8mb4
collation_server = utf8mb4_unicode_520_ci
root@okbsd.com:~# service mysql-server restart
Stopping mysql.
Waiting for PIDS: 7135.
Starting mysql.
root@okbsd.com:~# service mysql-server status
mysql is running as pid 7341.
# Install Apache
pkg install apache24
sysrc apache24_enable="YES"
service apache24 start
service apache24 status
# Use a web browser and go to ...
http://okbsd.com
It Works!
# Install perl PHP module
pkg install p5-DBD-mysql
# Install PHP and PHP modules
pkg install php83 mod_php83 php83-mysqli php83-curl php83-zip php83-gd php83-xml php83-mbstring
pkg install php83-bcmath php83-tokenizer php83-zlib php83-imap php83-bz2
pkg install php83-pecl-imagick php83-ldap php83-intl php83-gmp php83-pecl-redis
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
sysrc php_fpm_enable=YES
service php_fpm start
service php_fpm status
nano /usr/local/etc/apache24/modules.d/001_mod-php.conf
<IfModule dir_module>
DirectoryIndex index.php index.html
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch "\.phps$">
SetHandler application/x-httpd-php-source
</FilesMatch>
</IfModule>
apachectl configtest
apachectl restart
mkdir -p /var/www/okbsd/html
echo '<!DOCTYPE html lang="en"><html><head><title>Title</title></head><body><h1>Hello World!</h1></body></html>' > /var/www/okbsd/html/index.php
echo '<?php phpinfo(); ?>' > /var/www/okbsd/html/info.php
chown -R root:www /var/www/okbsd
chmod 750 /var/www/okbsd
chmod 750 /var/www/okbsd/html
chmod -R o-rwx /var/www/okbsd/html
cd /usr/local/etc/apache24
cp httpd.conf httpd.conf.bak
nano httpd.conf
Listen 80
Listen [2604:2dc0:100:1261::10]:80
Listen 443
Listen [2604:2dc0:100:1261::10]:443
LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so
LoadModule ssl_module libexec/apache24/mod_ssl.so
<IfModule !mpm_prefork_module>
LoadModule cgid_module libexec/apache24/mod_cgid.so
</IfModule>
<IfModule mpm_prefork_module>
LoadModule cgi_module libexec/apache24/mod_cgi.so
</IfModule>
LoadModule speling_module libexec/apache24/mod_speling.so
LoadModule rewrite_module libexec/apache24/mod_rewrite.so
ServerAdmin postmaster@okbsd.com
ServerName okbsd.com
# change your paths to match your server file location
DocumentRoot "/var/www/okbsd/html"
<Directory "/var/www/okbsd/html">
# Options -Indexes -MultiViews +FollowSymLinks
Options -Indexes -MultiViews +SymLinksIfOwnerMatch
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
# If you want to run cgi's uncomment these and the handler
ScriptAlias /cgi-bin/ "/var/www/okbsd/cgi-bin/"
<Directory "/var/www/okbsd/cgi-bin">
AllowOverride None
# Options None
# Options ExecCGI
Options +ExecCGI -Indexes -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
<farther down in the file>
#AddHandler cgi-script .cgi
# Secure (SSL/TLS) connections
# Include etc/apache24/extra/httpd-ssl.conf
##################
# save and close #
##################
apachectl configtest
apachectl restart
##########################
# Setup SSL with certbot #
##########################
# you will need a virtual host for certbot
apt install py311-certbot py311-certbot-apache
# I setup some default files and certbot changed nad added files. For public
# email services it may be nicer to use something like mail.okbsd.com as
# ServerName instead of mx.okbsd.com. You can setup both just make sure remove
# the ServerAlias entries and add a configuration file for each hostname.
cd /usr/local/etc/apache24/Includes/
nano /usr/local/etc/apache24/Includes/10-mx.okbsd.conf
<VirtualHost *:80>
ServerName mx.okbsd.com
ServerAlias mail.okbsd.com
ServerAdmin postmaster@okbsd.com
CustomLog /var/log/httpd-access.log vhost_combined
ErrorLog /var/log/httpd-error.log
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>
# Save and close
# When running certbot you may get an ERROR ...
# Unable to read ssl_module file; not disabling session tickets.
# To fix it copy the files and change the following lines in httpd.conf, so
# certbot can find the modules.
mkdir /usr/lib/apache2/modules
cp /usr/local/libexec/apache24/mod_ssl.so /usr/lib/apache2/modules
cp /usr/local/libexec/apache24/mod_socache_shmcb.so /usr/lib/apache2/modules
# Change the paths in httpd.conf
nano /usr/local/etc/apache24/httpd.conf
LoadModule socache_shmcb_module /usr/lib/apache2/modules/mod_socache_shmcb.so
LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so
# Certbot will add includes at the end of httpd.conf and configuration files.
# Note if you will be using multiple hosts or domains the best way is to put all
# of the hosts in one certificate so that postfix and dovecot and apache can
# read just one cert. Apache and Dovecot support multiple certs but didn't see a
# way in Postfix. Here I am going to add mx.okbsd.com, and later we'll fix this
# to add mail.okbsd.com since having two mx hosts will speed up google email
# delivery with spam filtering delay.
# List certificates
certbot certficates
# Revoke and delete certificates
certbot revoke --cert-name <certname>
certbot delete
# Add a certificate for one host/domain, we'll add mail.okbsd.com later.
certbot --apache --agree-tos --redirect --hsts --staple-ocsp --email \
postmaster@okbsd.com --cert-name mx.okbsd.com -d mx.okbsd.com
# At this point I had some problems, then found there was no DNS for
# mail.okbsd.com and mx.okbsd.com and www.okbsd.com was CNAME back to
# namecheap's default, so added the records back again!
#
# Also Certbot said it needed a virtual host setup, so added that as well in another
# file. I did this in the Debian default location but used the FreeBSD Includes
# directory which already exists and is enabled by default.
# Certbot was saying some modules in apache were not enabled, so edited httpd.conf
# and fixed that and added them in the howto above, including module Rewrite.
# Certbot inserted Rewrite rules as shown below...
nano /usr/local/etc/apache24/Includes/10-mx.okbsd.conf
<VirtualHost *:80>
ServerName mx.okbsd.com
ServerAlias mail.okbsd.com
ServerAdmin postmaster@okbsd.com
CustomLog /var/log/httpd-access.log vhost_combined
ErrorLog /var/log/httpd-error.log
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =mail.okbsd.com [OR]
RewriteCond %{SERVER_NAME} =mx.okbsd.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
# Certbot also generated Includes/10-mx.okbsd-le-ssl.conf
nano /usr/local/etc/apache24/Includes/10-mx.okbsd-le-ssl.conf
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName mx.okbsd.com
ServerAlias mail.okbsd.com
ServerAdmin postmaster@okbsd.com
CustomLog /var/log/httpd-access.log vhost_combined
ErrorLog /var/log/httpd-error.log
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
Include /usr/local/etc/letsencrypt/options-ssl-apache.conf
Header always set Strict-Transport-Security "max-age=31536000"
SSLCertificateFile /usr/local/etc/letsencrypt/live/mx.okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/mx.okbsd.com/privkey.pem
SSLUseStapling on
</VirtualHost>
</IfModule>
# Check it by going to the site and see if it shows secure ...
https://mx.okbsd.com/index.php
# Also create your regular website config and certs ...
nano /usr/local/etc/apache24/Includes/00-okbsd.conf
<VirtualHost *:80>
ServerName okbsd.com
ServerAlias www.okbsd.com
ServerAlias 147.135.65.97
ServerAlias 2604:2dc0:100:1261::10
ServerAlias 127.0.0.1
ServerAdmin postmaster@okbsd.com
CustomLog /var/log/httpd-access.log vhost_combined
ErrorLog /var/log/httpd-error.log
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
</VirtualHost>
certbot --apache --agree-tos --redirect --hsts --staple-ocsp --email postmaster@okbsd.com -d okbsd.com
# This will create /usr/local/etc/apache24/Includes/00-okbsd-le-ssl.conf
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName okbsd.com
ServerAlias www.okbsd.com
ServerAlias 147.135.65.97
ServerAlias 2604:2dc0:100:1261::10
ServerAlias 127.0.0.1
ServerAdmin postmaster@okbsd.com
CustomLog /var/log/httpd-access.log vhost_combined
ErrorLog /var/log/httpd-error.log
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
SSLCertificateFile /usr/local/etc/letsencrypt/live/okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/okbsd.com/privkey.pem
Include /usr/local/etc/letsencrypt/options-ssl-apache.conf
Header always set Strict-Transport-Security "max-age=31536000"
SSLUseStapling on
</VirtualHost>
</IfModule>
# Test it, go to ...
https://okbsd.com
# Enable and configure httpd-ssl.conf default file
nano /usr/local/etc/apache24/httpd.conf
# Comment out the extra listen and add the default httpd-ssl.conf, you can only have one
# Listen directive for each ADDR:PORT combination.
# Listen 443
# Listen [2604:2dc0:100:1261::10]:443
# Secure (SSL/TLS) connections
Include etc/apache24/extra/httpd-ssl.conf
# Change or remove leading '#' in httpd-ssl.conf
# make a backup
cd /usr/local/etc/apache24/extra
cp /usr/local/etc/apache24/extra/httpd-ssl.conf /usr/local/etc/apache24/extra/httpd-ssl.conf.saved2
nano /usr/local/etc/apache24/extra/httpd-ssl.conf
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect file:/dev/urandom 512
Listen 443
Listen [2604:2dc0:100:1261::10]:443
# I initially edit this but it might improve security and simplify configuation to disable the
# _default_ in this file, and change the certbot generated file to _default_. The 00 means the file
# will be read before higher numbers and sometimes apache uses the first virtual host loaded as the
# default.
# Comment out or edit this Virtualhost section ...
<VirtualHost _default_:443>
# General setup for the virtual host
DocumentRoot "/var/www/okbsd/html"
ServerName okbsd.com:443
ServerAlias www.okbsd.com:443
ServerAdmin postmaster@okbsd.com
ErrorLog "/var/log/httpd-error.log"
TransferLog "/var/log/httpd-access.log"
DirectoryIndex index.php index.html
DocumentRoot /var/www/okbsd/html
<Directory /var/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
</Directory>
# SSLCertificateFile "/usr/local/etc/apache24/server.crt"
SSLCertificateFile /usr/local/etc/letsencrypt/live/okbsd.com/fullchain.pem
# SSLCertificateKeyFile "/usr/local/etc/apache24/server.key"
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/okbsd.com/privkey.pem
# if you want cgi
<Directory "/var/www/okbsd/cgi-bin">
SSLOptions +StdEnvVars
</Directory>
# Or Just comment out everyting from <VirtualHost to </Virtualhost and just
# use the 00-okbsd-le-ssl.conf as the default
# make a backup
cd /usr/local/etc/apache24/extra
cp /usr/local/etc/apache24/extra/httpd-ssl.conf /usr/local/etc/apache24/extra/httpd-ssl.conf.saved2
nano /usr/local/etc/apache24/extra/httpd-ssl.conf
<edit the virtualhost section put # before all lines
# If the VirtualHost section in httpd-ssl.conf is commented out change, this
# is recommended but probably not absolutely necessary.
nano /usr/local/etc/apache24/Includes/00-okbsd-le-ssl.conf
<VirtualHost _default_:443>
# Do not comment out the default <Directory sections in httpd.conf or you'll get a permissions
# denied error, but you can edit /usr/local/etc/apache24/Includes/00-okbsd.conf and change ...
# <VirtualHost *:80> to <VirtualHost _default_:80>.
nano /usr/local/etc/apache24/Includes/00-okbsd.conf
<VirtualHost _default_:80>
apachectl configtest
apachectl restart
# test it
https://mx.okbsd.com
https://mail.okbsd.com
https://okbsd.com
https://www.okbsd.com
# Setup a crontab to run certbot and renew all your certs...
crontab -e
0 2 * * 1 /usr/local/bin/certbot renew --quiet && apachectl restart
#
# We aren't done yet!
#
# Postfix Apache Postfix and Dovecot won't recognize the ServerAlias mail.okbsd.com, so let's fix
# that ...
# If you want to add a second host to your cert do not delete the old one just rerun the command
# with the same --cert-name as shown below ...
# Add a certificate for more than 1 host/domain
certbot --apache --agree-tos --redirect --hsts --staple-ocsp --email \
postmaster@okbsd.com --cert-name mx.okbsd.com -d mx.okbsd.com,mail.okbsd.com
# Certbot gets a little strange with multiple hosts/domains when using the --apache flag because it
# thinks there is multiple Listen 443 tags in apache configuration, and it will throw an error. To
# bypass this change to certonly when doing multiple hosts/domains in one certificate. This is very
# useful if you have 1 mail server with 2 names as mentioned above.
# To host multiple virtual domains with a cert for only 2 hostnames set the MX records in the
# virtual domain(s) to the hostname(s) of the primary mail server.
# Example DNS for domain2.com
MX @ mx.okbsd.com 0
MX @ mail.okbsd.com 10
# Add or update a certificate to add multiple hostnames in one cert
certbot certonly --webroot --agree-tos --redirect --hsts --staple-ocsp --email \
postmaster@okbsd.com --cert-name mx.okbsd.com \
-w /var/www/okbsd/html -d mx.okbsd.com,mail.okbsd.com
# Note that for each domain or hostname set, the path used will be the ones most recently
# specifified by the -w <path> directive.
certbot certonly --webroot --agree-tos --redirect --hsts --staple-ocsp --email \
postmaster@okbsd.com --cert-name mx.okbsd.com \
-w /var/www/okbsd/html -d mx.okbsd.com,mail.okbsd.com \
-w /var/www/domain2 -d mx.domain2.com,mail.domain2.com
# test the mx and mail domain certifcates
https://mx.okbsd.com
https://mail.okbsd.com
# test the regular certificates
https://okbsd.com
https://www.okbsd.com
# Postfix is a popular smtp server and we'll continue with postfix setup on the next page...