Browse Source

add blog to git

Cullum Smith 2 years ago
commit
bca56c20fa

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
1
+dist
2
+*.html
3
+rss.xml
4
+list.tmpl
5
+blog/list.tmpl

+ 73
- 0
Makefile View File

@@ -0,0 +1,73 @@
1
+HTGEN=./scripts/htgen
2
+MKLIST=./scripts/mklist
3
+RSSGEN=./scripts/rssgen
4
+BLOG=blog
5
+POSTS!=find ${BLOG} -type f -mindepth 2 -maxdepth 2 -name index.tmpl
6
+OS!=uname
7
+
8
+.if ${OS} == "Darwin"
9
+INSTALL=ginstall -Dp -m 0444
10
+LOCAL_TARGET=${HOME}/Public/www.c0ffee.net
11
+.else
12
+INSTALL=install -Dp -m 0444
13
+LOCAL_TARGET=/var/www/htdocs/www
14
+.endif
15
+
16
+HEAD=partials/head.tmpl
17
+RSYNC_TARGET=puffy:/var/www/htdocs/www
18
+DOMAIN=www.c0ffee.net
19
+BASEURL=https://${DOMAIN}
20
+RSS_TITLE="Cullum Smith's Blog"
21
+RSS_DESCRIPTION="Articles about BSD, privacy, self-hosting, and more."
22
+
23
+.PHONY: all clean tarball rsync local
24
+
25
+all: index.html resume/index.html ${BLOG}/index.html ${POSTS:S/.tmpl$/.html/g} rss.xml
26
+
27
+index.html: ${HEAD} index.tmpl list.tmpl partials/footer_openbsd.tmpl
28
+	${HTGEN} -o $@ ${HEAD} '@index.tmpl' list.tmpl partials/footer_openbsd.tmpl
29
+
30
+resume/index.html: ${HEAD} resume/index.tmpl partials/footer.tmpl
31
+	${HTGEN} -o $@ ${HEAD} '@resume/index.tmpl' partials/footer.tmpl
32
+
33
+${BLOG}/index.html: ${HEAD} ${BLOG}/index.tmpl ${BLOG}/list.tmpl partials/footer_blog.tmpl
34
+	${HTGEN} -o $@ ${HEAD} ${BLOG}/index.tmpl '@${BLOG}/list.tmpl' partials/footer_blog.tmpl
35
+
36
+list.tmpl: ${POSTS}
37
+	${MKLIST} -o $@ -n 5 ${BLOG}
38
+
39
+${BLOG}/list.tmpl: ${POST}
40
+	${MKLIST} -o $@ ${BLOG}
41
+
42
+.for POST in ${POSTS}
43
+${POST:S/.tmpl$/.html/g}: ${HEAD} partials/header_${BLOG}.tmpl ${POST} partials/footer_post.tmpl
44
+	${HTGEN} -o $@ ${HEAD} partials/header_${BLOG}.tmpl '@${POST}' partials/footer_post.tmpl
45
+.endfor
46
+
47
+rss.xml: ${POSTS}
48
+	${RSSGEN} -o $@ -b "${BASEURL}" -t ${RSS_TITLE} -d ${RSS_DESCRIPTION} ${BLOG}
49
+
50
+dist: all
51
+	mkdir -p dist
52
+	find . -type d -path ./dist -prune -o -type f -name '*.html' -print | sed 's|^\./||' | xargs -n1 -I{} ${INSTALL} {} dist/{}
53
+	${INSTALL} css/style.css dist/css/style.css
54
+	${INSTALL} favicon.png   dist/favicon.png
55
+	${INSTALL} robots.txt    dist/robots.txt
56
+	${INSTALL} rss.xml       dist/rss/index.rss
57
+	find files -type f -exec ${INSTALL} {} dist/{} \;
58
+	find img   -type f -exec ${INSTALL} {} dist/{} \;
59
+
60
+tarball: dist
61
+	tar cvzf ${DOMAIN}.tar.gz dist
62
+
63
+local: dist
64
+	rsync -rlpth dist/ ${LOCAL_TARGET}
65
+
66
+rsync: dist
67
+	rsync -rlpth dist/ ${RSYNC_TARGET}
68
+
69
+clean:
70
+	rm -f list.tmpl ${BLOG}/list.tmpl rss.xml
71
+	find . -name '*.html' -exec rm -f {} \;
72
+	rm -rf dist
73
+	rm -f ${DOMAIN}.tar.gz

+ 406
- 0
blog/dns-hidden-master/index.tmpl View File

@@ -0,0 +1,406 @@
1
+TITLE='DNS Hosting Guide: Hidden Master with DNSSEC'
2
+DESCRIPTION='Manage your own DNS using BIND in a hidden master configuration.'
3
+DATE=2017-11-04
4
+__HTML__
5
+<p>DNS is one of the few things I don't like to host myself. A DNS server running on a single host
6
+will cause slow queries for far-away clients, making your site seem less responsive. In addition, a
7
+failed DNS lookup is a much more serious problem than a web service being down. If your mail server
8
+isn't responding, most other mail servers will queue all your incoming mail to be retried later. But if
9
+the DNS lookup for your MX record fails, they will usually reject the message altogether.
10
+
11
+<p>Because of these issues, I have always used third-party DNS providers. Most professional DNS services
12
+are inexpensive for personal use, resistant to DDOS attacks and downtime, and support low-latency queries
13
+from anywhere in the world using <a href="https://en.wikipedia.org/wiki/Anycast">anycast routing</a>.
14
+However, using a paid DNS provider usually forces you to manage all your domains and subdomains through
15
+a clunky web interface. Until now!
16
+
17
+<p>This guide describes how to run the <a href="https://www.isc.org/downloads/bind/">BIND DNS server</a>
18
+in a <em>hidden master</em> configuration. The idea is that you run BIND locally, where you can easily
19
+edit your plain text zone file or automate your domain configuration, but use a secondary, more resilient
20
+DNS provider for all the actual query resolution. Your local BIND server will act as the primary (or <em>master</em>)
21
+DNS server, and will automatically notify your secondary DNS servers when any changes are made. The trick is that
22
+when setting your primary nameservers in your domain's registrar, you only use the IP addresses of your secondary
23
+nameservers. This way, you can easily manage your zone file locally, but none of the actual query traffic goes
24
+to your box.
25
+
26
+<p>I use <a href="https://cp.dnsmadeeasy.com/u/122648">DNS Made Easy</a> for my secondary DNS service. Their small business
27
+plan is about $30 per year, and that gets you support for 10 domain names, 5 million queries per month, and DNSSEC.
28
+I've found it more than adequate for a personal site, but there are other options as well—<a href="https://dyn.com">Dyn</a>
29
+comes to mind (but recently acquired by Oracle...buyer beware).
30
+
31
+<section>
32
+  <h2 id="installing-bind">Installing BIND</h2>
33
+
34
+  <p>As always, this guide assumes you're running FreeBSD. The instructions should map pretty closely to your Linux
35
+  distro of choice—just install <span class="monospace">bind</span> from your package manager and modify the file paths
36
+  where appropriate.
37
+
38
+  <p><del>On FreeBSD, install <span class="monospace">bind99</span> from ports. There are more recent versions available, but in
39
+  my experience they all had bugs in their <span class="monospace">rc</span> scripts and weird runtime issues. 9.9 is
40
+  the extended support release, and it's the only one that I can confirm works 100% on FreeBSD 11. Use other versions
41
+  at your own risk.</del>
42
+
43
+  <p><em><strong>EDIT (26 Nov 2017): These issues were actually caused by a problematic loader.conf optimization I had configured.</strong>
44
+  You can use BIND 9.11 without issue. Just make sure the <span class="monospace">net.inet.tcp.soreceive_stream</span> tunable is set to 0.
45
+  See <a href="https://forums.freebsd.org/threads/61064/">this forum post</a> for more information.</em>
46
+
47
+<pre>cd /usr/ports/dns/bind911
48
+make install clean</pre>
49
+
50
+  <p>I always make sure to build with the IPV6- and DNSSEC-related options. Then, enable <span class="monospace">bind</span>
51
+  to start on boot (the daemon is called <span class="monospace">named</span>):
52
+
53
+<pre><div class="code-title">/etc/rc.conf</div>named_enable="YES"</pre>
54
+
55
+  <p>Now you are ready to edit the configuration file. The annotated example below assumes you are hosting a domain
56
+  called <span class="monospace">example.com</span>. Most of the IP addresses in the example are fake. You will need
57
+  to substitute your own domain and relevant IP addresses where appropriate. Your secondary DNS provider should
58
+  provide you with the IP addresses for the zone transfers, as well as those of your public nameservers.
59
+
60
+<pre><div class="code-title">/usr/local/etc/namedb/named.conf</div><span class="code-comment">// IP addresses of your secondary nameservers, where the zone transfers will</span>
61
+<span class="code-comment">// take place. Your DNS provider should give you these addresses.</span>
62
+<span class="code-comment">// NOTE - these IPs are probably not the same as your DNS provider's public</span>
63
+<span class="code-comment">// nameservers (which will go in your zone file's ns1-3 A records).</span>
64
+masters secondaries {
65
+  198.51.100.51;
66
+  198.51.100.52;
67
+  198.51.100.53;
68
+};
69
+
70
+<span class="code-comment">// same as above - repetition needed for BIND's arcane config syntax</span>
71
+acl secondaries {
72
+  198.51.100.51;
73
+  198.51.100.52;
74
+  198.51.100.53;
75
+};
76
+
77
+<span class="code-comment">// localhost, and any other public IPs of your server</span>
78
+acl localnetworks {
79
+  127.0.0.1;
80
+  ::1;
81
+  203.0.113.41;
82
+  203.0.113.42;
83
+  2001:db8::2;
84
+  2001:db8::3;
85
+};
86
+
87
+options {
88
+  directory       "/usr/local/etc/namedb/working";
89
+  pid-file        "/var/run/named/pid";
90
+  dump-file       "/var/dump/named_dump.db";
91
+  statistics-file "/var/stats/named.stats";
92
+  key-directory   "/usr/local/etc/namedb/keys";
93
+
94
+  <span class="code-comment">// listen on all interfaces (needed for zone transfers to secondaries)</span>
95
+  listen-on    { any; };
96
+  listen-on-v6 { any; };
97
+
98
+  <span class="code-comment">// IP addresses of your upstream DNS servers. Your hosting provider most</span>
99
+  <span class="code-comment">// likely provides a DNS server. Alternatively, leave blank to have BIND</span>
100
+  <span class="code-comment">// recursively resolve all queries (slow).</span>
101
+  <span class="code-comment">//</span>
102
+  <span class="code-comment">// Note - below are Google's DNS servers. If you value your privacy, don't</span>
103
+  <span class="code-comment">// use them.</span>
104
+  forwarders {
105
+    8.8.8.8;
106
+    8.8.4.4;
107
+    2001:4860:4860::8888;
108
+    2001:4860:4860::8844;
109
+  };
110
+
111
+  <span class="code-comment">// If a lookup fails on upstream DNS servers, don't try to recursively</span>
112
+  <span class="code-comment">// resolve (comment out if not using forwarders).</span>
113
+  forward only;
114
+
115
+  <span class="code-comment">// When a zone is updated, only send NOTIFY to hosts in the zone's</span>
116
+  <span class="code-comment">// `also-notify` block (defined below).</span>
117
+  notify explicit;
118
+
119
+  <span class="code-comment">// Set safe default permissions. We will override these for some zones</span>
120
+  <span class="code-comment">// below.</span>
121
+  allow-transfer  { none; };
122
+  allow-update    { none; };
123
+  allow-recursion { localnetworks; };
124
+  allow-query     { localnetworks; };
125
+
126
+  <span class="code-comment">// If your server has multiple IP addresses, uncomment the two lines below</span>
127
+  <span class="code-comment">// and change the source address to the one you configured your secondary</span>
128
+  <span class="code-comment">// DNS provider to use.</span>
129
+  <span class="code-comment">//  query-source address 203.0.113.41;</span>
130
+  <span class="code-comment">//  notify-source        203.0.113.41;</span>
131
+
132
+  <span class="code-comment">// Comment out the three lines below if you don't want DNSSEC.</span>
133
+  dnssec-enable yes;
134
+  dnssec-validation auto;
135
+  dnssec-lookaside auto;
136
+};
137
+
138
+<span class="code-comment">// Don't attempt to resolve any private IPs</span>
139
+include "/usr/local/etc/namedb/localzones.conf";
140
+
141
+<span class="code-comment">// Your domain name goes here.</span>
142
+zone "example.com" in {
143
+  <span class="code-comment">// We are the "master" (or primary) server for our domain, but it just</span>
144
+  <span class="code-comment">// happens that we won't be getting any external queries.</span>
145
+  type master;
146
+
147
+  <span class="code-comment">// Comment out the two lines below if you don't want DNSSEC.</span>
148
+  auto-dnssec maintain;
149
+  inline-signing yes;
150
+
151
+  <span class="code-comment">// only allow zone transfers from localhost or our secondary DNS provider</span>
152
+  allow-transfer {
153
+    localnetworks;
154
+    secondaries;
155
+  };
156
+
157
+  <span class="code-comment">// only allow DNS queries from localhost or our secondary DNS provider</span>
158
+  allow-query {
159
+    localnetworks;
160
+    secondaries;
161
+  };
162
+
163
+  <span class="code-comment">// send NOTIFY messages to secondary DNS provider when the zone changes</span>
164
+  also-notify {
165
+    secondaries;
166
+  };
167
+
168
+  <span class="code-comment">// your domain's zone file goes here</span>
169
+  file "/usr/local/etc/namedb/master/example.com.db";
170
+};</pre>
171
+
172
+  <p>Now you need to write a zone file for your domain—this file contains the actual DNS records.
173
+
174
+  <section>
175
+    <h3 id="dnssec">Optional: Configuring DNSSEC</h3>
176
+
177
+    <p>If you want to configure DNSSEC for your domain, you'll need to generate some keys. Make sure your secondary
178
+    DNS provider supports DNSSEC first (<a href="https://support.dnsmadeeasy.com/index.php?/Knowledgebase/Article/View/172/18/do-you-support-dnssec">I know that DNS Made Easy does</a>).
179
+    I use the ECDSA algorithm when generating keys, since they are smaller and more computationally efficient.
180
+    However, if you're concerned about maximum compatibility with other DNS resolvers, you probably want to stick with
181
+    RSA—just replace <span class="monospace">ECDSAP256SHA256</span> with <span class="monospace">RSASHA256</span> below.
182
+    ECDSA is <a href="https://www.cloudflare.com/dns/dnssec/ecdsa-and-dnssec/">good enough for Cloudflare</a> though, so
183
+    I'm sticking with it for this example.
184
+
185
+    <p>First, generate a Zone Signing Key (ZSK) for your domain by running the following:
186
+
187
+<pre>dnssec-keygen -a ECDSAP256SHA256 -K /usr/local/etc/namedb/keys -n ZONE example.com
188
+<span class="code-comment">Generating key pair.</span>
189
+<span class="code-comment">Kexample.com.+013+29679</span></pre>
190
+
191
+    <p>This will generate a keypair for the <span class="monospace">example.com</span> in BIND's key directory. 
192
+    Next, generate a Key Signing Key (KSK) for the domain in a similar fashion:
193
+
194
+<pre>dnssec-keygen -f KSK -a ECDSAP256SHA256 -K /usr/local/etc/namedb/keys -n ZONE example.com
195
+<span class="code-comment">Generating key pair.</span>
196
+<span class="code-comment">Kexample.com.+013+15315</span> </pre>
197
+
198
+    <p>Take note of the KSK's generated filename—you'll need it in a bit. You should now have 4 files for this domain
199
+    in BIND's key directory: one pair for the ZSK, and another pair for the KSK. We will come back to these at the end of
200
+    the guide when you configure DNS settings at your registrar.
201
+
202
+  </section>
203
+
204
+</section>
205
+
206
+<section>
207
+  <h2 id="zone-file">Writing a Zone File</h2>
208
+
209
+  <p>Now we come to the fun part: writing your zone file! This is a plain text file where you'll specify all the DNS records
210
+  for your domain. The below example uses fake IP addresses for a domain named <span class="monospace">example.com</span>. I've
211
+  included some commentary to help you out, but basically you'll just be translating the existing records you configured in your original
212
+  DNS provider's web portal.
213
+
214
+<pre><div class="code-title">/usr/local/etc/namedb/master/example.com.db</div><span class="code-comment">; The $TTL variable defines a default TTL for all records in this file.</span>
215
+<span class="code-comment">; This value specifies how long other DNS servers should keep a record in</span>
216
+<span class="code-comment">; their cache. Individual records may override this value.</span>
217
+$TTL 3h
218
+
219
+<span class="code-comment">; your bare domain name</span>
220
+$ORIGIN example.com.
221
+
222
+<span class="code-comment">; "Start of Authority" record. First line should contain your  primary</span>
223
+<span class="code-comment">; nameserver and administrative contact's email (replace '@' with '.')</span>
224
+@  IN  SOA  ns1.example.com.  root.example.com. (
225
+
226
+<span class="code-comment">; serial:   you *must* increment this number whenever any change is made</span>
227
+<span class="code-comment">;           to this file, otherwise updates will not propagate to your</span>
228
+<span class="code-comment">;           secondary DNS servers</span>
229
+2017101800
230
+<span class="code-comment">; refresh:  how often your secondary DNS servers should poll your primary</span>
231
+<span class="code-comment">;           server for changes</span>
232
+1d
233
+<span class="code-comment">; retry:    how long your secondary DNS servers should wait before</span>
234
+<span class="code-comment">;           retrying after a failed update</span>
235
+3m
236
+<span class="code-comment">; expire:   how long your secondary DNS servers should be considered</span>
237
+<span class="code-comment">;           authoritative if your primary nameserver disappears</span>
238
+1w
239
+<span class="code-comment">; minimum:  "negative caching TTL," or how long other servers should wait</span>
240
+<span class="code-comment">;           before re-querying a record that didn't exist on the previous</span>
241
+<span class="code-comment">;           attempt</span>
242
+3h
243
+)
244
+
245
+<span class="code-comment">; Your domain's public nameservers go in the NS records here. You'll need</span>
246
+<span class="code-comment">; an A record for each one that points to your secondary DNS provider.</span>
247
+IN  NS     ns1.example.com.
248
+IN  NS     ns2.example.com.
249
+IN  NS     ns3.example.com.
250
+
251
+<span class="code-comment">; MX record (if you have a mail server)</span>
252
+IN  MX  10 mail.example.com.
253
+
254
+<span class="code-comment">; server host definitions</span>
255
+@           IN  A      203.0.113.41
256
+@           IN  AAAA   2001:db8::2
257
+mail        IN  A      203.0.113.42
258
+mail        IN  AAAA   2001:db8::3
259
+awesomebox  IN  A      203.0.113.43
260
+awesomebox  IN  AAAA   2001:db8::4
261
+
262
+<span class="code-comment">; These records should contain the IP addresses of your secondary DNS</span>
263
+<span class="code-comment">; provider's PUBLIC nameservers. Clients will use these DNS servers when</span>
264
+<span class="code-comment">; querying your domain.</span>
265
+ns1         IN  A      198.51.100.11
266
+ns1         IN  AAAA   2001:db8:beef::7
267
+ns2         IN  A      198.51.100.12
268
+ns2         IN  AAAA   2001:db8:beef::8
269
+ns3         IN  A      198.51.100.13
270
+ns3         IN  AAAA   2001:db8:beef::9</pre>
271
+</section>
272
+
273
+<section>
274
+  <h2 id="zone-transfer">Configuring Zone Transfers</h2>
275
+
276
+  <p>At this point, we're done configuring BIND. The next step is to ensure your secondary DNS provider can connect
277
+  to your server to perform zone transfers. You'll need to configure your server as the primary DNS server in your
278
+  secondary DNS provider's web portal. With <a href="https://cp.dnsmadeeasy.com/u/122648">DNS Made Easy</a>, this page is found in the <em>Advanced</em> menu under
279
+  <em>Secondary IP Sets</em>. Specify your server's public IP address here.
280
+
281
+  <p>If you have a firewall in place, you'll need to allow TCP and UDP traffic over port 53. If you used my <a href="https://www.c0ffee.net/blog/freebsd-server-guide#pf">FreeBSD Server Guide</a>
282
+  to configure the PF firewall, you can just add <span class="monospace">domain</span> to the <span class="monospace">inbound_tcp_services</span>
283
+  and <span class="monospace">inbound_udp_services</span> variables. Be sure to reload PF's ruleset:
284
+
285
+<pre>pfctl -f /etc/pf.conf</pre>
286
+
287
+  <p>Now, the moment of truth. It's time to start BIND and test your new DNS server!
288
+
289
+<pre>service named start</pre>
290
+
291
+  <p>Check <span class="monospace">/var/log/messages</span> to ensure BIND started up properly. Hopefully you didn't make any typos.
292
+  You can verify BIND is working by doing a simple DNS query:
293
+
294
+<pre>dig @127.0.0.1 +short google.com
295
+<span class="code-comment">172.217.5.206</span></pre>
296
+
297
+  <p>Also, make sure BIND is correctly serving the domain you configured in your zone file:
298
+
299
+<pre>dig @127.0.0.1 +short example.com
300
+<span class="code-comment">203.0.113.41</span></pre>
301
+
302
+  <p>Now, head to your secondary DNS provider's web portal. When BIND started up, it should have read your zone file and sent a
303
+  <span class="monospace">NOTIFY</span> to your secondary DNS servers, informing them to do a zone transfer from your hidden master.
304
+  If that happened successfully, your provider's web portal should show the DNS servers as in sync, with the current serial numbers
305
+  matching.
306
+
307
+  <p>If that didn't happen, or you see a problem, increment the serial number in your zone file and give BIND a reload:
308
+
309
+<pre>service named reload</pre>
310
+
311
+  <p>This should re-read your zone file and update your secondary servers. Check for any suspicious messages in your log files.
312
+
313
+  <p>Once you have zone transfers working, and your primary and secondary nameservers are in sync, you're ready to officially
314
+  change your public nameservers at your domain's registrar.
315
+
316
+</section>
317
+
318
+<section>
319
+  <h2 id="notifying-registrar">Notifying Your Registrar</h2>
320
+
321
+  <p>Your registrar has the secret sauce that tells other DNS servers which nameservers to query for information
322
+  about your domain. Once you've verified everything is working, you can switch your nameservers over to your secondary
323
+  DNS provider. You probably want to do this late at night, or during a time when you don't expect much traffic to your
324
+  site. I use <a href="https://www.namecheap.com/?aff=108349">Namecheap</a>, but the instructions should carry over to
325
+  most other registrars.
326
+
327
+  <p>In your registrar's web portal, your domain's settings page should have an option to set your nameservers. At <a href="https://www.namecheap.com/?aff=108349">Namecheap</a>,
328
+  you want to select <em>Custom DNS</em>. You will then need to provide the fully qualified domain name of your secondary
329
+  DNS provider's <em>public</em> DNS servers. As <a href="https://cp.dnsmadeeasy.com/u/122648">DNS Made Easy</a> states at the top of their portal: <em>These are the name servers that you will want to add as NS records in your zone and also assign to your domain at your domain registrar.</em>
330
+
331
+  <section>
332
+    <h3>Side Note: Vanity Nameservers</h3>
333
+    <p>If you'd like your public nameservers for <span class="monospace">example.com</span> to look like <span class="monospace">ns1.example.com</span>
334
+    instead of <span class="monospace">ns1.yourdnsprovider.com</span>, then you can configure "vanity nameservers" for your domain.
335
+    First, make sure you have A records (and probably AAAA records) for your secondary DNS provider's public name servers in your zone file (I emphasized this in
336
+    the example zone file above).
337
+
338
+    <p>I can't speak for other registrars, but at <a href="https://www.namecheap.com/?aff=108349">Namecheap</a>, you can go to the <em>Advanced DNS</em> page for your domain and
339
+    scroll down to <em>Personal DNS Server</em>. Then you can add <span class="monospace">ns1</span>, <span class="monospace">ns2</span>...
340
+    and map them to the IP addresses of your secondary DNS provider's public nameservers.
341
+
342
+    <p>Then, in the <em>Custom DNS</em> field, you can just put <span class="monospace">ns1.example.com</span>, <span class="monospace">ns2.example.com</span>, etc.
343
+
344
+    <p>Doing this creates a "glue record" at your registrar for your domain's DNS servers. You can Google this if you're interested in
345
+    the details. Also, the web interface at <a href="https://www.namecheap.com/?aff=108349">Namecheap</a> currently only allows IPv4 glue records. I had to open a support ticket to
346
+    have IPv6 glue records added for <a href="https://cp.dnsmadeeasy.com/u/122648">DNS Made Easy</a>'s public IPv6 servers.
347
+  </section>
348
+
349
+  <section>
350
+    <h3>Optional: DNSSEC at the Registrar</h3>
351
+
352
+    <p>If you configured DNSSEC above, there is one last step to complete while you're on your registrar's web portal. You'll
353
+    need to provide the SHA-1 and SHA-256 digests of the KSK you generated to your registrar. Your registrar will then add some
354
+    fancy records for you so that other resolvers can cryptographically verify your DNS records. (Sorry for the hand-wavy
355
+    explanation—it's 1:00 AM on a Friday night and I'm tired.)
356
+
357
+    <p>Remember the filename I asked you to remember from the <span class="monospace">dnssec-keygen</span> command above? We'll
358
+    use it now. You want the file containing the Key Signing Key (<strong>not</strong> the Zone Signing Key). It's annoying, because the filenames
359
+    look exactly the same except for a four-digit identifier at the end. It's easy to figure out though—the contents of the
360
+    <span class="monospace">.key</span> file will tell you which one it is.
361
+
362
+    <p>Once you've found the correct file, run the following command:
363
+
364
+<pre>dnssec-dsfromkey /usr/local/etc/namedb/keys/Kexample.com.+013+15315.key | awk '{print $4, $5, $6, $7}'
365
+<span class="code-comment">15315 13 1 7F5ED13547D9860965437D0F7CB6BFA7C70F1F62</span>
366
+<span class="code-comment">15315 13 2 AD0C012F749F0422E0CC88D11B65248E78945F149572D54C8AE7C5B63C30E621</span></pre>
367
+
368
+<p>You will use this output to populate the DS records for your domain at your registrar. At <a href="https://www.namecheap.com/?aff=108349">Namecheap</a>, this is located
369
+    under <em>Advanced DNS</em>→<em>DNSSEC</em>. The first column is the key tag, which corresponds to the key's file name.
370
+    The second column is the encryption type. If you used ECDSA, this will be <strong>13</strong>.  If you went with RSA, you'll use <strong>8</strong> here.
371
+    The third column is the digest type: <strong>1</strong> for SHA-1 and <strong>2</strong> for SHA-256. The final column contains the actual digest.
372
+
373
+    <p>These columns correspond to the four fields for DS records in the <a href="https://www.namecheap.com/?aff=108349">Namecheap</a> web portal. Copy and paste the appropriate values
374
+    there. Other registrars should have a similar process.
375
+
376
+    <p>It will take an hour or so for your DNS updates to propagate. You can verify DNSSEC is working by by querying a different
377
+    DNS server (the below example uses Google's public DNS).
378
+
379
+<pre>dig @8.8.8.8 example.com +dnssec | grep -m1 flags:
380
+<span class="code-comment">;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1</span></pre>
381
+
382
+    <p>If you see the <span class="monospace">ad</span> flag, then your DNSSEC was validated successfully. You can also check
383
+    your DNSSEC status on <a href="https://dnssec-debugger.verisignlabs.com">Verisign's test page</a>.
384
+  </section>
385
+
386
+</section>
387
+
388
+<section>
389
+  <h2 id="conclusion">Conclusion</h2>
390
+
391
+  <p>Once you've gotten all this working, you might consider setting the default nameserver on your server to your local BIND
392
+  instance. In addition to using no network overhead, you'll also take advantage of BIND's default query cache. All it takes
393
+  is a simple edit to your <span class="monospace">resolv.conf</span>:
394
+
395
+<pre><div class="code-title">/etc/resolv.conf</div>nameserver 127.0.0.1
396
+nameserver ::1</pre>
397
+
398
+  <p>If you perform DNS updates frequently, I think you'll find the hidden master setup an invaluable productivity boost for any
399
+  domains you control. Remember: to update your zone, just make the necessary record changes in your zone file, increment the serial,
400
+  and issue a <span class="monospace">service named reload</span>.
401
+
402
+  <p>As always, contact me via <a href="mailto:cullum@c0ffee.net">email</a> or ping me on <a href="https://twitter.com/cullumsmith">Twitter</a>
403
+  with any questions or issues you have.
404
+
405
+</section>
406
+

+ 197
- 0
blog/dovecot-push-notifications/index.tmpl View File

@@ -0,0 +1,197 @@
1
+TITLE='Dovecot Push Notifications for iOS'
2
+DESCRIPTION='Native Apple push notifications for your self-hosted mail server.'
3
+DATE=2017-09-20
4
+__HTML__
5
+<p><strong>EDIT:</strong> <em>Apple has <a href=https://support.apple.com/en-us/HT208312">recently announced</a> that they
6
+are dropping mail suport from macOS Server Fall 2018. Once your APNS certificate expires after one year, the push notifications
7
+will stop working, and it seems like we won't be able to get new certificates from the Server app. Due to this news, I've stopped
8
+maintaining the patchset, since it's a fair amount of manual work to update it for each Dovecot release. Feel free
9
+to read on if you're interested in how this cool trick works though!</em>
10
+
11
+<p>Using a patched version of Dovecot and a small Perl script, it's possible to get native
12
+Apple push notifications for new mail using the stock iOS mail client. This is accomplished
13
+by mimicking Apple's <span class="monospace">XAPPLEPUSHSERVICE</span> IMAP extension for Dovecot
14
+used in macOS Server, whose source code is published on the
15
+<a href="https://opensource.apple.com/source/dovecot/dovecot-293/">Apple Open Source website</a>.
16
+
17
+<p>If you're running Dovecot on FreeBSD, this guide will be extremely easy: you can just use
18
+my patched Dovecot port <a href="https://github.com/cullum/freebsd-ports/tree/master/mail/dovecot">here</a>.
19
+It should work just as well on other Unix-like operating systems with a bit of manual work.
20
+
21
+<section>
22
+  <h2 id="acknowledgements">Acknowledgements</h2>
23
+
24
+  <p>All the credit for this goes to <a href="https://github.com/matthewpowell">Matthew Powell</a>
25
+  on GitHub. He wrote the <a href="https://github.com/matthewpowell/pushnotify">Dovecot patch and notification daemon</a>
26
+  to get push notifications working. I just packaged everything into nice FreeBSD ports.
27
+
28
+  <p>Much of this knowledge was discovered a few years ago by <a href="https://github.com/st3fan">Stefan Arentz</a>
29
+  in his <span class="monospace"><a href="https://github.com/st3fan/dovecot-xaps-plugin">dovecot-xaps-plugin</a></span>
30
+  project.
31
+
32
+</section>
33
+
34
+<section>
35
+  <h2 id="requirements">What You'll Need</h2>
36
+
37
+  <ul class="paragraph-list">
38
+    <li><strong>macOS Server:</strong> you will need access to an Apple device running macOS,
39
+      and a copy of <a href="https://www.apple.com/macos/server/">macOS Server</a>. You can
40
+      <a href="https://itunes.apple.com/us/app/macos-server/id883878097?mt=12">download macOS Server from the Mac App Store</a>
41
+      for $19.99. The macOS Server app is the only way to get the magic APNS certificates from
42
+      Apple that can send push notifications to the Mail app on your iPhone. Basically, we are
43
+      fooling your iPhone into thinking your Dovecot instance is actually running on a blessed
44
+      Mac server. Enable the <em>Push Notifications</em> option in the Server app to have Apple provision
45
+      the necessary certificates to your macOS Keychain.
46
+
47
+    <li><strong>A working Dovecot installation:</strong> you should have Dovecot installed and
48
+      working before trying to add push notifications into the mix. I recommend using
49
+      <a href="/blog/mail-server-guide/">my mail server guide</a>.
50
+  </ul>
51
+
52
+</section>
53
+
54
+<section>
55
+  <h2 id="installation">Installation</h2>
56
+
57
+  <p>The setup has two components: (1) a patched Dovecot installation to handle the APNS token
58
+  negotiation over IMAP, and (2) a small Perl daemon which sends notifications to Apple's push
59
+  servers whenever Dovecot receives a new message in a user's inbox.
60
+
61
+  <p>On FreeBSD, you can install both of these components by building my <span class="monospace"><a href="https://github.com/cullum/freebsd-ports/tree/master/mail/dovecot">mail/dovecot</a></span>
62
+  port with the <span class="monospace">APNS</span> option. This should automatically pull in
63
+  my <span class="monospace"><a href="https://github.com/cullum/freebsd-ports/tree/master/mail/dovecot-apns-daemon">mail/dovecot-apns-daemon</a></span> port as a dependency:
64
+
65
+<pre># clone my custom ports repo
66
+git clone https://github.com/cullum/freebsd-ports /usr/local/custom-ports
67
+
68
+# symlink my custom ports into your ports tree
69
+# (I need to find a cleaner way to do this)
70
+rm -rf /usr/ports/mail/dovecot
71
+ln -s /usr/local/custom-ports/devel/p5-Privileges-Drop   /usr/ports/devel/p5-Privileges-Drop
72
+ln -s /usr/local/custom-ports/net/p5-Net-APNS-Persistent /usr/ports/net/p5-Net-APNS-Persistent
73
+ln -s /usr/local/custom-ports/mail/dovecot-apns-daemon   /usr/ports/mail/dovecot-apns-daemon
74
+ln -s /usr/local/custom-ports/mail/dovecot               /usr/ports/mail/dovecot
75
+
76
+# build the patched dovecot
77
+cd /usr/ports/mail/dovecot
78
+make config  # ensure the APNS option is selected
79
+make reinstall clean</pre>
80
+
81
+  <p>The <span class="monospace">pkg-message</span> tells you how to export the magic APNS certificates
82
+  from your macOS Keychain to your FreeBSD server:
83
+
84
+<pre>Apple Push Notifications require a valid certificate keypair from
85
+a working copy of OS X Server. Export the following APNS certificate
86
+from your OS X keychain:
87
+
88
+APSP:com.apple.servermgrd.apns.mail 
89
+
90
+By default, the dovecot_apns daemon will look in the following
91
+locations for the certificate key pair:
92
+
93
+/usr/local/etc/dovecot-apns/mail.crt
94
+/usr/local/etc/dovecot-apns/mail.key
95
+
96
+If you exported a .p12 file from your OS X keychain, you can
97
+convert it to the proper PEM format with the following commands:
98
+
99
+openssl pkcs12 -in push.p12 -clcerts -nokeys | sed '/BEGIN CERTIFICATE/,$!d' &gt; mail.crt
100
+openssl pkcs12 -in push.p12 -nodes -nocerts | sed '/BEGIN RSA PRIVATE KEY/,$!d' &gt; mail.key
101
+
102
+The dovecot_apns daemon must be running for device registration and
103
+push notifications to work. Enable it in /etc/rc.conf:
104
+
105
+echo 'dovecot_apns_enable="YES"' &gt;&gt; /etc/rc.conf
106
+</pre>
107
+
108
+  <p>As well as how to configure Dovecot:
109
+
110
+<pre>Set the following variable somewhere in your Dovecot configuration:
111
+
112
+aps_topic = com.apple.mail.XServer.XXXXXXXXX
113
+
114
+replacing the X's to match the UID field in your APNS certificate.</pre>
115
+
116
+  <p>If you exported your mail push certificate as <span class="monospace">push.p12</span>, you
117
+  can get your <span class="monospace">aps_topic</span> value with the following command:
118
+
119
+<pre>openssl pkcs12 -in push.p12 -clcerts -nokeys -nomacver | grep -o 'com\.apple\.mail\.XServer\..*' | awk -F/ '{print $1}'</pre>
120
+
121
+  <p>I have mine configured like this:
122
+
123
+<pre><div class="code-title">/usr/local/etc/dovecot/conf.d/90-apns.conf</div>aps_topic = com.apple.mail.XServer.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</pre>
124
+
125
+  <p>Once you have your patched Dovecot installed, your APNS certificates in place, and your
126
+  Dovecot configuration updated, give the daemons a kick:
127
+
128
+<pre>service dovecot restart
129
+service dovecot_apns start</pre>
130
+
131
+  <p>Dovecot and the APNS daemon will both log to <span class="monospace">/var/log/maillog</span>.
132
+  Toggle Airplane Mode on your iPhone to force the IMAP connection to reset. You should see the
133
+  token negotiation logged in your mail log. On your iPhone, your mail account's fetch schedule
134
+  should automatically change to <em>push</em> in Settings → Accounts &#38; Passwords → Fetch New Data.
135
+
136
+  <p>Enjoy the battery savings and instant email notifications! I'll do my best to keep my Dovecot port
137
+  on GitHub in sync with whatever version is in the official FreeBSD ports tree, though updates may
138
+  not be instantaneous.
139
+
140
+  <section>
141
+    <h3>If You're Not Using FreeBSD</h3>
142
+
143
+    <p>If you're using Linux or something other than FreeBSD, you should still be able to get
144
+    this working. You'll just need to apply <a href="https://raw.githubusercontent.com/cullum/freebsd-ports/master/mail/dovecot/files/apns-2.2.32.patch">the Dovecot patch</a>
145
+    (currently valid for Dovecot 2.2.32) before building Dovecot from source. You'll also need
146
+    to install the Perl dependencies for the <span class="monospace">pushnotify.pl</span> script
147
+    using CPAN or your distribution's package manager. Finally, patch <span class="monospace">pushnotify.pl</span>
148
+    using <a href="https://raw.githubusercontent.com/cullum/freebsd-ports/master/mail/dovecot-apns-daemon/files/patch-pushnotify_pushnotify.pl">my patch</a>
149
+    and run it as a systemd unit file or <span class="monospace">tmux</span> session or something.
150
+    
151
+    <p>Or, just follow the instructions on <a href="https://github.com/matthewpowell/pushnotify">the original repo</a>,
152
+    it's probably easier. 😃
153
+
154
+  </section>
155
+
156
+</section>
157
+
158
+<section>
159
+  <h2 id="how-it-works">But How Does It Work?</h2>
160
+
161
+  <p>When your iPhone connects to an IMAP server, it checks for <span class="monospace">XAPPLEPUSHSERVICE</span>
162
+  in the server's <span class="monospace">CAPABILITY</span> list. If this special string is found, the iOS Mail
163
+  app assumes that it has connected to a macOS Server, which should support a custom song-and-dance
164
+  of IMAP commands to register for push notifications.
165
+
166
+  <p>In our case, we have simply patched Dovecot in a similar fashion to Apple's macOS Server. When
167
+  your iPhone sees the <span class="monospace">XAPPLEPUSHSERVICE</span> capability, it sends a
168
+  special command to register its device token for push notifications. Our patched Dovecot intercepts
169
+  this token and hands it off to our Perl APNS daemon over a local UNIX socket (<span class="monospace">/var/run/dovecot/apns</span>).
170
+  The APNS daemon stores a map of email accounts to APNS tokens in a flat file database, which you
171
+  can view at <span class="monospace">/var/db/dovecot-apns/devices</span>.
172
+
173
+  <p>When an email account receives a new message in its inbox, our patched Dovecot sends another message
174
+  over the APNS daemon's UNIX socket. The daemon looks up the email account's associated APNS token.
175
+  It then uses the <em>mail.XServer</em> keypair you exported from your macOS keychain to sign a
176
+  notification message, which it sends to Apple's push notification server. Your phone then receives a push
177
+  notification regarding the new email over a persistent, highly optimized connection to iCloud.
178
+
179
+  <p>As far as I can tell, buying macOS Server is the only way to get the necessary <em>mail.XServer</em>
180
+  certificate to send push notifications to the stock iOS Mail app. Other companies that advertise native
181
+  iOS push email (<a href="https://blog.fastmail.com/2015/07/17/push-email-now-available-in-ios-mail/">such as Fastmail</a>)
182
+  probably have a working relationship with Apple, which allows them to get more permanent APNS
183
+  certificates—the ones provisioned to macOS Server expire after one year and must be re-exported.
184
+
185
+</section>
186
+
187
+<section>
188
+  <h2 id="conclusion">Conclusion</h2>
189
+
190
+  <p>I can't guarantee how robust this setup is for "production" use, but it works great for my family's
191
+  email server. I do usually have to restart the APNS daemon whenever I restart Dovecot. Also, remember
192
+  your APNS certificate will need to be renewed after one year.
193
+  
194
+  <p>If you decide to try it out, <a href="https://twitter.com/cullumsmith">contact me on Twitter</a>
195
+  and let me know of any issues you have.
196
+</section>
197
+

+ 158
- 0
blog/freebsd-full-disk-encryption-uefi/index.tmpl View File

@@ -0,0 +1,158 @@
1
+TITLE='FreeBSD: Full-Disk Encryption + UEFI'
2
+DESCRIPTION='How to install FreeBSD using a GELI-encrypted UFS root partition on UEFI.'
3
+DATE=2017-12-14
4
+__HTML__
5
+<p>After the almost comical stream of OS X security bugs recently, I dug up my old ThinkPad T530 and installed FreeBSD as my
6
+primary OS. Since a laptop is portable and easily stolen, full-disk encryption is a must. There are plenty of resources
7
+online for setting up an encrypted ZFS root partition on FreeBSD, but I still prefer UFS on desktop setups. Don't get
8
+me wrong—ZFS is my top choice for any kind of RAID situation—but I've always found it a bit overkill (and RAM intensive)
9
+for a single-disk OS partition. And I definitely wanted UEFI for that native resolution console at boot time. :-)
10
+
11
+<p>There were hardly any guides online for installing FreeBSD to a GELI-encrypted UFS partition, and there was even
12
+<em>less</em> information about how to get such a setup working with UEFI. However, I eventually figured it out,
13
+so here's a quick how-to in case another discerning daemon finds his way here.
14
+
15
+<section>
16
+  <h2 id="bios">Configuring Your BIOS</h2>
17
+
18
+  <p>I'm not sure if "BIOS" is the right word anymore, but you know what I mean. Reboot your computer and spam the
19
+  F2 or Delete key or whatever magic incantation you need in order to get to your BIOS settings. You'll definitely
20
+  need to disable Secure Boot, since <a href="https://wiki.freebsd.org/SecureBoot">it doesn't work yet</a> (and why
21
+  would you want it, anyway?). On my ThinkPad, I also had to disable all the compatibility boot options. Most
22
+  of these options were labeled "CSM".
23
+
24
+  <p>While you're in the BIOS, you might want to go ahead and disable the TPM if you have one—I've seen many reports
25
+  that it <a href="https://unrelenting.technology/notes/2017-11-22-15-11-44">breaks resuming from suspend in FreeBSD</a>.
26
+</section>
27
+
28
+<section>
29
+  <h2 id="partitioning">Partitioning the Disk</h2>
30
+
31
+  <p>At this point, I'm assuming that you've successfully booted the FreeBSD installation media via UEFI. If the installer
32
+  won't boot in pure UEFI mode, then you're probably out of luck—but the GELI encryption section of this guide might still
33
+  be helpful to you.
34
+
35
+  <p>Once you get to the partitioning step in the FreeBSD installer, choose the <span class="monospace">Shell</span> option
36
+  to manually partition the disks. The first thing you'll need to do is figure out which block device corresponds to your hard
37
+  drive. To show the current disk layout, just run:
38
+
39
+  <pre>gpart show</pre>
40
+  
41
+  <p>I'm going to assume your hard drive is called <span class="monospace">ada0</span>. Let's blow away the current partition
42
+  table and write a fresh GPT partitioning scheme.
43
+
44
+<pre>gpart destroy -F ada0
45
+gpart create -s gpt ada0</pre>
46
+
47
+  <p>The first partition you'll need is an <em>EFI System Partition</em>. This is a small FAT-formatted partition from which
48
+  your computer's firmware will boot the operating system. It just needs to be large enough to hold the FreeBSD UEFI
49
+  bootloader—800 KB is plenty. 
50
+
51
+<pre>gpart add -t efi -l freebsd-efi -a 4k -s 800k ada0
52
+newfs_msdos /dev/gpt/freebsd-efi</pre>
53
+
54
+  <p>Your computer's UEFI firmware should look for a boot executable in a specific location on this partition. You'll need
55
+  to mount the partition, create the folder hierarchy, and copy over the FreeBSD UEFI bootloader from the install media:
56
+
57
+<pre>mount -t msdosfs /dev/gpt/freebsd-efi /mnt
58
+mkdir -p /mnt/EFI/BOOT
59
+cp /boot/boot1.efi /mnt/EFI/BOOT/BOOTX64.efi
60
+echo BOOTx64.efi &gt; /mnt/EFI/BOOT/STARTUP.NSH
61
+umount /mnt</pre>
62
+
63
+  <p>Next, you'll need a boot partition. Confusing, I know. The EFI partition you just created contains
64
+  a small UEFI bootloader. However, this bootloader's only purpose is to look for a UFS (or ZFS) partition which contains the <em>real</em> 
65
+  FreeBSD bootloader, and then run it. The boot partition will also contain the kernel, boot configuration, and kernel modules.
66
+  
67
+  <p>This partition will have to remain unencrypted, since the bootloader needs to be able to find a kernel to execute. There
68
+  are some guides online for storing your boot partition and kernel on an external USB stick to achieve a fully encrypted system,
69
+  but I'm not that paranoid.
70
+
71
+  <p>Anyway, create the boot partition. 1 GB is probably overkill for the FreeBSD kernel, but I've got plenty of disk space. If
72
+  you have an SSD, be sure to pass the <span class="monospace">-t</span> flag to <span class="monospace">newfs</span> to enable
73
+  TRIM support.
74
+
75
+<pre>gpart add -t freebsd-ufs -l freebsd-boot -a 4k -s 1g ada0
76
+newfs -t -U -L bootfs /dev/gpt/freebsd-boot</pre>
77
+
78
+  <p>Finally, create a partition for your root filesystem. I don't bother with swap for a desktop machine, so I'll just use
79
+  the entire remainder of the disk.
80
+
81
+  <pre>gpart add -t freebsd-ufs -l freebsd-root -a 4k ada0</pre>
82
+
83
+  <p>Notice we didn't create a filesystem this time. That comes in the next section.
84
+
85
+</section>
86
+
87
+<section>
88
+  <h2 id="geli">GELI Encryption</h2>
89
+
90
+  <p>Now it's time to create your encrypted partition! FreeBSD's framework for disk encryption is called <a href="https://www.freebsd.org/doc/handbook/disks-encrypting.html">GELI</a>.
91
+  Basically, it's a layer in between the filesystem and the physical disk that manages encryption/decryption of the data blocks. Creating your
92
+  GELI root partition is a one-liner:
93
+
94
+  <pre>geli init -b -e AES-XTS -l 256 -s 4096 /dev/gpt/freebsd-root</pre>
95
+
96
+  <p>The <span class="monospace">-b</span> flag is critical, as it allows the encrypted partition to be used as a root filesystem.
97
+
98
+  <p>This will prompt you for an encryption passphrase. Use a good one! You will have to enter this passphrase every time you boot
99
+  your computer (and if you forget it, you're SOL). Once that's done, issue the following command to unlock the drive (it will
100
+  prompt you for the passphrase you just created):
101
+
102
+  <pre>geli attach /dev/gpt/freebsd-root</pre>
103
+
104
+  <p><em>Now</em> you can create the root UFS filesystem. Note the <span class="monospace">.eli</span> extension on the block device
105
+  this time:
106
+
107
+  <pre>newfs -t -U -L rootfs /dev/gpt/freebsd-root.eli</pre>
108
+
109
+</section>
110
+
111
+<section>
112
+  <h2 id="mounting">Mounting the Filesystems</h2>
113
+
114
+  <p>To complete the partitioning step, the FreeBSD installer expects you to mount your root filesystem at <span class="monospace">/mnt</span>:
115
+
116
+  <pre>mount /dev/gpt/freebsd-root.eli /mnt</pre>
117
+
118
+  <p>However, there is one <strong>very important</strong> caveat regarding the boot partition. The bootloader expects everything to be
119
+  under a folder called <span class="monospace">/boot</span> <em>on the boot partition itself</em>. Therefore, for the FreeBSD installer
120
+  to work, we'll need to mount the boot partition under a separate directory and create a symlink:
121
+
122
+<pre>mkdir /mnt/bootfs
123
+mount /dev/gpt/freebsd-boot /mnt/bootfs
124
+cd /mnt
125
+mkdir bootfs/boot
126
+ln -s bootfs/boot</pre>
127
+
128
+  <p><em>(Special thanks to ross at <a href="http://daemon-notes.com/articles/system/encryption">daemon-notes.com</a> for that tidbit.)</em>
129
+
130
+  <p>Finally, you'll need to create an <span class="monospace">fstab</span> and <span class="monospace">loader.conf</span> file for
131
+  your system to be bootable. At this stage in the installation, you can place these under <span class="monospace">/tmp/bsdinstall_*</span>
132
+  and the installer will copy them to the target filesystem appropriately.
133
+
134
+<pre><div class="code-title">/tmp/bsdinstall_etc/fstab</div>/dev/gpt/freebsd-root.eli /       ufs rw 1 1
135
+/dev/gpt/freebsd-boot     /bootfs ufs rw 0 0</pre>
136
+<p>
137
+<pre><div class="code-title">/tmp/bsdinstall_boot/loader.conf</div>geom_eli_load="YES"
138
+vfs.root.mountfrom="ufs:ada0p3.eli"</pre>
139
+
140
+  <p>At this point, you're finished! Exit the shell to continue the FreeBSD installation.
141
+
142
+</section>
143
+
144
+<section>
145
+  <h2 id="conclusion">Conclusion</h2>
146
+
147
+  <p>Once the installer has finished, you may want to open a shell before you reboot, just to make sure your <span class="monospace">fstab</span>
148
+  and <span class="monospace">loader.conf</span> files look correct. With any luck, your computer's UEFI firmware will be able to find your
149
+  bootloader and launch the FreeBSD kernel.
150
+
151
+  <p>When your system reboots, it will prompt you for your encryption passphrase during the boot process. The prompt is easy to miss
152
+  during the text-scrolling frenzy, so if it seems hung, just type your passphrase and press enter.
153
+
154
+  <p>As always, contact me via <a href="mailto:cullum@c0ffee.net">email</a> or ping me on <a href="https://twitter.com/cullumsmith">Twitter</a>
155
+  with any questions or issues you have.
156
+
157
+</section>
158
+

+ 1083
- 0
blog/freebsd-on-a-laptop/index.tmpl
File diff suppressed because it is too large
View File


+ 760
- 0
blog/freebsd-server-guide/index.tmpl View File

@@ -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
+

+ 10
- 0
blog/index.tmpl View File

@@ -0,0 +1,10 @@
1
+TITLE='Cullum Smith: Blog'
2
+DESCRIPTION="Cullum Smith's Blog"
3
+__HTML__
4
+%%NAV%%
5
+
6
+<header>
7
+  <h1 class="title">%%AUTHOR%%'s Blog</h1>
8
+</header>
9
+
10
+<main>

+ 1673
- 0
blog/mail-server-guide/index.tmpl
File diff suppressed because it is too large
View File


+ 1118
- 0
blog/openbsd-on-a-laptop/index.tmpl
File diff suppressed because it is too large
View File


+ 436
- 0
blog/openvpn-guide/index.tmpl View File

@@ -0,0 +1,436 @@
1
+TITLE='OpenVPN Setup Guide'
2
+DESCRIPTION='Browse securely from anywhere using a personal VPN with OpenVPN, LDAP, FreeBSD, and PF.'
3
+DATE=2017-11-26
4
+__HTML__
5
+<p>A VPN allows you to securely extend a private network over the internet via tunneling protocols and traffic encryption. For most
6
+people, a VPN offers two primary features: (1) the ability to access services on your local network over the internet, and (2) secure
7
+internet connectivity over an untrusted network. In this guide, I'll describe how to set up a personal VPN using 
8
+<a href="https://openvpn.net">OpenVPN</a> on FreeBSD. The configuration can use both SSL certificates and LDAP credentials for authentication. We'll also be using the PF
9
+firewall to NAT traffic from our VPN out to the internet.
10
+
11
+<p>One important note about running your own VPN: since you are most likely hosting your server using a VPS or hosting provider, with a
12
+public IP address allocated specifically to you, your VPN will <strong>not</strong> give you any extra anonymity on the internet. If anything,
13
+you'll be making yourself more of a target, since all your activity can be trivially traced back to your server's IP address. So while
14
+your VPN will protect you from a snooping hacker on the free WiFi at Starbucks, it won't protect you from a federal investigation.
15
+
16
+<p>This guide assumes you are running FreeBSD with the PF firewall. If you're using a different Unix flavor, I'll probably get you
17
+most of the way there—but you'll be on your own when configuring your firewall and networking.
18
+
19
+<p>Finally, I've used <span class="monospace">example.com</span> and a non-routable public IP address for all the examples in this guide.
20
+You'll need to replace them with your own domain name and public IP address.
21
+
22
+<p>With all that out of the way, let's get started.
23
+
24
+<section>
25
+  <h2>Configuring the OpenVPN Server</h2>
26
+  
27
+  <p>First, you'll need to install OpenVPN. You can use your distribution's package manager, but my examples assume you're using the FreeBSD
28
+  ports tree. I recommend building with the <span class="monospace">EASYRSA</span> option—you'll need it later.
29
+
30
+<pre>cd /usr/ports/security/openvpn
31
+make install clean</pre>
32
+
33
+  <p>OpenVPN should ship with a default configuration file. Open it up in your editor to see all the available options. I've pasted my own
34
+  configuration below, along with some commentary where appropriate. You'll almost certainly need to make some changes.
35
+
36
+<pre><div class="code-title">/usr/local/etc/openvpn/openvpn.conf</div><span class="code-comment"># port to listen on - 1194 is OpenVPN default</span>
37
+port 1194
38
+
39
+<span class="code-comment"># OpenVPN works best over UDP, but has support for TCP as well. UDP is</span>
40
+<span class="code-comment"># recommended, since tunneling TCP over TCP has well-known performance</span>
41
+<span class="code-comment"># issues.</span>
42
+proto udp
43
+
44
+<span class="code-comment"># OpenVPN supports TUN and TAP devices for the virtual network:</span>
45
+<span class="code-comment">#  TUN: uses layer 3, less overhead but cannot bridge with other interfaces</span>
46
+<span class="code-comment">#  TAP: uses layer 2, more overhead (emulates ethernet frames) but can</span>
47
+<span class="code-comment">#       bridge with other interfaces</span>
48
+<span class="code-comment"># The configuration I present here uses TUN.</span>
49
+dev tun
50
+
51
+<span class="code-comment"># DH params, CA, and key pair for your VPN server. Replace example.com with</span>
52
+<span class="code-comment"># your domain name. We will generate these using easy-rsa in the next step.</span>
53
+dh /usr/local/etc/openvpn/keys/dh.pem
54
+ca /usr/local/etc/openvpn/keys/ca.crt
55
+cert /usr/local/etc/openvpn/keys/vpn.example.com.crt <span class="code-comment"># change me!</span>
56
+key /usr/local/etc/openvpn/keys/vpn.example.com.key  <span class="code-comment"># change me!</span>
57
+
58
+<span class="code-comment"># Modern cipher recommendations from Mozilla. Comment these out if you need</span>
59
+<span class="code-comment"># to support old/legacy clients.</span>
60
+tls-version-min 1.2
61
+tls-cipher ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384
62
+
63
+<span class="code-comment"># No need to set block cipher manually anymore - OpenVPN 2.4+ automatically</span>
64
+<span class="code-comment"># negotiates AES-256-GCM. Uncomment if you use older clients that default</span>
65
+<span class="code-comment"># to insecure ciphers.</span>
66
+<span class="code-comment"># cipher AES-256-CBC</span>
67
+
68
+<span class="code-comment"># VPN network - server accessible @ 10.8.0.1</span>
69
+topology subnet
70
+server 10.8.0.0 255.255.255.0
71
+
72
+<span class="code-comment"># cache client IP addresses in a file for later re-use</span>
73
+ifconfig-pool-persist ipp.txt
74
+
75
+<span class="code-comment"># This line will force clients to route ALL their internet traffic through</span>
76
+<span class="code-comment"># the VPN. If you only want to use your VPN to access internal services,</span>
77
+<span class="code-comment"># comment this out.</span>
78
+push "redirect-gateway def1 bypass-dhcp"
79
+
80
+<span class="code-comment"># These lines tell clients which DNS servers to use once they are connected</span>
81
+<span class="code-comment"># to the VPN. If you run a local DNS server, you can have clients use the</span>
82
+<span class="code-comment"># server's own address (10.8.0.1). If you don't run a local DNS server, you</span>
83
+<span class="code-comment"># can substitute your server's configured nameserver here (check</span>
84
+<span class="code-comment"># /etc/resolv.conf).</span>
85
+push "dhcp-option DNS 10.8.0.1"
86
+push "dhcp-option DOMAIN example.com" <span class="code-comment"># change me!</span>
87
+
88
+<span class="code-comment"># let clients see each other</span>
89
+client-to-client
90
+
91
+<span class="code-comment"># ping every 10s, timeout after 120s</span>
92
+keepalive 10 120
93
+
94
+<span class="code-comment"># max simultaneous clients</span>
95
+max-clients 20
96
+
97
+<span class="code-comment"># drop privileges</span>
98
+user nobody
99
+group nobody
100
+persist-key
101
+persist-tun
102
+
103
+<span class="code-comment"># log levels 0-9</span>
104
+verb 3
105
+
106
+<span class="code-comment"># silence repeated messages</span>
107
+mute 10
108
+
109
+<span class="code-comment"># notify clients when the server restarts so they can automatically</span>
110
+<span class="code-comment"># reconnect</span>
111
+explicit-exit-notify 1
112
+
113
+<span class="code-comment"># experimental TUN UDP I/O optimizations</span>
114
+fast-io
115
+
116
+<span class="code-comment"># Uncomment the following line if you want to use LDAP authentication in</span>
117
+<span class="code-comment"># addition to SSL certificates.</span>
118
+<span class="code-comment"># plugin /usr/local/lib/openvpn-auth-ldap.so "/usr/local/etc/openvpn/auth-ldap.conf"</pre></span>
119
+
120
+  <section> 
121
+    <h3>LDAP Authentication</h3>
122
+
123
+    <p>For added security, you can have clients supply their LDAP credentials in addition to their
124
+    provisioned SSL certificates. You'll need to install a plugin first:
125
+
126
+<pre>cd /usr/ports/security/openvpn-auth-ldap
127
+make install clean</pre>
128
+
129
+    <p>Then, just supply your LDAP connectivity details in a separate configuration file. Make sure
130
+    you include each option below—I spent hours troubleshooting this part because I had neglected the
131
+    <span class="monospace">Timeout</span> parameter.
132
+
133
+<pre><div class="code-title">/usr/local/etc/openvpn/auth-ldap.conf</div>&lt;LDAP&gt;
134
+  URL              ldap://localhost
135
+  TLSEnable        no
136
+  FollowReferrals  no
137
+  Timeout          15
138
+&lt;/LDAP&gt;
139
+
140
+&lt;Authorization&gt;
141
+  BaseDN        "ou=users,dc=example,dc=com"
142
+  SearchFilter  "(&amp;(uid=%u))"
143
+  RequireGroup  false
144
+&lt;/Authorization&gt;</pre>
145
+
146
+  </section>
147
+
148
+  <h3>Notes on Using Your Own DNS Server</h3>
149
+
150
+  <p>If you're running your own DNS server for the VPN, make sure it's listening for DNS queries on the VPN's interface.
151
+  If you followed my <a href="/blog/dns-hidden-master/">DNS Hosting Guide</a>, you'll just need to add the VPN's network address to
152
+  BIND's configuration file:
153
+
154
+<pre><div class="code-title">/usr/local/etc/namedb/named.conf</div><span class="code-comment">// localhost, and any other public IPs of your server</span>
155
+acl localnetworks {
156
+  127.0.0.1;
157
+  ::1;
158
+  <strong>10.8.0.0/24;</strong>
159
+  203.0.113.41;
160
+  203.0.113.42;
161
+  2001:db8::2;
162
+  2001:db8::3;
163
+};</pre>
164
+</section>
165
+
166
+<section>
167
+
168
+  <h2>Generating the Server Certificates</h2>
169
+
170
+  <p>Finally, you need to generate a Certificate Authority and an SSL key pair. You'll distribute the CA to your
171
+  clients so they can verify the authenticity of your VPN server. These files can be generated using the Easy-RSA
172
+  package. Install it now if you didn't specify it in OpenVPN's build options earlier.
173
+
174
+<pre>cd /usr/ports/security/easy-rsa
175
+make install clean</pre>
176
+
177
+  <p>Copy the whole Easy-RSA package into OpenVPN's configuration directory.
178
+
179
+<pre>cp -r /usr/local/share/easy-rsa /usr/local/etc/openvpn/easy-rsa
180
+cd /usr/local/etc/openvpn/easy-rsa
181
+</pre>
182
+  <p><em><strong>EDIT (29 Nov 2017): In a production setup, it's never a good idea to do certificate management on a public-facing server.</strong>
183
+    Once you've verified everything works, you should move your Easy-RSA directory to a secure location away from the prying eyes of the internet. (Thanks
184
+    to <a href="https://twitter.com/DavidSommerseth">@DavidSommerseth</a> for reminding me to point this out.)</em>
185
+
186
+  <p>Easy-RSA is configured by setting options in the <span class="monospace">vars</span> configuration file:
187
+
188
+<pre><div class="code-title">/usr/local/etc/openvpn/easy-rsa/vars</div>set_var EASYRSA_DN           "cn_only"
189
+
190
+<span class="code-comment"># Elliptic curve cryptography is faster and arguably more secure than RSA.</span>
191
+<span class="code-comment"># I use EC in my setup, but stick to RSA if you need to support older</span>
192
+<span class="code-comment"># clients.</span>
193
+set_var EASYRSA_ALGO         ec
194
+set_var EASYRSA_CURVE        secp384r1
195
+
196
+<span class="code-comment"># generated certificates will expire after 10 years.</span>
197
+set_var EASYRSA_CA_EXPIRE    3650
198
+set_var EASYRSA_CERT_EXPIRE  3650</pre>
199
+
200
+  <p>Now you're ready to generate your certificate infrastructure:
201
+
202
+<pre>./easyrsa.real init-pki
203
+
204
+./easyrsa.real build-ca
205
+<span class="code-comment"># You will be prompted for a password when generating the CA. Keep it</span>
206
+<span class="code-comment"># somewhere safe, since you will need it when generating client certs.</span>
207
+<span class="code-comment"># You can put whatever you like for the Common Name. I use</span>
208
+<span class="code-comment"># "vpn.example.com CA". </span>
209
+
210
+<span class="code-comment"># relace "vpn.example.com" with your server's FQDN. </span>
211
+./easyrsa.real build-server-full vpn.example.com nopass <span class="code-comment"># change me!</span>
212
+<span class="code-comment"># enter password from previous step when prompted.</span>
213
+
214
+./easyrsa.real gen-dh
215
+</pre>
216
+
217
+  <p>Copy the generated files into a separate directory, as we specified in <span class="monospace">openvpn.conf</span>:
218
+
219
+<pre>mkdir /usr/local/etc/openvpn/keys
220
+cd /usr/local/etc/openvpn/keys
221
+cp ../easy-rsa/pki/ca.crt .
222
+cp ../easy-rsa/pki/dh.pem .
223
+cp ../easy-rsa/pki/issued/vpn.example.com.crt  . <span class="code-comment"># change me!</span>
224
+cp ../easy-rsa/pki/private/vpn.example.com.key . <span class="code-comment"># change me!</span></pre>
225
+
226
+  <p>Enable OpenVPN to start on boot:
227
+
228
+<pre><div class="code-title">/etc/rc.conf</div>openvpn_enable="YES"</pre>
229
+
230
+  <p>Finally, start OpenVPN!
231
+
232
+<pre>service openvpn start</pre>
233
+
234
+  <p>You can check for any startup issues in <span class="monospace">/var/log/messages</span>.
235
+  
236
+</section>
237
+
238
+<section>
239
+  <h2>Routing VPN Traffic to the Internet</h2>
240
+
241
+  <p>OpenVPN will create a secure virtual network for your VPN clients, but it's up to your firewall to
242
+  route traffic from your VPN interface out to the internet using <a href="https://en.wikipedia.org/wiki/Network_address_translation">Network Address Translation (NAT)</a>.
243
+  If you followed the <a href="freebsd-server-guide#pf">PF section of my FreeBSD Server Guide</a>,
244
+  you just need to make a few small tweaks to <span class="monospace">pf.conf</span>. I've highlighted the important changes in bold.
245
+
246
+<pre><div class="code-title">/etc/pf.conf</div># the external network interface to the internet
247
+<span class="code-comment"># public-facing interface</span>
248
+ext_if="vtnet0"
249
+
250
+<span class="code-comment"># your public-facing IP address -  VPN traffic will NAT out of this address</span>
251
+<strong>ext_ip="203.0.113.42"</strong> <span class="code-comment"># change me!</span>
252
+
253
+<span class="code-comment"># vpn interface</span>
254
+<strong>vpn_if="tun0"
255
+vpn_net = "10.8.0.0/24"</strong>
256
+
257
+<span class="code-comment"># port on which sshd is running</span>
258
+ssh_port = "55022"
259
+
260
+<span class="code-comment"># allowed inbound ports (services hosted by this machine)</span>
261
+inbound_tcp_services = "{auth, http, https, " $ssh_port ", <strong>openvpn</strong> }"
262
+inbound_udp_services = "{dhcpv6-client, <strong>openvpn</strong>}"
263
+
264
+<span class="code-comment"># politely send TCP RST for blocked packets. The alternative is</span>
265
+<span class="code-comment"># "set block-policy drop", which will cause clients to wait for a timeout</span>
266
+<span class="code-comment"># before giving up.</span>
267
+set block-policy return
268
+
269
+<span class="code-comment"># log only on the external interface</span>
270
+set loginterface $ext_if
271
+
272
+<span class="code-comment"># skip all filtering on localhost</span>
273
+set skip on lo
274
+
275
+<span class="code-comment"># reassemble all fragmented packets before filtering them</span>
276
+scrub in on $ext_if all fragment reassemble
277
+
278
+<span class="code-comment"># route traffic from VPN interface out to the internet</span>
279
+<strong>nat on ! $vpn_if from $vpn_net to any -&gt; $ext_ip</strong>
280
+
281
+<span class="code-comment"># block forged client IPs (such as private addresses from WAN interface)</span>
282
+antispoof for $ext_if
283
+
284
+<span class="code-comment"># default behavior: block all traffic</span>
285
+block all
286
+
287
+<span class="code-comment"># all traffic through VPN interface is assumed to be safe</span>
288
+<strong>pass quick on $vpn_if</strong>
289
+
290
+<span class="code-comment"># allow all icmp traffic (like ping)</span>
291
+pass quick on $ext_if proto icmp all
292
+pass quick on $ext_if proto icmp6 all
293
+
294
+<span class="code-comment"># allow incoming traffic to services hosted by this machine</span>
295
+pass in quick on $ext_if proto tcp to port $inbound_tcp_services
296
+pass in quick on $ext_if proto udp to port $inbound_udp_services
297
+
298
+<span class="code-comment"># allow all outgoing traffic</span>
299
+pass out quick on $ext_if</pre>
300
+
301
+  <p>Reload PF for these changes to take effect (you may want to do this from a serial console in case you
302
+  messed something up):
303
+
304
+<pre>pfctl -f /etc/pf.conf</pre>
305
+
306
+  <p>Tell the kernel to enable packet forwarding in order to support NAT:
307
+
308
+<pre>sysctl net.inet.ip.forwarding=1</pre>
309
+
310
+  <p>One last thing: since your server will now be forwarding packets, <a href="https://wiki.freebsd.org/10gFreeBSD/Router#Disabling_LRO_and_TSO">you must disable hardware offloading on your network card to avoid nasty issues</a>:
311
+
312
+<pre><span class="code-comment"># replace vtnet0 with your external network interface</span>
313
+ifconfig vtnet0 -tso -lro</pre>
314
+
315
+  <p>To make these changes permanent, make the following changes in <span class="monospace">/etc/rc.conf</span>:
316
+
317
+<pre><div class="code-title">/etc/rc.conf</div><span class="code-comment"># disable TSO and LRO on your primary NIC when routing packets</span>
318
+ifconfig_vtnet0="inet 203.0.113.42 netmask 255.255.255.0 <strong>-tso -lro</strong>"
319
+
320
+<span class="code-comment"># enable packet forwarding</span>
321
+gateway_enable="YES"</pre>
322
+  
323
+</section>
324
+
325
+<section>
326
+  <h2>Provisioning Your VPN Clients</h2>
327
+
328
+  <p>For clients to connect to your VPN server, they will need a client configuration file (usually with an
329
+  <span class="monospace">.ovpn</span> extension) and a certificate key pair signed by your VPN's CA. You'll
330
+  have to generate these files on your server and provide them to your clients out of band. I usually
331
+  just put the files in a tarball and email them, but you might have more stringent security requirements.
332
+  Proceed accordingly.
333
+
334
+  <p>The client configuration file will be the same for all clients, so let's start with that first. Create a
335
+  file called <span class="monospace">client.conf</span> in OpenVPN's configuration directory. Most of the
336
+  options in this file will mimic your configuration in <span class="monospace">openvpn.conf</span>.
337
+
338
+<pre><div class="code-title">/usr/local/etc/openvpn/client.conf</div>client
339
+
340
+dev tun
341
+proto udp
342
+
343
+<span class="code-comment"># FQDN of your VPN server</span>
344
+remote vpn.example.com 1194 <span class="code-comment"># change me!</span>
345
+
346
+<span class="code-comment"># let clients use any random port on their side</span>
347
+nobind
348
+
349
+ca ca.crt
350
+cert client.crt
351
+key client.key
352
+
353
+<span class="code-comment"># No need to set block cipher manually anymore - OpenVPN 2.4+ automatically</span>
354
+<span class="code-comment"># negotiates AES-256-GCM. Uncomment if you use older clients that default</span>
355
+<span class="code-comment"># to insecure ciphers.</span>
356
+<span class="code-comment"># cipher AES-256-CBC</span>
357
+
358
+<span class="code-comment"># keep trying to resolve remote hostname indefinitely</span>
359
+resolv-retry infinite
360
+
361
+<span class="code-comment"># reuse resources between invocations</span>
362
+persist-key
363
+persist-tun
364
+
365
+<span class="code-comment"># WLANs produce a lot of duplicate packets - mute this warning</span>
366
+mute-replay-warnings
367
+
368
+<span class="code-comment"># verify remote certificate</span>
369
+remote-cert-tls server
370
+
371
+<span class="code-comment"># log level 0-9</span>
372
+verb 3
373
+
374
+<span class="code-comment"># silence repeated messages</span>
375
+mute 10
376
+
377
+<span class="code-comment"># uncomment the following line if you're using LDAP authentication</span>
378
+<span class="code-comment"># auth-user-pass</pre></span>
379
+
380
+  <p>Now you need to create a client certificate. You'll need a different certificate for each device you
381
+  want to connect to the VPN, because a single certificate cannot be used for multiple simultaneous connections.
382
+  In this example, we'll create a certificate called <span class="monospace">macbook</span> for my $2000 <span class="monospace">ssh</span> machine.
383
+
384
+<pre>cd /usr/local/etc/openvpn/easy-rsa
385
+
386
+<span class="code-comment"># Generate a client keypair for "macbook" - you will need to provide the CA</span>
387
+<span class="code-comment"># password you specified last time.</span>
388
+./easyrsa.real build-client-full macbook nopass</pre>
389
+
390
+  <p>Note the <span class="monospace">nopass</span> option used here—since I'm additionally using password authentication
391
+  via LDAP, I don't see a need to encrypt the certificate with a password. If you aren't using password authentication, you probably
392
+  want to have your clients generate their own private key and send you a Certificate Signing Request. You can read about that
393
+  process in <a href="https://github.com/OpenVPN/easy-rsa/blob/master/README.quickstart.md">the Easy-RSA documentation</a>.
394
+
395
+  <p>Anyway, the <span class="monospace">macbook</span> key pair is now located in the <span class="monospace">pki</span> directory
396
+  on the server. Now we need to shuffle some filenames around and generate a tarball so I can get the configuration onto my MacBook.
397
+
398
+<pre>CLIENT=macbook
399
+SERVER=vpn.example.com <span class="code-comment"># change me!</span>
400
+
401
+mkdir /tmp/${CLIENT}
402
+cp pki/ca.crt /tmp/${CLIENT}/ca.crt
403
+cp pki/issued/${CLIENT}.crt /tmp/${CLIENT}/client.crt
404
+cp pki/private/${CLIENT}.key /tmp/${CLIENT}/client.key
405
+cp ../client.conf /tmp/${CLIENT}/${SERVER}.ovpn
406
+chmod 644 /tmp/${CLIENT}/*
407
+tar cvzf /tmp/${CLIENT}.tar.gz /tmp/${CLIENT}
408
+rm -rf /tmp/${CLIENT}</pre>
409
+
410
+  <p>A tarball with the server's CA certificate, the client key pair, and the client configuration file for <span class="monospace">macbook</span>
411
+  is now located at <span class="monospace">/tmp/macbook.tar.gz</span>. You can then <span class="monospace">scp</span> (or worse, email) this file to the client machine and
412
+  fire up your OpenVPN client. On macOS, I'm a big fan of <a href="https://tunnelblick.net">Tunnelblick</a>. Just double-click the <span class="monospace">.ovpn</span>
413
+  file and Tunnelblick will automatically import your VPN profile.
414
+  
415
+  <p>As of this writing, there is currently one small change to make in Tunnelblick: edit your VPN profile and change <em>OpenVPN version</em> to <em>Latest (2.4.4)</em>.
416
+  This allows you to use the more secure GCM cipher. In future versions of Tunnelblick, this step may be unnecessary.
417
+
418
+  <p>After that, you can connect to your VPN server and start browsing. You can verify your traffic is being tunneled through the VPN by checking your external public IP address
419
+  (I use <a href="http://icanhazip.com">icanhazip.com</a>). If you run into any issues, check the OpenVPN logs on your client and server. 
420
+  To troubleshoot, try pinging a public IP address (like <span class="monospace">8.8.8.8</span>), as well as your own server (<span class="monospace">10.8.0.1</span>).
421
+  If you can ping locally but can't ping out to the internet, it's most likely a firewall or routing issue.
422
+</section>
423
+
424
+<section>
425
+  <h2>Conclusion</h2>
426
+
427
+  <p>A VPN is a must-have tool to protect your privacy, especially when using a sketchy public network. It also provides a reliable and convenient way
428
+  to securely access your personal "intranet" from anywhere in the world.
429
+  
430
+  <p> Recent versions of OpenVPN have a very small resource footprint, making it
431
+  suitable for use on a VPS. When maxing out my server's internet connection with a speed test, OpenVPN delivered 85 mbps while using only
432
+  50% of a single CPU core. With typical traffic, system load is minimal.
433
+  
434
+  <p>As always, contact me via <a href="mailto:cullum@c0ffee.net">email</a> or ping me on <a href="https://twitter.com/cullumsmith">Twitter</a>
435
+  with any questions or issues you have.
436
+</section>

+ 122
- 0
blog/self-hosting-guide/index.tmpl View File

@@ -0,0 +1,122 @@
1
+TITLE='A Guide to Self-Hosting Your Online Services'
2
+DESCRIPTION='Take charge of your data by self-hosting email, chat, file sync, and more.'
3
+DATE=2016-12-31
4
+__HTML__
5
+<p>In a post-<a href="https://en.wikipedia.org/wiki/PRISM_(surveillance_program)">PRISM</a> world, you've
6
+probably accepted the fact that the NSA, CIA, or some other
7
+three-letter agency will read your email, text messages, smartphone
8
+pictures, and basically anything else you send over the internet. And if it's not the government
9
+spying on you, it will be some monolithic corporation like Google or Facebook eager to catalog
10
+every minutia of your digital life so they can sell it to whatever advertising company comes along.
11
+
12
+<p>Many of the digital protocols in use today—such as email, XMPP, and CalDAV—were originally
13
+designed with self-hosting in mind. In ages past, universities, large companies, and even some nerdy
14
+individuals hosted their own mail servers and the like. It's only recently that we have traded our
15
+privacy for the walled-garden convenience of letting advertising companies handle all our data. Every
16
+online service costs some amount of money to operate, so <em>if you aren't paying for it, then you
17
+are the product.</em>
18
+
19
+<p>In this guide, I will share the steps I have taken to take back my family's digital privacy.
20
+By self-hosting online services like email, chat, file synchronization, calendar/contacts sync, and
21
+more, <em>you</em> can be the master of your data—and most of the time, your homegrown solution
22
+will work better than proprietary alternatives. All it takes is a little work, and I've already
23
+done the hard part for you.
24
+
25
+<p><strong>The downside:</strong> it takes time and effort to get this stuff up and running. It's
26
+fairly set-and-forget once you've configured everything, but you're essentially signing up to be
27
+your own Systems Administrator. Nerds and techies will probably view it as a fun side project, but
28
+it's definitely not for everyone.
29
+
30
+<section>
31
+  <h2 id="requirements">What You'll Need</h2>
32
+
33
+  <ul class="paragraph-list">
34
+    <li><strong>A domain name:</strong> you will need a personal domain name to access your digital world.
35
+    I use <a href="https://www.c0ffee.net/">c0ffee.net</a> (obviously), but you will need to
36
+    register your own at one of the numerous domain registrars. I've always been happy with
37
+    <a href="https://www.namecheap.com/?aff=108349">Namecheap</a>.
38
+
39
+    <li><strong>A hosting provider:</strong> you will need a server somewhere to host all your
40
+    services. For most people hosting email, chat, and maybe a blog for their immediate friends or
41
+    family, a VPS is more than adequate. If you plan to have 100+ users or want to store terabytes of
42
+    music or backups, a dedicated sever may be a more cost-effective option.
43
+
44
+    <p>I'm a <a href="https://www.freebsd.org/">FreeBSD</a> guy, so I use
45
+    <a href="https://arpnetworks.com/">ARP Networks</a> for my hosting.  But I have used
46
+    <a href="https://www.linode.com/">Linode</a>,
47
+    <a href="https://www.digitalocean.com/">DigitalOcean</a>, and
48
+    <a href="https://www.vultr.com/">Vultr</a>
49
+    in the past and been happy with them.
50
+
51
+    <p>If you have an awesome home internet connection and a static IP address, you may be able to
52
+    get away with using a server in your house. However, many ISPs block certain ports—almost all of them
53
+    block port 25 for example—making hosting a mail server impossible. In addition,
54
+    most major email providers will reject mail from residential IP addresses due to spammers. For the
55
+    smoothest experience, nothing is going to beat a dedicated server or VPS in a colocation facility.
56
+
57
+    <li><strong>Some DevOps skills:</strong> you will need to be familiar with Unix/Linux, as well
58
+    as some basics in networking. If you've ever installed Linux, set up a webserver, or built a package
59
+    from source, you probably know enough to make it through. But be careful, you may end up learning
60
+    enough to make this your career (like me)!
61
+  </ul>
62
+</section>
63
+
64
+<section>
65
+  <h2 id="security">Some Notes on Security</h2>
66
+
67
+  <p>Along the way, I will point out some common-sense security measures you can take to keep
68
+  government agents and attackers from pwning your system. However, only you can judge
69
+  the security requirements and risk tolerance for your circumstances. The advice I give you may
70
+  prevent a script kiddie from brute-forcing your password, but it's unlikely to prevent a state-sponsored
71
+  actor from exploiting a zero-day in Postfix to gain access to your system. Ultimately, as long as your
72
+  server is hosted off-site, you are trusting <em>someone</em> with your data.
73
+
74
+  <p>Friends of mine have often asserted that my self-hosting efforts are futile, because (1) the government
75
+  can probably crack most encryption protocols, and (2) most communication goes to someone else using Gmail
76
+  or Facebook, etc. To this I have the following replies:
77
+
78
+  <ol class="paragraph-list">
79
+    <li>Our current situation will never get any better if we continue to hand our private data to
80
+    governments and corporations on a silver platter. With NSA programs like
81
+    <a href="https://en.wikipedia.org/wiki/XKeyscore">XKeyscore</a>, our government has a search
82
+    engine for our private data in Gmail. At least by hosting my own services, I can make their unlawful
83
+    surveillance a little more difficult.
84
+
85
+    <li>I do not want my private emails or chat messages scraped in order to facilitate more effective
86
+    advertisements. I wouldn't let a random corporation go through my postal mail, email is no different.
87
+
88
+    <li>I do not want to be dependent on the whims of a corporation for the services I depend on. Consider
89
+    <a href="https://makeawebsitehub.com/the-google-product-murders/">this list</a> of discontinued Google
90
+    products. Google may have
91
+    <a href="https://googleblog.blogspot.com/2013/03/a-second-spring-of-cleaning.html">canned Google Reader</a>,
92
+    but my <a href="https://tt-rss.org/">Tiny Tiny RSS</a> instance is still chugging along.
93
+
94
+    <li>It is my hope that by documenting my efforts here, we may be one step closer to an automated,
95
+    open-source solution for average users to host their own online services.
96
+
97
+    <li>I actually enjoy tinkering with self-hosted software. It's a fun hobby, and it often provides better
98
+    features than the proprietary alternatives.
99
+  </ol>
100
+
101
+  <p>With that out of the way, let's get to the guide!
102
+</section>
103
+
104
+<section>
105
+  <h2 id="configuration">Configuring Your Own Digital Empire</h2>
106
+
107
+  <p>The following links will become available as I get time to write these blog posts. I'll take you through
108
+  how I've set up each of the services below. I'm running everything on a FreeBSD server, so the instructions will be from
109
+  a BSD perspective. They should work equally well for most Linux distros with some minor tweaks.
110
+  <ul>
111
+    <li><a href="/blog/freebsd-server-guide/">Configuring a FreeBSD Server: Initial Setup and Tuning</a>
112
+    <li><a href="/blog/dns-hidden-master/">DNS: Running BIND as a Hidden Master with DNSSEC</a>
113
+    <li><a class="disabled">NGINX: Configuring a Secure, Performant Web Server</a>
114
+    <li><a class="disabled">LDAP: Single-Sign-On for All Your Services</a>
115
+    <li><a href="/blog/mail-server-guide/">Email: A Modern Stack using Postfix, Dovecot, Rspamd, Solr, and LDAP</a>
116
+    <li><a class="disabled">Chat: Text, Voice, and Video Chat with Matrix</a>
117
+    <li><a class="disabled">File Sync: Keeping Files Synchronized Across Your Devices Using Syncthing</a>
118
+    <li><a href="/blog/openvpn-guide/">VPN: Secure, Private Browsing Using OpenVPN</a>
119
+    <li><a class="disabled">Music: A Self-Hosted Spotify Replacement Using Madsonic and DSub</a>
120
+    <li><a class="disabled">IRC: Stay Connected with ZNC</a>
121
+  </ul>
122
+</section>

+ 87
- 0
blog/unifi-cloud-key-ssl-certificate/index.tmpl View File

@@ -0,0 +1,87 @@
1
+TITLE='Unifi Cloud Key: Custom SSL Certificate'
2
+DESCRIPTION='Eliminate annoying HTTPS warnings with your own valid SSL certificate.'
3
+DATE=2017-11-05
4
+__HTML__
5
+<p>On my home network, I have a <a href="https://www.pfsense.org">pfSense box</a> as a gateway for a few
6
+<a href="https://www.ubnt.com">Ubiquiti</a> switches and access points. Ubiquiti makes great networking
7
+gear for small- to medium-sized deployments. You can control all your Ubiquiti products using
8
+the Unifi Controller app, which you can run on any computer on your network.
9
+
10
+<p>If you don't have a dedicated server to use as the Unifi Controller, or you just want something with a
11
+smaller footprint, Ubiquity provides a small, POE-powered device called the <a href="https://www.ubnt.com/unifi/unifi-cloud-key/">Cloud Key</a>
12
+which you can use as the Controller for your network. It's kind of like a Raspberry Pi, but comes with all
13
+the Ubiquity controller software preinstalled.
14
+
15
+<p>To use the Cloud Key, you just plug it into your switch, figure out it's IP address, and point your web
16
+browser there. Of course, not knowing where it's going to be deployed, the Cloud Key just presents a self-signed
17
+HTTPS certificate by default—causing modern browsers to emit all kinds of draconian warning messages. I have a
18
+DHCP mapping and hostname configured for the Cloud Key in pfSense, so I can reach it from my home network by
19
+going to <span class="monospace">cloudkey.c0ffee.net</span>. I also have a wildcard SSL
20
+certificate from Comodo. So I thought to myself, "I'll just copy my certificate over to the Cloud Key, change a
21
+setting somewhere, and I can get rid of that stupid error message!"
22
+
23
+<p>Unfortunately, this was such a royal pain that I decided to document the necessary steps so that the next poor
24
+soul that attempts this doesn't waste as much of the his life in the process as I did.
25
+
26
+<section>
27
+  <h2>Parting the Clouds</h2>
28
+  
29
+  <p>In the instructions below, I'm going to assume you have a certificate pair for <span class="monospace">example.com</span>,
30
+  and your Cloud Key is located at <span class="monospace">cloudkey.example.com</span>. You will also need the root certificate (as
31
+  well as any intermediate certificates) for your certificate authority concatenated into a single file. The intermediate
32
+  certificate should be placed <em>before</em> the root certificate. I'm going to assume you named this file <span class="monospace">chain.crt</span>.
33
+
34
+  <p>First, copy the certificates to the Cloud Key. The root password should be the same one you use to log into the web interface.
35
+
36
+<pre>scp chain.crt example.com.{crt,key} root@unifi.example.com:</pre>
37
+
38
+  <p>SSH to your Cloud Key:
39
+
40
+<pre>ssh root@unifi.example.com</pre>
41
+
42
+  <p>Now, the fun begins.
43
+
44
+<pre>
45
+<span class="code-comment"># stop the unifi web service</span>
46
+service unifi stop
47
+
48
+<span class="code-comment"># backup the default certificate</span>
49
+mkdir backup
50
+cp -r /etc/ssl/private/ backup
51
+
52
+<span class="code-comment"># remove the default SSL bundle</span>
53
+rm /etc/ssl/private/cert.tar
54
+
55
+<span class="code-comment"># MAGIC - discovered through random forum posts, wailing, and gnashing </span>
56
+<span class="code-comment"># of teeth</span>
57
+openssl pkcs12 -export -in example.com.crt -inkey example.com.key -out example.com.p12 -name unifi -CAfile chain.crt -caname root
58
+keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore /usr/lib/unifi/data/keystore -srckeystore example.com.p12 -srcstoretype PKCS12 -srcstorepass aircontrolenterprise -alias unifi
59
+cp example.com.crt /etc/ssl/private/cloudkey.crt
60
+cp example.com.key /etc/ssl/private/cloudkey.key
61
+rm /etc/ssl/private/ssl-cert-snakeoil.key
62
+chown root:ssl-cert /etc/ssl/private/*
63
+chmod 640 /etc/ssl/private/*
64
+tar -cvf cert.tar *
65
+chown root:ssl-cert cert.tar
66
+chmod 640 cert.tar
67
+service nginx restart
68
+
69
+<span class="code-comment"># NOTE: if you have an ECC certificate like me, you must also complete</span>
70
+<span class="code-comment"># the following magic incantations.</span>
71
+<span class="code-comment"># (if you don't know what an ECC certificate is, just ignore this part.)</span>
72
+<span class="code-comment">#</span>
73
+<span class="code-comment"># echo "unifi.https.sslEnabledProtocols=TLSv1.2" &gt;&gt; /usr/lib/unifi/data/system.properties</span>
74
+<span class="code-comment"># echo "unifi.https.ciphers=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256" &gt;&gt; /usr/lib/unifi/data/system.properties</span>
75
+
76
+<span class="code-comment"># finally, restart the unifi service</span>
77
+service unifi start
78
+</pre>
79
+
80
+  <p>After that, you should be able to access the Cloud Key using your existing SSL certificate. You should
81
+  change your "Controller Hostname/IP" in the Unifi controller settings to your FQDN (<span class="monospace">cloudkey.example.com</span>, in this case).
82
+  I also changed my "Device Name" in the Cloud Key settings to <span class="monospace">cloudkey</span> for consistency.
83
+  
84
+  <p>Now, join me in complaining to Ubiquiti that this isn't possible to accomplish in the Cloud Key's web interface.
85
+
86
+</section>
87
+

+ 241
- 0
css/style.css View File

@@ -0,0 +1,241 @@
1
+body {
2
+   color: #333;
3
+   line-height: 1.4;
4
+   margin: 2em auto;
5
+   max-width: 38em;
6
+   padding: 0 1em;
7
+}
8
+
9
+h1,h2,h3,h4,h5 {
10
+   line-height: 1.2;
11
+}
12
+
13
+header {
14
+  margin-bottom: 2em;
15
+}
16
+
17
+header p {
18
+  margin-top: -1em;
19
+}
20
+
21
+nav {
22
+  display: inline;
23
+}
24
+
25
+nav a:before {
26
+  content: "‹ ";
27
+}
28
+
29
+footer {
30
+  padding: .5em 0;
31
+  display: flex;
32
+  justify-content: space-between;
33
+  align-items: center;
34
+}
35
+
36
+hr {
37
+   background: #333;
38
+   border: 0;
39
+   height: 1px;
40
+}
41
+
42
+a {
43
+   text-decoration: none;
44
+}
45
+
46
+a:hover {
47
+   text-decoration: underline;
48
+}
49
+
50
+ul {
51
+   list-style-type: square;
52
+}
53
+
54
+pre {
55
+  background-color: #f5f5f5;
56
+  border: 1px solid #ccc;
57
+  border-radius: 2px;
58
+  color: #333;
59
+  font-family: monospace;
60
+  line-height: 1.2;
61
+  margin: 0 0 10px;
62
+  overflow-x: auto;
63
+  padding: 8px;
64
+  white-space: pre;
65
+  word-wrap: normal;
66
+}
67
+
68
+footer .author {
69
+  font-style: italic;
70
+}
71
+
72
+.photo-panel {
73
+   margin: 2em 0;
74
+   overflow: auto;
75
+}
76
+
77
+.photo-panel ul {
78
+  display: inline-block;
79
+  list-style-position: inside;
80
+  margin: 0;
81
+  padding-left: 0;
82
+}
83
+
84
+.photo-panel img {
85
+  float: left;
86
+  height: 150px;
87
+  margin-right: 1.5em;
88
+  width: 150px;
89
+}
90
+
91
+.post-list {
92
+  margin-bottom: 10px;
93
+}
94
+
95
+.post-list .date {
96
+  width: 6em;
97
+}
98
+
99
+.paragraph-list li {
100
+  margin: 1em 0;
101
+}
102
+
103
+.disabled {
104
+  color: #ccc;
105
+}
106
+.disabled a:hover {
107
+   text-decoration: none;
108
+}
109
+
110
+.posted-on {
111
+  float: right;
112
+}
113
+
114
+.code-title {
115
+  border-bottom: 1px solid #333;
116
+  font-family: sans-serif;
117
+  font-size: 80%;
118
+  font-weight: bold;
119
+  margin-bottom: .8em;
120
+}
121
+
122
+.monospace {
123
+  font-family: monospace;
124
+}
125
+
126
+.blog img {
127
+  width: 100%;
128
+  margin: 1em 0 0 0;
129
+}
130
+
131
+.code-comment {
132
+  font-style: italic;
133
+  color: #888;
134
+}
135
+
136
+.license {
137
+  font-size: 80%;
138
+}
139
+
140
+.license img {
141
+  vertical-align: middle;
142
+}
143
+
144
+/* * resume * */
145
+.resume .section-heading {
146
+  border-bottom: solid 1px;
147
+}
148
+
149
+.resume .header {
150
+  margin-bottom: 2em;
151
+}
152
+
153
+.resume .name {
154
+  margin-bottom: 0;
155
+  text-align: center;
156
+}
157
+
158
+.resume .profession {
159
+  margin: .5em 0;
160
+  text-align: center;
161
+}
162
+
163
+.resume .homepage, .resume .date, .resume .university, .resume .location {
164
+  float: right;
165
+}
166
+
167
+.resume .education .date {
168
+  font-style: italic;
169
+}
170
+
171
+.resume .degree, .resume .university, .resume .employer, .resume .title {
172
+  font-weight: bold;
173
+}
174
+
175
+.resume .location {
176
+  font-style: italic;
177
+}
178
+
179
+.resume .description > ul {
180
+  padding-left:1.2em;
181
+  margin-top: 0;
182
+}
183
+
184
+.resume .summary .description {
185
+  font-size: 95%;
186
+}
187
+
188
+.resume .experience .description {
189
+  font-size: 95%;
190
+  margin: .25em 0 1em 0;
191
+}
192