--- title: FreeBSD 14 on the Desktop date: November 20, 2024 description: KDE 5 on your laptop, using a real Unix! --- After [much deliberation](../reevaluating-rhel/), I finally decided to migrate my entire infrastructure from [Rocky Linux](https://rockylinux.org/) to [FreeBSD](https://www.freebsd.org/). Why FreeBSD? Perhaps you yearn for a simpler time, when `ifconfig` configured your network interfaces. When `/etc/motd` didn't download advertisements from the web. When adults actually packaged their software, instead of shipping 400 MB Flatpaks that make syscalls over D-Bus. Rest easy, weary netizen. While the [teenagers](https://www.jwz.org/doc/cadt.html) busy themselves with `systemd-resolved`, Netplan, and other horrors, you can still find peace in the tranquility of `/etc/rc.conf`. The enemy, ensnared by the YAML tarpit, is not **yet** at our gates (*sic transit gloria mundi*, etc). Anyway, let's build a FreeBSD desktop system with KDE. This guide will assume you're using Intel graphics with X11 (don't @ me about Wayland 🤡). On my 5-year-old ThinkPad X1 Carbon, I'm getting about 6-7 hours of battery life with FreeBSD. Not too bad! ![](kde5.jpg "KDE Plasma 5 on FreeBSD"){.center} ## Installation Grab a FreeBSD memstick image from [here](https://www.freebsd.org/where/) and `dd` it to a USB stick: ```bash curl -OJ https://download.freebsd.org/releases/amd64/amd64/ISO-IMAGES/14.1/FreeBSD-14.1-RELEASE-amd64-memstick.img sudo dd if=FreeBSD-14.1-RELEASE-amd64-memstick.img of=/dev/sdX bs=1M conv=sync ``` The installation wizard is straightforward. Make sure your system is configured for UEFI boot, and select ZFS (GPT) for the disk layout. Once you reboot, login as root using the password specified during installation. ## Devices, Drivers, and Tuning In this section, we'll configure device drivers and make various tweaks to get optimum performance out of a desktop system. You're not required to use *all* of these, but they've worked well for me. ### Bootloader Tunables First, open up `/boot/loader.conf` and consider adding the following: ```bash # /boot/loader.conf # Faster boot time. autoboot_delay="3" # Load PF firewall module. pf_load="YES" # Enable querying CPU information and temperature. cpuctl_load="YES" coretemp_load="YES" # 99% of users will never need destructive dtrace. security.bsd.allow_destructive_dtrace="0" # Bump up some default limits for desktop usage. kern.ipc.shmseg="1024" kern.ipc.shmmni="1024" kern.maxproc="100000" # If your system supports Intel Speed Shift (check dmesg), set this to 0: machdep.hwpstate_pkg_ctrl="0" # Enable PCI power saving. hw.pci.do_power_nodriver="3" # Optimizations for Intel graphics. compat.linuxkpi.i915_enable_fbc="1" compat.linuxkpi.i915_fastboot="1" # Load Linux binary compatibility layer. linux_load="YES" linux64_load="YES" # Load FUSE module (filesystems in user-space). fusefs_load="YES" # CUSE is needed for webcamd. cuse_load="YES" # Enable this module to use USB tethering (Android/iPhone) if_urndis_load="YES" ################ # Network tuning ################ # H-TCP congestion control algorithm designed to perform better over fast, # long-distance networks (like the internet). You might consider using it. cc_htcp_load="YES" # Enable faster soreceive() implementation. net.inet.tcp.soreceive_stream="1" # Increase network interface queue length. net.isr.defaultqlimit="2048" net.link.ifqmaxlen="2048" ######################## # Laptop-related options ######################## # Increase ZFS transaction timeout to save battery. vfs.zfs.txg.timeout="10" # Power saving for Intel graphics. compat.linuxkpi.i915_disable_power_well="1" compat.linuxkpi.i915_enable_dc="2" # Enable Thinkpad buttons. acpi_ibm_load="YES" ``` ### Sysctl Tweaks Next, open up `/etc/sysctl.conf` and consider setting the following sysctls. Note that you can view the description of any sysctl by running `sysctl -d`. ```bash # /etc/sysctl.conf #################### # sEcuRitY HaRdeNinG #################### hw.kbd.keymap_restrict_change=4 kern.coredump=0 kern.elf32.aslr.pie_enable=1 kern.random.fortuna.minpoolsize=128 kern.randompid=1 net.inet.icmp.drop_redirect=1 net.inet.ip.process_options=0 net.inet.ip.random_id=1 net.inet.ip.redirect=0 net.inet.ip.rfc1122_strong_es=1 net.inet.tcp.always_keepalive=0 net.inet.tcp.drop_synfin=1 net.inet.tcp.icmp_may_rst=0 net.inet.tcp.syncookies=0 net.inet6.ip6.redirect=0 security.bsd.unprivileged_proc_debug=1 security.bsd.unprivileged_read_msgbuf=0 # Some guides will tell you use these. # More trouble than they're worth, IMO: # #kern.elf32.allow_wx=0 #kern.elf64.allow_wx=0 #security.bsd.hardlink_check_gid=1 #security.bsd.hardlink_check_uid=1 #security.bsd.see_other_gids=0 #security.bsd.see_other_uids=0 ################################## # Network performance tuning # # The default values for many of these sysctls are optimized for the latencies # of a local network. The modifications below should result in better TCP # performance over connections with a larger RTT (like the internet), but at # the expense of higher memory utilization. # # source: trust me, bro ############################### kern.ipc.maxsockbuf=2097152 kern.ipc.soacceptqueue=1024 kern.ipc.somaxconn=1024 net.inet.tcp.abc_l_var=44 net.inet.tcp.cc.abe=1 net.inet.tcp.cc.algorithm=htcp net.inet.tcp.cc.htcp.adaptive_backoff=1 net.inet.tcp.cc.htcp.rtt_scaling=1 net.inet.tcp.ecn.enable=1 net.inet.tcp.fast_finwait2_recycle=1 net.inet.tcp.fastopen.server_enable=1 net.inet.tcp.finwait2_timeout=5000 net.inet.tcp.initcwnd_segments=44 net.inet.tcp.keepcnt=2 net.inet.tcp.keepidle=62000 net.inet.tcp.keepinit=5000 net.inet.tcp.minmss=536 net.inet.tcp.msl=2500 net.inet.tcp.mssdflt=1448 net.inet.tcp.nolocaltimewait=1 net.inet.tcp.recvbuf_max=2097152 net.inet.tcp.recvspace=65536 net.inet.tcp.sendbuf_inc=65536 net.inet.tcp.sendbuf_max=2097152 net.inet.tcp.sendspace=65536 net.local.stream.recvspace=65536 net.local.stream.sendspace=65536 ####################### # Desktop optimizations ####################### # Prevent shared memory from being swapped to disk. kern.ipc.shm_use_phys=1 # Increase scheduler preemption threshold for snappier GUI experience. kern.sched.preempt_thresh=224 # Allow unprivileged users to mount things. vfs.usermount=1 # Don't switch virtual consoles back and forth on suspend. # With some graphics cards, switching to a different VT breaks hardware acceleration. # https://github.com/freebsd/drm-kmod/issues/175 kern.vt.suspendswitch=0 ######################## # Power saving (laptops) ######################## hw.snd.latency=7 ``` ### WiFi WiFi is not where FreeBSD shines. Hope you can live with 802.11g. First, you'll need to figure out which driver supports your card (if any). For Intel cards, this will likely be `iwn(4)`, `iwm(4)`, or `iwlwifi(4)`. Check those man pages. My card happens to be an Intel Wireless AC 8265, which is supported by the `iwm` driver. First, make sure the required kernel modules are loaded on boot: ```bash # /boot/loader.conf if_iwm_load="YES" iwm8265fw_load="YES" ``` Next, have `rc(8)` create a `wlan0` device on boot: ```bash sysrc -v wlans_iwm0=wlan0 sysrc -v create_args_wlan0='country US regdomain FCC' sysrc -v ifconfig_wlan0='WPA DHCP powersave' ``` The `WPA` option will use `wpa_supplicant(8)` to manage WiFi networks. You can either edit `/etc/wpa_supplicant.conf` by hand, or use the graphical interface provided by `networkmgr`: ```bash pkg install sudo networkmgr ``` Note that `networkmgr` requires root permissions. You can allow all members of the `operator` group to run `networkmgr` without a password using `sudo`: ```bash # /usr/local/etc/sudoers.d/networkmgr %operator ALL=NOPASSWD: /usr/local/bin/networkmgr ``` ### CPU Microcode and Power Savings Install the latest CPU microcode: ```bash pkg install cpu-microcode ``` Edit `/boot/loader.conf` to load the microcode on boot: ```bash # /boot/loader.conf cpu_microcode_load="YES" cpu_microcode_name="/boot/firmware/intel-ucode.bin" ``` You can save a lot of battery (and heat) by enabling lower CPU C-states: ```bash sysrc -v performance_cx_lowest=Cmax economy_cx_lowest=Cmax ``` Note that with modern Intel processors, it is no longer necessary to run `powerd(8)`. ### Intel Graphics Driver Install the Intel graphics driver and make sure it's loaded on boot: ```bash pkg install drm-kmod libva-intel-media-driver sysrc -v kld_list+=i915kms ``` ### Webcam With any luck, your webcam will be supported by `webcamd`: ```bash pkg install webcamd v4l-utils sysrc -v webcamd_enable=YES ``` ### Sound Many ports are built with [sndio](https://sndio.org/) support by default (like Firefox). You can think of it as a BSD-native `pulseaudio`. ```bash pkg install sndio sysrc -v sndiod_enable=YES # There appears to be a race condition with sndiod and clear_tmp_enable. # When /tmp is cleared out on boot, the sndiod socket is inadvertently removed! sysrc -v clear_tmp_enable=NO ``` #### Using different audio devices simultaneously FreeBSD's OSS has an unfortunate limitation: only one audio device can be used at a time. For example, I was unable to use my webcam's integrated microphone and my USB speakers simultaneously during video chats. As described on the [FreeBSD Wiki](https://wiki.freebsd.org/Sound#virtual_oss_.28advanced.29), the `virtual_oss(8)` package exists to work around this limitation: ```bash pkg install virtual_oss ``` First, check the contents of `/dev/sndstat` to determine your device numbering: ``` $ cat /dev/sndstat Installed devices: pcm0: (rec) pcm1: (play) default ``` Since my output (`-O`) device has index 1, and my recording (`-R`) device has index 0, I'll enable `virtual_oss` like so: ```bash sysrc -v virtual_oss_enable=YES sysrc -v virtual_oss_dsp='-T /dev/sndstat -C 2 -c 2 -S -r 48000 -b 16 -s 25ms -O /dev/dsp1 -R /dev/dsp0 -d dsp' ``` You'll need to set the `-r` flag to the sample rate and `-b` to the bit depth of your device (you can usually find these values in `dmesg`). If your devices have different sample rates, the `-S` flag enables automatic resampling. The `-s` flag sets the buffer size. I had to increase this to `25ms` to avoid clipping. ### Device Permissions via devfs You should create a custom `devfs(8)` ruleset to allow unprivileged users to access various hardware devices. Create `/etc/devfs.rules` with the following: ```ini # /etc/devfs.rules [localrules=1000] add path 'drm/*' mode 0660 group operator add path 'backlight/*' mode 0660 group operator add path 'video*' mode 0660 group operator add path 'usb/*' mode 0660 group operator ``` If you plan on burning CDs, you will need a few more lines. First, check the output of `camcontrol devlist` to determine the `pass(4)` device associated with your CD burner: ``` $ camcontrol devlist at scbus0 target 0 lun 0 (ses0,pass0) at scbus1 target 0 lun 1 (pass1,nda0) at scbus2 target 0 lun 0 (cd0,pass2) ``` In my case, `cd0` is associated with `pass2`, so I will add the following: ```ini add path 'xpt*' mode 0660 group operator add path 'cd*' mode 0660 group operator add path 'pass2' mode 0660 group operator ``` Be sure to set the default ruleset like so: ```bash sysrc -v devfs_system_ruleset=localrules ``` ### USB Power Saving If you're using a laptop, you'll want to power down inactive USB devices to save battery life. Add the following to `/etc/rc.local`: ```bash # /etc/rc.local usbconfig | awk -F: '{ print $1 }' | xargs -rtn1 -I% usbconfig -d % power_save ``` ### Suspend on Lid Close For laptops, you'll need a `devd` rule to automatically suspend when the lid is closed. Create `/etc/devd/lid-close.conf` with the following: ``` # /etc/devd/lid-close.conf notify 20 { match "system" "ACPI"; match "subsystem" "Lid"; match "notify" "0x00"; action "/usr/local/libexec/kde-lock-and-suspend"; }; ``` On FreeBSD, you can enter sleep mode by running `acpiconf -s3`. But if we're logged into a desktop session, we'd like to make sure our screen is locked first. Long ago, in a more sensible time, we'd just run `pkill -USR1 xidle` to lock the screen. Sadly, KDE requires that we enter the teenage wasteland of D-Bus to accomplish this. Create `/usr/local/libexec/kde-lock-and-suspend` like so: ```bash #!/bin/sh # /usr/local/libexec/kde-lock-and-suspend # For any active KDE session, lock the screen via dbus. /usr/local/bin/qdbus-qt5 --literal --system \ org.freedesktop.ConsoleKit \ /org/freedesktop/ConsoleKit/Manager \ org.freedesktop.ConsoleKit.Manager.GetSessions \ | /usr/bin/sed 's/^.*\(Session[0-9]*\).*$/\1/' \ | /usr/bin/xargs -rtn1 -I% \ /usr/local/bin/qdbus-qt5 --system \ org.freedesktop.ConsoleKit \ /org/freedesktop/ConsoleKit/% \ org.freedesktop.ConsoleKit.Session.Lock # Give the previous command some time to complete. sleep 0.5 # Suspend! /usr/sbin/acpiconf -s3 ``` Don't forget to make it executable: ```bash chmod 755 /usr/local/libexec/kde-lock-and-suspend ``` ### ThinkPad Backlight Controls I had to do a bit of work to get the backlight keys working on my ThinkPad X1 Carbon. First make sure the `acpi_ibm` kernel module is loaded: ```bash kldload acpi_ibm ``` Then, set the following sysctl to allow `devd(8)` to handle the button events: ```bash sysctl dev.acpi_ibm.0.handlerevents='0x10 0x11' ``` We'll need a `devd(8)` rule to handle these events. Create `/etc/devd/thinkpad-brightness.conf` with the following: ``` # /etc/devd/thinkpad-brightness.conf notify 20 {  match "system" "ACPI";  match "subsystem" "IBM";  match "notify" "0x10";  action "/usr/local/libexec/thinkpad-brightness up"; }; notify 20 {  match "system" "ACPI";  match "subsystem" "IBM";  match "notify" "0x11";  action "/usr/local/libexec/thinkpad-brightness down"; }; ``` Finally, create the following script at `/usr/local/libexec/thinkpad-brightness`: ```bash #!/bin/sh # /usr/local/libexec/thinkpad-brightness case $1 in up) if [ "$cur" -ge 50 ]; then delta=10 elif [ "$cur" -ge 10 ]; then delta=5 else delta=2 fi /usr/bin/backlight incr "$delta" ;; down) if [ "$cur" -le 10 ]; then delta=2 elif [ "$cur" -le 50 ]; then delta=5 else delta=10 fi /usr/bin/backlight decr "$delta" ;; esac ``` Don't forget to make it executable: ```bash chmod 755 /usr/local/libexec/thinkpad-brightness ``` ### Reboot Reboot to apply these changes and make sure you didn't break anything: ```bash reboot ``` ## PF Firewall It's sensible to block unexpected incoming connections. Create `/etc/pf.conf` with the following: ```bash # /etc/pf.conf # Replace this with the names of your network interfaces. egress = "{ em0, wlan0, ue0 }" allowed_tcp_ports = "{ ssh }" # If you do any voice/video chats, you may need to open UDP ports for RTP. allowed_udp_ports = "{ 1024:65535 }" set block-policy return set skip on lo scrub in on $egress all fragment reassemble antispoof quick for $egress block all pass out quick on $egress inet pass in quick on $egress inet proto icmp all icmp-type { echoreq, unreach } pass in quick on $egress inet proto tcp to port $allowed_tcp_ports pass in quick on $egress inet proto udp to port $allowed_udp_ports ``` Activate the firewall: ```bash sysrc -v pf_enable=YES service pf start ``` ## Disable Periodic Scripts Out of the box, FreeBSD includes a bunch of `periodic(8)` scripts that churn through your hard disk, reach out to the internet, and send emails. I disable most of these. You can check `/etc/defaults/periodic.conf` for a full list. ```bash sysrc -v -f /etc/periodic.conf \ daily_backup_aliases_enable=NO \ daily_backup_gpart_enable=NO \ daily_backup_passwd_enable=NO \ daily_clean_disks_verbose=NO \ daily_clean_hoststat_enable=NO \ daily_clean_preserve_verbose=NO \ daily_clean_rwho_verbose=NO \ daily_clean_tmps_verbose=NO \ daily_show_info=NO \ daily_show_success=NO \ daily_status_disks_enable=NO \ daily_status_include_submit_mailq=NO \ daily_status_mail_rejects_enable=NO \ daily_status_mail_rejects_enable=NO \ daily_status_mailq_enable=NO \ daily_status_network_enable=NO \ daily_status_security_enable=NO \ daily_status_uptime_enable=NO \ daily_status_world_kernel=NO \ daily_status_zfs_zpool_list_enable=NO \ daily_submit_queuerun=NO \ monthly_accounting_enable=NO \ monthly_show_info=NO \ monthly_show_success=NO \ monthly_status_security_enable=NO \ security_show_info=NO \ security_show_success=NO \ security_status_chkmounts_enable=NO \ security_status_chksetuid_enable=NO \ security_status_chkuid0_enable=NO \ security_status_ipf6denied_enable=NO \ security_status_ipfdenied_enable=NO \ security_status_ipfwdenied_enable=NO \ security_status_ipfwlimit_enable=NO \ security_status_kernelmsg_enable=NO \ security_status_logincheck_enable=NO \ security_status_loginfail_enable=NO \ security_status_neggrpperm_enable=NO \ security_status_passwdless_enable=NO \ security_status_pfdenied_enable=NO \ security_status_tcpwrap_enable=NO \ weekly_locate_enable=NO \ weekly_show_info=NO \ weekly_show_success=NO \ weekly_status_security_enable=NO \ weekly_whatis_enable=NO ``` ## Add Users Create your local user account. Make sure to add yourself to the `operator` and `wheel` groups. ```bash pw useradd \ -n robertlee \ -c 'Robert E. Lee' \ -s /bin/sh \ -M 700 \ -d /home/robertlee \ -G operator,wheel ``` You'll probably want to install `sudo`: ```bash pkg install sudo ``` Update `/usr/local/etc/sudoers` to give sudo permissions to the `wheel` group: ``` # /usr/local/etc/sudoers %wheel ALL=(ALL:ALL) ALL ``` ## Set Locale Set your locale for login shells in `/etc/login.conf`. Modify this file as shown below with your preferred locale: ```diff --- login.conf +++ login.conf @@ -23,7 +23,9 @@ :umtxp=unlimited:\ :priority=0:\ :ignoretime@:\ - :umask=022: + :umask=022:\ + :charset=UTF-8:\ + :lang=en_US.UTF-8: ``` Rebuild the login database to apply this change: ```bash cap_mkdb /etc/login.conf ``` For non-login shells, create `/etc/profile.d/locale.sh` like so: ```bash # /etc/profile.d/locale.sh export LANG=en_US.UTF-8 export CHARSET=UTF-8 ``` ## Enable NTP `ntpd(8)` will keep your system clock up-to-date. Edit `/etc/ntp.conf` with your preferred NTP servers: ``` tos minclock 3 maxclock 6 pool 0.freebsd.pool.ntp.org iburst pool 2.freebsd.pool.ntp.org iburst restrict default limited kod nomodify notrap noquery nopeer restrict source limited kod nomodify notrap noquery restrict 127.0.0.1 restrict ::1 leapfile "/var/db/ntpd.leap-seconds.list" ``` Start `ntpd`: ```bash sysrc -v ntpd_enable=YES ntpd_sync_on_start=YES service ntpd start ``` ## Set the Timezone In case you didn't do this during the installation, set your timezone: ```bash cp -v /usr/share/zoneinfo/America/New_York /etc/localtime ``` ## Switch to openssh-portable The `ssh` in FreeBSD's base system is heavily patched with stuff I don't use. I prefer to use the vanilla `openssh-portable` from ports. ```bash pkg install openssh-portable ``` Edit `/usr/local/etc/ssh/sshd_config` as appropriate: ```bash # /usr/local/etc/ssh/sshd_config PermitRootLogin prohibit-password UsePAM yes UseDNS no Subsystem sftp /usr/local/libexec/sftp-server ``` Replace the running `sshd` with the new one: ```bash sysrc -v sshd_enable=NO openssh_enable=YES service sshd stop service openssh start ``` The `ssh` command will continue using the base system's `/usr/bin/ssh` unless you update your `$PATH`. You can edit `/etc/login.conf` to make the change for all users: ```diff --- login.conf +++ login.conf @@ -4,7 +4,7 @@ :welcome=/var/run/motd:\ :setenv=BLOCKSIZE=K:\ :mail=/var/mail/$:\ - :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\ + :path=/sbin /bin /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin ~/bin:\ :nologin=/var/run/nologin:\ :cputime=unlimited:\ :datasize=unlimited:\ ``` Rebuild the login database to apply this change: ```bash cap_mkdb /etc/login.conf ``` ## Fix 256-color XTerm The `termcap(5)` database on FreeBSD has a [bug](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=280679) which prevents "bright" colors from rendering on `xterm`-like terminals. You can fix it with the following line noise: ```bash mkdir -p /usr/local/share/site-terminfo cat <<'EOF' | tic -o /usr/local/share/site-terminfo - xterm-256color|xterm with 256 colors, am, bce, ccc, km, mc5i, mir, msgr, npc, xenl, colors#0x100, cols#80, it#8, lines#24, pairs#0x10000, acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, bel=^G, blink=\E[5m, bold=\E[1m, cbt=\E[Z, civis=\E[?25l, clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r, csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m, dl=\E[%p1%dM, dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L, ind=\n, indn=\E[%p1%dS, initc=\E]4;%p1%d;rgb:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, invis=\E[8m, is2=\E[!p\E[?3;4l\E[4l\E>, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H, kIC=\E[2;2~, kLFT=\E[1;2D, kNXT=\E[6;2~, kPRV=\E[5;2~, kRIT=\E[1;2C, ka1=\EOw, ka3=\EOy, kb2=\EOu, kbs=^?, kc1=\EOq, kc3=\EOs, kcbt=\E[Z, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA, kdch1=\E[3~, kend=\EOF, kent=\EOM, kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S, kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR, kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~, kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~, kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R, kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~, kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R, kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~, kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~, kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~, kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, khome=\EOH, kich1=\E[2~, kind=\E[1;2B, kmous=\E[<, knp=\E[6~, kpp=\E[5~, kri=\E[1;2A, mc0=\E[i, mc4=\E[4i, mc5=\E[5i, meml=\El, memu=\Em, mgc=\E[?69l, nel=\EE, oc=\E]104\007, op=\E[39;49m, rc=\E8, rep=%p1%c\E[%p2%{1}%-%db, rev=\E[7m, ri=\EM, rin=\E[%p1%dT, ritm=\E[23m, rmacs=\E(B, rmam=\E[?7l, rmcup=\E[?1049l\E[23;0;0t, rmir=\E[4l, rmkx=\E[?1l\E>, rmm=\E[?1034l, rmso=\E[27m, rmul=\E[24m, rs1=\Ec\E]104\007, rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7, setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m, setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m, sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, sgr0=\E(B\E[m, sitm=\E[3m, smacs=\E(0, smam=\E[?7h, smcup=\E[?1049h\E[22;0;0t, smglr=\E[?69h\E[%i%p1%d;%p2%ds, smir=\E[4h, smkx=\E[?1h\E=, smm=\E[?1034h, smso=\E[7m, smul=\E[4m, tbc=\E[3g, u6=\E[%i%d;%dR, u7=\E[6n, u8=\E[?%[;0123456789]c, u9=\E[c, vpa=\E[%i%p1%dd, EOF ``` ## Install Root Certificates FreeBSD trusts a limited number of certificate authorities out of the box. Install the root CA bundle from Mozilla to trust all the standard ones: ```bash pkg install ca_root_nss ``` ## Install KDE and Desktop Applications Grab a cup of coffee and kick back while you install KDE and all the desktop packages. You might not want all of these, they're just what I find useful. ```bash pkg install \ audacious-plugins-qt5 \ audacious-qt5 \ chromium \ digikam \ elisa \ en-hunspell \ firefox \ freedesktop-sound-theme \ k3b \ kde5 \ kid3-kf5 \ kmix \ konversation \ libreoffice \ libva-utils \ libvdpau-va-gl \ merkuro \ sddm \ signal-desktop \ thunderbird \ vdpauinfo \ xorg ``` ## Install Fonts You'll find that some websites don't render quite right without these fonts installed: ```bash pkg install \ cantarell-fonts \ droid-fonts-ttf \ inconsolata-ttf \ noto-basic \ noto-emoji \ roboto-fonts-ttf \ ubuntu-font \ webfonts ``` And of course, how can you live without [Terminus](https://files.ax86.net/terminus-ttf/): ```bash pkg install terminus-font terminus-ttf ``` If you want to use the bitmapped version, you'll need to update `xorg.conf.d`: ``` # /usr/local/etc/X11/xorg.conf.d/terminus.conf Section "Files" FontPath "/usr/local/share/fonts/terminus-font/" EndSection ``` ## Enable D-Bus D-Bus is required for KDE and just about every GUI application these days. ```bash sysrc -v dbus_enable=YES service dbus start ``` ## Configure SDDM [sddm](https://github.com/sddm/sddm) is the preferred login manager for KDE. Enable and start it: ```bash sysrc -v sddm_enable=YES service sddm start ``` With any luck, you'll be dumped to a graphical login screen where you can launch KDE. KDE under Wayland won't even start for me. To prevent my wife from accidentally selecting it, I disabled Wayland in `sddm.conf(5)` like so: ```ini # /usr/local/etc/sddm.conf [General] DisplayServer = x11 [Wayland] SessionDir = /dev/null ``` Hopefully by the time Wayland runs on FreeBSD, the RedHat teenagers will have moved on to another display server. X11 works fine. ## Known Issues This section describes what doesn't work on FreeBSD, and some potential workarounds. ### User switching is broken There is a long-standing [ConsoleKit2 bug](https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=221452) that prevents user switching from working reliably on FreeBSD. There is [another bug](https://github.com/freebsd/drm-kmod/issues/175) that results in broken graphics acceleration whenever a VT switch is performed. Therefore, it's best to just disable user switching for now. You can disable it for all users by adding the following to `/usr/local/etc/xdg/kdeglobals`: ``` # /usr/local/etc/xdg/kdeglobals [KDE Action Restrictions] action/start_new_session=false action/switch_user=false ``` ### Processes aren't killed on logout On FreeBSD, multiple processes remain running indefinitely after logging out of a KDE session. Chromium is especially annoying: it continues running after logout, but gets trapped in some crazy state where it consumes 100% of a CPU core forever. I imagine the KDE developers are mostly concerned with systemd-based Linux distributions, where `logind` ensures that all processes associated with a user session are forcibly killed when the user logs out. So this probably isn't on anyone's radar. Luckily, KDE Plasma has the ability to run a cleanup script whenever a user logs out. Create the following directory: ```bash mkdir -p /usr/local/etc/xdg/plasma-workspace/shutdown ``` Then create `/usr/local/etc/xdg/plasma-workspace/shutdown/cleanup.sh` like so: ```bash #!/bin/sh # /usr/local/etc/xdg/plasma-workspace/shutdown/cleanup.sh # Some processes don't kill themselves when the X server dies. # This script takes care of them. pkill signal-desktop chrome baloo_file dirmngr pkill -f /usr/local/libexec/geoclue-2.0/demos/agent ``` Don't forget to make this file executable: ```bash chmod +x /usr/local/etc/xdg/plasma-workspace/shutdown/cleanup.sh ``` ### Baloo creates a gazillion .nfs files If you have NFS-mounted home directories (like I do), you may notice that your homedir is littered with hundreds of `.nfs` files. KDE comes with a file indexing service called Baloo. Baloo seems to keep lots of open file handles on the files it's indexing. If these files get deleted, the NFS [silly rename](https://linux-nfs.org/wiki/index.php/Server-side_silly_rename) hack is triggered, causing a bunch of `.nfs` files to be created. I've read that Baloo doesn't index network mounts, but apparently it does (at least on FreeBSD). You can disable Baloo entirely by creating `/usr/local/etc/xdg/baloofilerc` with the following: ```ini # /usr/local/etc/xdg/baloofilerc [Basic Settings] Indexing-Enabled=false ``` ### Hardware video acceleration broken in Chromium Video playback in Chromium is supposed to be hardware-accelerated using [VA-API](https://wiki.archlinux.org/title/Hardware_video_acceleration). However, despite installing `libva-intel-media-driver`, my CPU was pegged at 60% or so when watching a YouTube video. I blindly copy-pasted dozens of command-line flags for Chromium until I found the incantation that enabled hardware-accelerated video playback: ```bash chrome --enable-features=Vulkan,VulkanFromANGLE,DefaultANGLEVulkan ``` With those magic flags, CPU usage does not noticeably increase during video playback. To make this change permanent, you can use a custom `.desktop` override for Chromium. First, create a new directory to hold our custom `.desktop` files: ```bash mkdir -p /usr/local/share-override/applications ``` Then, you must set the `$XDG_DATA_DIRS` environment variable so your new directory takes precedence: ```diff --- login.conf +++ login.conf @@ -2,7 +2,7 @@ :passwd_format=sha512:\ :copyright=/etc/COPYRIGHT:\ :welcome=/var/run/motd:\ - :setenv=BLOCKSIZE=K:\ + :setenv=BLOCKSIZE=K,XDG_DATA_DIRS=/usr/local/share-override\c/usr/local/share:\ :mail=/var/mail/$:\ :path=/sbin /bin /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin ~/bin:\ :nologin=/var/run/nologin:\ ``` And, as usual: ```bash cap_mkdb /etc/login.conf ``` Finally, create a custom `chromium-browser.desktop` file like so: ```ini # /usr/local/share-override/desktop/chromium-browser.desktop [Desktop Entry] Type=Application Version=1.0 Encoding=UTF-8 Name=Chromium Comment=Google web browser based on WebKit Icon=chrome Exec=chrome --enable-features=Vulkan,VulkanFromANGLE,DefaultANGLEVulkan %U Categories=Application;Network;WebBrowser; MimeType=text/html;text/xml;application/xhtml+xml;x-scheme-handler/http;x-scheme-handler/https;x-scheme-handler/ftp; StartupNotify=true ``` Luckily, video acceleration in Firefox seems to work properly without any fiddling. ### Screen tearing Until the X11 people cut a release containing [this PR](https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1006), you will experience some screen tearing with the default modesetting driver. Allegedly, you can install the `xf86-video-intel` driver and enable the `TearFree` option in `xorg.conf`. However, I believe this driver is largely unmaintained, so YMMV. I found that screen tearing is greatly reduced by setting **Latency** to *Force lowest latency* under System Settings → Display and Monitor → Compositor. Please do not tell me to use Wayland. At the time of this writing, it does not work.