How to setup FreeBSD with a riced desktop - part 1 - Basic setup

Published on 2020-01-22. Modified on 2022-04-14.

In this three part tutorial I am going to show you how you can setup FreeBSD with a riced Xfce or i3 desktop.

Table of contents


When I migrated from Microsoft Windows on the desktop back in 1998 KDE became my favorite desktop on GNU/Linux. Later when I discovered BSD I also made use of KDE on my FreeBSD desktop. I kept running KDE until the change from KDE 3 to KDE 4 plasma, which I hated. It was bloated and slow. I also didn't like GNOME, so I tested out some of the alternative window managers and desktops, and I eventually ran with Blackbox on my OpenBSD desktop and Xfce on my GNU/Linux and FreeBSD desktops.

A couple of years ago I switched to the tilling window manager i3 and it is now my favorite window manager on all my workstations, whether GNU/Linux or BSD.

I have tried out other tilling window managers, like dwm, Ion and Xmonad, but I prefer i3. It is fast, easy to setup, and easy to use. I really like it.

The reason why I use a tilling window manager today is because of the highly improved productivity it provides. It takes some getting used too, but once you "get it", it becomes a pain to use a regular window manager or desktop system.

In the second part of the tutorial I'm going to share how I used to rice the Xfce desktop on FreeBSD. I used an identical setup on Debian GNU/Linux and Arch Linux, so it is of course also possible to do the same on other systems. In the third part of the tutorial I'm going to share my setup with i3 gaps.

I'm going to assume that you have a running installation of FreeBSD 13.0 with a supported and working graphics card. If you're unsure you can start by looking at the FreeBSD wiki on the graphics section.

FreeBSD has a limited support for GPUs compared to GNU/Linux, but you can get a pretty cool setup going with HD graphics if you use an Intel i5 or i7 CPU with the build-in GPU. The advantage of the Intel HD Graphics is that the driver is open source. NVIDIA provides a binary driver for FreeBSD. It is of course closed source, but it performs pretty well. I have no experience using AMD graphic cards.

On my FreeBSD workstation I'm using Intel HD Graphics and I am able to watch HD videos without any issues.

Keyboard layout, UTF-8, and a couple of other things

I'm going to assume you have added the normal user account to the wheel group, if not, do that using:

# pw group mod wheel -G foo

On a fresh install of FreeBSD I like to setup UTF-8 and make sure that my Danish keyboard layout is working, both in the console and in Xorg. I prefer to run with the "en_US.UTF-8" setting in order to keep all system messages from third party applications in English.

FreeBSD has two console drivers, the older syscons console driver, which is the default that gets setup during installation of 12.1, and the newer vt virtual terminal console driver. Each of them has its own set of keymaps.

The first thing I do is to setup a new virtual console using vt.

The vt device provides multiple virtual terminals with a more extensive feature set:

Add the following to /boot/loader.conf:


You can always change the language of your keyboard, the monitor's font size, and many other things. The default keyboard map is the standard US keyboard, frequently called QWERTY.

All the available keymaps for syscons is located in the /usr/share/syscons/keymaps/ directory, but since we're setting up vt the keymaps are located in /usr/share/vt/keymaps/.

I use the dk keyboard map so I run the command:

# sysrc keymap=dk

In my case the following line is added to /etc/rc.conf:


Then you need to setup a login class in /etc/login.conf with UTF-8:

danish|danish Users Accounts:\

You can change the "danish" part to whatever language you're using.

As mentioned, I'm using the en_US.UTF-8 setting here in order to keep system messages in English.

On FreeBSD users may individually create a file called .login_conf in their home directory using the same format, consisting of a single entry with a record id of "me". If present, this file is used by login to set user defined environment settings which override those specified in the system login capabilities database.

The default /etc/login.conf shipped with FreeBSD is an out of the box configuration. Whenever changes to this, or the user's ~/.login_conf, file are made, the modifications will not be picked up until cap_mkdb is used to compile the file into a database. This database file will have a .db extension and is accessed through cgetent. See getcap(3) for a more in-depth description of the format of a capability database.

In terminal run:

# cap_mkdb /etc/login.conf

And then finally set the login class for the users you want to use UTF-8. I do that both for "root" and the normal user "foo":

# pw user mod root -L danish
# pw user mod foo -L danish

Another thing I like to do is to minimize the 10 second pause during the initial boot screen.

Edit /boot/loader.conf and add the following:


This will change the boot delay from 10 seconds to 2 seconds.

You can take a look at /boot/default/loader.conf to see if there are other options you like to change. Don't change anything in /boot/default/loader.conf. Add the option to /boot/loader.conf, it will override the default settings.

Reboot the machine, login as the normal user, and verify that the settings took effect by running:

$ locale

Setup pkg

I have logged in as the normal user and used su to become root. Then I run the pkg command in order to install the FreeBSD package management tool.

# pkg
The package management tool is not yet installed on your system.
Do you want to fetch and install it now? [y/N]:

After pkg has been installed I like to change the "quarterly" setting to "latest" in order to get more recent packages quicker.

The "quarterly" setting is meant to bring some stability to the packages. The ports/packages is rolling release on FreeBSD and occasionally this results in broken ports. It can happen that a single change that hasn't been tested well enough has broken a large amount of other ports due to dependency issue.

I'm used to Arch Linux and like more bleeding edge software. If some of the packages break on FreeBSD, it's easy to even remove all of the them and start from scratch. However, if you're running ZFS you can just take a snapshot before you upgrade and if anything breaks, you can rollback. UFS also supports snapshots, but I have no experience using that.

The FreeBSD.conf file in /etc/pkg/ determines what repository pkg is going to use. In order to change that from "quarterly" to "latest" we need to create a new directory and create a new FreeBSD.conf file:

# mkdir -p /usr/local/etc/pkg/repos
# vi /usr/local/etc/pkg/repos/FreeBSD.conf

Then insert the following:

FreeBSD: {
  url: "pkg+${ABI}/latest"

Then update the package database:

# pkg update

Verify that pkg is using the "latest" repository:

# pkg -vv
  FreeBSD: {
    url             : "pkg+",
    enabled         : yes,
    priority        : 0,
    mirror_type     : "SRV",
    signature_type  : "FINGERPRINTS",
    fingerprints    : "/usr/share/keys/pkg"

Now we're ready to install some packages.

Change the shell

While it's a bad practice to change the default shell for the root user to something not in the base install, I like to begin by changing the default shell for the normal user.

I have used a couple of different shells over the years, but I prefer Zsh or Bash. In this case I'm going to install Bash.

# pkg install bash bash-completion

Change the normal user shell to Bash:

# chpass -s /usr/local/bin/bash foo

Logout and login again as the normal user.

Normally I have all my dotfiles in a private Git repository. During a new installation I begin by installing Git and then clone my dotfiles. Within the Git repository I also have a shell script that automatically create symlinks to all my dotfiles for all the applications I use. I also have a shell script that detects what kind of OS I'm setting up, and it then fetches a list of the packages I use on a regular basis.

For this tutorial we'll just create a basic .bashrc file and setup a couple of other things too.

Change whatever you need to suit your needs.

#  _               _
# | |__   __ _ ___| |__  _ __ ___
# | '_ \ / _` / __| '_ \| '__/ __|
# | |_) | (_| \__ \ | | | | | (__
# |_.__/ \__,_|___/_| |_|_|  \___|

# Bootstraping

# If not running interactively, don't do anything.
if [[ $- != *i* ]] ; then

# Basic setup

# I prefer less to more.
export PAGER=less
export MANPAGER=less

# I prefer to set both EDITOR and VISUAL to Vim or Neovim.
export EDITOR=nvim
export VISUAL=nvim

# Don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options

# Append to the history file, don't overwrite it.
shopt -s histappend

# For setting history length see HISTSIZE and HISTFILESIZE in bash(1).

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize

# Uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt

if [[ -n $force_color_prompt ]]; then
    if [[ -x /usr/bin/tput ]] && tput setaf 1 >&/dev/null; then
        # We have color support; assume it's compliant with Ecma-48
        # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
        # a case would tend to support setf rather than setaf.)

# Set a default prompt.
PS1='\[\033[01;31m\]\u\[\033[01;33m\]@\[\033[01;36m\]\h \[\033[01;33m\]\w \[\033[01;35m\]\$ \[\033[00m\]'

# Uncomment if you want to try an advanced prompt.
#PS1="\[\e[0;34m\]┌─[\[\e[1;33m● \h\e[0;34m\]]─[\[\e[1;36m\u\e[0;34m\]]─[\e[1;37m\w\e[0;34m]─\[$(tput sgr0)\]\[\033[38;5;7m\][\[$(tput sgr0)\]\[\033[38;5;11m\]\A\[$(tput sgr0)\]\[\033[38;5;7m\]]\[$(tput sgr0)\]\[\033[38;5;15m\]$_EXIT_STATUS_STR: \$\[\e[0;34m\]\n\[\e[0;34m\]└─╼ \[\e[1;35m\]>> \[\e[00;00m\]"

# Enable Bash completion.
if [[ -f /usr/local/share/bash-completion/ ]]; then
    source /usr/local/share/bash-completion/

In the above I have set the default editor to Neovim. I'm going to install that in a while, until then I'll just use vi. Feel free to change the editor to something else.

Bash reads .bash_profile in the terminal and .bashrc in X. I prefer to keep everything in .bashrc so I'll just create a symlink to that:

$ ln -s .bashrc .bash_profile

Logout and login again and validate that Bash is up and running with a color prompt.

Occasionally I like to install fzf, the command-line fuzzy finder, and set that up with Bash. On FreeBSD you can install fzf with pkg:

# pkg install fzf

Then edit .bashrc and add the following to the end of it:

# Plugins

# fzf
if [[ -d '/usr/local/share/examples/fzf/' ]]; then
    source /usr/local/share/examples/fzf/shell/completion.bash
    source /usr/local/share/examples/fzf/shell/key-bindings.bash

The fuzzy finder does make Bash a bit more slow, but sometimes I like to use it.

Last I like to create a separate file for aliases. I do that because Zsh and Bash can share those and sometimes I change between Zsh and Bash.

I add the following to .bashrc:

# Aliases

source ~/.aliases

Then create the .aliases file and set that up:

# Enable color support of ls and also add handy aliases.
alias ls='ls -G'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

Install doas and a couple of other applications

I also like to install doas, from the OpenBSD project, which is an alternative to sudo, in order to make it easy for the normal user to issue commands without using su to become root.

# pkg install doas

Then I create the doas.conf file and setup a couple of commands:

# vi /usr/local/etc/doas.conf
permit nopass foo cmd shutdown
permit nopass foo cmd pkg

Then I like to add a couple of aliases to easily reboot or shutdown the machine from the console:

alias sss='doas shutdown -p now'
alias rrr='doas shutdown -r now'

I also create an alias for starting X. Some people recommend to use a graphical login manager, but I often login to my machine and perform tasks without the need for X, as such I prefer to start X manually when I need it.

alias x='startx'

I never use a network manager, instead I setup all the network and VPN and whatever else I run with using only aliases and manual configuration. I have always preferred that to any kind of GUI setup because you know exactly what's going on. Running a single command in the console that takes care of everything is more convenient and much easier to debug if something isn't working.

Last I like to install a couple of application before I begin to setup X.

$ doas pkg install nnn mc claws-mail claws-mail-pgp neovim firefox mpv pinentry-gtk2 git hexchat gimp evince filezilla google-fonts

Neovim is my favorite editor and combined with a couple of plugins it can become a really well working and fast editor comparable to the more heavy IDEs.

I'm not going to demonstrate how I setup Neovim because you're most likely using something else, or if you're using Neovim or Vim, then you already know how to do that.

Claws-mail is my favorite email client on my desktop. It is well maintained, fast, and simple to setup with multiple accounts and it has very good support for GPG encryption. It also has a bunch of nice plug-ins for things like reading RSS feeds like email, and other things. Sometimes I use Mutt in the console, but I generally prefer Claws-mail.

I also like to use Hexchat for IRC when I'm on my desktop. It's fast and easy to customize. I occasionally use Irssi too.

I mostly use MuPDF or Xpdf for reading PDF files, but if I need to print a PDF document, Evince usually provides a better result.

I sometimes use FileZilla when I need to transfer files to a web host that only supports FTPS, that is FTP over TLS, not SFTP.

Google provides a lot of great fonts for free, I also like to install those.

Final comments

This was the basic setup. In the next part of the tutorial I'm going to install Xorg and Xfce and then "rice" the desktop a bit.