Roland's FreeBSD configuration page

Introduction

After installing the base system, I made some changes so that the system suits me better. I’m documenting them here in the hope that they will be useful for others. These settings were started for FreeBSD 5.3 on amd64, but have been continuously updated to 8.0-RELEASE.

To keep track of things, I keep configuration files (including the kernel configuration) under revision control with git. This is explained on my configfiles page.

Parallel port

My Laserjet 2550 printer attached to the parallel port printed very slowly. The system logfile mentioned that the system was throttling interrupts from the parallel port because of an “interrupt storm”. After reading the ppc(4) manual page, I added the following to /boot/device.hints, to put the port into polling mode:

hint.ppc.0.flags="0x28"

The flag 0x08 puts the port into ECP mode, and 0x20 makes the driver poll the port, instead of using an interrupt.

When using CUPS like I am, its programs need to have access to the printer device. In my case connected to the parallel port;

# chown root:cups /dev/lpt0
# chmod g+rw /dev/lpt0

To make this change permanent, you can add the following rules to /etc/devfs.conf;

# Give cups printer access
own     lpt0    root:cups
perm    lpt0    0660

This will make sure that the relevant group and permissions will be installed after the next reboot. In case you have a USB connected printer, you should add a rule to devfs.rules for a ulpt(4) device.

The printer now works fine with CUPS. One caveat I came across, is that you need to use the command-line tool lpadmin(8) to install a printer with a PPD file. I used the following command to install my printer in CUPS:

# /usr/local/sbin/lpadmin -E -p clj2550 -v parallel:/dev/lpt0 -P clj2550.ppd

Sound

My computer has an Asus P5KPL-VM motherboard, which has HDA compatible sound chip (Realtek ALC662) on board. To enable that, I added the following devices to my kernel configuration file:

# Soundcard support
device          sound
device          snd_hda

While playing music with xmms(1) on 6.x, I noticed little clicks and lags in the sound output. After some googling I added the following line to /boot/device.hints, to enlarge the DMA buffer for the sound driver (the default was 4096 bytes).

hint.pcm.0.buffersize="16384"

This was sufficient to fix the problem. N.B., as of 7.x this should not be necessary anymore, because the default buffer size has increased.

The sound driver is able to combine sounds from different sources and output then through one device. This is activated in sysctl.conf by setting the number of virtual channels or vchans, see sound(4).

Ethernet/ADSL

My ADSL connection goes through a Thompson ADSL ethernet modem/router. This makes the setup very easy, because to the computer it’s just another IP gateway to the internet. So it’s compatible with almost all operating systems. If you want easy setup, go for something like this.

My aforementioned motherboard has a Attansic/Atheros L1 ethernet chip on-board. I also have an extra PCI ethernet card, an Realtek 8139. To enable these, I added the following to my kernel configuration file:

# PCI ethernet device
device  miibus
device  age             # Attansic/Atheros L1 Gigabit Ethernet
device  rl              # RealTek 8129/8139

The following settings were added to /etc/rc.conf to enable these devices:

# Network settings
ifconfig_lo0="inet 127.0.0.1"
ifconfig_age0="inet 10.0.0.150/24 polling media 100baseTX mediaopt full-duplex"
ifconfig_rl0="inet 192.168.0.1/24 polling media 100baseTX mediaopt full-duplex"
defaultrouter="10.0.0.138"
tcp_extensions="NO"

The defaultrouter entry points to my ADSL modem. The IP address for the age0 interface can be freely chosen from the 10.0.0.x address range. This Just Works™.

Devfs

Since 5.3 FreeBSD has a dynamic /dev filesystem. This means that entries in /dev are created or removed depending on the available devices.

When devices are created, they get default ownership and permission settings. These settings can be changed via the devfs(8) program, or with the chown(1) and chmod(1) utilities. The problem is that settings made in this manner do not survive a reboot, and settings made with chmod and chown do not survive a device being unplugged.

Enter the files /etc/devfs.conf and /etc/devfs.rules. The first one is suited for changing those devices that are available at boot time, and are not likely to be unplugged, like CD-ROM drives etc. The second one is best suited for setting permissions etc. for devices that can be plugged in and removed during normal system operation, e.g. USB devices. See also devfs.conf(5) and devfs.rules(5).

What I wanted to do is give groups of users access to the CD-ROM, floppy and USB devices, without giving everybody access and thereby compromising system security. So I created three groups (with the pw(8) utility); usb, floppy and cdrom, and made the users that were authorized to use these devices members of these groups.

CD/DVD-RW

Since I wanted to use cdrecord to write CDs, and growisofs to write DVDs, I had to set up the CD drive commands to go through the CAM interface. To do this, the following devices were set in the kernel configuration:

device          atapicam        # Emulate ATAPI devices as SCSI via CAM
                                # Requires scbus and pass

device          scbus           # SCSI bus (required for SCSI)
device          cd              # Compact Disc
device          da              # Direct Access (disks)
device          pass            # Passthrough device

(The da device is added because it is used for USB mass storage devices, as we’ll see later.) As far as I know, these cannot be loaded as modules.

After the new kernel is installed, and the system is rebooted, there will be a couple of new devices ; cdN instead of acdN (N is a number), passN and xpt0. The cdrecord program needs access to those devices to function.

To do that, the following lines are added to /etc/devfs.conf:

# Give members of group cdrom access to the CD/DVD-ROM and DVD+RW via the
# SCSI interface
own     xpt0    root:cdrom
perm    xpt0    0660
own     cd0     root:cdrom
perm    cd0     0660
own     cd1     root:cdrom
perm    cd1     0660
link    cd1     cdrom
link    cd1     dvd

What these commands essentially do is give members of the group cdrom read and write access to the devices necessary to let cdrecord function for a non-root user.

By default, ATAPI devices like CD-ROMs do not use DMA. You can enable DMA at runtime with the atacontrol(8) command. First, run atacontrol list (as root) to see on which channel your ATAPI device is. Say that it’s the master on channel 1. Then the next step is to see it’s current mode by running atacontrol mode 1. Next you can change the mode by running atacontrol mode 1 UDMA2 XXX. This should set the device to UDMA2, aka UDMA33. See the atacontrol manual page for a list of valid modes. You must specify modes for both master and slave, but XXX is an invalid mode and will be ignored.

To enable DMA for ATAPI devices at boot, add the following to /boot/loader.conf:

hw.ata.atapi_dma="1"

Devfs configuration for hot pluggable devices

To set permissions etc. for the USB devices that might not be plugged in at boot, we use /etc/devfs.rules. The rules set in this files are processed by the /etc/rc.d/devfs script which uses devfs(8) to put the rules in the devfs system.

I’ve got a couple of USB mass storage devices that can be accessed via the da(4) driver, and a scanner that works via the ugen(4) driver and libusb(3).

Note: Prior to 8.0, USB connected scanners used the uscanner(4)* *driver. This has been removed in 8.x.

To get these devices to work properly for non-root users (specifically the members of usb group), the following rules are set in /etc/devfs.rules:

[slackbox_usb=10]
add path 'da*' mode 0660 group usb
add path 'msdosfs/*' mode 0660 group usb
add path 'usb/*' mode 0660 group usb
add path 'ugen*' mode 0660 group usb

The first non-comment line assigns a name and number to a set of rules. The devfs(8) command only knows about the number, the name is for convenience in the startup script.

The second line assigns read/write permissions for the group usb to all partitions of USB mass-storage devices.

The third line does the same for all usb devices. Note that in 8.x USB devices appear in the subdirectory /dev/usb/ instead of directly under /dev/. The ugen devices in 8.x are just links to devices in /dev/usb/.

To activate these settings after the next reboot, a line has to be added to /etc/rc.conf:

# Set the default devfs ruleset.
devfs_system_ruleset="slackbox_usb"

Sysctl

The sysctl(8) program allows everybody to examine and root to modify kernel parameters. I have placed the following in my /etc/sysctl.conf file:

# /etc/sysctl.conf
# Time-stamp: <2009-11-29 13:46:44 rsmith>
# $Id: 69f0add3e942705a44942b5ba18be53adaf08d49 $

# Allow normal users to mount filesystems.
vfs.usermount=1

# Speed up disk reads.
vfs.read_max=32

# For X
kern.ipc.shmmax=67108864
kern.ipc.shmall=32768

# Use pcm1 as default.
hw.snd.default_unit=0
dev.pcm.0.play.vchans=4
hw.snd.maxautovchans=4

# Enable port forwarding (for NAT in pf.conf)
net.inet.ip.forwarding=1

# Blackhole against portscanning.
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1

# Do not log fatal signal exits. (from §11.10.4 in the Handbook)
kern.logsigexit=0

# More memory for directory hashes.
vfs.ufs.dirhash_maxmem=16777216

# Disallow memory mapping at the NULL address.
security.bsd.map_at_zero=0

As usual with configuration files, lines starting with a ‘#’ are comments.

With the variable vfs.usermount set, normal users are allowed to mount filesystems, provided they own the mount point. Setting vfs.read_max can increase read speeds. I did some testing and discovered that a value of 32 seemed about right for my setup. You can find the meaning of any sysctl by using the -d option of the sysctl(8) command.

Security

logins

To prevent logins from elsewhere, the following rule has been set as the only rule in the /etc/login.access file:

-:ALL:ALL EXCEPT LOCAL

This means that only local logins are possible. Do not use this if you want to be able to login remotely! See login.access(5).

firewall

My workstation is configured to run the pf firewall. This is done in /etc/rc.conf:

# PF Firewall
pf_enable="YES"

The filtering rules for the pf firewall are contained in /etc/pf.conf:

# /etc/pf.conf
# Time-stamp: <2009-11-14 17:07:18 rsmith>
# $Id: e120d78e3c04413c9a1cb8b882eeda8651e9d12d $
# Packet filter configuration for Slackbox.

# Macros: define common values, so they can be referenced and changed easily.
ext_if = "age0"
int_if = "rl0"

# Addresses that can't be routed externally. 
# See http://www.rfc-editor.org/rfc/rfc3330.txt
# (10.0.0.138 is my router, so it should be reachable!)
table <unroutable> const { 0.0.0.0/8, 10.0.0.0/8, !10.0.0.138, 127.0.0.0/8, \
169.254.0.0/16, 172.16.0.0/12, 192.0.2.0/24, 192.168.0.0/16, 240.0.0.0/4 }

# Options: tune the behavior of pf.
set optimization normal
set block-policy drop
set loginterface $ext_if
set skip on lo

# Normalization: reassemble fragments etc.
scrub in all

# Translate outgoing packets' source addresses (any protocol).
# In this case, any address but the gateway's external address is mapped.
# The sysctl net.inet.ip.forwarding should be set for this to work.
# Alternatively, set gateway_enable="YES" in /etc/rc.conf.
nat pass on $ext_if inet from $int_if:network to any -> $ext_if

# Filtering
antispoof quick for $int_if

# Nobody gets in from the outside!
block in log quick on $ext_if all label "inblock"

# Block packets to unroutable addresses
block out log quick on $ext_if from any to <unroutable> label "unroutable"

# Block by default. (pass rules should follow later).
block out log on $ext_if all label "outblock"

# Internal "network" is trusted.
pass quick on $int_if all flags any no state

# Let outgoing traffic through, and keep state (which is the default now)
# Not using modulate state becaue that seems to be broken.
pass out on $ext_if inet proto tcp all
pass out on $ext_if inet proto udp all 
# Let pings through.
pass out on $ext_if inet proto icmp all icmp-type 8 code 0

The setup above is designed for a workstation that has no servers running. Outgoing connection are remembered by the firewall, and it lets incoming packets related to outgoing ones in. Other incoming packets are blocked and dropped.

daemons

FreeBSD comes with the sensible default of most network daemons disabled (See /etc/defaults/rc.conf).

So if you want e-mail, you’ll have to activate sendmail in /etc/rc.conf, or install and activate another mail transfer agent. Because I find it easier to configure, I prefer postfix.

postfix-img
postfix-img

To disable sendmail completely, the following is set in /etc/rc.conf:

sendmail_enable="NONE"

Since sendmail(1) is symlinked to mailwrapper(8), we also need to configure the latter to use postfix, by editing /etc/mail/mailer.conf;

#
# Execute the Postfix sendmail program, named /usr/local/sbin/sendmail
#
sendmail        /usr/local/sbin/sendmail
send-mail       /usr/local/sbin/sendmail
mailq   /usr/local/sbin/sendmail
newaliases      /usr/local/sbin/sendmail

malloc.conf

By creating a symbolic link named malloc.conf in /etc, options for the malloc(3) family of library functions can be set. The different options are represented by letters. Capital letters mean that an option is enabled, while lowercase mean that an option is disabled. I used the following command;

# cd /etc; ln -s 'ajHR' malloc.conf

powerd

To reduce the power usage and temperature of my system when it’s idling I’ve enabled powerd(8) in it’s default adaptive mode. This is done in two steps.

First, the cpufreq(4) device has to be included in the kernel configuration;

# Control CPU frequency.
device cpufreq

After rebuilding and installing the kernel, powerd has to be enabled in /etc/rc.conf:

# Enable power monitoring.
powerd_enable="YES"
powerd_flags="-n hiadaptive -a hiadaptive"

The powerd_flags is used to set the options for powerd(8). The setting I use were chosen to get the CPU to slow down sooner.

smartd

The smartd(8) daemon monitors the health of SMART capable hard disks. This will warn you before a hard disk fails, so you can make a backup and replace it before you loose your data. It is part of the smartmontools package (in /usr/ports/sysutils), so you have to install that first.

Now a config file, /usr/local/etc/smartd.conf will need to be written. Below is the relevant part of mine:

/dev/ad4 -o on -s (S/../.././02|L/../../6/04) -H \
-l error -l selftest -t -I 194 -I 9 \
-M exec /usr/bin/mail -m rsmith@localhost 
/dev/ad6 -o on -s (S/../.././03|L/../../6/05) -H \
-l error -l selftest -t -I 194 -I 9 \
-M exec /usr/bin/mail -m rsmith@localhost

It is important to use the “-M exec” parameter, because smartd assumes /bin/mail, which doesn’t exist on FreeBSD. See the smartd.conf(5) manual page for the meaning of the parameters.

Cache write-through for hard disks

By default, most disk drives cache writes in internal memory before actually committing them to the disk.

This behavior can make it more likely to trigger inconsistencies on a filesystem using soft updates in case of a power failure. One can disable this feature by adding the following in /boot/loader.conf;

# Set ata devices to write-through cache.
hw.ata.wc="0"

There is a performance penalty associated with this, though.

Keeping ports up to date on multiple machines

If you have more than one FreeBSD machine, keeping the ports on them up-to-date means more work. There is a way around this, but it requires that the machines in question are running the same hardware architecture and major OS version, e.g. amd64 8.x. As a consequence of this method, all machines will have the same ports installed. I find that useful myself.

If this is the case, you can use the fastest machine to build ports, then distribute them to other machines with rsync(1).

Here is what I do to keep the ports on my laptop in sync with my desktop. Both are running 8.0-RELEASE amd64. Running the same minor release isn’t critical. Just make sure that the architecture and major release are the same. The faster desktop is used as the build machine.

The laptop has the following in /usr/local/etc/rsyncd.conf:

[local]
path = /usr/local
comment = usr/local directory tree
uid = root
gid = wheel
read only = false

If you don’t mind losing the ability to build ports on the dependent machines, you can remove the directories /usr/ports, /var/db/ports and /var/db/pkg on those machines, as I’ve done on the laptop.

make.conf

The file make.conf(5) is read (via sys.mk) by make(1) every time it runs. It follows makefile syntax and is used to set variables for make.

There are variables that are used for configuration of the system during a ‘make buildworld’ or ‘make kernel’. These will be covered first.

In 7.x part of the system configuration was moved to a separate file, src.conf(5).

It is also possible to set variables only when building in a specific directory. This is used for configuring ports(7).

System builds

Following is an annotated example of settings I’ve put in my make.conf. They are listed here as examples only. Do not just copy them! They will probably not be correct for your system and might ruin it when you use them. You have been warned!

The first thing I specify is the type of CPU that the system should be built for.

# Type of CPU the system is built for.
CPUTYPE=nocona

I’m running the amd64 version of FreeBSD on my Core2 based computer. Do not copy this setting unless you know that it is correct! Reading /usr/share/mk/bsd.cpu.mk gives you an idea what types are available, and what they do.

Next is defining the kernel configuration.

# Kernel configuration
KERNCONF=QUADSLACK

I’ve placed a file called QUADSLACK in the directory /usr/src/sys/amd64/conf. This file contains a description of which drivers and features I want the kernel to contain. In general, you should place your kernel configuration file (if you don’t want to use the standard kernel named GENERIC) in /usr/src/sys/[arch]/conf, where [arch] is the machine architecture of your system. For most people this should be i386 or amd64. To build your own kernel configuration, start off with making a copy of the GENERIC config for your FreeBSD version and architecture, and edit that.

Moving on to documentation. To save on disk space, and because it is probably the most complete, I only install the English documentation.

# Documentation languages
DOC_LANG=en_US.ISO8859-1

The following are added or updated when the perl port is installed of updated. Do not remove these!

# added by use.perl 2009-09-13 09:22:46
PERL_VERSION=5.10.1

Ports

Ports are applications that have been ‘ported’ to FreeBSD. I.e, someone has figured out where to download the source, and how to compile (with modifications, if necessary) and install it successfully. This knowledge is saved as instructions for the system to repeat that. This system also takes care on installing any prequisites. This is one of the main selling points of FreeBSD, in my opinion.

The following variables are used to configure certain ports. You can specify these variables when you invoke make to build a port, but this way you can’t forget them. A lot of ports use “options” these days. This presents you with a nice dialog where you can select features that you want in a port. But not all ports have been option-ized, and some things cannot be set with the options mechanism. To see what variables you can set, look through /usr/ports/[category]/[portname]/Makefile.

The statements like .if ${.CURDIR:M*/foo/bar} means that if make is invoked in a directory that ends in foo/bar, it should set the variables named in the .if/.endif block.

.if ${.CURDIR:M*/multimedia/ffmpeg}
WITH_FREETYPE2=yes 
WITH_MP3=yes 
WITH_OPTIMIZED_CFLAGS=yes 
WITHOUT_FFMPEG_FFSERVER=yes
.endif

.if ${.CURDIR:M*/mail/mutt-devel}
WITH_MUTT_SLANG2=yes
WITHOUT_MUTT_HTML=yes 
WITHOUT_MUTT_XML=yes 
WITHOUT_MUTT_COMPRESSED_FOLDERS=yes 
WITHOUT_NLS=yes 
NOPORTDOCS=yes
.endif

.if ${.CURDIR:M*/graphics/povray}
WITH_OPTIMIZED_FLAGS=yes
.endif

.if ${.CURDIR:M*/multimedia/mplayer}
WITH_DVD_DEVICE=/dev/cd1
WITH_CDROM_DEVICE=/dev/cd1
.endif

.if ${.CURDIR:M*/math/octave}
WITH_BLAS=yes
.endif

.if ${.CURDIR:M*/sysutils/conky}
WITH_XFT=yes
.endif

.if ${.CURDIR:M*/graphics/xd3d}
WITHOUT_GIFSICLE=yes
.endif

.if ${.CURDIR:M*/print/ghostscript*}
A4=yes
BATCH=yes
.endif

.if ${.CURDIR:M*/editors/emacs}
WITHOUT_GTK=yes
.endif

.if ${.CURDIR:M*/security/pinentry}
PINENTRY_GTK2=yes
.endif

.if ${.CURDIR:M*/sysutils/isomaster}
WITHOUT_NLS=yes
.endif

.if ${.CURDIR:M*/devel/git}
WITHOUT_GUI=yes
.endif

.if ${.CURDIR:M*/lang/gcc*}
WITHOUT_JAVA=yes
.endif

.if ${.CURDIR:M*/x11-servers/xorg-server}
WITH_OPENSSL_BASE=yes
.endif

.if ${.CURDIR:M*/cad/calculix}
# Add 'WITH_EXAMPLES=YES' to the command-line when running make install.
#WITH_EXAMPLES=YES
BROWSER=firefox
WITH_BLAS=YES
CCX_NPROC=4
.endif

.if ${.CURDIR:M*/math/arpack}
WITH_BLAS=YES
.endif

.if ${.CURDIR:M*/math/taucs}
WITH_BLAS=YES
.endif

.if ${.CURDIR:M*/print/freetype2}
WITH_LCD_FILTERING=YES
.endif

.if ${.CURDIR:M*/shells/bash}
NOPORTDOCS=YES
WITHOUT_NLS=YES
WITHOUT_HELP=YES
.endif

.if ${.CURDIR:M*/editors/openoffice.org-*}
WITHOUT_MOZILLA=YES
WITHOUT_GNOME=YES
WITH_SYSTEM_ICU=YES
WITH_GPC=YES
.endif

src.conf

In 7.x, most of the base system configuration has been moved to /etc/src.conf, as not to interfere with building ports.

Below is my src.conf as an example. Do not copy this to your system, but read src.conf(5) and figure out what you should use.

# /etc/src.conf
# Time-stamp: <2009-11-27 14:45:31 rsmith>
# $Id: a0441bcb84fe0f95886115e2670bf2257bfa8890 $

WITHOUT_ACCT=true
WITHOUT_AMD=true
WITHOUT_APM=true
WITHOUT_ATM=true
WITHOUT_AUDIT=true
WITHOUT_BLUETOOTH=true
WITHOUT_CDDL=true
WITHOUT_CTM=true
WITHOUT_CVS=true
WITHOUT_FLOPPY=true
WITHOUT_FREEBSD_UPDATE=true
WITHOUT_GCOV=true
WITHOUT_GDB=true
WITHOUT_GPIB=true
WITHOUT_I4B=true
WITH_IDEA=true
WITHOUT_INET6=true
WITHOUT_IPFILTER=true
WITHOUT_IPX=true
WITHOUT_LPR=true
WITHOUT_NDIS=true
WITHOUT_NETGRAPH=true
WITHOUT_OBJC=true
WITHOUT_PPP=true
WITHOUT_PROFILE=true
WITHOUT_QUOTAS=true
WITHOUT_RCMDS=true
WITHOUT_SENDMAIL=true
WITHOUT_SSP=true
WITHOUT_TELNET=true

Note that this configuration file only regulates which part of the system is built and installed. It does not remove old binaries and libraries! The reason for that is because the system cannot know with certainty which files are to be removed.

Discovering and removing old binaries is covered in my miscellaneous page

—– Copyright © 2010, Roland Smith rsmith@xs4all.nl

Creative Commons License
This <span xmlns:dc=“http://purl.org/dc/elements/1.1/” href=“http://purl.org/dc/dcmitype/Text” rel=“dc:type”>work is licensed under a Creative Commons Attribution 3.0 Unported License