Create a FreeBSD web server (FAMP stack)
FAMP stack? That’s FreeBSD + Apache + MariaDB + PHP.
Here’s the steps necessary to build an Apache web server with MariaDB on FreeBSD.
Before we begin:
- This guide is meant to supplement, but not override, the FreeBSD handbook, which should be considered the canonical documentation source for FreeBSD.
- This guide was written in January 2023 and applies to FreeBSD 12 and 13. If you found this guide from the future, please be aware these instructions may be outdated.
- This guide assumes you have some basic experience with Linux/BSD servers.
Table of contents
- Find hosting and provision an instance
- Set up the machine
- Simplify outbound email handling
- Install a web server (Apache + PHP)
- Install a database server (MariaDB)
- Final steps
- Tips and tricks
Step 1. Find hosting and provision an instance
You can create FreeBSD instances on:
- AWS Lightsail
- AWS EC2
- Vultr
FreeBSD is also supported on Linode and DigitalOcean, but requires some extra steps in order to get an instance up and running.
Choose a provider and build an instance. If you’re not sure what size to get, start small. A $5/mo AWS Lightsail instance (1 GB memory, 1 core CPU, 40 GB SSD) is more than sufficient to host several small WordPress sites. Static content caching will reduce load on the server and a CDN will reduce I/O load even further.
Step 2. Set up the machine
Update the system
Once the machine is provisioned, log in as root
and update the system.
First, update the FreeBSD core.
# freebsd-update fetch install
Then, update the non-core software packages.
# pkg update
# pkg upgrade
Set the timezone
# tzsetup
Install some useful applications
# pkg install sudo wget git bash bash-completion tmux htop ncdu lsblk p5-ack
Helpful hint: Be careful when installing vim
. Sometimes you might accidentally choose the X11 graphical version, which will load a ton of packages that you don't need (and don't want) running on a web server. If you run this command and see the total install size is over 15 MB and includes dozens of packages (like gtk3
, wayland
, adwaita-icon-theme
, or lots of libX___
packages) you're probably installing the wrong one.
# pkg install vim
Set up sudo access
Allow users in the wheel
group to use sudo
. Run visudo
and uncomment the following line:
%wheel ALL=(ALL) ALL
Set the hostname
Verify that your hostname looks appropriate.
# hostname
If you need to change it, edit /etc/rc.conf
and modify the hostname=""
line. Then, run sudo hostname [your-hostname]
to update the hostname without rebooting. Validate your work again by running hostname
.
Create a swapfile
Some VPS’s don’t create swapfiles when the instances are provisioned. It’s a good idea to create one, even a small one (512-1,024 MB).
First, create the swapfile and set permissions on it.
# dd if=/dev/zero of=/usr/swap0 bs=1m count=512
# chmod 600 /usr/swap0
Then, edit /etc/fstab
and add this line:
md99 none swap sw,file=/usr/swap0,late 0 0
Next, activate the swapfile with:
# swapon -aL
Create your non-root user account
Create a user account for yourself.
# adduser
You’ll need to answer a dozen or so questions during this process. Simply press [Enter]
unless you’re at one of these prompts:
- Select a username (should be all lowercase, no symbols or spaces).
- Provide the user’s full name.
- Invite the user into the
wheel
group so they can usesudo
. - Choose
bash
if you want. - Provide a password, and enter it twice to make sure it’s entered correctly.
- Review the entries.
- Stop adding users if you’re done.
The process will look like this:
Username: btorres <--- (1)
Full name: B'Elanna Torres <--- (2)
Uid (Leave empty for default):
Login group [btorres]:
Login group is btorres. Invite btorres into other groups? []: wheel <--- (3)
Login class [default]:
Shell (sh csh tcsh bash rbash git-shell nologin) [sh]: <--- (4)
Home directory [/home/btorres]:
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]:
Use an empty password? (yes/no) [no]:
Use a random password? (yes/no) [no]:
Enter password: <--- (5)
Enter password again: <--- (5)
Lock out the account after creation? [no]:
Username : btorres
Password : *****
Full Name : B'Elanna Torres
Uid : 1002
Class :
Groups : btorres wheel
Home : /home/btorres
Home Mode :
Shell : /bin/sh
Locked : no
OK? (yes/no): yes <--- (6)
adduser: INFO: Successfully added (btorres) to the user database.
Add another user? (yes/no): no <--- (7)
Goodbye!
If you want to change an existing user’s shell to bash
:
# chsh -s /usr/local/bin/bash [username]
And then add this to the bottom of ~/.profile
so that the system will parse ~/.bashrc
on login:
# Load .bashrc on login
if [[ $- == *i* && -f ~/.bashrc ]]; then
. ~/.bashrc
fi
Important note: Do not change root's shell (or the ec2-user
's if on AWS).
Since FreeBSD separates the base operating system from third-party packages and ports, non-base shells are installed to /usr/local/bin
, a location that might not be mountable at boot time with a damaged system.
It's also possible that the system could enter a state where bash
can't run for any number of reasons (during OS upgrades, botched package updates, etc.).
If you change root's (or AWS's ec2-user
's) shell away from the default, you risk being unable to log in to the system with no way to correct the problem. So, don't change those user's shells.
Set up SSH
Ensure you’re familar with and are using SSH key-based authentication.
Switch to your new user account.
# su [username]
Add your SSH public keys to ~/.ssh/authorized_keys
, then lock down that file’s permissions. That file might not exist for new users, so you’ll need to create it.
$ vim ~/.ssh/authorized_keys
(paste in your public keys)
(save and quit)
$ chmod 600 ~/.ssh/authorized_keys
Log out as your user and return to root with:
exit
Step 3. Simplify outbound email handling
FreeBSD comes with a feature-rich inbound/outbound email system via sendmail
. It’s too complex for most server installs that only need to send outbound emails (such as system alerts, cron job results, password reset emails via PHP, etc.).
We’ll replace sendmail
with the lightweight, outbound-only ssmtp
.
Disable sendmail
Edit /etc/rc.conf
and add this to the bottom:
# Disable sendmail (we're using ssmtp)
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
Then, stop the running sendmail
service with:
service sendmail stop
Install ssmtp
Follow these steps to install ssmtp
.
Step 4. Install a web server (Apache + PHP)
We’ll use Apache here, but there are several other web servers you could choose, including Nginx or Lighttpd.
Install Apache
Find and install the latest version of Apache.
# pkg search apache | grep -i server
apache-solr-8.11.2 High performance search server built using Lucene Java
apache24-2.4.54 Version 2.4.x of Apache web server <---
p5-Apache-ASP-2.63 Active Server Pages for Apache
p5-Apache-Config-Preproc-1.07 Preprocess Apache server configuration files
p5-Apache-Solr-1.07 High level interface to the Solr server
p5-Apache2-SOAP-0.73_4 Apache2 mod_perl2 SOAP Server
p5-Config-ApacheFormat-1.2_2 Parse a configuration file in the same syntax as the Apache...
# pkg install apache24
Ping your hostname and ensure that it resolves to the machine’s IP address. If you need to make changes, check either /etc/nsswitch.conf
or /etc/hosts
.
# ping [hostname]
Enable Apache at boot:
# sysrc apache24_enable="YES"
Configure Apache
Edit the following configuration files:
/usr/local/etc/apache24/httpd.conf
- Make a backup copy of this file
- Set
ServerName
to either a FQDN or the server’s IP address - Uncomment these lines:
Include etc/apache24/extra/httpd-ssl.conf
Include etc/apache24/extra/httpd-mpm.conf
# Uncomment any modules you want to enable
LoadModule authn_socache_module libexec/apache24/mod_authn_socache.so
LoadModule socache_shmcb_module libexec/apache24/mod_socache_shmcb.so
LoadModule ssl_module libexec/apache24/mod_ssl.so
LoadModule deflate_module libexec/apache24/mod_deflate.so
LoadModule expires_module libexec/apache24/mod_expires.so
LoadModule headers_module libexec/apache24/mod_headers.so
LoadModule speling_module libexec/apache24/mod_speling.so
LoadModule alias_module libexec/apache24/mod_alias.so
LoadModule rewrite_module libexec/apache24/mod_rewrite.so
/usr/local/etc/apache24/extra/httpd-ssl.conf
- Make a backup copy of this file
- Comment out line
Listen 443
- Remove the default SSL virtualhost example at the bottom of the file. (Hint: it starts with
<VirtualHost _default_:443>
and continues for about 170 lines until the closing</VirtualHost>
. Remove all of those lines.) - Add these lines (and follow the link in your web browser, ensure the protocols listed below are still up-to-date):
# These are the recommendations as of 2023-01.
# Review in the future to make sure they're still recommended.
# https://docs.freebsd.org/en/books/handbook/network-servers/#_ssl_support
SSLProtocol all -SSLv3 -SSLv2 +TLSv1.2 +TLSv1.3
SSLProxyProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
Later, you’ll add your virtualhost files and other common configs to /usr/local/etc/apache24/Includes/
.
Validate the configuration
Let’s ensure our configuration files are set up properly. Run:
# apachectl -t
Later, if Apache is running and you want to validate the configuration files, run:
# service apache24 configtest
If you get the “Could not reliably determine the server’s fully qualified domain name” error, try adding a ServerName
parameter in /usr/local/etc/apache24/httpd.conf
If no errors, start Apache:
# service apache24 start
Browse to the machine’s IP address (or hostname) and make sure you see the Apache “It works!” message. If you don’t see anything, ensure that Apache is running, and monitor /var/log/httpd-error.log
and /var/log/httpd-apache.log
for hints that can help you identify problems.
If you’re stuck, perhaps there’s some misconfiguration somewhere. Apache’s default configuration file pathway is, in order:
/usr/local/etc/apache24/httpd.conf
/usr/local/etc/apache24/extra/httpd-mpm.conf
/usr/local/etc/apache24/extra/proxy-html.conf
/usr/local/etc/apache24/extra/httpd-ssl.conf
/usr/local/etc/apache24/Include/*.conf
Add PHP support to Apache
Find the latest versions of PHP:
# pkg search php | grep -i scripting
drush-php74-8.4.11 Drupal command line and scripting interface
drush-php80-8.4.11 Drupal command line and scripting interface
drush-php81-8.4.11 Drupal command line and scripting interface
drush-php82-8.4.11 Drupal command line and scripting interface
mod_php74-7.4.32_1 PHP Scripting Language
mod_php80-8.0.25 PHP Scripting Language
mod_php81-8.1.12 PHP Scripting Language (8.1.X branch)
mod_php82-8.2.0.r2_1 PHP Scripting Language (8.2.X branch)
php74-7.4.32 PHP Scripting Language
php80-8.0.25 PHP Scripting Language <---
php81-8.1.12 PHP Scripting Language (8.1.X branch) <---
php82-8.2.0.r2 PHP Scripting Language (8.2.X branch) <---
Install PHP and related packages:
# pkg install php80 mod_php80 php80-mysqli php80-pdo
# For WordPress support, also install:
# pkg install php80-{curl,dom,exif,fileinfo,filter,gd,iconv,mbstring,phar,simplexml,sodium,xml,xmlreader,zip,zlib}
Put a php.ini
file into place.
FreeBSD’s PHP doesn’t come with a php.ini
file. There are two templates provided, one for production machines, and one for development machines. You’ll need to select one to start with and then customize from there.
The development template has settings that reduce or eliminate OPcode caching, so code changes will be visible immediately, at the expense of page rendering speed.
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
-- OR --
# cp /usr/local/etc/php.ini-development /usr/local/etc/php.ini
Edit /usr/local/etc/php.ini
and ensure this is set:
cgi.fix_pathinfo=0
Backup the php-fpm config file, then edit it:
# cp /usr/local/etc/php-fpm.d/www.conf{,.orig}
# vim /usr/local/etc/php-fpm.d/www.conf
Ensure [user] and [group] are = www
Update Apache to look for and execute index.php
files by editing /usr/local/etc/apache24/httpd.conf
and adding index.php
to DirectoryIndex
, like so:
DirectoryIndex index.php index.html index.htm
Next, connect Apache with PHP by editing (or creating) /usr/local/etc/apache24/Includes/php.conf
:
<FilesMatch "\.php$">
SetHandler application/x-httpd-php
</FilesMatch>
<FilesMatch "\.phps$">
SetHandler application/x-httpd-php-source
</FilesMatch>
Enable PHP at boot:
# sysrc php_fpm_enable=YES
Create a demo page to show that PHP is working at /usr/local/www/apache24/data/index.php
and put in these contents:
<html><body>
<?php phpinfo(); ?>
</body></html>
Then, start PHP:
# service php-fpm start
Browse to your web server’s hostname or IP address and you should see a long PHP information page.
If you don’t see anything, or if you get any errors, monitor /var/log/php-fpm.log
for hints that can help you identify problems. Also, check the Apache log files /var/log/httpd-error.log
and /var/log/httpd-apache.log
for clues.
Install a database server (MariaDB)
Find the latest version of MariaDB, then install it.
# pkg search mariadb | grep -i server
mariadb103-server-10.3.37 Multithreaded SQL database (server)
mariadb104-server-10.4.27 Multithreaded SQL database (server)
mariadb105-server-10.5.18 Multithreaded SQL database (server)
mariadb106-server-10.6.11 Multithreaded SQL database (server) <---
# pkg install mariadb106-server
Set MariaDB to start at boot and start the service.
# sysrc mysql_enable=YES
# service mysql-server start
Secure the installation
# /usr/local/bin/mysql_secure_installation
When prompted:
- Do not provide a root password, just press
[Enter]
- Use Unix socket authentication
- Remove test users and databases
- Prevent remote login
- Flush the tables to save settings
Validate that the server is running
# mysql
You should see the MySQL prompt. Type exit
to quit.
Helpful hint: Sometimes applications will complain they can't connect to the database instance on the local machine via localhost
. If that's the case, try using 127.0.0.1
, and if that fails, try whatever localhost
is defined as in /usr/local/etc/mysql/my.cnf
:
localhost:/var/run/mysql/mysql.sock
Final steps
After every server setup is complete, you should restart the system to make sure all systems come back online as expected.
Log in as your non-root user and try some sudo
commands to ensure you can escalate permissions when needed.
Tips and tricks
Silence the login tips and tricks (fortunes)
Edit ~/.profile
and comment out the line with /usr/bin/fortune
.
To completely silence the rest of the login messages, add a blank file named ~/.hushlogin
.
Disable the daily system email reports
The server will send you daily reports with system statuses and security reports. Instead of cluttering up your inbox, let’s send the reports to files instead.
First, create a folder to store the files:
sudo mkdir /var/log/periodic
Then, edit /etc/periodic.conf
and add these lines to the bottom of the file:
# Instead of spamming yourself with daily email reports,
# output the results of these reports to a file.
# daily_output="root"
daily_output="/var/log/periodic/$(date +%Y%m%d)-daily.log"
# daily_status_security_output="root"
daily_status_security_output="/var/log/periodic/$(date +%Y%m%d)-daily-security.log"
# weekly_output="root"
weekly_output="/var/log/periodic/$(date +%Y%m%d)-weekly.log"
# weekly_status_security_output="root"
weekly_status_security_output="/var/log/periodic/$(date +%Y%m%d)-weekly-security.log"
# monthly_output="root"
monthly_output="/var/log/periodic/$(date +%Y%m%d)-monthly.log"
# monthly_status_security_output="root"
monthly_status_security_output="/var/log/periodic/$(date +%Y%m%d)-monthly-security.log"
Enable locate
locate
lets you quickly find files on your machine. It’s installed by default, but unusuble until you prime the database:
/etc/periodic/weekly/310.locate
To automatically refresh the database weekly:
sudo sysrc weekly_locate_enable="YES"
Then, you can quickly find any file on your machine with:
$ locate rc.conf
/etc/defaults/rc.conf
/etc/rc.conf
/etc/rc.conf.d
/usr/share/examples/jails/rc.conf.jails
/usr/share/man/man5/rc.conf.5.gz
/usr/share/man/man5/rc.conf.local.5.gz
/usr/share/man/man5/src.conf.5.gz
/var/db/etcupdate/current/etc/defaults/rc.conf
Since the database is only updated weekly, you might want to re-prime it after installing new software or making big changes to the system. Simply run the first command above to re-prime the database and scan your filesystem for new files.