Fossil SCM

Moved the www/tls-nginx.md doc contents into its companion doc www/server/debian/nginx.md and updated it for Ubuntu 20.04 LTS and Snap-based Certbot.

wyoung 2020-11-16 02:05 trunk
Commit 0e63df14904c97fa79077deb68dac42310471af2b368f01bc629178d289f43a3
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -100,11 +100,10 @@
100100
Of Fossil}
101101
tech_overview.wiki {SQLite Databases Used By Fossil}
102102
th1.md {The TH1 Scripting Language}
103103
tickets.wiki {The Fossil Ticket System}
104104
theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
105
- tls-nginx.md {Proxying Fossil via HTTPS with nginx}
106105
unvers.wiki {Unversioned Files}
107106
webpage-ex.md {Webpage Examples}
108107
webui.wiki {The Fossil Web Interface}
109108
whyusefossil.wiki {Why You Should Use Fossil}
110109
whyusefossil.wiki {Benefits Of Version Control}
111110
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -100,11 +100,10 @@
100 Of Fossil}
101 tech_overview.wiki {SQLite Databases Used By Fossil}
102 th1.md {The TH1 Scripting Language}
103 tickets.wiki {The Fossil Ticket System}
104 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
105 tls-nginx.md {Proxying Fossil via HTTPS with nginx}
106 unvers.wiki {Unversioned Files}
107 webpage-ex.md {Webpage Examples}
108 webui.wiki {The Fossil Web Interface}
109 whyusefossil.wiki {Why You Should Use Fossil}
110 whyusefossil.wiki {Benefits Of Version Control}
111
--- www/mkindex.tcl
+++ www/mkindex.tcl
@@ -100,11 +100,10 @@
100 Of Fossil}
101 tech_overview.wiki {SQLite Databases Used By Fossil}
102 th1.md {The TH1 Scripting Language}
103 tickets.wiki {The Fossil Ticket System}
104 theory1.wiki {Thoughts On The Design Of The Fossil DVCS}
 
105 unvers.wiki {Unversioned Files}
106 webpage-ex.md {Webpage Examples}
107 webui.wiki {The Fossil Web Interface}
108 whyusefossil.wiki {Why You Should Use Fossil}
109 whyusefossil.wiki {Benefits Of Version Control}
110
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -176,11 +176,10 @@
176176
<li><a href="server/"><b>How To Configure A Fossil Server</b></a></li>
177177
<li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li>
178178
<li><a href="mirrortogithub.md"><b>How To Mirror A Fossil Repository On GitHub</b></a></li>
179179
<li><a href="encryptedrepos.wiki"><b>How To Use Encrypted Repositories</b></a></li>
180180
<li><a href="hacker-howto.wiki">How-To &mdash; Hacker</a></li>
181
-<li><a href="tls-nginx.md">HTTPS with nginx &mdash; Proxying Fossil via</a></li>
182181
<li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
183182
<li><a href="hashes.md">Identification &mdash; Hashes: Fossil Artifact</a></li>
184183
<li><a href="image-format-vs-repo-size.md"><b>Image Format vs Fossil Repo Size</b></a></li>
185184
<li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
186185
<li><a href="inout.wiki"><b>Import And Export To And From Git</b></a></li>
@@ -207,11 +206,10 @@
207206
<li><a href="mirrorlimitations.md">Mirrors &mdash; Limitations On Git</a></li>
208207
<li><a href="globs.md">Name Glob Patterns &mdash; File</a></li>
209208
<li><a href="checkin_names.wiki">Names &mdash; Check-in And Version</a></li>
210209
<li><a href="adding_code.wiki">New Features To Fossil &mdash; Adding</a></li>
211210
<li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
212
-<li><a href="tls-nginx.md">nginx &mdash; Proxying Fossil via HTTPS with</a></li>
213211
<li><a href="alerts.md">Notifications &mdash; Email Alerts And</a></li>
214212
<li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
215213
<li><a href="pop.wiki">Operation &mdash; Principles Of</a></li>
216214
<li><a href="cgi.wiki">Options &mdash; CGI Script Configuration</a></li>
217215
<li><a href="env-opts.md">Options &mdash; Environment Variables and Global</a></li>
@@ -235,11 +233,10 @@
235233
<li><a href="embeddeddoc.wiki">Project Documentation &mdash; Embedded</a></li>
236234
<li><a href="foss-cklist.wiki">Projects &mdash; Checklist For Successful Open-Source</a></li>
237235
<li><a href="childprojects.wiki">Projects &mdash; Child</a></li>
238236
<li><a href="fossil_prompt.wiki">Prompt &mdash; Fossilized Bash</a></li>
239237
<li><a href="sync.wiki">Protocol &mdash; The Fossil Sync</a></li>
240
-<li><a href="tls-nginx.md"><b>Proxying Fossil via HTTPS with nginx</b></a></li>
241238
<li><a href="history.md">Purpose And History Of Fossil &mdash; The</a></li>
242239
<li><a href="faq.wiki">Questions &mdash; Frequently Asked</a></li>
243240
<li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li>
244241
<li><a href="quickstart.wiki">Quick Start Guide &mdash; Fossil</a></li>
245242
<li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li>
@@ -327,11 +324,10 @@
327324
<li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
328325
<li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
329326
<li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
330327
<li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
331328
<li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
332
-<li><a href="tls-nginx.md">via HTTPS with nginx &mdash; Proxying Fossil</a></li>
333329
<li><a href="image-format-vs-repo-size.md">vs Fossil Repo Size &mdash; Image Format</a></li>
334330
<li><a href="grep.md">vs POSIX grep &mdash; Fossil grep</a></li>
335331
<li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
336332
<li><a href="customskin.md">Web Pages &mdash; Theming: Customizing The Appearance of</a></li>
337333
<li><a href="webpage-ex.md"><b>Webpage Examples</b></a></li>
338334
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -176,11 +176,10 @@
176 <li><a href="server/"><b>How To Configure A Fossil Server</b></a></li>
177 <li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li>
178 <li><a href="mirrortogithub.md"><b>How To Mirror A Fossil Repository On GitHub</b></a></li>
179 <li><a href="encryptedrepos.wiki"><b>How To Use Encrypted Repositories</b></a></li>
180 <li><a href="hacker-howto.wiki">How-To &mdash; Hacker</a></li>
181 <li><a href="tls-nginx.md">HTTPS with nginx &mdash; Proxying Fossil via</a></li>
182 <li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
183 <li><a href="hashes.md">Identification &mdash; Hashes: Fossil Artifact</a></li>
184 <li><a href="image-format-vs-repo-size.md"><b>Image Format vs Fossil Repo Size</b></a></li>
185 <li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
186 <li><a href="inout.wiki"><b>Import And Export To And From Git</b></a></li>
@@ -207,11 +206,10 @@
207 <li><a href="mirrorlimitations.md">Mirrors &mdash; Limitations On Git</a></li>
208 <li><a href="globs.md">Name Glob Patterns &mdash; File</a></li>
209 <li><a href="checkin_names.wiki">Names &mdash; Check-in And Version</a></li>
210 <li><a href="adding_code.wiki">New Features To Fossil &mdash; Adding</a></li>
211 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
212 <li><a href="tls-nginx.md">nginx &mdash; Proxying Fossil via HTTPS with</a></li>
213 <li><a href="alerts.md">Notifications &mdash; Email Alerts And</a></li>
214 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
215 <li><a href="pop.wiki">Operation &mdash; Principles Of</a></li>
216 <li><a href="cgi.wiki">Options &mdash; CGI Script Configuration</a></li>
217 <li><a href="env-opts.md">Options &mdash; Environment Variables and Global</a></li>
@@ -235,11 +233,10 @@
235 <li><a href="embeddeddoc.wiki">Project Documentation &mdash; Embedded</a></li>
236 <li><a href="foss-cklist.wiki">Projects &mdash; Checklist For Successful Open-Source</a></li>
237 <li><a href="childprojects.wiki">Projects &mdash; Child</a></li>
238 <li><a href="fossil_prompt.wiki">Prompt &mdash; Fossilized Bash</a></li>
239 <li><a href="sync.wiki">Protocol &mdash; The Fossil Sync</a></li>
240 <li><a href="tls-nginx.md"><b>Proxying Fossil via HTTPS with nginx</b></a></li>
241 <li><a href="history.md">Purpose And History Of Fossil &mdash; The</a></li>
242 <li><a href="faq.wiki">Questions &mdash; Frequently Asked</a></li>
243 <li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li>
244 <li><a href="quickstart.wiki">Quick Start Guide &mdash; Fossil</a></li>
245 <li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li>
@@ -327,11 +324,10 @@
327 <li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
328 <li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
329 <li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
330 <li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
331 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
332 <li><a href="tls-nginx.md">via HTTPS with nginx &mdash; Proxying Fossil</a></li>
333 <li><a href="image-format-vs-repo-size.md">vs Fossil Repo Size &mdash; Image Format</a></li>
334 <li><a href="grep.md">vs POSIX grep &mdash; Fossil grep</a></li>
335 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
336 <li><a href="customskin.md">Web Pages &mdash; Theming: Customizing The Appearance of</a></li>
337 <li><a href="webpage-ex.md"><b>Webpage Examples</b></a></li>
338
--- www/permutedindex.html
+++ www/permutedindex.html
@@ -176,11 +176,10 @@
176 <li><a href="server/"><b>How To Configure A Fossil Server</b></a></li>
177 <li><a href="newrepo.wiki"><b>How To Create A New Fossil Repository</b></a></li>
178 <li><a href="mirrortogithub.md"><b>How To Mirror A Fossil Repository On GitHub</b></a></li>
179 <li><a href="encryptedrepos.wiki"><b>How To Use Encrypted Repositories</b></a></li>
180 <li><a href="hacker-howto.wiki">How-To &mdash; Hacker</a></li>
 
181 <li><a href="fossil-from-msvc.wiki">IDE &mdash; Integrating Fossil in the Microsoft Express 2010</a></li>
182 <li><a href="hashes.md">Identification &mdash; Hashes: Fossil Artifact</a></li>
183 <li><a href="image-format-vs-repo-size.md"><b>Image Format vs Fossil Repo Size</b></a></li>
184 <li><a href="tech_overview.wiki">Implementation Of Fossil &mdash; A Technical Overview Of The Design And</a></li>
185 <li><a href="inout.wiki"><b>Import And Export To And From Git</b></a></li>
@@ -207,11 +206,10 @@
206 <li><a href="mirrorlimitations.md">Mirrors &mdash; Limitations On Git</a></li>
207 <li><a href="globs.md">Name Glob Patterns &mdash; File</a></li>
208 <li><a href="checkin_names.wiki">Names &mdash; Check-in And Version</a></li>
209 <li><a href="adding_code.wiki">New Features To Fossil &mdash; Adding</a></li>
210 <li><a href="newrepo.wiki">New Fossil Repository &mdash; How To Create A</a></li>
 
211 <li><a href="alerts.md">Notifications &mdash; Email Alerts And</a></li>
212 <li><a href="foss-cklist.wiki">Open-Source Projects &mdash; Checklist For Successful</a></li>
213 <li><a href="pop.wiki">Operation &mdash; Principles Of</a></li>
214 <li><a href="cgi.wiki">Options &mdash; CGI Script Configuration</a></li>
215 <li><a href="env-opts.md">Options &mdash; Environment Variables and Global</a></li>
@@ -235,11 +233,10 @@
233 <li><a href="embeddeddoc.wiki">Project Documentation &mdash; Embedded</a></li>
234 <li><a href="foss-cklist.wiki">Projects &mdash; Checklist For Successful Open-Source</a></li>
235 <li><a href="childprojects.wiki">Projects &mdash; Child</a></li>
236 <li><a href="fossil_prompt.wiki">Prompt &mdash; Fossilized Bash</a></li>
237 <li><a href="sync.wiki">Protocol &mdash; The Fossil Sync</a></li>
 
238 <li><a href="history.md">Purpose And History Of Fossil &mdash; The</a></li>
239 <li><a href="faq.wiki">Questions &mdash; Frequently Asked</a></li>
240 <li><a href="qandc.wiki"><b>Questions And Criticisms</b></a></li>
241 <li><a href="quickstart.wiki">Quick Start Guide &mdash; Fossil</a></li>
242 <li><a href="quotes.wiki"><b>Quotes: What People Are Saying About Fossil, Git, and DVCSes in General</b></a></li>
@@ -327,11 +324,10 @@
324 <li><a href="ssl.wiki"><b>Using SSL with Fossil</b></a></li>
325 <li><a href="env-opts.md">Variables and Global Options &mdash; Environment</a></li>
326 <li><a href="whyusefossil.wiki">Version Control &mdash; Benefits Of</a></li>
327 <li><a href="checkin_names.wiki">Version Names &mdash; Check-in And</a></li>
328 <li><a href="fossil-v-git.wiki">Versus Git &mdash; Fossil</a></li>
 
329 <li><a href="image-format-vs-repo-size.md">vs Fossil Repo Size &mdash; Image Format</a></li>
330 <li><a href="grep.md">vs POSIX grep &mdash; Fossil grep</a></li>
331 <li><a href="webui.wiki">Web Interface &mdash; The Fossil</a></li>
332 <li><a href="customskin.md">Web Pages &mdash; Theming: Customizing The Appearance of</a></li>
333 <li><a href="webpage-ex.md"><b>Webpage Examples</b></a></li>
334
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -4,20 +4,19 @@
44
instructions][scgii], which may suffice for your purposes if your needs
55
are simple.
66
77
Here, we add more detailed information on nginx itself, plus details
88
about running it on Debian type OSes. We focus on Debian 10 (Buster) and
9
-Ubuntu 18.04 here, which are common Tier 1 OS offerings for [virtual
10
-private servers][vps]. This material may not work for older OSes. It is
9
+Ubuntu 20.04 here, which are common Tier 1 OS offerings for [virtual
10
+private servers][vps] at the time of writing. This material may not work for older OSes. It is
1111
known in particular to not work as given for Debian 9 and older!
1212
13
-If you want to add TLS to this configuration, that is covered [in a
14
-separate document][tls] which was written with the assumption that
15
-you’ve read this first.
13
+We also cover adding TLS to the basic configuration, because several
14
+details depend on the host OS and web stack details. Besides, TLS is
15
+widely considered part of the baseline configuration these days.
1616
1717
[scgii]: ../any/scgi.md
18
-[tls]: ../../tls-nginx.md
1918
[vps]: https://en.wikipedia.org/wiki/Virtual_private_server
2019
2120
2221
## <a name="benefits"></a>Benefits
2322
@@ -88,11 +87,11 @@
8887
8988
* **SCGI** — The [SCGI protocol][scgip] provides the simplicity of CGI
9089
without its performance problems.
9190
9291
* **SSH** — This method exists primarily to avoid the need for HTTPS,
93
- but we *want* HTTPS. (We’ll get to that in [another document][tls].)
92
+ but we *want* HTTPS. (We’ll get to that [below](#tls).)
9493
There is probably a way to get nginx to proxy Fossil to HTTPS via
9594
SSH, but it would be pointlessly complicated.
9695
9796
SCGI it is, then.
9897
@@ -190,20 +189,20 @@
190189
repetition across `server { }` blocks when setting up multiple domains
191190
on a single server.
192191
193192
The configuration for `foo.net` is similar.
194193
195
-See [the nginx docs](http://nginx.org/en/docs/) for more ideas.
194
+See [the nginx docs](https://nginx.org/en/docs/) for more ideas.
196195
197196
198197
## <a name="http"></a>Proxying HTTP Anyway
199198
200199
[Above](#modes), we argued that proxying SCGI is a better option than
201200
making nginx reinterpret Fossil’s own implementation of HTTP. If you
202201
want Fossil to speak HTTP, just [set Fossil up as a standalone
203202
server](../any/none.md). And if you want nginx to [provide TLS
204
-encryption for Fossil][tls], proxying HTTP instead of SCGI provides no
203
+encryption for Fossil](#tls), proxying HTTP instead of SCGI provides no
205204
benefit.
206205
207206
However, it is still worth showing the proper method of proxying
208207
Fossil’s HTTP server through nginx if only to make reading nginx
209208
documentation on other sites easier:
@@ -216,6 +215,390 @@
216215
The most common thing people get wrong when hand-rolling a configuration
217216
like this is to get the slashes wrong. Fossil is senstitive to this. For
218217
instance, Fossil will not collapse double slashes down to a single
219218
slash, as some other HTTP servers will.
220219
220
+
221
+## <a name="tls"></a> Adding TLS (HTTPS) Support
222
+
223
+One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP access
224
+(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
225
+TLS. One such option is nginx on Debian, so we show the details of that
226
+here.
227
+
228
+You can extend this guide to other operating systems by following the
229
+instructions found via [the front Certbot web page][cb] instead, telling
230
+it what OS and web stack you’re using. Chances are good that they’ve got
231
+a good guide for you already.
232
+
233
+
234
+### <a id="leew"></a> Configuring Let’s Encrypt, the Easy Way
235
+
236
+If your web serving needs are simple, [Certbot][cb] can configure nginx
237
+for you and keep its certificates up to date. Simply follow Certbot’s
238
+[nginx on Ubuntu 20.04 LTS guide][cbnu].
239
+
240
+Unfortunately, the setup above was beyond Certbot’s ability to cope the
241
+last time we tried it. The use of per-subdomain files in particular
242
+confused Certbot, so we had to [arrange these details manually](#lehw),
243
+else the Let’s Encrypt [ACME] exchange failed in the necessary domain
244
+validation steps.
245
+
246
+At this point, if your configuration needs are simple, needing only a
247
+single Internet domain and a single Fossil repo, you might wish to try
248
+to reduce the above configuration to a more typical single-file nginx
249
+config, which Certbot might then cope with out of the box.
250
+
251
+
252
+
253
+### <a id="lehw"></a> Configuring Let’s Encrypt, the Hard Way
254
+
255
+The primary motivation for this section is that it documents the manual
256
+Certbot configuration on my public Fossil-based site. I’m addressing
257
+the “me” years hence who needs to upgrade to Ubuntu 22.04 or 24.04 LTS
258
+and has forgotten all of this stuff. 😉
259
+
260
+
261
+#### Step 1: Shifting into Manual
262
+
263
+The first thing we’ll do is install Certbot in the normal way, but we’ll
264
+turn off all of the Certbot automation and won’t follow through with use
265
+of the `--nginx` plugin:
266
+
267
+ $ sudo snap install --classic certbot
268
+ $ sudo systemctl disable certbot.timer
269
+
270
+Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the
271
+nginx plugins. You’re looking for two lines setting the “install” and
272
+“auth” plugins to “nginx”. You can comment them out or remove them
273
+entirely.
274
+
275
+
276
+#### Step 2: Configuring nginx
277
+
278
+This is a straightforward extension to the HTTP-only configuration
279
+[above](#config):
280
+
281
+ server {
282
+ server_name .foo.net;
283
+
284
+ include local/tls-common;
285
+
286
+ charset utf-8;
287
+
288
+ access_log /var/log/nginx/foo.net-https-access.log;
289
+ error_log /var/log/nginx/foo.net-https-error.log;
290
+
291
+ # Bypass Fossil for the static Doxygen docs
292
+ location /doc/html {
293
+ root /var/www/foo.net;
294
+
295
+ location ~* \.(html|ico|css|js|gif|jpg|png)$ {
296
+ expires 7d;
297
+ add_header Vary Accept-Encoding;
298
+ access_log off;
299
+ }
300
+ }
301
+
302
+ # Redirect everything else to the Fossil instance
303
+ location / {
304
+ include scgi_params;
305
+ scgi_pass 127.0.0.1:12345;
306
+ scgi_param HTTPS "on";
307
+ scgi_param SCRIPT_NAME "";
308
+ }
309
+ }
310
+ server {
311
+ server_name .foo.net;
312
+ root /var/www/foo.net;
313
+ include local/http-certbot-only;
314
+ access_log /var/log/nginx/foo.net-http-access.log;
315
+ error_log /var/log/nginx/foo.net-http-error.log;
316
+ }
317
+
318
+One big difference between this and the HTTP-only case is
319
+that we need two `server { }` blocks: one for HTTPS service, and
320
+one for HTTP-only service.
321
+
322
+
323
+##### HTTP over TLS (HTTPS) Service
324
+
325
+The first `server { }` block includes this file, `local/tls-common`:
326
+
327
+ listen 443 ssl;
328
+
329
+ ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
330
+ ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
331
+
332
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
333
+
334
+ ssl_stapling on;
335
+ ssl_stapling_verify on;
336
+
337
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
338
+ ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-CBC-SHA:ECDHE-ECDSA-AES256-CBC-SHA:ECDHE-ECDSA-AES128-CBC-SHA256:ECDHE-ECDSA-AES256-CBC-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-CBC-SHA:ECDHE-RSA-AES256-CBC-SHA:ECDHE-RSA-AES128-CBC-SHA256:ECDHE-RSA-AES256-CBC-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-CBC-SHA:DHE-RSA-AES256-CBC-SHA:DHE-RSA-AES128-CBC-SHA256:DHE-RSA-AES256-CBC-SHA256";
339
+ ssl_session_cache shared:le_nginx_SSL:1m;
340
+ ssl_prefer_server_ciphers on;
341
+ ssl_session_timeout 1440m;
342
+
343
+These are the common TLS configuration parameters used by all domains
344
+hosted by this server.
345
+
346
+The first line tells nginx to accept TLS-encrypted HTTP connections on
347
+the standard HTTPS port. It is the same as `listen 443; ssl on;` in
348
+older versions of nginx.
349
+
350
+Since all of those domains share a single TLS certificate, we reference
351
+the same `example.com/*.pem` files written out by Certbot with the
352
+`ssl_certificate*` lines.
353
+
354
+The `ssl_dhparam` directive isn’t strictly required, but without it, the
355
+server becomes vulnerable to the [Logjam attack][lja] because some of
356
+the cryptography steps are precomputed, making the attacker’s job much
357
+easier. The parameter file this directive references should be
358
+generated automatically by the Let’s Encrypt package upon installation,
359
+making those parameters unique to your server and thus unguessable. If
360
+the file doesn’t exist on your system, you can create it manually, so:
361
+
362
+ $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048
363
+
364
+Beware, this can take a long time. On a shared Linux host I tried it on
365
+running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle
366
+iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds!
367
+
368
+The next section is also optional. It enables [OCSP stapling][ocsp], a
369
+protocol that improves the speed and security of the TLS connection
370
+negotiation.
371
+
372
+The next section containing the `ssl_protocols` and `ssl_ciphers` lines
373
+restricts the TLS implementation to only those protocols and ciphers
374
+that are currently believed to be safe and secure. This section is the
375
+one most prone to bit-rot: as new attacks on TLS and its associated
376
+technologies are discovered, this configuration is likely to need to
377
+change. Even if we fully succeed in keeping this document up-to-date in
378
+the face of the evolving security landscape, we’re recommending static
379
+configurations for your server: it will thus be up to you to track
380
+changes in this document and others to merge the changes into your local
381
+static configuration.
382
+
383
+Running a TLS certificate checker against your site occasionally is a
384
+good idea. The most thorough service I’m aware of is the [Qualys SSL
385
+Labs Test][qslt], which gives the site I’m basing this guide on an “A+”
386
+rating at the time of this writing. The long `ssl_ciphers` line above is
387
+based on [their advice][qslc]: the default nginx configuration tells
388
+OpenSSL to use whatever ciphersuites it considers “high security,” but
389
+some of those have come to be considered “weak” in the time between that
390
+judgement and the time of this writing. By explicitly giving the list of
391
+ciphersuites we want OpenSSL to use within nginx, we can remove those
392
+that become considered weak in the future.
393
+
394
+<a id=”hsts”></a>There are a few things you can do to get an even better
395
+grade, such as to enable [HSTS][hsts]:
396
+
397
+ add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
398
+
399
+This prevents a particular variety of [man in the middle attack][mitm]
400
+where our HTTP-to-HTTPS permanent redirect is intercepted, allowing the
401
+attacker to prevent the automatic upgrade of the connection to a secure
402
+TLS-encrypted one. I didn’t enable that in the configuration above
403
+because it is something a site administrator should enable only after
404
+the configuration is tested and stable, and then only after due
405
+consideration. There are ways to lock your users out of your site by
406
+jumping to HSTS hastily. When you’re ready, there are [guides you can
407
+follow][nest] elsewhere online.
408
+
409
+
410
+##### HTTP-Only Service
411
+
412
+While we’d prefer not to offer HTTP service at all, we need to do so for
413
+two reasons:
414
+
415
+* The temporary reason is that until we get Let’s Encrypt certificates
416
+ minted and configured properly, we can’t use HTTPS yet at all.
417
+
418
+* The ongoing reason is that the Certbot [ACME][acme] HTTP-01
419
+ challenge used by the Let’s Encrypt service only runs over HTTP. This is
420
+ not only because it has to work before HTTPS is first configured,
421
+ but also because it might need to work after a certificate is
422
+ accidentally allowed to lapse to get that server back into a state
423
+ where it can speak HTTPS safely again.
424
+
425
+So, from the second `service { }` block, we include this file to set up
426
+the minimal HTTP service we require, `local/http-certbot-only`:
427
+
428
+ listen 80;
429
+ listen [::]:80;
430
+
431
+ # This is expressed as a rewrite rule instead of an "if" because
432
+ # http://wiki.nginx.org/IfIsEvil
433
+ #rewrite ^(/.well-known/acme-challenge/.*) $1 break;
434
+
435
+ # Force everything else to HTTPS with a permanent redirect.
436
+ #return 301 https://$host$request_uri;
437
+
438
+As written above, this configuration does nothing other than to tell
439
+nginx that it’s allowed to serve content via HTTP on port 80 as well.
440
+We’ll uncomment the `rewrite` and `return` directives below, when we’re
441
+ready to begin testing.
442
+
443
+Notice that most of the nginx directives given [above](#config) moved up
444
+into the TLS `server { }` block, because we eventually want this site to
445
+be as close to HTTPS-only as we can get it.
446
+
447
+
448
+#### Step 3: Dry Run
449
+
450
+We want to first request a dry run, because Let’s Encrypt puts some
451
+rather low limits on how often you’re allowed to request an actual
452
+certificate. You want to be sure everything’s working before you do
453
+that. You’ll run a command something like this:
454
+
455
+ $ sudo certbot certonly --webroot --dry-run \
456
+ --webroot-path /var/www/example.com \
457
+ -d example.com -d www.example.com \
458
+ -d example.net -d www.example.net \
459
+ --webroot-path /var/www/foo.net \
460
+ -d foo.net -d www.foo.net
461
+
462
+There are two key options here.
463
+
464
+First, we’re telling Certbot to use its `--webroot` plugin instead of
465
+the automated `--nginx` plugin. With this plugin, Certbot writes the
466
+[ACME][acme] HTTP-01 challenge files to the static web document root
467
+directory behind each domain. For this example, we’ve got two web
468
+roots, one of which holds documents for two different second-level
469
+domains (`example.com` and `example.net`) with `www` at the third level
470
+being optional. This is a common sort of configuration these days, but
471
+you needn’t feel that you must slavishly imitate it. The other web root
472
+is for an entirely different domain, also with `www` being optional.
473
+Since all of these domains are served by a single nginx instance, we
474
+need to give all of this in a single command, because we want to mint a
475
+single certificate that authenticates all of these domains.
476
+
477
+The second key option is `--dry-run`, which tells Certbot not to do
478
+anything permanent. We’re just seeing if everything works as expected,
479
+at this point.
480
+
481
+
482
+##### Troubleshooting the Dry Run
483
+
484
+If that didn’t work, try creating a manual test:
485
+
486
+ $ mkdir -p /var/www/example.com/.well-known/acme-challenge
487
+ $ echo hi > /var/www/example.com/.well-known/acme-challenge/test
488
+
489
+Then try to pull that file over HTTP — not HTTPS! — as
490
+`http://example.com/.well-known/acme-challenge/test`. I’ve found that
491
+using Firefox or Safari is better for this sort of thing than Chrome,
492
+because Chrome is more aggressive about automatically forwarding URLs to
493
+HTTPS even if you requested “`http`”.
494
+
495
+In extremis, you can do the test manually:
496
+
497
+ $ curl -i http://example.com/.well-known/acme-challenge/test
498
+ HTTP/1.1 200 OK
499
+ Server: nginx/1.14.0 (Ubuntu)
500
+ Date: Sat, 19 Jan 2019 19:43:58 GMT
501
+ Content-Type: application/octet-stream
502
+ Content-Length: 3
503
+ Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT
504
+ Connection: keep-alive
505
+ ETag: "5c436ac2-4"
506
+ Accept-Ranges: bytes
507
+
508
+ hi
509
+
510
+The key bits you’re looking for here are the “200 OK” response code at
511
+the start and the “hi” line at the end. (Or whatever you wrote in to the
512
+test file.)
513
+
514
+If you get a 301 redirect to an `https://` URI, you either haven’t
515
+uncommented the `rewrite` line for HTTP-only service for this directory,
516
+or there’s some other problem with the “redirect to HTTPS” config.
517
+
518
+If you get a 404 or other error response, you need to look into your web
519
+server logs to find out what’s going wrong.
520
+
521
+If you’re still running into trouble, the log file written by Certbot
522
+can be helpful. It tells you where it’s writing the ACME files early in
523
+each run.
524
+
525
+
526
+
527
+#### Step 4: Getting Your First Certificate
528
+
529
+Once the dry run is working, you can drop the `--dry-run` option and
530
+re-run the long command above. (The one with all the `--webroot*`
531
+flags.) This should now succeed, and it will save all of those flag
532
+values to your Let’s Encrypt configuration file, so you don’t need to
533
+keep giving them.
534
+
535
+
536
+
537
+#### Step 5: Test It
538
+
539
+Edit the `local/http-certbot-only` file and uncomment the `redirect` and
540
+`return` directives, then restart your nginx server and make sure it now
541
+forces everything to HTTPS like it should:
542
+
543
+ $ sudo systemctl restart nginx
544
+
545
+Test ideas:
546
+
547
+* Visit both Fossil and non-Fossil URLs
548
+
549
+* Log into the repo, log out, and log back in
550
+
551
+* Clone via `http`: ensure that it redirects to `https`, and that
552
+ subsequent `fossil sync` commands go directly to `https` due to the
553
+ 301 permanent redirect.
554
+
555
+This forced redirect is why we don’t need the Fossil Admin &rarr; Access
556
+"Redirect to HTTPS on the Login page" setting to be enabled. Not only
557
+is it unnecessary with this HTTPS redirect at the front-end proxy level,
558
+it would actually [cause an infinite redirect loop if
559
+enabled](./ssl.wiki#rloop).
560
+
561
+
562
+
563
+#### Step 6: Switch to HTTPS Sync
564
+
565
+Fossil remembers permanent HTTP-to-HTTPS redirects on sync since version
566
+2.9, so all you need to do to switch your syncs to HTTPS is:
567
+
568
+ $ fossil sync -R /path/to/repo.fossil
569
+
570
+
571
+#### Step 7: Renewing Automatically
572
+
573
+Now that the configuration is solid, you can renew the LE cert with the
574
+`certbot` command from above without the `--dry-run` flag plus a restart
575
+of nginx:
576
+
577
+ sudo certbot certonly --webroot \
578
+ --webroot-path /var/www/example.com \
579
+ -d example.com -d www.example.com \
580
+ -d example.net -d www.example.net \
581
+ --webroot-path /var/www/foo.net \
582
+ -d foo.net -d www.foo.net
583
+ sudo systemctl restart nginx
584
+
585
+I put those commands in a script in the `PATH`, then arrange to call that
586
+periodically. Let’s Encrypt doesn’t let you renew the certificate very
587
+often unless forced, and when forced there’s a maximum renewal counter.
588
+Nevertheless, some people recommend running this daily and just letting
589
+it fail until the server lets you renew. Others arrange to run it no
590
+more often than it’s known to work without complaint. Suit yourself.
591
+
592
+
593
+[acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
594
+[cb]: https://certbot.eff.org/
595
+[cbnu]: https://certbot.eff.org/lets-encrypt/ubuntufocal-nginx
596
+[hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
597
+[lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security)
598
+[mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
599
+[nest]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
600
+[ocsp]: https://en.wikipedia.org/wiki/OCSP_stapling
601
+[qslc]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
602
+[qslt]: https://www.ssllabs.com/ssltest/
603
+
221604
*[Return to the top-level Fossil server article.](../)*
222605
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -4,20 +4,19 @@
4 instructions][scgii], which may suffice for your purposes if your needs
5 are simple.
6
7 Here, we add more detailed information on nginx itself, plus details
8 about running it on Debian type OSes. We focus on Debian 10 (Buster) and
9 Ubuntu 18.04 here, which are common Tier 1 OS offerings for [virtual
10 private servers][vps]. This material may not work for older OSes. It is
11 known in particular to not work as given for Debian 9 and older!
12
13 If you want to add TLS to this configuration, that is covered [in a
14 separate document][tls] which was written with the assumption that
15 you’ve read this first.
16
17 [scgii]: ../any/scgi.md
18 [tls]: ../../tls-nginx.md
19 [vps]: https://en.wikipedia.org/wiki/Virtual_private_server
20
21
22 ## <a name="benefits"></a>Benefits
23
@@ -88,11 +87,11 @@
88
89 * **SCGI** — The [SCGI protocol][scgip] provides the simplicity of CGI
90 without its performance problems.
91
92 * **SSH** — This method exists primarily to avoid the need for HTTPS,
93 but we *want* HTTPS. (We’ll get to that in [another document][tls].)
94 There is probably a way to get nginx to proxy Fossil to HTTPS via
95 SSH, but it would be pointlessly complicated.
96
97 SCGI it is, then.
98
@@ -190,20 +189,20 @@
190 repetition across `server { }` blocks when setting up multiple domains
191 on a single server.
192
193 The configuration for `foo.net` is similar.
194
195 See [the nginx docs](http://nginx.org/en/docs/) for more ideas.
196
197
198 ## <a name="http"></a>Proxying HTTP Anyway
199
200 [Above](#modes), we argued that proxying SCGI is a better option than
201 making nginx reinterpret Fossil’s own implementation of HTTP. If you
202 want Fossil to speak HTTP, just [set Fossil up as a standalone
203 server](../any/none.md). And if you want nginx to [provide TLS
204 encryption for Fossil][tls], proxying HTTP instead of SCGI provides no
205 benefit.
206
207 However, it is still worth showing the proper method of proxying
208 Fossil’s HTTP server through nginx if only to make reading nginx
209 documentation on other sites easier:
@@ -216,6 +215,390 @@
216 The most common thing people get wrong when hand-rolling a configuration
217 like this is to get the slashes wrong. Fossil is senstitive to this. For
218 instance, Fossil will not collapse double slashes down to a single
219 slash, as some other HTTP servers will.
220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221 *[Return to the top-level Fossil server article.](../)*
222
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -4,20 +4,19 @@
4 instructions][scgii], which may suffice for your purposes if your needs
5 are simple.
6
7 Here, we add more detailed information on nginx itself, plus details
8 about running it on Debian type OSes. We focus on Debian 10 (Buster) and
9 Ubuntu 20.04 here, which are common Tier 1 OS offerings for [virtual
10 private servers][vps] at the time of writing. This material may not work for older OSes. It is
11 known in particular to not work as given for Debian 9 and older!
12
13 We also cover adding TLS to the basic configuration, because several
14 details depend on the host OS and web stack details. Besides, TLS is
15 widely considered part of the baseline configuration these days.
16
17 [scgii]: ../any/scgi.md
 
18 [vps]: https://en.wikipedia.org/wiki/Virtual_private_server
19
20
21 ## <a name="benefits"></a>Benefits
22
@@ -88,11 +87,11 @@
87
88 * **SCGI** — The [SCGI protocol][scgip] provides the simplicity of CGI
89 without its performance problems.
90
91 * **SSH** — This method exists primarily to avoid the need for HTTPS,
92 but we *want* HTTPS. (We’ll get to that [below](#tls).)
93 There is probably a way to get nginx to proxy Fossil to HTTPS via
94 SSH, but it would be pointlessly complicated.
95
96 SCGI it is, then.
97
@@ -190,20 +189,20 @@
189 repetition across `server { }` blocks when setting up multiple domains
190 on a single server.
191
192 The configuration for `foo.net` is similar.
193
194 See [the nginx docs](https://nginx.org/en/docs/) for more ideas.
195
196
197 ## <a name="http"></a>Proxying HTTP Anyway
198
199 [Above](#modes), we argued that proxying SCGI is a better option than
200 making nginx reinterpret Fossil’s own implementation of HTTP. If you
201 want Fossil to speak HTTP, just [set Fossil up as a standalone
202 server](../any/none.md). And if you want nginx to [provide TLS
203 encryption for Fossil](#tls), proxying HTTP instead of SCGI provides no
204 benefit.
205
206 However, it is still worth showing the proper method of proxying
207 Fossil’s HTTP server through nginx if only to make reading nginx
208 documentation on other sites easier:
@@ -216,6 +215,390 @@
215 The most common thing people get wrong when hand-rolling a configuration
216 like this is to get the slashes wrong. Fossil is senstitive to this. For
217 instance, Fossil will not collapse double slashes down to a single
218 slash, as some other HTTP servers will.
219
220
221 ## <a name="tls"></a> Adding TLS (HTTPS) Support
222
223 One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP access
224 (a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
225 TLS. One such option is nginx on Debian, so we show the details of that
226 here.
227
228 You can extend this guide to other operating systems by following the
229 instructions found via [the front Certbot web page][cb] instead, telling
230 it what OS and web stack you’re using. Chances are good that they’ve got
231 a good guide for you already.
232
233
234 ### <a id="leew"></a> Configuring Let’s Encrypt, the Easy Way
235
236 If your web serving needs are simple, [Certbot][cb] can configure nginx
237 for you and keep its certificates up to date. Simply follow Certbot’s
238 [nginx on Ubuntu 20.04 LTS guide][cbnu].
239
240 Unfortunately, the setup above was beyond Certbot’s ability to cope the
241 last time we tried it. The use of per-subdomain files in particular
242 confused Certbot, so we had to [arrange these details manually](#lehw),
243 else the Let’s Encrypt [ACME] exchange failed in the necessary domain
244 validation steps.
245
246 At this point, if your configuration needs are simple, needing only a
247 single Internet domain and a single Fossil repo, you might wish to try
248 to reduce the above configuration to a more typical single-file nginx
249 config, which Certbot might then cope with out of the box.
250
251
252
253 ### <a id="lehw"></a> Configuring Let’s Encrypt, the Hard Way
254
255 The primary motivation for this section is that it documents the manual
256 Certbot configuration on my public Fossil-based site. I’m addressing
257 the “me” years hence who needs to upgrade to Ubuntu 22.04 or 24.04 LTS
258 and has forgotten all of this stuff. 😉
259
260
261 #### Step 1: Shifting into Manual
262
263 The first thing we’ll do is install Certbot in the normal way, but we’ll
264 turn off all of the Certbot automation and won’t follow through with use
265 of the `--nginx` plugin:
266
267 $ sudo snap install --classic certbot
268 $ sudo systemctl disable certbot.timer
269
270 Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the
271 nginx plugins. You’re looking for two lines setting the “install” and
272 “auth” plugins to “nginx”. You can comment them out or remove them
273 entirely.
274
275
276 #### Step 2: Configuring nginx
277
278 This is a straightforward extension to the HTTP-only configuration
279 [above](#config):
280
281 server {
282 server_name .foo.net;
283
284 include local/tls-common;
285
286 charset utf-8;
287
288 access_log /var/log/nginx/foo.net-https-access.log;
289 error_log /var/log/nginx/foo.net-https-error.log;
290
291 # Bypass Fossil for the static Doxygen docs
292 location /doc/html {
293 root /var/www/foo.net;
294
295 location ~* \.(html|ico|css|js|gif|jpg|png)$ {
296 expires 7d;
297 add_header Vary Accept-Encoding;
298 access_log off;
299 }
300 }
301
302 # Redirect everything else to the Fossil instance
303 location / {
304 include scgi_params;
305 scgi_pass 127.0.0.1:12345;
306 scgi_param HTTPS "on";
307 scgi_param SCRIPT_NAME "";
308 }
309 }
310 server {
311 server_name .foo.net;
312 root /var/www/foo.net;
313 include local/http-certbot-only;
314 access_log /var/log/nginx/foo.net-http-access.log;
315 error_log /var/log/nginx/foo.net-http-error.log;
316 }
317
318 One big difference between this and the HTTP-only case is
319 that we need two `server { }` blocks: one for HTTPS service, and
320 one for HTTP-only service.
321
322
323 ##### HTTP over TLS (HTTPS) Service
324
325 The first `server { }` block includes this file, `local/tls-common`:
326
327 listen 443 ssl;
328
329 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
330 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
331
332 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
333
334 ssl_stapling on;
335 ssl_stapling_verify on;
336
337 ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
338 ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-CBC-SHA:ECDHE-ECDSA-AES256-CBC-SHA:ECDHE-ECDSA-AES128-CBC-SHA256:ECDHE-ECDSA-AES256-CBC-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-CBC-SHA:ECDHE-RSA-AES256-CBC-SHA:ECDHE-RSA-AES128-CBC-SHA256:ECDHE-RSA-AES256-CBC-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-CBC-SHA:DHE-RSA-AES256-CBC-SHA:DHE-RSA-AES128-CBC-SHA256:DHE-RSA-AES256-CBC-SHA256";
339 ssl_session_cache shared:le_nginx_SSL:1m;
340 ssl_prefer_server_ciphers on;
341 ssl_session_timeout 1440m;
342
343 These are the common TLS configuration parameters used by all domains
344 hosted by this server.
345
346 The first line tells nginx to accept TLS-encrypted HTTP connections on
347 the standard HTTPS port. It is the same as `listen 443; ssl on;` in
348 older versions of nginx.
349
350 Since all of those domains share a single TLS certificate, we reference
351 the same `example.com/*.pem` files written out by Certbot with the
352 `ssl_certificate*` lines.
353
354 The `ssl_dhparam` directive isn’t strictly required, but without it, the
355 server becomes vulnerable to the [Logjam attack][lja] because some of
356 the cryptography steps are precomputed, making the attacker’s job much
357 easier. The parameter file this directive references should be
358 generated automatically by the Let’s Encrypt package upon installation,
359 making those parameters unique to your server and thus unguessable. If
360 the file doesn’t exist on your system, you can create it manually, so:
361
362 $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048
363
364 Beware, this can take a long time. On a shared Linux host I tried it on
365 running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle
366 iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds!
367
368 The next section is also optional. It enables [OCSP stapling][ocsp], a
369 protocol that improves the speed and security of the TLS connection
370 negotiation.
371
372 The next section containing the `ssl_protocols` and `ssl_ciphers` lines
373 restricts the TLS implementation to only those protocols and ciphers
374 that are currently believed to be safe and secure. This section is the
375 one most prone to bit-rot: as new attacks on TLS and its associated
376 technologies are discovered, this configuration is likely to need to
377 change. Even if we fully succeed in keeping this document up-to-date in
378 the face of the evolving security landscape, we’re recommending static
379 configurations for your server: it will thus be up to you to track
380 changes in this document and others to merge the changes into your local
381 static configuration.
382
383 Running a TLS certificate checker against your site occasionally is a
384 good idea. The most thorough service I’m aware of is the [Qualys SSL
385 Labs Test][qslt], which gives the site I’m basing this guide on an “A+”
386 rating at the time of this writing. The long `ssl_ciphers` line above is
387 based on [their advice][qslc]: the default nginx configuration tells
388 OpenSSL to use whatever ciphersuites it considers “high security,” but
389 some of those have come to be considered “weak” in the time between that
390 judgement and the time of this writing. By explicitly giving the list of
391 ciphersuites we want OpenSSL to use within nginx, we can remove those
392 that become considered weak in the future.
393
394 <a id=”hsts”></a>There are a few things you can do to get an even better
395 grade, such as to enable [HSTS][hsts]:
396
397 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
398
399 This prevents a particular variety of [man in the middle attack][mitm]
400 where our HTTP-to-HTTPS permanent redirect is intercepted, allowing the
401 attacker to prevent the automatic upgrade of the connection to a secure
402 TLS-encrypted one. I didn’t enable that in the configuration above
403 because it is something a site administrator should enable only after
404 the configuration is tested and stable, and then only after due
405 consideration. There are ways to lock your users out of your site by
406 jumping to HSTS hastily. When you’re ready, there are [guides you can
407 follow][nest] elsewhere online.
408
409
410 ##### HTTP-Only Service
411
412 While we’d prefer not to offer HTTP service at all, we need to do so for
413 two reasons:
414
415 * The temporary reason is that until we get Let’s Encrypt certificates
416 minted and configured properly, we can’t use HTTPS yet at all.
417
418 * The ongoing reason is that the Certbot [ACME][acme] HTTP-01
419 challenge used by the Let’s Encrypt service only runs over HTTP. This is
420 not only because it has to work before HTTPS is first configured,
421 but also because it might need to work after a certificate is
422 accidentally allowed to lapse to get that server back into a state
423 where it can speak HTTPS safely again.
424
425 So, from the second `service { }` block, we include this file to set up
426 the minimal HTTP service we require, `local/http-certbot-only`:
427
428 listen 80;
429 listen [::]:80;
430
431 # This is expressed as a rewrite rule instead of an "if" because
432 # http://wiki.nginx.org/IfIsEvil
433 #rewrite ^(/.well-known/acme-challenge/.*) $1 break;
434
435 # Force everything else to HTTPS with a permanent redirect.
436 #return 301 https://$host$request_uri;
437
438 As written above, this configuration does nothing other than to tell
439 nginx that it’s allowed to serve content via HTTP on port 80 as well.
440 We’ll uncomment the `rewrite` and `return` directives below, when we’re
441 ready to begin testing.
442
443 Notice that most of the nginx directives given [above](#config) moved up
444 into the TLS `server { }` block, because we eventually want this site to
445 be as close to HTTPS-only as we can get it.
446
447
448 #### Step 3: Dry Run
449
450 We want to first request a dry run, because Let’s Encrypt puts some
451 rather low limits on how often you’re allowed to request an actual
452 certificate. You want to be sure everything’s working before you do
453 that. You’ll run a command something like this:
454
455 $ sudo certbot certonly --webroot --dry-run \
456 --webroot-path /var/www/example.com \
457 -d example.com -d www.example.com \
458 -d example.net -d www.example.net \
459 --webroot-path /var/www/foo.net \
460 -d foo.net -d www.foo.net
461
462 There are two key options here.
463
464 First, we’re telling Certbot to use its `--webroot` plugin instead of
465 the automated `--nginx` plugin. With this plugin, Certbot writes the
466 [ACME][acme] HTTP-01 challenge files to the static web document root
467 directory behind each domain. For this example, we’ve got two web
468 roots, one of which holds documents for two different second-level
469 domains (`example.com` and `example.net`) with `www` at the third level
470 being optional. This is a common sort of configuration these days, but
471 you needn’t feel that you must slavishly imitate it. The other web root
472 is for an entirely different domain, also with `www` being optional.
473 Since all of these domains are served by a single nginx instance, we
474 need to give all of this in a single command, because we want to mint a
475 single certificate that authenticates all of these domains.
476
477 The second key option is `--dry-run`, which tells Certbot not to do
478 anything permanent. We’re just seeing if everything works as expected,
479 at this point.
480
481
482 ##### Troubleshooting the Dry Run
483
484 If that didn’t work, try creating a manual test:
485
486 $ mkdir -p /var/www/example.com/.well-known/acme-challenge
487 $ echo hi > /var/www/example.com/.well-known/acme-challenge/test
488
489 Then try to pull that file over HTTP — not HTTPS! — as
490 `http://example.com/.well-known/acme-challenge/test`. I’ve found that
491 using Firefox or Safari is better for this sort of thing than Chrome,
492 because Chrome is more aggressive about automatically forwarding URLs to
493 HTTPS even if you requested “`http`”.
494
495 In extremis, you can do the test manually:
496
497 $ curl -i http://example.com/.well-known/acme-challenge/test
498 HTTP/1.1 200 OK
499 Server: nginx/1.14.0 (Ubuntu)
500 Date: Sat, 19 Jan 2019 19:43:58 GMT
501 Content-Type: application/octet-stream
502 Content-Length: 3
503 Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT
504 Connection: keep-alive
505 ETag: "5c436ac2-4"
506 Accept-Ranges: bytes
507
508 hi
509
510 The key bits you’re looking for here are the “200 OK” response code at
511 the start and the “hi” line at the end. (Or whatever you wrote in to the
512 test file.)
513
514 If you get a 301 redirect to an `https://` URI, you either haven’t
515 uncommented the `rewrite` line for HTTP-only service for this directory,
516 or there’s some other problem with the “redirect to HTTPS” config.
517
518 If you get a 404 or other error response, you need to look into your web
519 server logs to find out what’s going wrong.
520
521 If you’re still running into trouble, the log file written by Certbot
522 can be helpful. It tells you where it’s writing the ACME files early in
523 each run.
524
525
526
527 #### Step 4: Getting Your First Certificate
528
529 Once the dry run is working, you can drop the `--dry-run` option and
530 re-run the long command above. (The one with all the `--webroot*`
531 flags.) This should now succeed, and it will save all of those flag
532 values to your Let’s Encrypt configuration file, so you don’t need to
533 keep giving them.
534
535
536
537 #### Step 5: Test It
538
539 Edit the `local/http-certbot-only` file and uncomment the `redirect` and
540 `return` directives, then restart your nginx server and make sure it now
541 forces everything to HTTPS like it should:
542
543 $ sudo systemctl restart nginx
544
545 Test ideas:
546
547 * Visit both Fossil and non-Fossil URLs
548
549 * Log into the repo, log out, and log back in
550
551 * Clone via `http`: ensure that it redirects to `https`, and that
552 subsequent `fossil sync` commands go directly to `https` due to the
553 301 permanent redirect.
554
555 This forced redirect is why we don’t need the Fossil Admin &rarr; Access
556 "Redirect to HTTPS on the Login page" setting to be enabled. Not only
557 is it unnecessary with this HTTPS redirect at the front-end proxy level,
558 it would actually [cause an infinite redirect loop if
559 enabled](./ssl.wiki#rloop).
560
561
562
563 #### Step 6: Switch to HTTPS Sync
564
565 Fossil remembers permanent HTTP-to-HTTPS redirects on sync since version
566 2.9, so all you need to do to switch your syncs to HTTPS is:
567
568 $ fossil sync -R /path/to/repo.fossil
569
570
571 #### Step 7: Renewing Automatically
572
573 Now that the configuration is solid, you can renew the LE cert with the
574 `certbot` command from above without the `--dry-run` flag plus a restart
575 of nginx:
576
577 sudo certbot certonly --webroot \
578 --webroot-path /var/www/example.com \
579 -d example.com -d www.example.com \
580 -d example.net -d www.example.net \
581 --webroot-path /var/www/foo.net \
582 -d foo.net -d www.foo.net
583 sudo systemctl restart nginx
584
585 I put those commands in a script in the `PATH`, then arrange to call that
586 periodically. Let’s Encrypt doesn’t let you renew the certificate very
587 often unless forced, and when forced there’s a maximum renewal counter.
588 Nevertheless, some people recommend running this daily and just letting
589 it fail until the server lets you renew. Others arrange to run it no
590 more often than it’s known to work without complaint. Suit yourself.
591
592
593 [acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
594 [cb]: https://certbot.eff.org/
595 [cbnu]: https://certbot.eff.org/lets-encrypt/ubuntufocal-nginx
596 [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
597 [lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security)
598 [mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
599 [nest]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
600 [ocsp]: https://en.wikipedia.org/wiki/OCSP_stapling
601 [qslc]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
602 [qslt]: https://www.ssllabs.com/ssltest/
603
604 *[Return to the top-level Fossil server article.](../)*
605
+1 -1
--- www/ssl.wiki
+++ www/ssl.wiki
@@ -280,11 +280,11 @@
280280
fix the setting, and then upload it to the repository server
281281
again.</p>
282282
283283
It's best to enforce TLS-only access at the front-end proxy level
284284
anyway. It not only avoids the problem entirely, it can be significantly
285
-more secure. The [./tls-nginx.md|nginx TLS proxy guide] shows one way
285
+more secure. The [server/debian/nginx.md#tls | nginx-on-Debian proxy guide] shows one way
286286
to achieve this.</p>
287287
288288
289289
<h2>Terminology Note</h2>
290290
291291
--- www/ssl.wiki
+++ www/ssl.wiki
@@ -280,11 +280,11 @@
280 fix the setting, and then upload it to the repository server
281 again.</p>
282
283 It's best to enforce TLS-only access at the front-end proxy level
284 anyway. It not only avoids the problem entirely, it can be significantly
285 more secure. The [./tls-nginx.md|nginx TLS proxy guide] shows one way
286 to achieve this.</p>
287
288
289 <h2>Terminology Note</h2>
290
291
--- www/ssl.wiki
+++ www/ssl.wiki
@@ -280,11 +280,11 @@
280 fix the setting, and then upload it to the repository server
281 again.</p>
282
283 It's best to enforce TLS-only access at the front-end proxy level
284 anyway. It not only avoids the problem entirely, it can be significantly
285 more secure. The [server/debian/nginx.md#tls | nginx-on-Debian proxy guide] shows one way
286 to achieve this.</p>
287
288
289 <h2>Terminology Note</h2>
290
291
+1 -427
--- www/tls-nginx.md
+++ www/tls-nginx.md
@@ -1,430 +1,3 @@
11
# Proxying Fossil via HTTPS with nginx
22
3
-One of the [many ways](./ssl.wiki) to provide TLS-encrypted HTTP access
4
-(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
5
-TLS. This document explains how to use the powerful [nginx web
6
-server](http://nginx.org/) to do that.
7
-
8
-This document is an extension of the [Serving via nginx on Debian][nod]
9
-document. Please read that first, then come back here to extend its
10
-configuration with TLS.
11
-
12
-[nod]: ./server/debian/nginx.md
13
-
14
-
15
-## Install Certbot
16
-
17
-The [nginx-on-Debian document][nod] had you install a few non-default
18
-packages to the system, but there’s one more you need for this guide:
19
-
20
- $ sudo apt install certbot
21
-
22
-You can extend this guide to other operating systems by following the
23
-instructions found via [the front Certbot web page][cb] instead, telling
24
-it what OS and web stack you’re using. Chances are good that they’ve got
25
-a good guide for you already.
26
-
27
-
28
-# Configuring Let’s Encrypt, the Easy Way
29
-
30
-If your web serving needs are simple, [Certbot][cb] can configure nginx
31
-for you and keep its certificates up to date. Simply follow Certbot’s
32
-[nginx on Ubuntu 18.04 LTS guide][cbnu]. We’d recommend one small
33
-change: to use the version of Certbot in the Ubuntu package repository
34
-rather than download it from the Certbot site.
35
-
36
-You should be able to use the nginx configuration given in our [Serving
37
-via nginx on Debian][nod] guide with little to no change. The main thing
38
-to watch out for is that the TCP port number in the nginx configuration
39
-needs to match the value you gave when starting Fossil. If you followed
40
-that guide’s advice, it will be 9000. Another option is to use [the
41
-`fslsrv` script](/file/tools/fslsrv), in which case the TCP port number
42
-will be 12345 or higher.
43
-
44
-
45
-# Configuring Let’s Encrypt, the Hard Way
46
-
47
-If you’re finding that you can’t get certificates to be issued or
48
-renewed using the Easy Way instructions, the problem is usually that
49
-your nginx configuration is too complicated for Certbot’s `--nginx`
50
-plugin to understand. It attempts to rewrite your nginx configuration
51
-files on the fly to achieve the renewal, and if it doesn’t put its
52
-directives in the right locations, the domain verification can fail.
53
-
54
-Let’s Encrypt uses the [Automated Certificate Management
55
-Environment][acme] protocol (ACME) to determine whether a given client
56
-actually has control over the domain(s) for which it wants a certificate
57
-minted. Let’s Encrypt will not blithely let you mint certificates for
58
-`google.com` and `paypal.com` just because you ask for it!
59
-
60
-Your author’s configuration, glossed [in the HTTP-only guide][nod],
61
-is complicated enough that
62
-the current version of Certbot (0.28 at the time of this writing) can’t
63
-cope with it. That’s the primary motivation for me to write this guide:
64
-I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04
65
-or 22.04 LTS and has forgotten all of this stuff. 😉
66
-
67
-
68
-## Step 1: Shifting into Manual
69
-
70
-The first thing to do is to turn off all of the Certbot automation,
71
-because it’ll only get in our way. First, disable the Certbot package’s
72
-automatic background updater:
73
-
74
- $ sudo systemctl disable certbot.timer
75
-
76
-Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the
77
-nginx plugins. You’re looking for two lines setting the “install” and
78
-“auth” plugins to “nginx”. You can comment them out or remove them
79
-entirely.
80
-
81
-
82
-## Step 2: Configuring nginx
83
-
84
-This is a straightforward extension to [the HTTP-only
85
-configuration](./server/debian/nginx.md#config):
86
-
87
- server {
88
- server_name .foo.net;
89
-
90
- include local/tls-common;
91
-
92
- charset utf-8;
93
-
94
- access_log /var/log/nginx/foo.net-https-access.log;
95
- error_log /var/log/nginx/foo.net-https-error.log;
96
-
97
- # Bypass Fossil for the static Doxygen docs
98
- location /doc/html {
99
- root /var/www/foo.net;
100
-
101
- location ~* \.(html|ico|css|js|gif|jpg|png)$ {
102
- expires 7d;
103
- add_header Vary Accept-Encoding;
104
- access_log off;
105
- }
106
- }
107
-
108
- # Redirect everything else to the Fossil instance
109
- location / {
110
- include scgi_params;
111
- scgi_pass 127.0.0.1:12345;
112
- scgi_param HTTPS "on";
113
- scgi_param SCRIPT_NAME "";
114
- }
115
- }
116
- server {
117
- server_name .foo.net;
118
- root /var/www/foo.net;
119
- include local/http-certbot-only;
120
- access_log /var/log/nginx/foo.net-http-access.log;
121
- error_log /var/log/nginx/foo.net-http-error.log;
122
- }
123
-
124
-One big difference between this and the HTTP-only case is
125
-that we need two `server { }` blocks: one for HTTPS service, and
126
-one for HTTP-only service.
127
-
128
-
129
-### HTTP over TLS (HTTPS) Service
130
-
131
-The first `server { }` block includes this file, `local/tls-common`:
132
-
133
- listen 443 ssl;
134
-
135
- ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
136
- ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
137
-
138
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
139
-
140
- ssl_stapling on;
141
- ssl_stapling_verify on;
142
-
143
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
144
- ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256”;
145
- ssl_session_cache shared:le_nginx_SSL:1m;
146
- ssl_prefer_server_ciphers on;
147
- ssl_session_timeout 1440m;
148
-
149
-These are the common TLS configuration parameters used by all domains
150
-hosted by this server.
151
-
152
-The first line tells nginx to accept TLS-encrypted HTTP connections on
153
-the standard HTTPS port. It is the same as `listen 443; ssl on;` in
154
-older versions of nginx.
155
-
156
-Since all of those domains share a single TLS certificate, we reference
157
-the same `example.com/*.pem` files written out by Certbot with the
158
-`ssl_certificate*` lines.
159
-
160
-The `ssl_dhparam` directive isn’t strictly required, but without it, the
161
-server becomes vulnerable to the [Logjam attack][lja] because some of
162
-the cryptography steps are precomputed, making the attacker’s job much
163
-easier. The parameter file this directive references should be
164
-generated automatically by the Let’s Encrypt package upon installation,
165
-making those parameters unique to your server and thus unguessable. If
166
-the file doesn’t exist on your system, you can create it manually, so:
167
-
168
- $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048
169
-
170
-Beware, this can take a long time. On a shared Linux host I tried it on
171
-running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle
172
-iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds!
173
-
174
-The next section is also optional. It enables [OCSP stapling][ocsp], a
175
-protocol that improves the speed and security of the TLS connection
176
-negotiation.
177
-
178
-The next section containing the `ssl_protocols` and `ssl_ciphers` lines
179
-restricts the TLS implementation to only those protocols and ciphers
180
-that are currently believed to be safe and secure. This section is the
181
-one most prone to bit-rot: as new attacks on TLS and its associated
182
-technologies are discovered, this configuration is likely to need to
183
-change. Even if we fully succeed in [keeping this document
184
-up-to-date](#evolution), the nature of this guide is to recommend static
185
-configurations for your server. You will have to keep an eye on this
186
-sort of thing and evolve your local configuration as the world changes
187
-around it.
188
-
189
-Running a TLS certificate checker against your site occasionally is a
190
-good idea. The most thorough service I’m aware of is the [Qualys SSL
191
-Labs Test][qslt], which gives the site I’m basing this guide on an “A”
192
-rating at the time of this writing. The long `ssl_ciphers` line above is
193
-based on [their advice][qslc]: the default nginx configuration tells
194
-OpenSSL to use whatever ciphersuites it considers “high security,” but
195
-some of those have come to be considered “weak” in the time between that
196
-judgement and the time of this writing. By explicitly giving the list of
197
-ciphersuites we want OpenSSL to use within nginx, we can remove those
198
-that become considered weak in the future.
199
-
200
-<a id=”hsts”></a>There are a few things you can do to get an even better
201
-grade, such as to enable [HSTS][hsts], which prevents a particular
202
-variety of [man in the middle attack][mitm] where our HTTP-to-HTTPS
203
-permanent redirect is intercepted, allowing the attacker to prevent the
204
-automatic upgrade of the connection to a secure TLS-encrypted one. I
205
-didn’t enable that in the configuration above, because it is something a
206
-site administrator should enable only after the configuration is tested
207
-and stable, and then only after due consideration. There are ways to
208
-lock your users out of your site by jumping to HSTS hastily. When you’re
209
-ready, there are [guides you can follow][nest] elsewhere online.
210
-
211
-
212
-### HTTP-Only Service
213
-
214
-While we’d prefer not to offer HTTP service at all, we need to do so for
215
-two reasons:
216
-
217
-* The temporary reason is that until we get Let’s Encrypt certificates
218
- minted and configured properly, we can’t use HTTPS yet at all.
219
-
220
-* The ongoing reason is that the Certbot [ACME][acme] HTTP-01
221
- challenge used by the Let’s Encrypt service only runs over HTTP. This is
222
- not only because it has to work before HTTPS is first configured,
223
- but also because it might need to work after a certificate is
224
- accidentally allowed to lapse, to get that server back into a state
225
- where it can speak HTTPS safely again.
226
-
227
-So, from the second `service { }` block, we include this file to set up
228
-the minimal HTTP service we require, `local/http-certbot-only`:
229
-
230
- listen 80;
231
- listen [::]:80;
232
-
233
- # This is expressed as a rewrite rule instead of an "if" because
234
- # http://wiki.nginx.org/IfIsEvil
235
- #rewrite ^(/.well-known/acme-challenge/.*) $1 break;
236
-
237
- # Force everything else to HTTPS with a permanent redirect.
238
- #return 301 https://$host$request_uri;
239
-
240
-As written above, this configuration does nothing other than to tell
241
-nginx that it’s allowed to serve content via HTTP on port 80 as well.
242
-We’ll uncomment the `rewrite` and `return` directives below, when we’re
243
-ready to begin testing.
244
-
245
-Notice that this configuration is very different from that in the
246
-[HTTP-only nginx on Debian][nod] guide. Most of that guide’s nginx
247
-directives moved up into the TLS `server { }` block, because we
248
-eventually want this site to be as close to HTTPS-only as we can get it.
249
-
250
-
251
-## Step 3: Dry Run
252
-
253
-We want to first request a dry run, because Let’s Encrypt puts some
254
-rather low limits on how often you’re allowed to request an actual
255
-certificate. You want to be sure everything’s working before you do
256
-that. You’ll run a command something like this:
257
-
258
- $ sudo certbot certonly --webroot --dry-run \
259
- --webroot-path /var/www/example.com \
260
- -d example.com -d www.example.com \
261
- -d example.net -d www.example.net \
262
- --webroot-path /var/www/foo.net \
263
- -d foo.net -d www.foo.net
264
-
265
-There are two key options here.
266
-
267
-First, we’re telling Certbot to use its `--webroot` plugin instead of
268
-the automated `--nginx` plugin. With this plugin, Certbot writes the
269
-[ACME][acme] HTTP-01 challenge files to the static web document root
270
-directory behind each domain. For this example, we’ve got two web
271
-roots, one of which holds documents for two different second-level
272
-domains (`example.com` and `example.net`) with `www` at the third level
273
-being optional. This is a common sort of configuration these days, but
274
-you needn’t feel that you must slavishly imitate it; the other web root
275
-is for an entirely different domain, also with `www` being optional.
276
-Since all of these domains are served by a single nginx instance, we
277
-need to give all of this in a single command, because we want to mint a
278
-single certificate that authenticates all of these domains.
279
-
280
-The second key option is `--dry-run`, which tells Certbot not to do
281
-anything permanent. We’re just seeing if everything works as expected,
282
-at this point.
283
-
284
-
285
-### Troubleshooting the Dry Run
286
-
287
-If that didn’t work, try creating a manual test:
288
-
289
- $ mkdir -p /var/www/example.com/.well-known/acme-challenge
290
- $ echo hi > /var/www/example.com/.well-known/acme-challenge/test
291
-
292
-Then try to pull that file over HTTP — not HTTPS! — as
293
-`http://example.com/.well-known/acme-challenge/test`. I’ve found that
294
-using Firefox or Safari is better for this sort of thing than Chrome,
295
-because Chrome is more aggressive about automatically forwarding URLs to
296
-HTTPS even if you requested “`http`”.
297
-
298
-In extremis, you can do the test manually:
299
-
300
- $ telnet foo.net 80
301
- GET /.well-known/acme-challenge/test HTTP/1.1
302
- Host: example.com
303
-
304
- HTTP/1.1 200 OK
305
- Server: nginx/1.14.0 (Ubuntu)
306
- Date: Sat, 19 Jan 2019 19:43:58 GMT
307
- Content-Type: application/octet-stream
308
- Content-Length: 3
309
- Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT
310
- Connection: keep-alive
311
- ETag: "5c436ac2-4"
312
- Accept-Ranges: bytes
313
-
314
- hi
315
-
316
-You type the first two lines at the remote system, plus the doubled
317
-“Enter” to create the blank line, and you get something back that
318
-hopefully looks like the rest of the text above.
319
-
320
-The key bits you’re looking for here are the “hi” line at the end — the
321
-document content you created above — and the “200 OK” response code. If
322
-you get a 404 or other error response, you need to look into your web
323
-server logs to find out what’s going wrong.
324
-
325
-Note that it’s important to do this test with HTTP/1.1 when debugging a
326
-name-based virtual hosting configuration like this. Unless you test only
327
-with the primary domain name alias for the server, this test will fail.
328
-Using the example configuration above, you can only use the
329
-easier-to-type HTTP/1.0 protocol to test the `foo.net` alias.
330
-
331
-If you’re still running into trouble, the log file written by Certbot
332
-can be helpful. It tells you where it’s writing it early in each run.
333
-
334
-
335
-
336
-## Step 4: Getting Your First Certificate
337
-
338
-Once the dry run is working, you can drop the `--dry-run` option and
339
-re-run the long command above. (The one with all the `--webroot*`
340
-flags.) This should now succeed, and it will save all of those flag
341
-values to your Let’s Encrypt configuration file, so you don’t need to
342
-keep giving them.
343
-
344
-
345
-
346
-## Step 5: Test It
347
-
348
-Edit the `local/http-certbot-only` file and uncomment the `redirect` and
349
-`return` directives, then restart your nginx server and make sure it now
350
-forces everything to HTTPS like it should:
351
-
352
- $ sudo systemctl restart nginx
353
-
354
-Test ideas:
355
-
356
-* Visit both Fossil and non-Fossil URLs
357
-
358
-* Log into the repo, log out, and log back in
359
-
360
-* Clone via `http`: ensure that it redirects to `https`, and that
361
- subsequent `fossil sync` commands go directly to `https` due to the
362
- 301 permanent redirect.
363
-
364
-This forced redirect is why we don’t need the Fossil Admin &rarr; Access
365
-"Redirect to HTTPS on the Login page" setting to be enabled. Not only
366
-is it unnecessary with this HTTPS redirect at the front-end proxy level,
367
-it would actually [cause an infinite redirect loop if
368
-enabled](./ssl.wiki#rloop).
369
-
370
-
371
-
372
-## Step 6: Re-Point Fossil at Your Repositories
373
-
374
-As of Fossil 2.9, the permanent HTTP-to-HTTPS redirect we enabled above
375
-causes Fossil to remember the new URL automatically the first time it’s
376
-redirected to it. All you need to do to switch your syncs to HTTPS is:
377
-
378
- $ cd ~/path/to/checkout
379
- $ fossil sync
380
-
381
-
382
-## Step 7: Renewing Automatically
383
-
384
-Now that the configuration is solid, you can renew the LE cert with the
385
-`certbot` command from above without the `--dry-run` flag plus a restart
386
-of nginx:
387
-
388
- sudo certbot certonly --webroot \
389
- --webroot-path /var/www/example.com \
390
- -d example.com -d www.example.com \
391
- -d example.net -d www.example.net \
392
- --webroot-path /var/www/foo.net \
393
- -d foo.net -d www.foo.net
394
- sudo systemctl restart nginx
395
-
396
-I put those commands in a script in the `PATH`, then arrange to call that
397
-periodically. Let’s Encrypt doesn’t let you renew the certificate very
398
-often unless forced, and when forced there’s a maximum renewal counter.
399
-Nevertheless, some people recommend running this daily and just letting
400
-it fail until the server lets you renew. Others arrange to run it no
401
-more often than it’s known to work without complaint. Suit yourself.
402
-
403
-
------------
404
-
405
-<a id=”evolution”></a>
406
-**Document Evolution**
407
-
408
-Large parts of this article have been rewritten several times now due to
409
-shifting technology in the TLS and proxying spheres.
410
-
411
-There is no particularly good reason to expect that this sort of thing
412
-will not continue to happen, so we consider this to be a living
413
-document. If you do not have commit access on the `fossil-scm.org`
414
-repository to update this document as the world changes around it, you
415
-can discuss this document [on the forum][fd]. This document’s author
416
-keeps an eye on the forum and expects to keep this document updated with
417
-ideas that appear in that thread.
418
-
419
-[acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
420
-[cb]: https://certbot.eff.org/
421
-[cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx
422
-[fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157
423
-[hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
424
-[lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security)
425
-[mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
426
-[nest]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
427
-[ocsp]: https://en.wikipedia.org/wiki/OCSP_stapling
428
-[qslc]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
429
-[qslt]: https://www.ssllabs.com/ssltest/
3
+This document has [moved](./server/debian/nginx.md#tls).
4304
--- www/tls-nginx.md
+++ www/tls-nginx.md
@@ -1,430 +1,3 @@
1 # Proxying Fossil via HTTPS with nginx
2
3 One of the [many ways](./ssl.wiki) to provide TLS-encrypted HTTP access
4 (a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
5 TLS. This document explains how to use the powerful [nginx web
6 server](http://nginx.org/) to do that.
7
8 This document is an extension of the [Serving via nginx on Debian][nod]
9 document. Please read that first, then come back here to extend its
10 configuration with TLS.
11
12 [nod]: ./server/debian/nginx.md
13
14
15 ## Install Certbot
16
17 The [nginx-on-Debian document][nod] had you install a few non-default
18 packages to the system, but there’s one more you need for this guide:
19
20 $ sudo apt install certbot
21
22 You can extend this guide to other operating systems by following the
23 instructions found via [the front Certbot web page][cb] instead, telling
24 it what OS and web stack you’re using. Chances are good that they’ve got
25 a good guide for you already.
26
27
28 # Configuring Let’s Encrypt, the Easy Way
29
30 If your web serving needs are simple, [Certbot][cb] can configure nginx
31 for you and keep its certificates up to date. Simply follow Certbot’s
32 [nginx on Ubuntu 18.04 LTS guide][cbnu]. We’d recommend one small
33 change: to use the version of Certbot in the Ubuntu package repository
34 rather than download it from the Certbot site.
35
36 You should be able to use the nginx configuration given in our [Serving
37 via nginx on Debian][nod] guide with little to no change. The main thing
38 to watch out for is that the TCP port number in the nginx configuration
39 needs to match the value you gave when starting Fossil. If you followed
40 that guide’s advice, it will be 9000. Another option is to use [the
41 `fslsrv` script](/file/tools/fslsrv), in which case the TCP port number
42 will be 12345 or higher.
43
44
45 # Configuring Let’s Encrypt, the Hard Way
46
47 If you’re finding that you can’t get certificates to be issued or
48 renewed using the Easy Way instructions, the problem is usually that
49 your nginx configuration is too complicated for Certbot’s `--nginx`
50 plugin to understand. It attempts to rewrite your nginx configuration
51 files on the fly to achieve the renewal, and if it doesn’t put its
52 directives in the right locations, the domain verification can fail.
53
54 Let’s Encrypt uses the [Automated Certificate Management
55 Environment][acme] protocol (ACME) to determine whether a given client
56 actually has control over the domain(s) for which it wants a certificate
57 minted. Let’s Encrypt will not blithely let you mint certificates for
58 `google.com` and `paypal.com` just because you ask for it!
59
60 Your author’s configuration, glossed [in the HTTP-only guide][nod],
61 is complicated enough that
62 the current version of Certbot (0.28 at the time of this writing) can’t
63 cope with it. That’s the primary motivation for me to write this guide:
64 I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04
65 or 22.04 LTS and has forgotten all of this stuff. 😉
66
67
68 ## Step 1: Shifting into Manual
69
70 The first thing to do is to turn off all of the Certbot automation,
71 because it’ll only get in our way. First, disable the Certbot package’s
72 automatic background updater:
73
74 $ sudo systemctl disable certbot.timer
75
76 Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the
77 nginx plugins. You’re looking for two lines setting the “install” and
78 “auth” plugins to “nginx”. You can comment them out or remove them
79 entirely.
80
81
82 ## Step 2: Configuring nginx
83
84 This is a straightforward extension to [the HTTP-only
85 configuration](./server/debian/nginx.md#config):
86
87 server {
88 server_name .foo.net;
89
90 include local/tls-common;
91
92 charset utf-8;
93
94 access_log /var/log/nginx/foo.net-https-access.log;
95 error_log /var/log/nginx/foo.net-https-error.log;
96
97 # Bypass Fossil for the static Doxygen docs
98 location /doc/html {
99 root /var/www/foo.net;
100
101 location ~* \.(html|ico|css|js|gif|jpg|png)$ {
102 expires 7d;
103 add_header Vary Accept-Encoding;
104 access_log off;
105 }
106 }
107
108 # Redirect everything else to the Fossil instance
109 location / {
110 include scgi_params;
111 scgi_pass 127.0.0.1:12345;
112 scgi_param HTTPS "on";
113 scgi_param SCRIPT_NAME "";
114 }
115 }
116 server {
117 server_name .foo.net;
118 root /var/www/foo.net;
119 include local/http-certbot-only;
120 access_log /var/log/nginx/foo.net-http-access.log;
121 error_log /var/log/nginx/foo.net-http-error.log;
122 }
123
124 One big difference between this and the HTTP-only case is
125 that we need two `server { }` blocks: one for HTTPS service, and
126 one for HTTP-only service.
127
128
129 ### HTTP over TLS (HTTPS) Service
130
131 The first `server { }` block includes this file, `local/tls-common`:
132
133 listen 443 ssl;
134
135 ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
136 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
137
138 ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
139
140 ssl_stapling on;
141 ssl_stapling_verify on;
142
143 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
144 ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256”;
145 ssl_session_cache shared:le_nginx_SSL:1m;
146 ssl_prefer_server_ciphers on;
147 ssl_session_timeout 1440m;
148
149 These are the common TLS configuration parameters used by all domains
150 hosted by this server.
151
152 The first line tells nginx to accept TLS-encrypted HTTP connections on
153 the standard HTTPS port. It is the same as `listen 443; ssl on;` in
154 older versions of nginx.
155
156 Since all of those domains share a single TLS certificate, we reference
157 the same `example.com/*.pem` files written out by Certbot with the
158 `ssl_certificate*` lines.
159
160 The `ssl_dhparam` directive isn’t strictly required, but without it, the
161 server becomes vulnerable to the [Logjam attack][lja] because some of
162 the cryptography steps are precomputed, making the attacker’s job much
163 easier. The parameter file this directive references should be
164 generated automatically by the Let’s Encrypt package upon installation,
165 making those parameters unique to your server and thus unguessable. If
166 the file doesn’t exist on your system, you can create it manually, so:
167
168 $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048
169
170 Beware, this can take a long time. On a shared Linux host I tried it on
171 running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle
172 iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds!
173
174 The next section is also optional. It enables [OCSP stapling][ocsp], a
175 protocol that improves the speed and security of the TLS connection
176 negotiation.
177
178 The next section containing the `ssl_protocols` and `ssl_ciphers` lines
179 restricts the TLS implementation to only those protocols and ciphers
180 that are currently believed to be safe and secure. This section is the
181 one most prone to bit-rot: as new attacks on TLS and its associated
182 technologies are discovered, this configuration is likely to need to
183 change. Even if we fully succeed in [keeping this document
184 up-to-date](#evolution), the nature of this guide is to recommend static
185 configurations for your server. You will have to keep an eye on this
186 sort of thing and evolve your local configuration as the world changes
187 around it.
188
189 Running a TLS certificate checker against your site occasionally is a
190 good idea. The most thorough service I’m aware of is the [Qualys SSL
191 Labs Test][qslt], which gives the site I’m basing this guide on an “A”
192 rating at the time of this writing. The long `ssl_ciphers` line above is
193 based on [their advice][qslc]: the default nginx configuration tells
194 OpenSSL to use whatever ciphersuites it considers “high security,” but
195 some of those have come to be considered “weak” in the time between that
196 judgement and the time of this writing. By explicitly giving the list of
197 ciphersuites we want OpenSSL to use within nginx, we can remove those
198 that become considered weak in the future.
199
200 <a id=”hsts”></a>There are a few things you can do to get an even better
201 grade, such as to enable [HSTS][hsts], which prevents a particular
202 variety of [man in the middle attack][mitm] where our HTTP-to-HTTPS
203 permanent redirect is intercepted, allowing the attacker to prevent the
204 automatic upgrade of the connection to a secure TLS-encrypted one. I
205 didn’t enable that in the configuration above, because it is something a
206 site administrator should enable only after the configuration is tested
207 and stable, and then only after due consideration. There are ways to
208 lock your users out of your site by jumping to HSTS hastily. When you’re
209 ready, there are [guides you can follow][nest] elsewhere online.
210
211
212 ### HTTP-Only Service
213
214 While we’d prefer not to offer HTTP service at all, we need to do so for
215 two reasons:
216
217 * The temporary reason is that until we get Let’s Encrypt certificates
218 minted and configured properly, we can’t use HTTPS yet at all.
219
220 * The ongoing reason is that the Certbot [ACME][acme] HTTP-01
221 challenge used by the Let’s Encrypt service only runs over HTTP. This is
222 not only because it has to work before HTTPS is first configured,
223 but also because it might need to work after a certificate is
224 accidentally allowed to lapse, to get that server back into a state
225 where it can speak HTTPS safely again.
226
227 So, from the second `service { }` block, we include this file to set up
228 the minimal HTTP service we require, `local/http-certbot-only`:
229
230 listen 80;
231 listen [::]:80;
232
233 # This is expressed as a rewrite rule instead of an "if" because
234 # http://wiki.nginx.org/IfIsEvil
235 #rewrite ^(/.well-known/acme-challenge/.*) $1 break;
236
237 # Force everything else to HTTPS with a permanent redirect.
238 #return 301 https://$host$request_uri;
239
240 As written above, this configuration does nothing other than to tell
241 nginx that it’s allowed to serve content via HTTP on port 80 as well.
242 We’ll uncomment the `rewrite` and `return` directives below, when we’re
243 ready to begin testing.
244
245 Notice that this configuration is very different from that in the
246 [HTTP-only nginx on Debian][nod] guide. Most of that guide’s nginx
247 directives moved up into the TLS `server { }` block, because we
248 eventually want this site to be as close to HTTPS-only as we can get it.
249
250
251 ## Step 3: Dry Run
252
253 We want to first request a dry run, because Let’s Encrypt puts some
254 rather low limits on how often you’re allowed to request an actual
255 certificate. You want to be sure everything’s working before you do
256 that. You’ll run a command something like this:
257
258 $ sudo certbot certonly --webroot --dry-run \
259 --webroot-path /var/www/example.com \
260 -d example.com -d www.example.com \
261 -d example.net -d www.example.net \
262 --webroot-path /var/www/foo.net \
263 -d foo.net -d www.foo.net
264
265 There are two key options here.
266
267 First, we’re telling Certbot to use its `--webroot` plugin instead of
268 the automated `--nginx` plugin. With this plugin, Certbot writes the
269 [ACME][acme] HTTP-01 challenge files to the static web document root
270 directory behind each domain. For this example, we’ve got two web
271 roots, one of which holds documents for two different second-level
272 domains (`example.com` and `example.net`) with `www` at the third level
273 being optional. This is a common sort of configuration these days, but
274 you needn’t feel that you must slavishly imitate it; the other web root
275 is for an entirely different domain, also with `www` being optional.
276 Since all of these domains are served by a single nginx instance, we
277 need to give all of this in a single command, because we want to mint a
278 single certificate that authenticates all of these domains.
279
280 The second key option is `--dry-run`, which tells Certbot not to do
281 anything permanent. We’re just seeing if everything works as expected,
282 at this point.
283
284
285 ### Troubleshooting the Dry Run
286
287 If that didn’t work, try creating a manual test:
288
289 $ mkdir -p /var/www/example.com/.well-known/acme-challenge
290 $ echo hi > /var/www/example.com/.well-known/acme-challenge/test
291
292 Then try to pull that file over HTTP — not HTTPS! — as
293 `http://example.com/.well-known/acme-challenge/test`. I’ve found that
294 using Firefox or Safari is better for this sort of thing than Chrome,
295 because Chrome is more aggressive about automatically forwarding URLs to
296 HTTPS even if you requested “`http`”.
297
298 In extremis, you can do the test manually:
299
300 $ telnet foo.net 80
301 GET /.well-known/acme-challenge/test HTTP/1.1
302 Host: example.com
303
304 HTTP/1.1 200 OK
305 Server: nginx/1.14.0 (Ubuntu)
306 Date: Sat, 19 Jan 2019 19:43:58 GMT
307 Content-Type: application/octet-stream
308 Content-Length: 3
309 Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT
310 Connection: keep-alive
311 ETag: "5c436ac2-4"
312 Accept-Ranges: bytes
313
314 hi
315
316 You type the first two lines at the remote system, plus the doubled
317 “Enter” to create the blank line, and you get something back that
318 hopefully looks like the rest of the text above.
319
320 The key bits you’re looking for here are the “hi” line at the end — the
321 document content you created above — and the “200 OK” response code. If
322 you get a 404 or other error response, you need to look into your web
323 server logs to find out what’s going wrong.
324
325 Note that it’s important to do this test with HTTP/1.1 when debugging a
326 name-based virtual hosting configuration like this. Unless you test only
327 with the primary domain name alias for the server, this test will fail.
328 Using the example configuration above, you can only use the
329 easier-to-type HTTP/1.0 protocol to test the `foo.net` alias.
330
331 If you’re still running into trouble, the log file written by Certbot
332 can be helpful. It tells you where it’s writing it early in each run.
333
334
335
336 ## Step 4: Getting Your First Certificate
337
338 Once the dry run is working, you can drop the `--dry-run` option and
339 re-run the long command above. (The one with all the `--webroot*`
340 flags.) This should now succeed, and it will save all of those flag
341 values to your Let’s Encrypt configuration file, so you don’t need to
342 keep giving them.
343
344
345
346 ## Step 5: Test It
347
348 Edit the `local/http-certbot-only` file and uncomment the `redirect` and
349 `return` directives, then restart your nginx server and make sure it now
350 forces everything to HTTPS like it should:
351
352 $ sudo systemctl restart nginx
353
354 Test ideas:
355
356 * Visit both Fossil and non-Fossil URLs
357
358 * Log into the repo, log out, and log back in
359
360 * Clone via `http`: ensure that it redirects to `https`, and that
361 subsequent `fossil sync` commands go directly to `https` due to the
362 301 permanent redirect.
363
364 This forced redirect is why we don’t need the Fossil Admin &rarr; Access
365 "Redirect to HTTPS on the Login page" setting to be enabled. Not only
366 is it unnecessary with this HTTPS redirect at the front-end proxy level,
367 it would actually [cause an infinite redirect loop if
368 enabled](./ssl.wiki#rloop).
369
370
371
372 ## Step 6: Re-Point Fossil at Your Repositories
373
374 As of Fossil 2.9, the permanent HTTP-to-HTTPS redirect we enabled above
375 causes Fossil to remember the new URL automatically the first time it’s
376 redirected to it. All you need to do to switch your syncs to HTTPS is:
377
378 $ cd ~/path/to/checkout
379 $ fossil sync
380
381
382 ## Step 7: Renewing Automatically
383
384 Now that the configuration is solid, you can renew the LE cert with the
385 `certbot` command from above without the `--dry-run` flag plus a restart
386 of nginx:
387
388 sudo certbot certonly --webroot \
389 --webroot-path /var/www/example.com \
390 -d example.com -d www.example.com \
391 -d example.net -d www.example.net \
392 --webroot-path /var/www/foo.net \
393 -d foo.net -d www.foo.net
394 sudo systemctl restart nginx
395
396 I put those commands in a script in the `PATH`, then arrange to call that
397 periodically. Let’s Encrypt doesn’t let you renew the certificate very
398 often unless forced, and when forced there’s a maximum renewal counter.
399 Nevertheless, some people recommend running this daily and just letting
400 it fail until the server lets you renew. Others arrange to run it no
401 more often than it’s known to work without complaint. Suit yourself.
402
403
------------
404
405 <a id=”evolution”></a>
406 **Document Evolution**
407
408 Large parts of this article have been rewritten several times now due to
409 shifting technology in the TLS and proxying spheres.
410
411 There is no particularly good reason to expect that this sort of thing
412 will not continue to happen, so we consider this to be a living
413 document. If you do not have commit access on the `fossil-scm.org`
414 repository to update this document as the world changes around it, you
415 can discuss this document [on the forum][fd]. This document’s author
416 keeps an eye on the forum and expects to keep this document updated with
417 ideas that appear in that thread.
418
419 [acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment
420 [cb]: https://certbot.eff.org/
421 [cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx
422 [fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157
423 [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security
424 [lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security)
425 [mitm]: https://en.wikipedia.org/wiki/Man-in-the-middle_attack
426 [nest]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
427 [ocsp]: https://en.wikipedia.org/wiki/OCSP_stapling
428 [qslc]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices
429 [qslt]: https://www.ssllabs.com/ssltest/
430
--- www/tls-nginx.md
+++ www/tls-nginx.md
@@ -1,430 +1,3 @@
1 # Proxying Fossil via HTTPS with nginx
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
------------
3 This document has [moved](./server/debian/nginx.md#tls).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button