|
@@ -0,0 +1,760 @@
|
|
1
|
+TITLE='FreeBSD Server Guide'
|
|
2
|
+DESCRIPTION='A guide to configuring your new FreeBSD server for performance and security.'
|
|
3
|
+DATE=2017-01-21
|
|
4
|
+__HTML__
|
|
5
|
+<p><a href="https://www.freebsd.org/">FreeBSD</a> is a secure, high-performance Unix-like operating system.
|
|
6
|
+It has been my server OS of choice since I started this self-hosting hobby in my college days. In this post,
|
|
7
|
+I'll describe how I set up my FreeBSD servers—installing packages, securing the firewall, tweaking network
|
|
8
|
+performance, and configuring daemons. This will be similar to those "first five minutes on a server" articles,
|
|
9
|
+but with a focus on FreeBSD 11. If you're not a BSD fan, you're misinformed, but much of the advice in here
|
|
10
|
+will apply to any Unix-like server that you connect to the internet.
|
|
11
|
+
|
|
12
|
+<hr>
|
|
13
|
+
|
|
14
|
+<ol>
|
|
15
|
+ <li><a href="#why-freebsd">Why FreeBSD?</a>
|
|
16
|
+ <li><a href="#building-ports">Building Ports</a>
|
|
17
|
+ <li><a href="#hardware-configuration">Hardware Configuration</a>
|
|
18
|
+ <li><a href="#network-settings">Network Settings</a>
|
|
19
|
+ <li><a href="#environment-setup">Environment Setup</a>
|
|
20
|
+ <li><a href="#tweaking-network-performance">Tweaking Network Performance</a>
|
|
21
|
+ <li><a href="#ssh">LibreSSL and OpenSSH</a>
|
|
22
|
+ <li><a href="#ntp">Clock Sync with OpenNTP</a>
|
|
23
|
+ <li><a href="#pf">Securing the PF Firewall</a>
|
|
24
|
+ <li><a href="#conclusion">Conclusion</a>
|
|
25
|
+</ol>
|
|
26
|
+
|
|
27
|
+<hr>
|
|
28
|
+<section>
|
|
29
|
+ <h2 id="why-freebsd">Why FreeBSD?</h2>
|
|
30
|
+
|
|
31
|
+ <p>Simply put, I use FreeBSD because it makes my life easier. Compared to Linux, it is a more integrated,
|
|
32
|
+ stable, and well-documented operating system. And I don't mean <em>stable</em> in the sense that it has fewer
|
|
33
|
+ bugs, but in the sense that it doesn't do things like <a href="https://www.mail-archive.com/ubuntu-devel-announce@lists.ubuntu.com/msg00893.html">
|
|
34
|
+ switch init systems twice in the same decade</a>. In addition, the <a href="https://opensource.org/licenses/BSD-2-Clause">BSD License</a>
|
|
35
|
+ provides far more freedom to developers and users than the convoluted, marxist <a href="https://www.gnu.org/licenses/gpl-3.0.en.html">GPLv3</a>.
|
|
36
|
+
|
|
37
|
+ <p>For an introduction to FreeBSD from a Linux perspective, <a href="https://www.over-yonder.net/~fullermd/rants/bsd4linux/01">this guide</a>
|
|
38
|
+ is usually cited as the best on the 'net. But for a shortened version: FreeBSD is an operating system, Linux
|
|
39
|
+ is a kernel. FreeBSD is a <a href="https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/Cathedral_of_Saint_John_the_Baptist,_Charleston_SC,_Interior_view_20160704_1.jpg/1280px-Cathedral_of_Saint_John_the_Baptist,_Charleston_SC,_Interior_view_20160704_1.jpg">cathedral</a>,
|
|
40
|
+ Linux is a <a href="https://queue.acm.org/detail.cfm?id=2349257">bazaar</a>. But subjectively,
|
|
41
|
+ FreeBSD just <em>feels</em> better than Linux. Third party software is kept totally independent from the
|
|
42
|
+ base OS, <a href="https://www.freebsd.org/doc/handbook/jails.html">jails</a> and <a href="https://www.freebsd.org/doc/handbook/zfs.html">ZFS</a>
|
|
43
|
+ are awesome, <span class="monospace"><a href="https://www.freebsd.org/doc/handbook/firewalls-pf.html">PF</a></span> puts
|
|
44
|
+ <span class="monospace">iptables</span> to shame...I could go on and on. If you go with FreeBSD, you'll miss out on
|
|
45
|
+ whatever the new Linux hotness of the day is. But in return, you'll get a solid, reliable Unix system that will quietly
|
|
46
|
+ serve you well for years to come.
|
|
47
|
+</section>
|
|
48
|
+
|
|
49
|
+<section>
|
|
50
|
+ <h2 id="building-ports">Building Ports</h2>
|
|
51
|
+
|
|
52
|
+ <p>Before we dive into system configuration, we'll at least want <span class="monospace">vim</span>
|
|
53
|
+ installed. Third-party software packages in FreeBSD are called <em>ports</em>. You can either install
|
|
54
|
+ binary packages using the <span class="monospace">pkg</span> utility or build them from source. I prefer to
|
|
55
|
+ build from source, as you get more fine-grained control over compile-time options and package
|
|
56
|
+ dependencies. It doesn't really matter which method you choose, as long as you're consistent—mixing
|
|
57
|
+ source and binary packages can sometimes cause odd behavior.
|
|
58
|
+
|
|
59
|
+ <p>To start building ports, we'll need the latest version of the ports tree. Grab a cup of coffee while
|
|
60
|
+ you run the following commands as root (it may take awhile).
|
|
61
|
+
|
|
62
|
+<pre>portsnap fetch
|
|
63
|
+portsnap extract
|
|
64
|
+</pre>
|
|
65
|
+
|
|
66
|
+ <p>Next, we'll specify some build options in <span class="monospace"><a href="https://www.freebsd.org/cgi/man.cgi?make.conf(5)">make.conf</a></span>.
|
|
67
|
+ Options that you put in this file will apply to every port you compile. It makes it easy to do things like
|
|
68
|
+ globally disable X11 support—we won't need that on a headless server. Here is what I have in my <span class="monospace">make.conf</span>:
|
|
69
|
+
|
|
70
|
+<pre><div class="code-title">/etc/make.conf</div><span class="code-comment"># allow compiler optimizations specific to our CPU model</span>
|
|
71
|
+CPUTYPE?=native
|
|
72
|
+
|
|
73
|
+<span class="code-comment"># optimization level O2 is the highest supported by FreeBSD and most ports.</span>
|
|
74
|
+CFLAGS=-O2 -pipe -fno-strict-aliasing
|
|
75
|
+
|
|
76
|
+<span class="code-comment"># COPTFLAGS only apply when building the kernel</span>
|
|
77
|
+COPTFLAGS=$CFLAGS
|
|
78
|
+
|
|
79
|
+<span class="code-comment"># don't pull in X11, CUPS, etc</span>
|
|
80
|
+OPTIONS_UNSET=DOCS NLS X11 EXAMPLES CUPS GUI DEBUG
|
|
81
|
+
|
|
82
|
+<span class="code-comment"># disable profiling, unless you like 1hr compile times</span>
|
|
83
|
+MK_PROFILE=no
|
|
84
|
+
|
|
85
|
+<span class="code-comment"># default version to use when certain ports are pulled in as dependencies</span>
|
|
86
|
+<span class="code-comment"># ..notice LibreSSL :-)</span>
|
|
87
|
+DEFAULT_VERSIONS+= ssl=libressl python=2.7 python2=2.7 python3=3.5 pgsql=9.6 php=7.0 ruby=2.3 perl=5.24 lua=5.1
|
|
88
|
+</pre>
|
|
89
|
+
|
|
90
|
+ <p>Now we can install <span class="monospace">vim</span>:
|
|
91
|
+
|
|
92
|
+ <pre><code>cd /usr/ports/editors/vim && make install clean</code></pre>
|
|
93
|
+
|
|
94
|
+ <p>You will be prompted to select some compile-time options before the package is built and installed
|
|
95
|
+ for you. You can search available packages by running <span class="monospace">make search name=$PACKAGENAME</span>
|
|
96
|
+ in <span class="monospace">/usr/ports</span>. I usually have at least the following installed on my servers:
|
|
97
|
+
|
|
98
|
+<pre>
|
|
99
|
+devel/git
|
|
100
|
+editors/vim
|
|
101
|
+ftp/curl
|
|
102
|
+net-mgmt/iftop
|
|
103
|
+ports-mgmt/portmaster
|
|
104
|
+security/sudo
|
|
105
|
+shells/zsh
|
|
106
|
+sysutils/coreutils
|
|
107
|
+sysutils/tmux
|
|
108
|
+</pre>
|
|
109
|
+</section>
|
|
110
|
+
|
|
111
|
+<section>
|
|
112
|
+ <h2 id="hardware-configuration">Hardware Configuration</h2>
|
|
113
|
+
|
|
114
|
+ <p>There are a few easy modifications we can make to improve FreeBSD's performance on modern hardware.
|
|
115
|
+ If you're using a solid state drive with the UFS file system, it's important to enable
|
|
116
|
+ <a href="https://en.wikipedia.org/wiki/Trim_(computing)">TRIM</a> support. You should also set filesystem
|
|
117
|
+ labels, so you won't have to worry about your disks getting renamed in between reboots (which often happens
|
|
118
|
+ when you enable AHCI). We can't make these changes while the disks are mounted, so you'll need to reboot
|
|
119
|
+ to single-user mode. Reboot your machine, and hit <span class="monospace">S</span> at the bootloader prompt.
|
|
120
|
+
|
|
121
|
+ <h3 id="enabling-trim">Enabling TRIM Support</h3>
|
|
122
|
+
|
|
123
|
+ <p>Once you've booted into the single-user shell, you can get a list of your partitions using
|
|
124
|
+ <span class="monospace">gpart show</span>. Here is what I see on my machine:
|
|
125
|
+
|
|
126
|
+ <pre><span class="code-comment"># gpart show</span>
|
|
127
|
+=> 34 1953525101 ada0 GPT (932G)
|
|
128
|
+ 34 2014 - free - (1.0M)
|
|
129
|
+ 2048 1953521664 1 freebsd-ufs (932G)
|
|
130
|
+ 1953523712 1423 - free - (712K)
|
|
131
|
+
|
|
132
|
+=> 34 500118125 ada1 GPT (238G)
|
|
133
|
+ 34 6 - free - (3.0K)
|
|
134
|
+ 40 1024 1 freebsd-boot (512K)
|
|
135
|
+ 1064 500117088 2 freebsd-ufs (238G)
|
|
136
|
+ 500118152 7 - free - (3.5K)
|
|
137
|
+</pre>
|
|
138
|
+
|
|
139
|
+ <p>So we've got two drives. <span class="monospace">ada0</span> is a 1 TB storage drive, and
|
|
140
|
+ <span class="monospace">ada1</span> is an SSD for the OS. The first partition just holds the
|
|
141
|
+ bootloader, but we'll want to make sure TRIM is enabled on the OS root partition.
|
|
142
|
+
|
|
143
|
+<pre><span class="code-comment"># tunefs -p /dev/ada1p2</span>
|
|
144
|
+tunefs: POSIX.1e ACLs: (-a) disabled
|
|
145
|
+tunefs: NFSv4 ACLs: (-N) disabled
|
|
146
|
+tunefs: MAC multilabel: (-l) disabled
|
|
147
|
+tunefs: soft updates: (-n) enabled
|
|
148
|
+tunefs: soft update journaling: (-j) enabled
|
|
149
|
+tunefs: gjournal: (-J) disabled
|
|
150
|
+tunefs: trim: (-t) disabled
|
|
151
|
+tunefs: maximum blocks per file in a cylinder group: (-e) 4096
|
|
152
|
+tunefs: average file size: (-f) 16384
|
|
153
|
+tunefs: average number of files in a directory: (-s) 64
|
|
154
|
+tunefs: minimum percentage of free space: (-m) 8%
|
|
155
|
+tunefs: optimization preference: (-o) time
|
|
156
|
+tunefs: volume label: (-L)
|
|
157
|
+</pre>
|
|
158
|
+
|
|
159
|
+ <p>Let's go ahead and enable TRIM on this partition.
|
|
160
|
+
|
|
161
|
+<pre>tunefs -t enable /dev/ada1p2</pre>
|
|
162
|
+
|
|
163
|
+ <h3 id="ufs-labels">Setting UFS Labels</h3>
|
|
164
|
+
|
|
165
|
+ <p>While we have everything unmounted, we can set filesystem labels as well:
|
|
166
|
+
|
|
167
|
+<pre>tunefs -L rootfs /dev/ada1p2
|
|
168
|
+tunefs -L storagefs /dev/ada0p1
|
|
169
|
+</pre>
|
|
170
|
+
|
|
171
|
+ <p>Type <span class="monospace">exit</span> to leave single-user mode and continue the boot process.
|
|
172
|
+ Once you're back into your system, you can edit <span class="monospace">/etc/fstab</span> with your
|
|
173
|
+ new filesystem labels.
|
|
174
|
+
|
|
175
|
+<pre><div class="code-title">/etc/fstab</div>/dev/ufs/rootfs / ufs rw 1 1
|
|
176
|
+/dev/ufs/storagefs /storage ufs rw 1 2
|
|
177
|
+
|
|
178
|
+<span class="code-comment"># old disk names - replaced with labels above</span>
|
|
179
|
+<span class="code-comment">#/dev/ada1p2 / ufs rw 1 1</span>
|
|
180
|
+<span class="code-comment">#/dev/ada0p1 /storage ufs rw 1 2</span>
|
|
181
|
+</pre>
|
|
182
|
+
|
|
183
|
+ <h3 id="kernel-modules">Loading Useful Kernel Modules</h3>
|
|
184
|
+
|
|
185
|
+ <p>I usually put the following in <span class="monospace">/boot/loader.conf</span>:
|
|
186
|
+
|
|
187
|
+<pre><div class="code-title">/boot/loader.conf</div><span class="code-comment"># bootloader prompt timeout (seconds)</span>
|
|
188
|
+autoboot_delay="5"
|
|
189
|
+
|
|
190
|
+<span class="code-comment"># enable temperature sensors</span>
|
|
191
|
+coretemp_load="YES"
|
|
192
|
+
|
|
193
|
+<span class="code-comment"># enable AHCI on modern hardware for better performance</span>
|
|
194
|
+ahci_load="YES"
|
|
195
|
+
|
|
196
|
+<span class="code-comment"># enable hardware accelerated AES (can speed up TLS)</span>
|
|
197
|
+aesni_load="YES"
|
|
198
|
+
|
|
199
|
+<span class="code-comment"># enable asynchronous I/O (big performance gains with NGINX)</span>
|
|
200
|
+aio_load="YES"
|
|
201
|
+
|
|
202
|
+<span class="code-comment"># in-memory file system</span>
|
|
203
|
+tmpfs_load="YES"
|
|
204
|
+
|
|
205
|
+<span class="code-comment"># load PF firewall and the Intel ethernet driver early at boot time</span>
|
|
206
|
+pf_load="YES"
|
|
207
|
+pflog_load="YES"
|
|
208
|
+if_igb_load="YES"
|
|
209
|
+</pre>
|
|
210
|
+
|
|
211
|
+ <h3 id="disk-readahead">Increasing Disk Read Ahead</h3>
|
|
212
|
+ <p>Finally, increasing the UFS read ahead value almost always results in better performance.
|
|
213
|
+ Add the following to <span class="monospace">/etc/sysctl.conf</span>:
|
|
214
|
+
|
|
215
|
+<pre><div class="code-title">/etc/sysctl.conf</div>vfs.read_max="128"
|
|
216
|
+</pre>
|
|
217
|
+
|
|
218
|
+ <p>You should reboot your machine after making these changes to make sure you didn't break anything.
|
|
219
|
+</section>
|
|
220
|
+
|
|
221
|
+<section>
|
|
222
|
+ <h2 id="network-settings">Network Settings</h2>
|
|
223
|
+
|
|
224
|
+ <p>Open up <span class="monospace">/etc/rc.conf</span> to configure your network interfaces. You will need
|
|
225
|
+ an IP address (and hopefully an IPv6 address) for the machine, as well as a hostname of your choosing. I
|
|
226
|
+ use dual NICs with a <a href="https://www.freebsd.org/doc/handbook/network-aggregation.html"><span class="monospace">lagg</span>
|
|
227
|
+ failover interface</a>, so I've included that in the snippet below. This example uses fake IP addresses,
|
|
228
|
+ you will need real ones!
|
|
229
|
+
|
|
230
|
+<pre><div class="code-title">/etc/rc.conf</div><span class="code-comment"># choose a hostname for this machine. you did register a domain, right?</span>
|
|
231
|
+hostname="beastie.c0ffee.net"
|
|
232
|
+
|
|
233
|
+<span class="code-comment"># My machine has two interfaces in a failover configuration:</span>
|
|
234
|
+<span class="code-comment"># igb0 and igb1 are physical interfaces, lagg0 is a virtual aggregate.</span>
|
|
235
|
+<span class="code-comment"># You should disable LRO and TSO if this machine will route packets.</span>
|
|
236
|
+ifconfig_igb0="up -lro -tso"
|
|
237
|
+ifconfig_igb1="up -lro -tso"
|
|
238
|
+cloned_interfaces="lagg0"
|
|
239
|
+
|
|
240
|
+<span class="code-comment"># Your IPv4 address, netmask, and default gateway go here.</span>
|
|
241
|
+<span class="code-comment"># Your hosting provider should provide this info.</span>
|
|
242
|
+ifconfig_lagg0="laggproto failover laggport igb0 laggport igb1 192.168.1.12/24"
|
|
243
|
+defaultrouter="192.168.1.1"
|
|
244
|
+
|
|
245
|
+<span class="code-comment"># IPv6 address and IPv6 gateway go here (if applicable).</span>
|
|
246
|
+ifconfig_lagg0_ipv6="inet6 2000:f2a5:a440::2/64"
|
|
247
|
+ipv6_defaultrouter="2000:f2a5:a440::1"
|
|
248
|
+ipv6_activate_all_interfaces="YES"
|
|
249
|
+
|
|
250
|
+<span class="code-comment"># If you only had one network interface, then the below would suffice:</span>
|
|
251
|
+<span class="code-comment"># ifconfig_igb0="inet 192.168.1.12/24 -lro -tso"</span>
|
|
252
|
+<span class="code-comment"># defaultrouter="192.168.1.1"</span>
|
|
253
|
+<span class="code-comment"># ifconfig_igb0_ipv6="inet6 2000:f2a5:a440::2/64"</span>
|
|
254
|
+<span class="code-comment"># ipv6_defaultrouter="2000:f2a5:a440::1"</span>
|
|
255
|
+<span class="code-comment"># ipv6_activate_all_interfaces="YES"</span>
|
|
256
|
+</pre>
|
|
257
|
+
|
|
258
|
+ <p>You will need to set your DNS servers in <span class="monospace">/etc/resolv.conf</span>. For example, if
|
|
259
|
+ you are using Google's DNS:
|
|
260
|
+
|
|
261
|
+<pre><div class="code-title">/etc/resolv.conf</div>nameserver 8.8.8.8
|
|
262
|
+nameserver 8.8.4.4
|
|
263
|
+search c0ffee.net
|
|
264
|
+</pre>
|
|
265
|
+
|
|
266
|
+ <p>Also, make sure to add your machine's IP addresses to <span class="monospace">/etc/hosts</span>:
|
|
267
|
+
|
|
268
|
+<pre><div class="code-title">/etc/hosts</div>::1 localhost localhost.c0ffee.net
|
|
269
|
+127.0.0.1 localhost localhost.c0ffee.net
|
|
270
|
+
|
|
271
|
+2000:f2a5:a440::2 beastie beastie.c0ffee.net
|
|
272
|
+192.168.1.12 beastie beastie.c0ffee.net
|
|
273
|
+</pre>
|
|
274
|
+</section>
|
|
275
|
+
|
|
276
|
+<section>
|
|
277
|
+ <h2 id="environment-setup">Environment Setup</h2>
|
|
278
|
+
|
|
279
|
+ <p>It's the current year, so you should enable UTF-8 for your locale and charset everywhere. Add the following to
|
|
280
|
+ <span class="monospace">/etc/profile</span>:
|
|
281
|
+
|
|
282
|
+<pre><div class="code-title">/etc/profile</div>LANG=en_US.UTF-8; export LANG
|
|
283
|
+CHARSET=UTF-8; export CHARSET
|
|
284
|
+</pre>
|
|
285
|
+
|
|
286
|
+ <p>Also, add the bolded lines below to your default login class in <span class="monospace">/etc/login.conf</span>:
|
|
287
|
+
|
|
288
|
+<pre><div class="code-title">/etc/login.conf</div>default:\
|
|
289
|
+ :passwd_format=sha512:\
|
|
290
|
+ :copyright=/etc/COPYRIGHT:\
|
|
291
|
+ :welcome=/etc/motd:\
|
|
292
|
+ :setenv=MAIL=/var/mail/$,BLOCKSIZE=K:\
|
|
293
|
+ :path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin ~/bin:\
|
|
294
|
+ :nologin=/var/run/nologin:\
|
|
295
|
+ :cputime=unlimited:\
|
|
296
|
+ :datasize=unlimited:\
|
|
297
|
+ :stacksize=unlimited:\
|
|
298
|
+ :memorylocked=64K:\
|
|
299
|
+ :memoryuse=unlimited:\
|
|
300
|
+ :filesize=unlimited:\
|
|
301
|
+ :coredumpsize=unlimited:\
|
|
302
|
+ :openfiles=unlimited:\
|
|
303
|
+ :maxproc=unlimited:\
|
|
304
|
+ :sbsize=unlimited:\
|
|
305
|
+ :vmemoryuse=unlimited:\
|
|
306
|
+ :swapuse=unlimited:\
|
|
307
|
+ :pseudoterminals=unlimited:\
|
|
308
|
+ :kqueues=unlimited:\
|
|
309
|
+ :umtxp=unlimited:\
|
|
310
|
+ :priority=0:\
|
|
311
|
+ :ignoretime@:\
|
|
312
|
+ :umask=022:\
|
|
313
|
+ <strong>:charset=UTF-8:\</strong>
|
|
314
|
+ <strong>:lang=en_US.UTF-8:</strong>
|
|
315
|
+</pre>
|
|
316
|
+
|
|
317
|
+ <p>You'll need to rebuild the login database after you edit that file:
|
|
318
|
+
|
|
319
|
+<pre>cap_mkdb /etc/login.conf
|
|
320
|
+</pre>
|
|
321
|
+
|
|
322
|
+ <p>You should also set your timezone. I'm on the east coast, so I use <span class="monospace">America/New_York</span>. Modify
|
|
323
|
+ according to your location.
|
|
324
|
+
|
|
325
|
+<pre>cp /usr/share/zoneinfo/America/New_York /etc/localtime
|
|
326
|
+</pre>
|
|
327
|
+</section>
|
|
328
|
+
|
|
329
|
+<section>
|
|
330
|
+ <h2 id="tweaking-network-performance">Tweaking Network Performance</h2>
|
|
331
|
+
|
|
332
|
+ <p>In my experience, the default TCP settings of the FreeBSD kernel yielded very poor network
|
|
333
|
+ performance. My server has a fairly fast 1 Gbps uplink, but the majority of my traffic must travel
|
|
334
|
+ all the way across the country to the east coast (about a 100ms round-trip-time). My biggest
|
|
335
|
+ problem involved
|
|
336
|
+ <a href="https://en.wikipedia.org/wiki/TCP_congestion_control#Slow_start">TCP Slow Start</a>,
|
|
337
|
+ the algorithm that initially increases the throughput of TCP connections. I could eventually
|
|
338
|
+ max out my server's network connection, but it would take 15 minutes or more for the transfer
|
|
339
|
+ speed to ramp up.
|
|
340
|
+
|
|
341
|
+ <p>To get decent
|
|
342
|
+ throughput, I had to tweak a fair amount of various kernel options and <span class="monospace">sysctl</span>s.
|
|
343
|
+ Most of my inspiration came from
|
|
344
|
+ <a href="https://calomel.org/freebsd_network_tuning.html">this awesome Calomel guide</a> and a
|
|
345
|
+ lot of trial and error. If you have a different network topology, you may have to modify some
|
|
346
|
+ of these values and see what works best for you.
|
|
347
|
+
|
|
348
|
+ <p>First, let's enable some boot-time kernel options in <span class="monospace">/boot/loader.conf</span>.
|
|
349
|
+
|
|
350
|
+<pre><div class="code-title">/boot/loader.conf</div><span class="code-comment"># Load the H-TCP algorithm. It has a more aggressive ramp-up to max</span>
|
|
351
|
+<span class="code-comment"># bandwidth, and is optimized for high-speed, high-latency connections.</span>
|
|
352
|
+cc_htcp_load="YES"
|
|
353
|
+
|
|
354
|
+<span class="code-comment"># accept filters allow the kernel to buffer certain incoming connections</span>
|
|
355
|
+<span class="code-comment"># until a complete request is received (such as HTTP headers). This can</span>
|
|
356
|
+<span class="code-comment"># reduce the number of context switches required by the CPU.</span>
|
|
357
|
+accf_http_load="YES"
|
|
358
|
+accf_data_load="YES"
|
|
359
|
+accf_dns_load="YES"
|
|
360
|
+
|
|
361
|
+<span class="code-comment"># The hostcache is used to "grade" the throughput of previous connections.</span>
|
|
362
|
+<span class="code-comment"># Calomel says that disabling it can increase throughput on connections</span>
|
|
363
|
+<span class="code-comment"># incorrectly marked as slow. I didn't notice much difference either way.</span>
|
|
364
|
+net.inet.tcp.hostcache.cachelimit="0"
|
|
365
|
+
|
|
366
|
+<span class="code-comment"># This is the network interface queue length. According to <a href="https://svnweb.freebsd.org/base?view=revision&revision=207554">this commit</a>,</span>
|
|
367
|
+<span class="code-comment"># the default value of 50 is far too low. Calomel recommends 2x the value</span>
|
|
368
|
+<span class="code-comment"># of hw.igb.txd, which has worked well for me.</span>
|
|
369
|
+net.link.ifqmaxlen="2048"
|
|
370
|
+
|
|
371
|
+<span class="code-comment"># Enables a faster but possibly buggy implementation of soreceive. I</span>
|
|
372
|
+<span class="code-comment"># haven't had any problems with it.</span>
|
|
373
|
+net.inet.tcp.soreceive_stream="1"
|
|
374
|
+
|
|
375
|
+<span class="code-comment"># FreeBSD sets an artificial limit on the number of packets an Intel card</span>
|
|
376
|
+<span class="code-comment"># can process per interrupt cycle (default 100). This is almost totally</span>
|
|
377
|
+<span class="code-comment"># useless on modern hardware. -1 means no limit.</span>
|
|
378
|
+hw.igb.rx_process_limit="-1"
|
|
379
|
+</pre>
|
|
380
|
+
|
|
381
|
+ <p>You'll have to reboot your machine for these changes to take effect.
|
|
382
|
+
|
|
383
|
+ <p>The rest of the network options can be tweaked on the fly using <span class="monospace">sysctl</span>:
|
|
384
|
+
|
|
385
|
+<pre><div class="code-title">/etc/sysctl.conf</div><span class="code-comment"># soacceptqueue is the kernel's backlog queue depth for accepting new TCP</span>
|
|
386
|
+<span class="code-comment"># connections. A larger value should prevent clients from being dropped</span>
|
|
387
|
+<span class="code-comment"># during sudden bursty periods at the expense of more RAM and CPU load.</span>
|
|
388
|
+kern.ipc.soacceptqueue=1024 <span class="code-comment"># (default 128)</span>
|
|
389
|
+
|
|
390
|
+<span class="code-comment"># maxsockbuf is the max amount of memory that can be allocated to a socket.</span>
|
|
391
|
+<span class="code-comment"># In practice, this value determines the <a href="https://en.wikipedia.org/wiki/TCP_window_scale_option">TCP window scaling</a> factor - the</span>
|
|
392
|
+<span class="code-comment"># number of bytes that can be transmitted without requiring an ACK. If our</span>
|
|
393
|
+<span class="code-comment"># server is not under heavy load, we want a large scaling factor, because</span>
|
|
394
|
+<span class="code-comment"># we can transmit packets as fast as the receiver can process them.</span>
|
|
395
|
+<span class="code-comment">#</span>
|
|
396
|
+<span class="code-comment"># The default maxsockbuf value (2MB) will result in a scaling factor of 6,</span>
|
|
397
|
+<span class="code-comment"># which is ideal for a low-latency gigabit network.</span>
|
|
398
|
+<span class="code-comment">#</span>
|
|
399
|
+<span class="code-comment"># However, my server is on the west coast, on a gigabit connection with</span>
|
|
400
|
+<span class="code-comment"># 100ms of latency to my hometown on the east coast. A scaling factor of 8:</span>
|
|
401
|
+<span class="code-comment">#</span>
|
|
402
|
+<span class="code-comment"># 2^8 x 65,535-byte IP packet size = 16,776,960 bytes</span>
|
|
403
|
+<span class="code-comment">#</span>
|
|
404
|
+<span class="code-comment"># happens to saturates my connection:</span>
|
|
405
|
+<span class="code-comment">#</span>
|
|
406
|
+<span class="code-comment"># 16,776,960 bytes * 8 / .1 sec latency / 10^9 = 1.3421568 Gbps</span>
|
|
407
|
+<span class="code-comment">#</span>
|
|
408
|
+<span class="code-comment"># You remember Bandwidth Delay Product from networking class, right? :-)</span>
|
|
409
|
+<span class="code-comment">#</span>
|
|
410
|
+<span class="code-comment"># A maxsockbuf value of 8MB will yield a scaling factor of 8. To see</span>
|
|
411
|
+<span class="code-comment"># how this is derived, you can check <a href="https://github.com/freebsd/freebsd/blob/master/sys/netinet/tcp_syncache.c#L1415">/sys/netinet/tcp_syncache.c</a>.</span>
|
|
412
|
+<span class="code-comment">#</span>
|
|
413
|
+kern.ipc.maxsockbuf=8388608
|
|
414
|
+
|
|
415
|
+<span class="code-comment"># sendspace and recvspace are the network buffer sizes *initially* allocated</span>
|
|
416
|
+<span class="code-comment"># to each TCP connection. Bandwidth can be improved by increasing the buffer</span>
|
|
417
|
+<span class="code-comment"># size at the cost of using more kernel memory per connection. Saturating my</span>
|
|
418
|
+<span class="code-comment"># gigabit connection with 100ms latency would require:</span>
|
|
419
|
+<span class="code-comment">#</span>
|
|
420
|
+<span class="code-comment"># 1000 megabits * .1 sec / 8 bits = 12.5 MB </span>
|
|
421
|
+<span class="code-comment">#</span>
|
|
422
|
+<span class="code-comment"># However, just 80 simultaneous connections would immediately consume a</span>
|
|
423
|
+<span class="code-comment"># GIGABYTE of RAM! Most of the traffic to my server is for small, static</span>
|
|
424
|
+<span class="code-comment"># HTML pages and some SSH connections, so I've set a smaller default size:</span>
|
|
425
|
+<span class="code-comment">#</span>
|
|
426
|
+<span class="code-comment"># 256 KB = 256 * 1024 bytes = 262,144 bytes</span>
|
|
427
|
+<span class="code-comment">#</span>
|
|
428
|
+<span class="code-comment"># The kernel will allocate more memory as needed (at a very slight</span>
|
|
429
|
+<span class="code-comment"># performance hit) for the occasional full-throttle transfer of large</span>
|
|
430
|
+<span class="code-comment"># files.</span>
|
|
431
|
+<span class="code-comment">#</span>
|
|
432
|
+net.inet.tcp.sendspace=262144 <span class="code-comment"># (default 32768)</span>
|
|
433
|
+net.inet.tcp.recvspace=262144 <span class="code-comment"># (default 65536)</span>
|
|
434
|
+
|
|
435
|
+<span class="code-comment"># sendbuf_max and recvbuf_max control the maximum send and recv buffer sizes</span>
|
|
436
|
+<span class="code-comment"># the kernel will ever allocate for a single TCP connection. I set mine to</span>
|
|
437
|
+<span class="code-comment"># 16 MB, which is slightly higher than the 12.5 MB I calculated above. This </span>
|
|
438
|
+<span class="code-comment"># should let me to saturate my 100ms connection, as well as leave some</span>
|
|
439
|
+<span class="code-comment"># wiggle room to saturate even higher-latency clients.</span>
|
|
440
|
+<span class="code-comment">#</span>
|
|
441
|
+<span class="code-comment"># You should probably make sure these values are at least as large as</span>
|
|
442
|
+<span class="code-comment"># maxsockbuf.</span>
|
|
443
|
+<span class="code-comment">#</span>
|
|
444
|
+net.inet.tcp.sendbuf_max=16777216
|
|
445
|
+net.inet.tcp.recvbuf_max=16777216
|
|
446
|
+
|
|
447
|
+<span class="code-comment"># sendbuf_inc and recvbuf_inc control the increments by which the kernel</span>
|
|
448
|
+<span class="code-comment"># increases sendspace and recvspace to sendbuf_max and recvbuf_max,</span>
|
|
449
|
+<span class="code-comment"># respectively. Higher values will cause fewer memory allocations, but may</span>
|
|
450
|
+<span class="code-comment"># result in wasted buffer space.</span>
|
|
451
|
+<span class="code-comment">#</span>
|
|
452
|
+net.inet.tcp.sendbuf_inc=32768 <span class="code-comment"># (default 8192)</span>
|
|
453
|
+net.inet.tcp.recvbuf_inc=65536 <span class="code-comment"># (default 16384)</span>
|
|
454
|
+
|
|
455
|
+<span class="code-comment"># increase the localhost buffer space, which may help localhost-only servers</span>
|
|
456
|
+<span class="code-comment"># more efficiently move data to network buffers.</span>
|
|
457
|
+net.local.stream.sendspace=16384 <span class="code-comment"># default (8192)</span>
|
|
458
|
+net.local.stream.recvspace=16384 <span class="code-comment"># default (8192)</span>
|
|
459
|
+
|
|
460
|
+<span class="code-comment"># increase the raw IP datagram buffers to the MTU for the localhost</span>
|
|
461
|
+<span class="code-comment"># interface (2^14 bytes = 16384). Thanks, Calomel!</span>
|
|
462
|
+net.inet.raw.maxdgram=16384
|
|
463
|
+net.inet.raw.recvspace=16384
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+<span class="code-comment"># *** these two settings gave me the most drastic improvement: ***</span>
|
|
467
|
+
|
|
468
|
+<span class="code-comment"># TCP Slow Start gradually ramps up the data transmission rate until the</span>
|
|
469
|
+<span class="code-comment"># throughput on the network path has been determined. TCP Appropriate Byte</span>
|
|
470
|
+<span class="code-comment"># Counting (ABC) allows the kernel to increase the window size</span>
|
|
471
|
+<span class="code-comment"># exponentially. According to Calomel, with maxseg set to the default of</span>
|
|
472
|
+<span class="code-comment"># 1460 bytes, setting abc_l_var to 44 allows an increase of about 64 KB per</span>
|
|
473
|
+<span class="code-comment"># step, which happens to be the receive buffer size of most hosts that don't</span>
|
|
474
|
+<span class="code-comment"># support window scaling.</span>
|
|
475
|
+<span class="code-comment">#</span>
|
|
476
|
+net.inet.tcp.abc_l_var=44 <span class="code-comment"># (default 2)</span>
|
|
477
|
+
|
|
478
|
+<span class="code-comment"># The TCP initial congestion window determines the *initial* amount of data</span>
|
|
479
|
+<span class="code-comment"># that can be sent over the network before requiring an ACK from the other</span>
|
|
480
|
+<span class="code-comment"># side. The Slow Start algorithm will improve this value over time. A larger</span>
|
|
481
|
+<span class="code-comment"># initcwnd will speed up short, bursty connections. Google recommends 16,</span>
|
|
482
|
+<span class="code-comment"># but according to Calomel, you should also test 44.</span>
|
|
483
|
+net.inet.tcp.initcwnd_segments=44 <span class="code-comment"># (default 10)</span>
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+<span class="code-comment"># Maximum Segment Size (MSS) specifies the largest amount of data that can</span>
|
|
487
|
+<span class="code-comment"># be placed in a single IPv4 TCP segment. This value is usually equal to:</span>
|
|
488
|
+<span class="code-comment">#</span>
|
|
489
|
+<span class="code-comment"># MTU (usually 1500) - 20 byte IPv4 header - 20 byte TCP header = 1460</span>
|
|
490
|
+<span class="code-comment">#</span>
|
|
491
|
+<span class="code-comment"># If you have net.inet.tcp.rfc1323 enabled (it is by default on FreeBSD),</span>
|
|
492
|
+<span class="code-comment"># then TCP hosts can negotiate timestamps which increases the TCP headers</span>
|
|
493
|
+<span class="code-comment"># by 12 bytes. So in the case we'll use 1460 - 12 = 1448 bytes.</span>
|
|
494
|
+<span class="code-comment">#</span>
|
|
495
|
+net.inet.tcp.mssdflt=1448 <span class="code-comment"># (default 536)</span>
|
|
496
|
+
|
|
497
|
+<span class="code-comment"># The Minimum MSS specifies the smallest amount of data we will send in a</span>
|
|
498
|
+<span class="code-comment"># single IPv4 TCP segment. RFC 6691 requires a minimum value of 576 bytes.</span>
|
|
499
|
+<span class="code-comment"># Subtracting a 20 byte IP header and 20 (or 32, see above) byte TCP header</span>
|
|
500
|
+<span class="code-comment"># gives us:</span>
|
|
501
|
+<span class="code-comment">#</span>
|
|
502
|
+<span class="code-comment"># 576 (minimum MTU) - 20 byte IPv4 header - 32 byte TCP header = 524 bytes.</span>
|
|
503
|
+<span class="code-comment">#</span>
|
|
504
|
+net.inet.tcp.minmss=524 <span class="code-comment"># (default 216)</span>
|
|
505
|
+
|
|
506
|
+<span class="code-comment"># use the H-TCP algorithm that we enabled in /boot/loader.conf above.</span>
|
|
507
|
+net.inet.tcp.cc.algorithm=htcp
|
|
508
|
+
|
|
509
|
+<span class="code-comment"># Enable H-TCP's adaptive backoff optimization, which increases buffer</span>
|
|
510
|
+<span class="code-comment"># efficiency along the network path.</span>
|
|
511
|
+net.inet.tcp.cc.htcp.adaptive_backoff=1
|
|
512
|
+
|
|
513
|
+<span class="code-comment"># Enable H-TCP's RTT scaling optimization, which increases fairness between</span>
|
|
514
|
+<span class="code-comment"># flows with different RTTs.</span>
|
|
515
|
+net.inet.tcp.cc.htcp.rtt_scaling=1
|
|
516
|
+
|
|
517
|
+<span class="code-comment"># RFC 6675 improves TCP Fast Recovery when combined with SACK (which is</span>
|
|
518
|
+<span class="code-comment"># enabled by default on FreeBSD - net.inet.tcp.sack.enable)</span>
|
|
519
|
+net.inet.tcp.rfc6675_pipe=1
|
|
520
|
+
|
|
521
|
+<span class="code-comment"># Disabling syncookies will give us more TCP features like window scale and</span>
|
|
522
|
+<span class="code-comment"># timestamps at the expense of making us more vulnerable to DoS attacks.</span>
|
|
523
|
+net.inet.tcp.syncookies=0
|
|
524
|
+
|
|
525
|
+<span class="code-comment"># disable the TIME_WAIT state for the localhost interface, this should</span>
|
|
526
|
+<span class="code-comment"># result in localhost sockets being freed more quickly.</span>
|
|
527
|
+net.inet.tcp.nolocaltimewait=1
|
|
528
|
+
|
|
529
|
+<span class="code-comment"># TSO (and LRO) should be disabled on machines that forward packets. I use</span>
|
|
530
|
+<span class="code-comment"># OpenVPN, sometimes, so I've disabled TSO here. These options can also be</span>
|
|
531
|
+<span class="code-comment"># disabled in /etc/rc.conf using the `-tso -lro` options.</span>
|
|
532
|
+net.inet.tcp.tso=0
|
|
533
|
+
|
|
534
|
+<span class="code-comment"># these two values control the number of frames the NIC will accept before</span>
|
|
535
|
+<span class="code-comment"># firing an interrupt. If the queue fills up and the machine is overloaded,</span>
|
|
536
|
+<span class="code-comment"># packets will be dropped. Increasing this value should mitigate packet loss</span>
|
|
537
|
+<span class="code-comment"># in case of a storm of short, bursty packets, but if</span>
|
|
538
|
+<span class="code-comment"># net.inet.ip.intr_queue_drops remains greater than 0, you probably just</span>
|
|
539
|
+<span class="code-comment"># need better hardware.</span>
|
|
540
|
+<span class="code-comment">#</span>
|
|
541
|
+net.inet.ip.intr_queue_maxlen=2048 <span class="code-comment"># (default 256)</span>
|
|
542
|
+net.route.netisr_maxqlen=2048 <span class="code-comment"># (default 256)</span>
|
|
543
|
+
|
|
544
|
+<span class="code-comment"># Disable Intel's hardware-based ethernet flow control. Instead we will rely</span>
|
|
545
|
+<span class="code-comment"># on TCP which is peer-based and more fair to each flow.</span>
|
|
546
|
+dev.igb.0.fc=0 <span class="code-comment"># (default 3)</span>
|
|
547
|
+dev.igb.1.fc=0 <span class="code-comment"># (default 3)</span>
|
|
548
|
+</pre>
|
|
549
|
+
|
|
550
|
+ <p>Run the following command to update the kernel with the new values:
|
|
551
|
+
|
|
552
|
+<pre>sysctl -f /etc/sysctl.conf
|
|
553
|
+</pre>
|
|
554
|
+</section>
|
|
555
|
+
|
|
556
|
+<section>
|
|
557
|
+ <h2 id="ssh">LibreSSL and OpenSSH</h2>
|
|
558
|
+
|
|
559
|
+ <p>In the <a href="#building-ports">Building Ports</a> section above, we set our default <span class="monospace">openssl</span>
|
|
560
|
+ implementation to <a href="https://www.libressl.org/">LibreSSL</a>. LibreSSL is a fork of OpenSSL initiated by the
|
|
561
|
+ OpenBSD developers after the <a href="http://heartbleed.com/">heartbleed</a> bug was discovered. It aims to be a
|
|
562
|
+ more secure, modern, and less crufty replacement for OpenSSL.
|
|
563
|
+
|
|
564
|
+ <p>You can check the <a href="https://wiki.freebsd.org/LibreSSL">wiki page</a> for details about running LibreSSL on
|
|
565
|
+ FreeBSD. Currently, OpenSSL is still the default implementation in the base system, but you can build almost all ports
|
|
566
|
+ using LibreSSL without any issues.
|
|
567
|
+
|
|
568
|
+ <p>The base SSH daemon will continue to use the base OpenSSL. To use a more up-to-date, upstream build with LibreSSL,
|
|
569
|
+ you can use the <span class="monospace">security/openssh-portable</span> port.
|
|
570
|
+
|
|
571
|
+<pre>cd /usr/ports/security/openssh-portable
|
|
572
|
+make install clean</pre>
|
|
573
|
+
|
|
574
|
+<p>The default build options are fine. I usually enable LDNS so I can get DNS fingerprint verification.
|
|
575
|
+
|
|
576
|
+<p>Here are the options I set in my <span class="monospace">sshd_config</span>. Many of them are taken from
|
|
577
|
+<a href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29">Mozilla's OpenSSH security guidelines</a>.
|
|
578
|
+At the very least, you'll want to set a non-default port for SSH unless you want Chinese botnets
|
|
579
|
+bruteforcing logins 24/7.
|
|
580
|
+
|
|
581
|
+<pre><div class="code-title">/usr/local/etc/ssh/sshd_config</div><span class="code-comment"># ANYTHING other than port 22!</span>
|
|
582
|
+Port 15522
|
|
583
|
+
|
|
584
|
+<span class="code-comment"># explicitly disable the less-secure protocol 1 </span>
|
|
585
|
+Protocol 2
|
|
586
|
+
|
|
587
|
+<span class="code-comment"># supported HostKey algorithms by order of preference.</span>
|
|
588
|
+<span class="code-comment"># I commented out the other ones.</span>
|
|
589
|
+HostKey /usr/local/etc/ssh/ssh_host_ed25519_key
|
|
590
|
+HostKey /usr/local/etc/ssh/ssh_host_rsa_key
|
|
591
|
+HostKey /usr/local/etc/ssh/ssh_host_ecdsa_key
|
|
592
|
+
|
|
593
|
+KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256
|
|
594
|
+Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
|
|
595
|
+MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com
|
|
596
|
+
|
|
597
|
+PermitRootLogin no
|
|
598
|
+StrictModes yes
|
|
599
|
+IgnoreRhosts yes
|
|
600
|
+
|
|
601
|
+<span class="code-comment"># only accept pubkey-based authentication</span>
|
|
602
|
+HostbasedAuthentication no
|
|
603
|
+PasswordAuthentication no
|
|
604
|
+PermitEmptyPasswords no
|
|
605
|
+ChallengeResponseAuthentication no
|
|
606
|
+AuthenticationMethods publickey
|
|
607
|
+
|
|
608
|
+X11Forwarding no
|
|
609
|
+UsePrivilegeSeparation sandbox
|
|
610
|
+
|
|
611
|
+Subsystem sftp /usr/local/libexec/sftp-server
|
|
612
|
+
|
|
613
|
+<span class="code-comment"># only these whitelisted users may connect</span>
|
|
614
|
+AllowUsers joeuser janeuser
|
|
615
|
+</pre>
|
|
616
|
+
|
|
617
|
+ <p>Finally, you'll need to disable the base OpenSSH daemon and enable the new one we installed from ports:
|
|
618
|
+
|
|
619
|
+<pre><div class="code-title">/etc/rc.conf</div><span class="code-comment">#sshd_enable="YES"</span>
|
|
620
|
+openssh_enable="YES"
|
|
621
|
+</pre>
|
|
622
|
+ <p>Now start the new SSH server:
|
|
623
|
+
|
|
624
|
+<pre>service openssh start
|
|
625
|
+</pre>
|
|
626
|
+
|
|
627
|
+ <p>Since we have disabled all login mechanisms except for pubkey-based authentication,
|
|
628
|
+ make sure you copy your public keys to your <span class="monospace">~/.ssh/authorized_keys</span>
|
|
629
|
+ file on your server. I recommend <a href="https://ed25519.cr.yp.to/">ed25519</a> keys, as they are
|
|
630
|
+ much faster and arguably more secure than RSA. You can generate ed25519 keys on your client
|
|
631
|
+ machines with the following:
|
|
632
|
+
|
|
633
|
+<pre>ssh-keygen -t ed25519
|
|
634
|
+</pre>
|
|
635
|
+
|
|
636
|
+ <p>When you have successfully logged in over the new SSH port, you can stop the old SSH daemon.
|
|
637
|
+</section>
|
|
638
|
+
|
|
639
|
+<pre>service sshd onestop
|
|
640
|
+</pre>
|
|
641
|
+
|
|
642
|
+<section>
|
|
643
|
+ <h2 id="ntp">Clock Sync with OpenNTP</h2>
|
|
644
|
+
|
|
645
|
+ <p>There have been numerous security advisories related to the base NTP daemon, and I get the feeling that the
|
|
646
|
+ code is written by scientists rather than sysadmins. I use OpenBSD's NTP daemon, available at
|
|
647
|
+ <span class="monospace">net/openntpd</span>.
|
|
648
|
+
|
|
649
|
+<pre>cd /usr/ports/net/openntpd
|
|
650
|
+make install clean
|
|
651
|
+</pre>
|
|
652
|
+
|
|
653
|
+ <p>First, make sure the base NTP daemon isn't running:
|
|
654
|
+
|
|
655
|
+<pre>service ntpd stop
|
|
656
|
+</pre>
|
|
657
|
+
|
|
658
|
+ <p>Then enable the new OpenNTP daemon in <span class="monospace">/etc/rc.conf</span>. Make sure the base
|
|
659
|
+ NTP daemon is disabled:
|
|
660
|
+
|
|
661
|
+<pre><div class="code-title">/etc/rc.conf</div><span class="code-comment">#ntpd_enable="YES"</span>
|
|
662
|
+openntpd_enable="YES"
|
|
663
|
+<span class="code-comment"># the -s flag instructs OpenNTP to set the clock immediately at startup</span>
|
|
664
|
+openntpd_flags="-s"
|
|
665
|
+</pre>
|
|
666
|
+
|
|
667
|
+ <p>Start the new NTP service:
|
|
668
|
+
|
|
669
|
+<pre>service openntpd start
|
|
670
|
+</pre>
|
|
671
|
+</section>
|
|
672
|
+
|
|
673
|
+<section>
|
|
674
|
+ <h2 id="pf">Securing the PF Firewall</h2>
|
|
675
|
+
|
|
676
|
+ <p><a href="https://www.freebsd.org/doc/handbook/firewalls-pf.html">PF</a>, the OpenBSD firewall, is included
|
|
677
|
+ in the FreeBSD base install. People argue about performance between PF and IPFW, but I think PF's syntax
|
|
678
|
+ is the easiest of any firewall in existence. We'll use a simple PF setup—just blocking all inbound connections
|
|
679
|
+ except to specific services we allow.
|
|
680
|
+
|
|
681
|
+ <p>The PF configuration lives at <span class="monospace">/etc/pf.conf</span>:
|
|
682
|
+
|
|
683
|
+<pre><div class="code-title">/etc/pf.conf</div><span class="code-comment"># the external network interface to the internet</span>
|
|
684
|
+ext_if="lagg0"
|
|
685
|
+
|
|
686
|
+<span class="code-comment"># port on which sshd is running</span>
|
|
687
|
+ssh_port = "15522"
|
|
688
|
+
|
|
689
|
+<span class="code-comment"># allowed inbound ports (services hosted by this machine)</span>
|
|
690
|
+inbound_tcp_services = "{auth, http, https, " $ssh_port " }"
|
|
691
|
+inbound_udp_services = "{dhcpv6-client,openvpn}"
|
|
692
|
+
|
|
693
|
+<span class="code-comment"># politely send TCP RST for blocked packets. The alternative is</span>
|
|
694
|
+<span class="code-comment"># "set block-policy drop", which will cause clients to wait for a timeout</span>
|
|
695
|
+<span class="code-comment"># before giving up.</span>
|
|
696
|
+set block-policy return
|
|
697
|
+
|
|
698
|
+<span class="code-comment"># log only on the external interface</span>
|
|
699
|
+set loginterface $ext_if
|
|
700
|
+
|
|
701
|
+<span class="code-comment"># skip all filtering on localhost</span>
|
|
702
|
+set skip on lo
|
|
703
|
+
|
|
704
|
+<span class="code-comment"># reassemble all fragmented packets before filtering them</span>
|
|
705
|
+scrub in on $ext_if all fragment reassemble
|
|
706
|
+
|
|
707
|
+<span class="code-comment"># block forged client IPs (such as private addresses from WAN interface)</span>
|
|
708
|
+antispoof for $ext_if
|
|
709
|
+
|
|
710
|
+<span class="code-comment"># default behavior: block all traffic</span>
|
|
711
|
+block all
|
|
712
|
+
|
|
713
|
+<span class="code-comment"># allow all icmp traffic (like ping)</span>
|
|
714
|
+pass quick on $ext_if proto icmp
|
|
715
|
+pass quick on $ext_if proto icmp6
|
|
716
|
+
|
|
717
|
+<span class="code-comment"># allow incoming traffic to services hosted by this machine</span>
|
|
718
|
+pass in quick on $ext_if proto tcp to port $inbound_tcp_services
|
|
719
|
+pass in quick on $ext_if proto udp to port $inbound_udp_services
|
|
720
|
+
|
|
721
|
+<span class="code-comment"># allow all outgoing traffic</span>
|
|
722
|
+pass out quick on $ext_if
|
|
723
|
+</pre>
|
|
724
|
+ <p>You should check the syntax of your PF configuration before enabling the firewall:
|
|
725
|
+
|
|
726
|
+<pre>pfctl -vnf /etc/pf.conf
|
|
727
|
+</pre>
|
|
728
|
+
|
|
729
|
+ <p>If all is well, enable the PF firewall daemon:
|
|
730
|
+
|
|
731
|
+<pre><div class="code-title">/etc/rc.conf</div>pf_enable="YES"
|
|
732
|
+</pre>
|
|
733
|
+
|
|
734
|
+ <p>And then start the service. Your SSH session might get reset. (Note: it may be
|
|
735
|
+ a good idea to have a serial console session open before you enable the firewall, in case you
|
|
736
|
+ accidentally lock yourself out.)
|
|
737
|
+
|
|
738
|
+<pre>service pf start
|
|
739
|
+</pre>
|
|
740
|
+
|
|
741
|
+ <p>You should now have a basic firewall configuration to protect your server from unintended
|
|
742
|
+ open ports. If you are feeling more paranoid, you can restrict outgoing traffic as well. Remember
|
|
743
|
+ that PF processes rules from top to bottom—the last matching rule wins (with the exception of
|
|
744
|
+ rules with the <span class="monospace">quick</span> modifier: those rules match immediately, and no further
|
|
745
|
+ matching is attempted).
|
|
746
|
+
|
|
747
|
+ <p>If you are following my <a href="/blog/self-hosting-guide/">self-hosting guide</a>, we will be coming
|
|
748
|
+ back to this PF configuration frequently as we enable new services.
|
|
749
|
+
|
|
750
|
+</section>
|
|
751
|
+
|
|
752
|
+<section>
|
|
753
|
+ <h2 id="conclusion">Conclusion</h2>
|
|
754
|
+
|
|
755
|
+ <p>If you've followed everything in this guide, you should have a relatively modern and secure FreeBSD server
|
|
756
|
+ that you can safely connect to the internet. Check back to this page as new FreeBSD versions get released. I will
|
|
757
|
+ continue to update this post with what I consider to be <em>Best Practices™️️</em> as the FreeBSD ecosystem
|
|
758
|
+ evolves.
|
|
759
|
+</section>
|
|
760
|
+
|