Setup Email Server From Scratch On FreeBSD #2 - 02 FAMP Install
01 Server Setup <- Intro -> 03 Postfix SMTPD
We believe in data independence, and support others who want data independence.
This tutorial is partially complete 2025-08-07
This is version 2 and everthing works up to and including Roundcube.
#######################
# FAMP & Posfix 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 update
pkg upgrade
# I have got this working with MariaDB before but the package version of opendmarc
# will try to remove MariaDB and install MySQL, so use the system default for
# compatiblility and simplicity of maintenance.
pkg install mysql80-server mysql80-client ghostscript10 netpbm
sysrc mysql_enable="YES"
service mysql-server start
service mysql-server status
mysql is running as pid 6690.
mysql --version
mysql Ver 8.0.42 for FreeBSD14.2 on amd64 (Source distribution)
mysql
> ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'secretpasswd';
> GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION;
> flush privileges;
> CREATE USER 'admin'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'secretalsouse m';
> GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost';
> flush privileges;
> exit
# Tune mysql server for higher efficiency, 32G memory available with 28 free.
cd /usr/local/etc/mysql
cp my.cnf my.cnf.bak
nano my.cnf
# --- edit or add ---
[mysqld]
...
innodb_buffer_pool_size = 12G
innodb_log_file_size = 1G
max_connections = 500
tmp_table_size = 128M
max_heap_table_size = 128M
sort_buffer_size = 2M
slow_query_log = 1
long_query_time = 1
# skip-name-resolve
lower_case_table_names = 1
character-set-server = utf8mb4
# collation-server = utf8mb4_general_ci
collation_server = utf8mb4_unicode_520_ci
service mysql-server restart
service mysql-server status
# If it doesn't restart check the logs, do not use skip-name-resolve.
tail -f /var/db/mysql/okbsd.com.err
##################
# 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
# These values will affect max attachment size in Roundcube
cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
nano /usr/local/etc/php.ini
# ---
max_execution_time = 600
max_input_time = 300
max_input_vars = 3000
memory_limit = 256M
post_max_size = 400M
upload_max_filesize = 200M
date.timezone = "America/Los_Angeles"
# ---
sysrc php_fpm_enable="YES"
service php_fpm start
service php_fpm status
apachectl restart
sockstat | grep 9000
www php-fpm 29241 8 tcp4 127.0.0.1:9000 *:*
www php-fpm 29240 8 tcp4 127.0.0.1:9000 *:*
root php-fpm 29239 7 tcp4 127.0.0.1:9000 *:*
# Backup Apache configuation.
cd /usr/local/etc/apache24
cp /usr/local/etc/apache24/httpd.conf /usr/local/etc/apache24/httpd.conf.default
cp /usr/local/etc/apache24/httpd.conf /usr/local/etc/apache24/httpd.conf.bak
# Apache Configuration - choose built in php or php-fpm, you do not need both
# Two host definitions in separate locations might yield unexpected results.
# In FreeBSD the httpd.conf set ServerName to 127.0.0.1 and in ssl module options set the vitual host host to
# 127.0.0.1, so these configurations will not be used except for local connections. Or, remove the Virtual Host
# section in /usr/local/etc/apache24/extra/httpd-ssl.conf and define _default_ in an include file.
# Then define real virtual hosts in include files.
nano /usr/local/etc/apache24/httpd.conf
# ---
Listen 80
LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so
LoadModule logio_module libexec/apache24/mod_logio.so
LoadModule proxy_module libexec/apache24/mod_proxy.so
LoadModule proxy_fcgi_module libexec/apache24/mod_proxy_fcgi.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
# For builtin php
# LoadModule php_module libexec/apache24/libphp.so
ServerAdmin postmaster@okbsd.com
ServerName 127.0.0.1
# change your paths to match your server file location
DocumentRoot "/usr/local/www/okbsd/html"
<Directory "/usr/local/www/okbsd/html">
# Options -Indexes -MultiViews +FollowSymLinks
Options -Indexes -MultiViews +SymLinksIfOwnerMatch
<IfModule dir_module>
DirectoryIndex index.php index.html
</IfModule>
# Add a vhost_combined log format to view by virtual hosts %v
<IfModule log_config_module>
...
# LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
...
CustomLog "/var/log/httpd-access.log" vhost_combined
</IfModule>
# If you want to run cgi's enable the following 3 sections and the handler
<IfModule alias_module>
....
# ScriptAlias /cgi-bin/ "/usr/local/www/apache24/cgi-bin/"
ScriptAlias /cgi-bin/ "/var/www/okbsd/cgi-bin/"
</IfModule>
<Directory "/var/www/okbsd/cgi-bin">
AllowOverride None
# Options ExecCGI
Options +ExecCGI -Indexes -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
# If you want cgi support, farther down in the file in mime_module
AAddHandler cgi-script .cgi
# Optional Apache performance tuning, values here are experimental
# and depend on the resources available. These can go after
# ErrorDocument settings
# see mpm config file
# StartServers 40
# MinSpareServers 40
# MaxSpareServers 60
KeepAlive Off
MaxKeepAliveRequests 20
KeepAliveTimeout 5
ServerLimit 512
MaxClients 512
MaxRequestsPerChild 60
# Do enable the following, not so optional.
# Supplemental configuration
...
# Server-pool management (MPM specific)
Include etc/apache24/extra/httpd-mpm.conf
Include etc/apache24/Includes/*.conf
# ---
# Optional Apache mpm fine tuning if more performance is needed, values here are
# experimental and depend on the resources available.
nano /usr/local/etc/apache24/extra/httpd-mpm.conf
# ---
<IfModule mpm_prefork_module>
StartServers 20
MinSpareServers 20
MaxSpareServers 30
MaxRequestWorkers 250
MaxConnectionsPerChild 150
</IfModule>
# ---
# You will need either libphp module or php-fpm module.
nano /usr/local/etc/apache24/modules.d/200_mod-php.conf
# ---
<IfModule dir_module>
DirectoryIndex index.php index.html
<FilesMatch "\.php$">
# libphp module
# SetHandler application/x-httpd-php
# php-fpm module
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>
<FilesMatch "\.phps$">
SetHandler application/x-httpd-php-source
</FilesMatch>
</IfModule>
# ---
# Optional fine tuning for php-fpm only, values here are experimental.
nano /usr/local/etc/php-fpm.d/www.conf
# ---
pm=static
pm.max_children=20
pm.max_requests = 1000
slowlog = /var/log/$pool.log.slow
request_slowlog_timeout = 30
request_terminate_timeout = 600
# ---
service php_fpm restart
# Create website directories and a test php
mkdir -p /usr/local/www/okbsd/html
mkdir -p /usr/local/www/okbsd/mail
echo '<?php print "<!DOCTYPE html lang=\"en\"><html><head><title>Title</title></head><body><h1>Hello World!</h1></body></html>"; ?>' > /usr/local/www/okbsd/html/index.php
echo '<?php phpinfo(); ?>' > /usr/local/www/okbsd/html/info.php
chown root:wheel /usr/local/www
chmod 755 /usr/local/www
chown -R root:www /usr/local/www/okbsd
find /usr/local/www/okbsd -type d -exec chmod 750 {} \;
find /usr/local/www/okbsd -type f -exec chmod 640 {} \;
apachectl configtest
apachectl restart
apachectl status
# Check that Apache and PHP are working.
http://okbsd.com/index.php
http://okbsd.com/info.php
# Create logs executable - an easy wasy to view apache errors
nano ~/bin/logs
# ---
#/bin/sh
clear; echo '' > /var/log/httpd-error.log; tail -f /var/log/httpd-error.log
# ---
chmod 750 ~/bin/logs
# To see errors use the 'logs' command you created in ~/bin,
logs
<refresh your webpage to generate new errors>
<view the errors>
<control-c to exit>
# Configure websites in Apache Configuration - In FreeBSD the default location for website files
# is /usr/local/www/apache24/data but to keep the path short and reduce typing I make a symbolic
# link and use /var/www/sitename/data.
nano /usr/local/etc/apache24/Includes/okbsd.conf
# ---
<VirtualHost _default_:80>
ServerName okbsd.com
ServerAlias www.okbsd.com
ServerAlias 147.135.37.135
ServerAlias [2604:2dc0:200:187::1]
ServerAdmin postmaster@okbsd.com
DirectoryIndex index.php index.html
DocumentRoot /usr/local/www/okbsd/html/
<Directory /usr/local/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# # If you want to run cgi's uncomment these and the handler
ScriptAlias /cgi-bin/ "/usr/local/www/okbsd/cgi-bin/"
<Directory "/usr/local/www/okbsd/cgi-bin">
AllowOverride None
Options +ExecCGI -Indexes -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
</VirtualHost>
# ---
nano /usr/local/etc/apache24/Includes/mail.okbsd.conf
# ---
<VirtualHost *:80>
ServerName mail.okbsd.com
ServerAlias smtp.okbsd.com
ServerAlias imap.okbsd.com
ServerAlias autoconfig.okbsd.com
#ServerAlias autodiscover.okbsd.com
ServerAdmin postmaster@okbsd.com
DirectoryIndex index.php index.html
DocumentRoot /usr/local/www/okbsd/html/
<Directory /usr/local/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Alias /mail "/usr/local/www/okbsd/mail/"
<Directory /usr/local/www/okbsd/mail/>
Options FollowSymLinks
AllowOverride All
Require all granted
</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>
# ---
apachectl configtest
apachectl restart
apachectl statis
# Check that Apache and PHP are working.
http://okbsd.com/index.php
http://okbsd.com/info.php
# Remove the info.php script for security
rm /usr/local/www/okbsd/html/info.php
##########################
# Setup SSL with certbot #
##########################
# Certbot needs a virtual host setup or it won't be able to generate the certificates.
pkg install py311-certbot-apache
# When running certbot you may get a warning ... certs can still be created but
# cron could have problems renewing certs.
Unable to read ssl_module file; not disabling session tickets.
# Add the following symbolic link to hide the warning.
ln -s /usr/local/libexec/apache24 /usr/local/etc/apache24/libexec/apache24
# To simplify management create on certificate with all 5 hostnames. For granular control,
# security, and an insigificant performance increase create separate certs for each service.
# With a combined cert web users can view the alternate imap and smtp hostnames in the cert.
# If this is not desirable create a separate cert for these 2 hosts or 1 cert for each host
# (granualar). Obscurity is not security so balance service separation with easy of management
# with 2 certificates 1) web services# 2) mail and webmail services.
certbot certonly --apache --agree-tos --redirect --hsts --staple-ocsp --email postmaster@okbsd.com --cert-name okbsd.com -d okbsd.com,www.okbsd.com
# Create a certificate for mail services, and mail. web services.
certbot certonly --apache --agree-tos --redirect --hsts --staple-ocsp --email postmaster@okbsd.com --cert-name mail.okbsd.com -d mail.okbsd.com,smtp.okbsd.com,imap.okbsd.com
# Secure private key certificate files.
chown -R root:www /usr/local/etc/letsencrypt/live
find /usr/local/etc/letsencrypt/live -type d -exec chmod 755 {} \;
find /usr/local/etc/letsencrypt/live -type f -exec chmod 644 {} \;
chown -R root:www /usr/local/etc/letsencrypt/archive
find /usr/local/etc/letsencrypt/archive -type d -exec chmod 755 {} \;
find /usr/local/etc/letsencrypt/archive -type f -exec chmod 644 {} \;
chmod o-rwx /usr/local/etc/letsencrypt/archive/*/privkey*.pem
# Setup a crontab to run certbot and renew all your certs...
crontab -e
0 2 * * 1 /usr/local/bin/certbot renew --quiet && apachectl restart
# To list certificates
certbot certificates
# To revoke and delete certificates
certbot revoke --cert-name <certname>
certbot delete --cert-name <certname>
# If you leave out 'certonly', certbot may modify your configuration files and add ssl
# configuration files based on the non-ssl configuration. Generally it is better to use
# 'certonly' and manage your own settings. Certbot without 'certonly' adds Rewrite rules
# to okbsd.conf to redirect all non ssl requests to ssl and adds includes to httpd.conf.
# Enable Apache SSL/HTTPS
nano /usr/local/etc/apache24/httpd.conf
# ---
# Secure (SSL/TLS) connections
Include etc/apache24/extra/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.bak
nano /usr/local/etc/apache24/extra/httpd-ssl.conf
# ---
SSLRandomSeed startup file:/dev/urandom 512
SSLRandomSeed connect file:/dev/urandom 512
...
<VirtualHost 127.0.0.1:443>
DocumentRoot "/usr/local/www/okbsd/html"
ServerName okbsd.com:443
ServerAdmin postmaster@okbsd.com
ErrorLog "/var/log/httpd-error.log"
TransferLog "/var/log/httpd-access.log"
SSLCertificateFile /usr/local/etc/letsencrypt/live/okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/okbsd.com/privkey.pem
...
CustomLog "/var/log/httpd-ssl_request.log" \
"%v:%p %h %l %u %t %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
# ---
/usr/local/etc/apache24/Includes/ssl-okbsd.conf
# ---
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost _default_:443>
ServerName okbsd.com
ServerAlias www.okbsd.com
ServerAlias 147.135.37.135
ServerAlias [2604:2dc0:200:187::1]
ServerAdmin postmaster@okbsd.com
TransferLog "/var/log/httpd-access.log"
CustomLog "/var/log/httpd-ssl_request.log" \
"%v:%p %h %l %u %t %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
DirectoryIndex index.php index.html
DocumentRoot /usr/local/www/okbsd/html/
<Directory /usr/local/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# If you want to run cgi's uncomment these and the handler
ScriptAlias /cgi-bin/ "/usr/local/www/okbsd/cgi-bin/"
<Directory "/usr/local/www/okbsd/cgi-bin">
AllowOverride None
Options +ExecCGI -Indexes -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
Include /usr/local/etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /usr/local/etc/letsencrypt/live/okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/okbsd.com/privkey.pem
Header always set Strict-Transport-Security "max-age=31536000"
</VirtualHost>
</IfModule>
nano /usr/local/etc/apache24/Includes/ssl-mail.okbsd.conf
# ---
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
<VirtualHost *:443>
ServerName mail.okbsd.com
#ServerAlias smtp.okbsd.com
#ServerAlias imap.okbsd.com
#ServerAlias autoconfig.okbsd.com
#ServerAlias autodiscover.okbsd.com
ServerAdmin postmaster@okbsd.com
DirectoryIndex index.php index.html
DocumentRoot /usr/local/www/okbsd/html/
<Directory /usr/local/www/okbsd/html/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Alias /mail "/usr/local/www/okbsd/mail/"
<Directory /usr/local/www/okbsd/mail/>
Options FollowSymLinks
AllowOverride All
Require all granted
</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]
Include /usr/local/etc/letsencrypt/options-ssl-apache.conf
Header always set Strict-Transport-Security "max-age=31536000"
SSLUseStapling on
SSLCertificateFile /usr/local/etc/letsencrypt/live/mail.okbsd.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/mail.okbsd.com/privkey.pem
</VirtualHost>
</IfModule>
apachectl configtest
apachectl restart
# test it
https://okbsd.com
https://www.okbsd.com
https://mail.okbsd.com
# Postfix is a popular smtp server and we'll continue with postfix setup on the next page...