/ Raspberry PI

Setup a complete FreeBSD server environment on your Raspberry PI

Disclaimer :

The Raspberry PI is a such a great device. You can do a really huge amount of fun things with this little board...
The goal of this paper is to show how you can build a full personnal server on your Raspberry PI, using FreeBSD and it's packages.
Of course, this paper is useful for the other platforms running on FreeBSD too !
Here's how we'll proceed :

  1. Get FreeBSD
  2. Configure FreeBSD
  3. Install and configure sudo
  4. Configure your Wifi with a static IPv4 and IPv6 address
  5. Install and start Packet Filter
  6. Install and configure nginx with "let's encrypt" SSL / PHP / MySQL
  7. Install and configure OpenSMTPd and SPAMd
  8. Install and configure Netdata with nginx to monitor your system
  9. Avoid OS detection
  10. Need help ?

Get FreeBSD :

FreeBSD Logo

FreeBSD 11.1 is released, so I decided to download and install the FreeBSD 11.1 image for my Raspberry PI 2 here : ftp://ftp.freebsd.org/pub/FreeBSD/releases/arm/armv6/ISO-IMAGES/11.1/FreeBSD-11.1-RELEASE-arm-armv6-RPI2.img.xz

Uncompress the file :

# xz -d FreeBSD-11.1-RELEASE-arm-armv6-RPI2.img.xz

Write the image file on your SD device (replace XXXX with the name of your device) :

# dd if=FreeBSD-11.1-RELEASE-arm-armv6-RPI2.img of=/dev/XXXX bs=1m

For Windows users you can use this tool.

Configure FreeBSD :

Time to setup everything we need to feel comfortable with...

It's time to boot your system !

First of all login to the root account :

Login : root
Password : root

Change your password :

# passwd

Delete the freebsd user :

# rmuser freebsd

Create your own user and put him in the wheel group :

# adduser 
Invite xxxx into other groups? wheel

Increase the kern.maxfiles value :

# vi /boot/loader.conf

Change the name of your server :

# vi /etc/rc.conf

Setup UTF-8 for your users :

# vi /etc/login.conf

Change your localtime if needed, synchronize the time and start ntpd at system startup :

As I am in France, you may want to change the localtime file and the ntp server too.

 # cp /usr/share/zoneinfo/Europe/Paris /etc/localtime
 # ntpdate ntp.nerim.net
 # sysrc ntpd_enable="YES"

Prepare fstab for SPAMd :

# vi /etc/fstab
fdescfs /dev/fd fdescfs rw 0 0

Install and configure sudo :

This step is just in the case you want to run your commands as an user for more security.

# pkg install sudo
# vi /usr/local/etc/sudoers
%wheel ALL=(ALL) ALL

Configure your Wifi with a static IPv4 and IPv6 adress :


You'll tell me, why would you use Wifi for a server ? It's just that I love the idea of being able to hide my little server where I want in my house...

Edit your loader.conf file :

# vi /boot/loader.conf

Edit your rc.conf file :

# vi /etc/rc.conf
ifconfig_wlan0="WPA inet netmask"

Edit your wpa_supplicant file :

# vi /etc/wpa_supplicant.conf

Set your nameserver

# vi /etc/resolv.conf

Ok now you can reboot and check if everything is ok :

# shutdown -r now

Install and start Packet Filter :

Let's build our powerfull firewall !

By default, PacketFilter is not included, so we'll have to download the kernel sources and build them :

# pkg install subversion 
# cd /usr/src && svn co svn://svn.freebsd.org/base/releng/11.1/ /usr/src
# vi /usr/src/sys/arm/conf/RPI2

You have to add the two following lines :

device pf 
device pflog

Now let's build and install our new kernel :

# cd /usr/src 
# make buildkernel KERNCONF=RPI2 
# make installkernel KERNCONF=RPI2

Enable PacketFilter at system startup :

# vi /etc/rc.conf 

Reboot your system :

# shutdown -r now

Install and configure nginx with let's encrypt SSL / MySQL :

nginx logo

All the web components we need !

Install the let's encrypt tool :

# pkg install py27-certbot

Time to create your SSL certificates :

# certbot certonly --standalone -d blog.cagedmonster.net -d mail.cagedmonster.net -d stats.cagedmonster.net

Install nginx and enable the service at system startup :

# pkg install nginx
# sysrc nginx_enable=YES

Install MySQL and enable the service at system startup :

# pkg install mysql80-server
# sysrc mysql_enable=yes
# service mysql-server start
# mysql_secure_installation 
Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?

Press y|Y for Yes, any other key for No: y

There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary                  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 2
Please set the password for root here.

New password:

Re-enter new password:

Estimated strength of the password: 100
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y

Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
- Dropping test database...

- Removing privileges on test database...

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y

All done!

Install php with mysql support (I don't recommend using PHP-7.x for now) :

# pkg install php56-mysqli-5.6.31
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini 
# sysrc php_fpm_enable=yes
# vi /usr/local/etc/php-fpm.conf
user = www
group = www
listen = /tmp/php-fpm.sock
listen.owner = www
listen.group = www
listen.mode = 0660
# service php-fpm start

Configure strong SSL for nginx, our goal is to be rated at least "A" on ssllabs :

# cd /etc/ssl/
# openssl dhparam -out dhparams.pem 4096
# vi /usr/local/etc/nginx/ssl.conf
ssl_prefer_server_ciphers on;
ssl_certificate /usr/local/etc/letsencrypt/live/<yourdomain>/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/<yourdomain>/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_dhparam /etc/ssl/dhparams.pem;
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000;includeSubdomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

Configure nginx with an automated redirection from "http" to "https" :

Of course, with http2 and IPv6....

# vi /usr/local/etc/nginx/nginx.conf
server {
   listen 80;
   listen         [::]:80;
   server_name    blog.cagedmonster.net;
   return         301 https://$server_name$request_uri;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name  blog.cagedmonster.net;
    root /usr/local/www/nginx/;
    index index.php;
    include ssl.conf;
    location ~ \.php$ {
            try_files $uri =404;
            fastcgi_pass unix:/tmp/php-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            fastcgi_read_timeout 600;

Start nginx :

# service nginx start

Install and configure OpenSMTPD and SPAMD


Install and enable OpenSMTPD at system startup :

# pkg install opensmtpd
# sysrc smtpd_enable=YES

Say "byebye" to Sendmail :

# vi /etc/mail/mailer.conf

sendmail        /usr/local/sbin/smtpctl
send-mail       /usr/local/sbin/smtpctl
mailq           /usr/local/sbin/smtpctl
makemap         /usr/local/libexec/opensmtpd/makemap
newaliases      /usr/local/libexec/opensmtpd/makemap

Configure the service with SSL and with delivery in the user's local mailbox :

# vi /usr/local/etc/mail/smtpd.conf
pki mail.cagedmonster.net certificate "/usr/local/etc/letsencrypt/live/<yourdomain>/fullchain.pem"
pki mail.cagedmonster.net key "/usr/local/etc/letsencrypt/live/<yourdomain>/privkey.pem"

listen on lo0
listen on wlan0 port 25 tls pki mail.cagedmonster.net

table aliases file:/etc/mail/aliases

accept from any for domain "cagedmonster.net" alias <aliases> deliver to mbox
accept for local alias <aliases> deliver to mbox

accept from local for any relay

Fix the certificates permissions (because OpenSMTPD requires it) and start the service :

# chmod 600 /usr/local/etc/letsencrypt/live/<yourdomain>/fullchain.pem && chmod 600 /usr/local/etc/letsencrypt/live/<yourdomain>/privkey.pem
# service smtpd start

Install spamd and enable the service at system startup :

# pkg install spamd
# sysrc obspamd_enable=YES
# sysrc obspamlogd_enable=YES

Configure and start spamd :

# cp /usr/local/etc/spamd/spamd.conf.sample /usr/local/etc/spamd/spamd.conf
# vi /etc/pf.conf
table <spamd-white> persist
no rdr inet proto tcp from <spamd-white> to any \
port smtp
rdr pass inet proto tcp from any to any \
port smtp -> port spamd
# pfctl -f /etc/pf.conf
# service obspamd start
# service obspamlogd start

Install and configure NetData with nginx :

Netdata is a great monitoring solution, easy to install, easy to use...

Install / enable netdata at system startup and launch it :

# pkg install netdata
# sysrc netdata_enable=YES
# vi /usr/local/etc/netdata/netdata.conf
bind to =
# service netdata start

Your service will run by defaut at :, we'll use nginx to have an access limited to our network :

# vi /usr/local/etc/nginx/nginx.conf
server {
   listen 80;
   listen         [::]:80;
   server_name    stats.cagedmonster.net;
   return         301 https://$server_name$request_uri;

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name  stats.cagedmonster.net;
    include ssl.conf;
    location / {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_pass_request_headers on;
    proxy_set_header Connection "keep-alive";
    proxy_store off;
    allow   2a01:cb06:3e0:eb00::/56;
    deny    all;

Restart nginx :

# service nginx restart

Avoid OS detection :

FreeBSD kernel has got a special option, TCP_DROP_SYNFIN, which actually drops all packets with the SYN and FIN flags activated.

# vi /etc/sysctl.conf
# shutdown -r

Need help ?