We have come across some of my preferred customisations. In this article, I explain how the files are being modified and their relationships with the system. It is hoped that this will give new comers an idea why and what to configure with a fresh FreeBSD installation.
What to Configure?
To understand how FreeBSD can be configured, we first understand the parts that can be configured. The startup process is roughly as follows and I will cover configuration of each stage in later sections, arranged according to the likeness one will use.
- The computer loads and execute the loader (more on step 6)
- The loader mounts according to the file system table (more on step 5)
- The loader loads the kernel into memory and execute (more on step 4)
- The init program is executed as the first program (not covered)
- The device file system is mounted (not covered)
- The rc program prepares the user space (more on step 1)
- Network neighbours are recognised (more on step 2)
- The periodic jobs are run (more on step 3)
Step 0: Modifying Files
Modifying a configuration file could be easy, but there are some geeky ways to do it right.
To read a configuration file, one uses the cat(1) command. Before some fluffy haters jump out and complain, let me say, cat means concatenate. That said, the concatenation tool is also useful dumping content of a single file.
Quite some FreeBSD configuration files are in name-value pairs, such as:
# cat /etc/rc.conf
In these cases, the sysrc(8) tool acts as a safe shortcut to modify the files. For example:
# sysrc -f /etc/rc.conf hostname="lea"
# cat /etc/rc.conf
You can use the same cat to pipe in the output. The >> symbol means appending to a file; contents following the command will be appended. (If you use > instead, you overwrite it instead.) The << defines the termination string, the termination string will not be inserted and it will be returned to the shell.
# cat >> /etc/rc.conf << EOF
# cat /etc/rc.conf
Since these are just name-value pairs, it does not harm more than causing your own confusions. The latest value assignment takes effect.
Last but not the least, for the files you want to manually edit, you can always use the ee(1) easy editor, or the visually (difficult) vi(1) editor.
Step 1: Run Command
To a new user, the most likely item to configure first is the run command. At later stage of system start, the rc(8) starts the desired processes for the users. Most of these configuration are done in two files. The values desired by the user goes to “/etc/rc.conf”. When a value required is absent, the default value is loaded from “/etc/defaults/rc.conf”. The former is empty or even absent after a fresh system install. The latter is installed and updated automatically and is very lengthy. By the way, the lengthy file can also act as your configuration guide; more on these later.
Step 1.1: Network Configuration
FreeBSD uses ifconfig(8) to configure network interfaces. For example, to configure network addresses of interface vtnet1 (the second virtual network interface), the default gateway and the hostname, one can use:
# sysrc vtnet1_ifconfig="inet 10.65.0.11 netmask 255.255.255.0"
vtnet1_ifconfig: -> inet 10.65.0.11 netmask 255.255.255.0
# sysrc defaultrouter="10.65.0.1"
defaultrouter: NO -> 10.65.0.1
# sysrc hostname="myhost"
hostname: -> myhost
In the example above, vtnet1 device exists because it exists in the hardware layer. Sometimes, the interfaces are purely software, like the gif(4) interface we mentioned in building virtual network. They can be generated in boot time with the cloned interface. Note there is a plus sign before the equal. This appends new values to the existing values. Once the interfaces are created, they can be configured with the typical “ifconfig” above.
# sysrc cloned_interfaces+="gif0"
cloned_interfaces: -> gif0
# sysrc cloned_interfaces+="gif1"
cloned_interfaces: gif0 -> gif0 gif1
Step 1.2: Service Configuration
The run command file allows defining what services to be switched on at boot. These services will be switched off gracefully at shutdown as well. For example, to enable the sshd(8) daemon, one will write this in “/etc/rc.conf”.
As an unofficial but nevertheless useful way, one can search for “_enabled” in the “/etc/defaults/rc.conf” to see what can be enabled or disabled:
# grep _enabled /etc/defaults/rc.conf
apm_enable="NO" # Set to YES to enable APM BIOS functions (or NO).
apmd_enable="NO" # Run apmd to handle APM event from userland.
ddb_enable="NO" # Set to YES to load ddb scripts at boot.
devd_enable="YES" # Run devd, to trigger programs on device tree changes.
kldxref_enable="NO" # Build linker.hints files with kldxref(8).
powerd_enable="NO" # Run powerd to lower our power usage.
In short, some interesting services are:
- ntpd(8): network time daemon, keep system time synchronised
- pf(4): packet filter (or, firewall), useful for protecting your system
- sendmail(1): mail server, in the previous page I recommend disabling it
- sshd(8): secure shell server, essential for you to login remotely
Step 1.3: Startup Script
One more place to configure run command is to directly type them into “/etc/rc.local”. Indeed, this was how FreeBSD 4.x or before worked. Every time a service was installed, the administrator opened an editor and input the required startup scripts there. It is still the preferred way for some other BSD family operating systems.
Step 2: Host Tables and Resolvers
When you have multiple machines connected in a network, you will want alias to them. FreeBSD provides a hosts(5) table “/etc/hosts”. As long as you can handle and synchronise the files on the different hosts, this is the most reliable and straight-forward method. (If not, you will need a centralised place, like a name server, for this purpose, and it is out of my scope today.)
One more network configuration is the domain name service, transforming domain names to IP addresses which are understandable to the network. It is configured with the resolv.conf(5) in “/etc/resolv.conf”. If you are using a cloud, it is usually automatically configured with DHCP.
Step 3: Periodic Jobs
There are quite a few ways to let jobs run periodically. I cover the maintenance and cron jobs here. The former is more common to execute some system default cleanup activities. The latter is more common for administrators’ customisations. In the previous article, I changed some maintenance job settings and used a cron job to periodically clean the network offenders (in case those are false positives).
Step 3.1: Maintenance Jobs
FreeBSD has periodic(8) for running periodic maintenance jobs. The settings are in “/etc/periodic.conf” and the default settings are in “/etc/defaults/periodic.conf”.
The file is read whenever the periodic job is run. After updating the periodic configuration, you can just let the next periodic job to run. Nothing special is needed to reload the configuration.
By default, the periodic jobs output are sent to the local mail server. The step 2 of the customisation script disables these mails and direct the output to the file. This saves you a few daily emails per server and provides one less attack vector.
Step 3.2: Cron Jobs
FreeBSD has cron(8) for running arbitrary commands on given time. There is a master cron job file available as plain crontab(5) table “/etc/crontab”, and a crontab(1) database for each user. Readers may feel strange the two items are both called crontab, with different numbers in the suffix. In short, the (5) is a file, and (1) is a command.
When editing the crontab(5), the format is as follows:
minute hour day month weekday user command args...
For example, the default FreeBSD comes with cron jobs that run the periodic jobs mentioned in the previous subsection. This means at every 03:01, command “periodic daily” is executed as the root user; at every 4:15 on Saturday, command “periodic weekly” is executed as the root user, etc.
1 3 * * * root periodic daily
15 4 * * 6 root periodic weekly
30 5 1 * * root periodic monthly
When editing with crontab(1), one uses “crontab -e” to edit his own list. This gives the user advantage of defining his own jobs without modifying the master table. The format is as follows, which is similar, yet the username is skipped for the obvious reason.
minute hour day month weekday command args...
Please note in the crontabs, it sometimes lacks the conventional environment variables. In particular, you may need to be more specific in pathnames, such as calling “/sbin/pfctl” instead of plainly “pfctl”.
Step 4: Kernel System Settings
FreeBSD provides sysctl(8) utility for configuring kernel and kernel module settings, and reading some system status as well.
Kernel settings can be configured in “/etc/sysctl.conf”, with a default file in “/etc/defaults/sysctl.conf”. The files are read on boot time. After adding new system configurations, you can either reboot to make it in effect, or run this command to reload immediately: “sysctl -f /etc/sysctl.conf”
These variables are useful when a user wants to have more control on the kernel behaviour. More on these can be found on the manual page tuning(7). You can list them by calling “sysctl -a”. The output is long, prepare your terminal to scroll back.
To a cloud server, most of the activities are network transfer; some interesting configurations are:
- net.inet.tcp.sendspace: bytes of initial space for sending for each TCP session
- net.inet.tcp.sendbuf_inc: bytes of sending space increment per session
- net.inet.tcp.sendbuf_max: bytes of maximum space for receiving per session
- net.inet.tcp.recvspace: bytes of initial space for receiving for each TCP session
- net.inet.tcp.recvbuf_inc: bytes of receiving space increment for session
- net.inet.tcp.recvbuf_max: bytes of maximum space for receiving per session
- kern.ipc.nmbclusters: total amount of space for network memory (in 2 KiB blocks)
- kern.ipc.somaxconn: maximum pending connections
By default, the network space values make sense. The sending space and receiving space are 32 KiB and 64 KiB respectively. This incurs 96 KiB when a connection is made. These can go up to 2 MiB for sending and another 2 MiB for receiving. The system reserves around 100 MiB network memory by default, which is enough for even for gigabit network.
If you find a real need, you can consider adjusting these values depending on the nature of the server. These values can be lowered if the server has a lot of connections serving small files and messages. They can be raised if the server has only a few connections and each serving large files and messages. If the server has a lot of connections each serving large files, the total amount of space for network memory has to be increased. You can check the buffer usage with command “netstat -m”.
The maximum pending connections, is set to be 128 as default value. That means, if there are 129 incoming connections together and the server software is not yet capable of completing any of the handshakes, the 129th will be lost. It is suggested to be set to 1024 or even higher. This will prevent the system being jammed easily by denial-of-service attack. If you have applied the customisation script, a client will be blocked if it tries to make too many connections in a short time.
Step 5: File System Table
FreeBSD uses file system table fstab(5) to define the file systems to be mounted. The table is read by the loader (below) when the system boots. (A file is read from the volume before the volume is officially mounted. This is quite counter-intuitive if you think again. But it make things much simpler.) If there are errors, one may end up locking the system from booting.
The file format is as follows:
block mount fstype options dump pass
For example, one of my virtual machine says:
/dev/ufs/rootfs / ufs rw 1 1
This means the UFS volume labeled “rootfs” to be mounted at the root directory /, as an UFS file system, read and write enabled, dump enabled, and checked for consistency first after rebooting from system crash.
Normally, this file is generated when you have a virtual machine ready. It is useful to modify it later when you insert disks to a virtual (or physical) machine.
Step 6: Loader Settings
Eventually, a user may want to configure how a kernel is loaded, and what kernel modules to be loaded together. FreeBSD comes with a simple yet efficient loader(8) for the purpose. The configuration values are in “/boot/loader.conf” and defaults in “/boot/defaults/loader.conf”. I recommend against changing these files randomly because they really affect how the kernel is loaded. Some settings I ever changed are:
- kern.maxproc: maximum processes in a system
- kern.maxfiles: maximum open file handles (including sockets) in a system
- geom_mirror_load: load the software RAID module (for booting the kernel)
- coretemp_load: load the module to detect Intel Core™ processor temperature
- amdtemp_load: load the module to detect AMD processor temperature
The maximum processes, and maximum open file handles are set according to the memory available in the machine. They are suggested to be set to a predefined value if you have a lot of open files or network sockets, or when the machine is to be shared by a lot of users. The process table and file table are initialised once and only once when the kernel loads, thus they are to be set in here instead of sysctl.
Step 7: Skeleton Files
Few accounts use only the default “root” user account. To have consistent personalisation across various created users, administrators often prepare skeleton files. The skeleton files are located at “/usr/share/skel”. For example, “/usr/share/skel/dot.cshrc” will be copied to “$HOME/.cshrc” of the newly created user.
Once the account is created, the file is owned by the created user. There are not automatic ways to update across multiple users. It is therefore important to have the customisations right before creating the users.
We have gone through various parts in FreeBSD that can be configured, especially in context to a new comer. We discussed how to configure the rc.conf, the host table, the resolver configuration, placing periodic jobs, adjusting kernel settings, setting file system mount points, kernel loading options, and finally skeleton files.