aboutsummaryrefslogblamecommitdiff
path: root/src/blog/freebsd-14-on-the-desktop/index.md
blob: b01653857b46fd14eb20adee6300745371b5629d (plain) (tree)
1
2
3
4
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130


                                
                                                     

















                                                                                                  


                                                                                
















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                                                     
---
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: <vendor 0x046d HD Pro Webcam C920> (rec)
pcm1: <Audioengine Ltd. Audioengine 2+> (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
<AHCI SGPIO Enclosure 2.00 0001>   at scbus0 target 0 lun 0 (ses0,pass0)
<CL1-3D256-Q11 NVMe SSSTC 256GB 22301116>  at scbus1 target 0 lun 1 (pass1,nda0)
<HL-DT-ST BD-RE BU40N 1.03>        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.