Why We Use Freebsd


I am often asked why we like to use FreeBSD so much. Sometimes I catch myself giving very detailed and theoretical answers. Since that isn’t always the clearest way, here is a practical example.

A Single Sign-On (SSO) solution was to be created for various applications. The components used are:

  • Keycloak
  • PostgreSQL for Keycloak
  • OAuth2-Proxy for applications that don’t support OAuth2 / OIDC.
  • A custom web application that provides an overview of all offered applications (Spring Boot, Java).
  • nginx as a reverse proxy

Five different services. In our setup, each service runs in its own jail. The jails are managed with BastilleBSD, a very lightweight jail manager. We use so-called thin jails: they share a common base system, so a typical installation only consumes storage for the installed packages (keycloak, postgres, etc.):

❯ sudo bastille create -V oauth2-proxy-1 14.2-RELEASE 10.20.30.1/24
❯ sudo pkg -j oauth2-proxy-1 install oauth2-proxy
❯ zfs list zroot/bastille/jails/oauth2-proxy-1/root
NAME                                       USED  AVAIL  REFER  MOUNTPOINT
zroot/bastille/jails/oauth2-proxy-1/root   248M  7.01G   248M  /srv/jails/oauth2-proxy-1/root

Lean, isn’t it?

This solution is possible because FreeBSD clearly separates the base system from additionally installed packages.

Regular snapshots are created of each jail. Thanks to ZFS, these snapshots are created lightning fast and use very little storage. Creation and management is done via ZFS autobackup with the basic rule 1h1d,1d1w.

These snapshots lead to extremely easy administration: for example, if an error occurs during an update of a jail, you can act very quickly:

do-something-stupid
❯ sudo do-something-stupid
❯ zfs list -t snapshot zroot/bastille/jails/oauth2-proxy-1/root
...
❯ sudo bastille stop oauth2-proxy-1
❯ sudo zfs rollback -r zroot/bastille/jails/oauth2-proxy-1/root@localsnap-20250402070000
❯ sudo bastille start oauth2-proxy-1

Besides being very lean and pleasant to configure, the jails have other advantages:

  • They can be easily copied. For example, this project requires multiple instances of OAuth2-Proxy. These are simply created via
    sudo bastille clone --live oauth2-proxy-1 oauth2-proxy-2 10.20.30.2
  • The processes are cleanly separated from each other. An attacker in one jail has no access to the host or any other jail.

By default, no service is exposed externally; all bind to their local address:

❯ sockstat -4 -l | grep oauth2-pro
www      oauth2-pro  9590 7   tcp4   10.20.30.1:4180     *:*
...

To connect nginx with the outside world, a simple command is enough:

❯ sudo bastille rdr nginx tcp 443 443

nginx itself acts as a reverse proxy and forwards the requests to the desired applications or jails.

I’m happy to provide more details on request.