In this series, I’ll use an exploration of Bastille to explain some basic functionality of FreeBSD. This article starts with perhaps the most structurally fundamental part of FreeBSD, the /usr/local/ directory.
Unlike most of my FreeBSD/Raspberry Pi articles, this one doesn’t have any real tangible outcome other than learning. As I mentioned in the initial post of this series, I’m a novice writing this series to both educate myself and other novices interested in learning FreeBSD. While tinkering with Bastille and figuring out how it worked, I realized following that thread helped to illuminate the BSD basics. Especially if (like me) you came from Linux (and may, like me, have done things without understanding the underlying mechanisms), dissecting these fundamentals can be helpful to utilize the advantages FreeBSD has to offer.
The initial problem I faced was that my I wanted to keep my jails on my external storage—a ZFS mirror—while my operating system itself ran off an SD card using UFS. Check out my articles regarding that setup if you want to understand this choice. A default Bastille install would install the jails on the SD card because that’s where the operating system lives. Of course, I broke things when trying to configure this setup, which led to my analysis of Bastille. Fortunately, Bastille is just a bunch of shell scripts which are simple enough to illuminate the FreeBSD basics to a layman.
FreeBSD Basics: /usr/local/
The first thing I used FreeBSD for was as an Apache web server. It seemed to work the same as on Linux but instead of sticking the config files in /etc/apache2/ or /etc/httpd/ they were in /usr/local/etc/apache2/. And instead of keeping the public files in /var/www/ they were in /usr/local/www/. Admittedly, I found this annoying because the further nested files required more typing.
After learning more about FreeBSD, this setup not only makes sense, but it also illustrates a key advantage of FreeBSD over Linux. Here is /usr/local/ on my FreeBSD Raspberry Pi:
root@beastie:/usr/local # ls bastille include libexec sbin bin lib man share etc libdata openssl
Two folders, bastille and openssl, were not part of the original installation. Now let’s look at /usr/local/ on Manjaro Linux:
sharp@macbook ~ ls /usr/local/ ✔ bin etc games include lib man sbin share src
Hey! Looks pretty similar, right? Let’s dig a bit deeper, and check out etc on FreeBSD:
root@beastie:/usr/local/etc # ls bash_completion.d papersize.a4 pkg.conf.sample bastille papersize.letter rc.d git periodic ssl man.d pkg.conf wireguard
We see some configuration files for various applications I have installed. Notably, for this series, we see Bastille. Now let’s check out /usr/local/etc/ on my Majaro Laptop:
sharp@macbook /usr/local/etc ~ ls ✔ sharp@macbook /usr/local/etc ~ ✔
Nada, and I have way more software installed on this machine than the Pi with FreeBSD (I could do this same example with bin or any other folder in /usr/local/ and gotten the same result). All those etc configuration files on Linux would appear in /etc/, where all the system configuration files are found. Why? Because in Linux distributions there is no system.
Why Does /usr/local/ Matter?
In FreeBSD, you install an operating system. Everything except for /usr/local/ is the operating system. Is much of the operating system composed of individual programs that can (and do) run independently from the OS? Sure. But in FreeBSD I have the base system isolated from everything I installed after the operating system itself. This has important implications for updates/upgrades, application installation/removal, and how the user can safely interact with the system. I know that I can safely tweak any file in /usr/local/etc/ and I won’t break the system. It might break an application, but I won’t break the system.
The same thing applies to other folders. For example, /usr/bin contains programs that are consider “base” FreeBSD programs while /usr/local/bin contains applications installed by the user. This means you can safely delete anything in /usr/local/bin and you know that anything in that folder was installed by you.
In Linux, there is no system. Or, perhaps more accurately, there are thousands of different systems and each distro is a unique one. Linux is just a kernel, and for the many systems to run on top of it and still be compatible, it still uses the traditional Unix folder structure but every application functions like a system application. Why? Because the default software that comprises the system is highly variable from distribution to distribution. SSH might be a default application on one system and not another.
In a way, this highlights a neat modular nature of Linux. Unfortunately, it makes things confusing for the user. A typical Linux /etc/ folder will have literally hundreds of configuration files of varying importance. Even more messy is /lib/, which holds language libraries, kernel modules, and drivers. If things are working smoothly, you won’t have to deal with it, but if you’re encountering dependency issues good luck distinguishing between an essential C library and something an application installed. On FreeBSD, applications will install these files in /usr/local/lib/.
Personally, I do not know why Linux systems ship with the /usr/local/ folder intact but they don’t seem to use it. My best guess is that there are still some applications out there that will install to these folders. It might be true that it exists for POSIX compatibility, which some Linux distros pay for.
Where is Bastille?
Above you can see that Bastille installed a folder in /usr/local/ but this is not everything it installed. Notably, everything it installed is nested somewhere in /usr/local/:
root@beastie:/ # find /usr/local/ -name bastille /usr/local/share/bastille /usr/local/etc/rc.d/bastille /usr/local/etc/bastille /usr/local/bin/bastille /usr/local/bastille
I only searched the /usr/local/ folder because otherwise the results would show my jails on the external drive and results from the ports (/usr/ports/), but other than the jails I manually configured to install on the external drive everything is in /usr/local/. Under the default configuration, jails, cache, backups, releases, and templates are stored in the /usr/local/bastille/ folder.
Looking at the other directories and why those files appear there will be the topic of a future article. I’ll start with the configuration file and trace my way through the references in the Bastille scripts to explain the purposes of these directories.
Did I miss anything? Get something wrong? I probably did—I’m not an expert. I’m doing this to help others learn with me. If you see something that needs corrected, please shoot me an e-mail.