Fossil SCM
Assorted improvements to www/tls-nginx.md
Commit
e629c1b79e8e3a2543083e0a9635eaecd80d05df702984d2d0a59b086e9aa1b9
Parent
a13820dc042b9e6…
1 file changed
+71
-54
+71
-54
| --- www/tls-nginx.md | ||
| +++ www/tls-nginx.md | ||
| @@ -48,11 +48,11 @@ | ||
| 48 | 48 | |
| 49 | 49 | |
| 50 | 50 | ## Fossil Remote Access Methods |
| 51 | 51 | |
| 52 | 52 | Fossil provides four major ways to access a repository it’s serving |
| 53 | -remotely, three of which you can use with nginx: | |
| 53 | +remotely, three of which are straightforward to use with nginx: | |
| 54 | 54 | |
| 55 | 55 | * **HTTP** — Fossil has a built-in HTTP server: `fossil server`. |
| 56 | 56 | While this method is efficient and it’s possible to use nginx to |
| 57 | 57 | proxy access to another HTTP server, this option is overkill for our |
| 58 | 58 | purposes. nginx is itself a fully featured HTTP server, so we will |
| @@ -134,36 +134,37 @@ | ||
| 134 | 134 | the `/code` URI on its domains, but that the “`foo`” repo is hosted at |
| 135 | 135 | the top level of its domain. You’ll want to do something like the |
| 136 | 136 | former for a Fossil repo that’s just one piece of a larger site, but the |
| 137 | 137 | latter for a repo that is basically the whole point of the site. |
| 138 | 138 | |
| 139 | -This script’s automatic restart feature makes Fossil upgrades easy: | |
| 140 | - | |
| 141 | - $ cd ~/src/fossil/trunk ; fossil up ; make ; killall fossil ; | |
| 142 | - sudo make install ; fslsrv | |
| 143 | - | |
| 144 | -I’ve written that as a single long command because I keep it in the | |
| 145 | -history for my Fossil servers, so I can just run it again from history. | |
| 146 | -You could put it in a shell script instead. | |
| 139 | +You might also want another script to automate the update, build, and | |
| 140 | +deployment steps for new Fossil versions: | |
| 141 | + | |
| 142 | + #!/bin/sh | |
| 143 | + cd $HOME/src/fossil/trunk | |
| 144 | + fossil up | |
| 145 | + make -j11 | |
| 146 | + killall fossil | |
| 147 | + sudo make install | |
| 148 | + fslsrv | |
| 147 | 149 | |
| 148 | 150 | The `killall fossil` step is needed only on OSes that refuse to let you |
| 149 | 151 | replace a running binary on disk. |
| 150 | 152 | |
| 151 | 153 | As written, the `fslsrv` script assumes a Linux environment. It expects |
| 152 | 154 | `/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`. |
| 153 | -It shouldn’t be difficult to port to very different systems, like macOS | |
| 154 | -or the BSDs. | |
| 155 | +It should not be difficult to port to systems like macOS or the BSDs. | |
| 155 | 156 | |
| 156 | 157 | |
| 157 | 158 | # Configuring Let’s Encrypt, the Easy Way |
| 158 | 159 | |
| 159 | 160 | If your web serving needs are simple, [Certbot][cb] can configure nginx |
| 160 | -for you and keep its certificates up to date. The details are pretty | |
| 161 | -much as in the Certbot documentation for [nginx on Ubuntu 18.04 LTS | |
| 162 | -guide][cbnu], except that where they recommend that you use the | |
| 163 | -first-party Certbot packages, we’ve found that the ones that come with | |
| 164 | -Ubuntu work just fine. | |
| 161 | +for you and keep its certificates up to date. You can follow the Certbot | |
| 162 | +documentation for [nginx on Ubuntu 18.04 LTS guide][cbnu] as-is, though | |
| 163 | +we’d recommend one small change: to use the version of Certbot in the | |
| 164 | +Ubuntu package repository rather than the first-party Certbot package | |
| 165 | +that the guide recommends. | |
| 165 | 166 | |
| 166 | 167 | The primary local configuration you need is to tell nginx how to proxy |
| 167 | 168 | certain URLs down to the Fossil instance you started above with the |
| 168 | 169 | `fslsrv` script: |
| 169 | 170 | |
| @@ -184,11 +185,17 @@ | ||
| 184 | 185 | If you’re finding that you can’t get certificates to be issued or |
| 185 | 186 | renewed using the Easy Way instructions, the problem is usually that |
| 186 | 187 | your nginx configuration is too complicated for Certbot’s `--nginx` |
| 187 | 188 | plugin to understand. It attempts to rewrite your nginx configuration |
| 188 | 189 | files on the fly to achieve the renewal, and if it doesn’t put its |
| 189 | -directives in the right locations, the ACME verification steps can fail. | |
| 190 | +directives in the right locations, the domain verification can fail. | |
| 191 | + | |
| 192 | +Let’s Encrypt uses the [Automated Certificate Management | |
| 193 | +Environment][acme] protocol (ACME) to determine whether a given client | |
| 194 | +actually has control over the domain(s) for which it wants a certificate | |
| 195 | +minted. Let’s Encrypt will not blithely let you mint certificates for | |
| 196 | +`google.com` and `paypal.com` just because you ask for it! | |
| 190 | 197 | |
| 191 | 198 | Your author’s configuration, glossed above, is complicated enough that |
| 192 | 199 | the current version of Certbot (0.28 at the time of this writing) can’t |
| 193 | 200 | cope with it. That’s the primary motivation for me to write this guide: |
| 194 | 201 | I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04 |
| @@ -306,11 +313,13 @@ | ||
| 306 | 313 | making those parameters unique to your server and thus unguessable. If |
| 307 | 314 | the file doesn’t exist on your system, you can create it manually, so: |
| 308 | 315 | |
| 309 | 316 | $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048 |
| 310 | 317 | |
| 311 | -Beware, this will take a few minutes of CPU time. | |
| 318 | +Beware, this can take a long time. On a shared Linux host I tried it on | |
| 319 | +running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle | |
| 320 | +iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds! | |
| 312 | 321 | |
| 313 | 322 | The next section is also optional. It enables [OCSP stapling][ocsp], a |
| 314 | 323 | protocol that improves the speed and security of the TLS connection |
| 315 | 324 | negotiation. |
| 316 | 325 | |
| @@ -349,22 +358,21 @@ | ||
| 349 | 358 | |
| 350 | 359 | |
| 351 | 360 | ### HTTP-Only Service |
| 352 | 361 | |
| 353 | 362 | While we’d prefer not to offer HTTP service at all, we need to do so for |
| 354 | -two reasons, one temporary and the other going forward indefinitely. | |
| 355 | - | |
| 356 | -First, until we get Let’s Encrypt certificates minted and configured | |
| 357 | -properly, we can’t use HTTPS yet at all. | |
| 358 | - | |
| 359 | -Second, the Certbot ACME HTTP-01 challenge used by the Let’s Encrypt | |
| 360 | -service only runs over HTTP, because it has to work before HTTPS is | |
| 361 | -working, or after a certificate is accidentally allowed to lapse. This | |
| 362 | -is the protocol Let’s Encrypt uses to determine whether we actually have | |
| 363 | -control over the domains we want our certificate to be minted for. | |
| 364 | -Let’s Encrypt will not just let you mint certificates for `google.com` | |
| 365 | -and `paypal.com`! | |
| 363 | +two reasons: | |
| 364 | + | |
| 365 | +* The temporary reason is that until we get Let’s Encrypt certificates | |
| 366 | + minted and configured properly, we can’t use HTTPS yet at all. | |
| 367 | + | |
| 368 | +* The ongoing reason is that the Certbot [ACME][acme] HTTP-01 | |
| 369 | + challenge used by the Let’s Encrypt service only runs over HTTP. This is | |
| 370 | + not only because it has to work before HTTPS is first configured, | |
| 371 | + but also because it might need to work after a certificate is | |
| 372 | + accidentally allowed to lapse, to get that server back into a state | |
| 373 | + where it can speak HTTPS safely again. | |
| 366 | 374 | |
| 367 | 375 | So, from the second `service { }` block, we include this file to set up |
| 368 | 376 | the minimal HTTP service we reqiure, `local/http-certbot-only`: |
| 369 | 377 | |
| 370 | 378 | listen 80; |
| @@ -384,28 +392,29 @@ | ||
| 384 | 392 | ready to begin testing. |
| 385 | 393 | |
| 386 | 394 | |
| 387 | 395 | #### Why the Repetition? |
| 388 | 396 | |
| 389 | -You need to do much the same sort of thing as above for each domain name | |
| 390 | -hosted by your nginx server. | |
| 397 | +These `server { }` blocks contain several directives that have to be | |
| 398 | +either completely repeated or copied with only trivial changes when | |
| 399 | +you’re hosting multiple domains from a single server. | |
| 391 | 400 | |
| 392 | -You might being to wonder, then, why I haven’t factored some of those | |
| 393 | -directives into the included files `local/tls-common` and | |
| 394 | -`local/http-certbot-only`. For example, why can’t the second HTTP-only | |
| 395 | -`server { }` block above just be these two lines: | |
| 401 | +You might then wonder, why haven’t I factored some of those directives | |
| 402 | +into the included files `local/tls-common` and | |
| 403 | +`local/http-certbot-only`? Why can’t the HTTP-only `server { }` block | |
| 404 | +above be just two lines? That is, why can I not say: | |
| 396 | 405 | |
| 397 | 406 | server_name .foo.net; |
| 398 | 407 | include local/http-certbot-only; |
| 399 | 408 | |
| 400 | -Then in `local/http-certbot-only`, we’d like to say: | |
| 409 | +Then in `local/http-certbot-only` say: | |
| 401 | 410 | |
| 402 | 411 | root /var/www/$host; |
| 403 | 412 | access_log /var/log/nginx/$host-http-access.log; |
| 404 | 413 | error_log /var/log/nginx/$host-http-error.log; |
| 405 | 414 | |
| 406 | -Sadly, nginx doesn’t allow variable subtitution into any of these | |
| 415 | +Sadly, nginx doesn’t allow variable subtitution into these particular | |
| 407 | 416 | directives. As I understand it, allowing that would make nginx slower, |
| 408 | 417 | so we must largely repeat these directives in each HTTP `server { }` |
| 409 | 418 | block. |
| 410 | 419 | |
| 411 | 420 | These configurations are, as shown, as small as I know how to get them. |
| @@ -429,20 +438,20 @@ | ||
| 429 | 438 | |
| 430 | 439 | There are two key options here. |
| 431 | 440 | |
| 432 | 441 | First, we’re telling Certbot to use its `--webroot` plugin instead of |
| 433 | 442 | the automated `--nginx` plugin. With this plugin, Certbot writes the |
| 434 | -ACME HTTP-01 challenge files to the static web document root directory | |
| 435 | -behind each domain. For this example, we’ve got two web roots, one of | |
| 436 | -which holds documents for two different second-level domains | |
| 437 | -(`example.com` and `example.net`) with `www` at the third level being | |
| 438 | -optional. This is a common sort of configuration these days, but you | |
| 439 | -needn’t feel that you must slavishly imitate it; the other web root is | |
| 440 | -for an entirely different domain, also with `www` being optional. Since | |
| 441 | -all of these domains are served by a single nginx instance, we need to | |
| 442 | -give all of this in a single command, because we want to mint a single | |
| 443 | -certificate that authenticates all of these domains. | |
| 443 | +[ACME][acme] HTTP-01 challenge files to the static web document root | |
| 444 | +directory behind each domain. For this example, we’ve got two web | |
| 445 | +roots, one of which holds documents for two different second-level | |
| 446 | +domains (`example.com` and `example.net`) with `www` at the third level | |
| 447 | +being optional. This is a common sort of configuration these days, but | |
| 448 | +you needn’t feel that you must slavishly imitate it; the other web root | |
| 449 | +is for an entirely different domain, also with `www` being optional. | |
| 450 | +Since all of these domains are served by a single nginx instance, we | |
| 451 | +need to give all of this in a single command, because we want to mint a | |
| 452 | +single certificate that authenticates all of these domains. | |
| 444 | 453 | |
| 445 | 454 | The second key option is `--dry-run`, which tells Certbot not to do |
| 446 | 455 | anything permanent. We’re just seeing if everything works as expected, |
| 447 | 456 | at this point. |
| 448 | 457 | |
| @@ -454,11 +463,11 @@ | ||
| 454 | 463 | $ mkdir -p /var/www/example.com/.well-known/acme-challenge |
| 455 | 464 | $ echo hi > /var/www/example.com/.well-known/acme-challenge/test |
| 456 | 465 | |
| 457 | 466 | Then try to pull that file over HTTP — not HTTPS! — as |
| 458 | 467 | `http://example.com/.well-known/acme-challenge/test`. I’ve found that |
| 459 | -using Firefox and Safari is better for this sort of thing than Chrome, | |
| 468 | +using Firefox or Safari is better for this sort of thing than Chrome, | |
| 460 | 469 | because Chrome is more aggressive about automatically forwarding URLs to |
| 461 | 470 | HTTPS even if you requested “`http`”. |
| 462 | 471 | |
| 463 | 472 | In extremis, you can do the test manually: |
| 464 | 473 | |
| @@ -476,17 +485,24 @@ | ||
| 476 | 485 | ETag: "5c436ac2-4" |
| 477 | 486 | Accept-Ranges: bytes |
| 478 | 487 | |
| 479 | 488 | hi |
| 480 | 489 | |
| 481 | -You’re looking for that “hi” line at the end and the “200 OK” response | |
| 482 | -here. If you get a 404 or other error response, you need to look into | |
| 483 | -your web server logs to find out what’s going wrong. | |
| 490 | +You type the first two lines at the remote system, plus the doubled | |
| 491 | +“Enter” to create the blank line, and you get something back that | |
| 492 | +hopefully looks like the rest of the text above. | |
| 493 | + | |
| 494 | +The key bits you’re looking for here are the “hi” line at the end — the | |
| 495 | +document content you created above — and the “200 OK” response code. If | |
| 496 | +you get a 404 or other error response, you need to look into your web | |
| 497 | +server logs to find out what’s going wrong. | |
| 484 | 498 | |
| 485 | 499 | Note that it’s important to do this test with HTTP/1.1 when debugging a |
| 486 | -name-based virtual hosting configuration like this, if the test domain | |
| 487 | -is one of the secondary names, as in the example above, `foo.net`. | |
| 500 | +name-based virtual hosting configuration like this. Unless you test only | |
| 501 | +with the primary domain name alias for the server, this test will fail. | |
| 502 | +Using the example configuration above, you can only use the | |
| 503 | +easier-to-type HTTP/1.0 protocol to test the `foo.net` alias. | |
| 488 | 504 | |
| 489 | 505 | If you’re still running into trouble, the log file written by Certbot |
| 490 | 506 | can be helpful. It tells you where it’s writing it early in each run. |
| 491 | 507 | |
| 492 | 508 | |
| @@ -583,10 +599,11 @@ | ||
| 583 | 599 | can discuss this document [on the forum][fd]. This document’s author |
| 584 | 600 | keeps an eye on the forum and expects to keep this document updated with |
| 585 | 601 | ideas that appear in that thread. |
| 586 | 602 | |
| 587 | 603 | [2016]: https://www.mail-archive.com/[email protected]/msg22907.html |
| 604 | +[acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment | |
| 588 | 605 | [cb]: https://certbot.eff.org/ |
| 589 | 606 | [cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx |
| 590 | 607 | [fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157 |
| 591 | 608 | [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security |
| 592 | 609 | [lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security) |
| 593 | 610 |
| --- www/tls-nginx.md | |
| +++ www/tls-nginx.md | |
| @@ -48,11 +48,11 @@ | |
| 48 | |
| 49 | |
| 50 | ## Fossil Remote Access Methods |
| 51 | |
| 52 | Fossil provides four major ways to access a repository it’s serving |
| 53 | remotely, three of which you can use with nginx: |
| 54 | |
| 55 | * **HTTP** — Fossil has a built-in HTTP server: `fossil server`. |
| 56 | While this method is efficient and it’s possible to use nginx to |
| 57 | proxy access to another HTTP server, this option is overkill for our |
| 58 | purposes. nginx is itself a fully featured HTTP server, so we will |
| @@ -134,36 +134,37 @@ | |
| 134 | the `/code` URI on its domains, but that the “`foo`” repo is hosted at |
| 135 | the top level of its domain. You’ll want to do something like the |
| 136 | former for a Fossil repo that’s just one piece of a larger site, but the |
| 137 | latter for a repo that is basically the whole point of the site. |
| 138 | |
| 139 | This script’s automatic restart feature makes Fossil upgrades easy: |
| 140 | |
| 141 | $ cd ~/src/fossil/trunk ; fossil up ; make ; killall fossil ; |
| 142 | sudo make install ; fslsrv |
| 143 | |
| 144 | I’ve written that as a single long command because I keep it in the |
| 145 | history for my Fossil servers, so I can just run it again from history. |
| 146 | You could put it in a shell script instead. |
| 147 | |
| 148 | The `killall fossil` step is needed only on OSes that refuse to let you |
| 149 | replace a running binary on disk. |
| 150 | |
| 151 | As written, the `fslsrv` script assumes a Linux environment. It expects |
| 152 | `/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`. |
| 153 | It shouldn’t be difficult to port to very different systems, like macOS |
| 154 | or the BSDs. |
| 155 | |
| 156 | |
| 157 | # Configuring Let’s Encrypt, the Easy Way |
| 158 | |
| 159 | If your web serving needs are simple, [Certbot][cb] can configure nginx |
| 160 | for you and keep its certificates up to date. The details are pretty |
| 161 | much as in the Certbot documentation for [nginx on Ubuntu 18.04 LTS |
| 162 | guide][cbnu], except that where they recommend that you use the |
| 163 | first-party Certbot packages, we’ve found that the ones that come with |
| 164 | Ubuntu work just fine. |
| 165 | |
| 166 | The primary local configuration you need is to tell nginx how to proxy |
| 167 | certain URLs down to the Fossil instance you started above with the |
| 168 | `fslsrv` script: |
| 169 | |
| @@ -184,11 +185,17 @@ | |
| 184 | If you’re finding that you can’t get certificates to be issued or |
| 185 | renewed using the Easy Way instructions, the problem is usually that |
| 186 | your nginx configuration is too complicated for Certbot’s `--nginx` |
| 187 | plugin to understand. It attempts to rewrite your nginx configuration |
| 188 | files on the fly to achieve the renewal, and if it doesn’t put its |
| 189 | directives in the right locations, the ACME verification steps can fail. |
| 190 | |
| 191 | Your author’s configuration, glossed above, is complicated enough that |
| 192 | the current version of Certbot (0.28 at the time of this writing) can’t |
| 193 | cope with it. That’s the primary motivation for me to write this guide: |
| 194 | I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04 |
| @@ -306,11 +313,13 @@ | |
| 306 | making those parameters unique to your server and thus unguessable. If |
| 307 | the file doesn’t exist on your system, you can create it manually, so: |
| 308 | |
| 309 | $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048 |
| 310 | |
| 311 | Beware, this will take a few minutes of CPU time. |
| 312 | |
| 313 | The next section is also optional. It enables [OCSP stapling][ocsp], a |
| 314 | protocol that improves the speed and security of the TLS connection |
| 315 | negotiation. |
| 316 | |
| @@ -349,22 +358,21 @@ | |
| 349 | |
| 350 | |
| 351 | ### HTTP-Only Service |
| 352 | |
| 353 | While we’d prefer not to offer HTTP service at all, we need to do so for |
| 354 | two reasons, one temporary and the other going forward indefinitely. |
| 355 | |
| 356 | First, until we get Let’s Encrypt certificates minted and configured |
| 357 | properly, we can’t use HTTPS yet at all. |
| 358 | |
| 359 | Second, the Certbot ACME HTTP-01 challenge used by the Let’s Encrypt |
| 360 | service only runs over HTTP, because it has to work before HTTPS is |
| 361 | working, or after a certificate is accidentally allowed to lapse. This |
| 362 | is the protocol Let’s Encrypt uses to determine whether we actually have |
| 363 | control over the domains we want our certificate to be minted for. |
| 364 | Let’s Encrypt will not just let you mint certificates for `google.com` |
| 365 | and `paypal.com`! |
| 366 | |
| 367 | So, from the second `service { }` block, we include this file to set up |
| 368 | the minimal HTTP service we reqiure, `local/http-certbot-only`: |
| 369 | |
| 370 | listen 80; |
| @@ -384,28 +392,29 @@ | |
| 384 | ready to begin testing. |
| 385 | |
| 386 | |
| 387 | #### Why the Repetition? |
| 388 | |
| 389 | You need to do much the same sort of thing as above for each domain name |
| 390 | hosted by your nginx server. |
| 391 | |
| 392 | You might being to wonder, then, why I haven’t factored some of those |
| 393 | directives into the included files `local/tls-common` and |
| 394 | `local/http-certbot-only`. For example, why can’t the second HTTP-only |
| 395 | `server { }` block above just be these two lines: |
| 396 | |
| 397 | server_name .foo.net; |
| 398 | include local/http-certbot-only; |
| 399 | |
| 400 | Then in `local/http-certbot-only`, we’d like to say: |
| 401 | |
| 402 | root /var/www/$host; |
| 403 | access_log /var/log/nginx/$host-http-access.log; |
| 404 | error_log /var/log/nginx/$host-http-error.log; |
| 405 | |
| 406 | Sadly, nginx doesn’t allow variable subtitution into any of these |
| 407 | directives. As I understand it, allowing that would make nginx slower, |
| 408 | so we must largely repeat these directives in each HTTP `server { }` |
| 409 | block. |
| 410 | |
| 411 | These configurations are, as shown, as small as I know how to get them. |
| @@ -429,20 +438,20 @@ | |
| 429 | |
| 430 | There are two key options here. |
| 431 | |
| 432 | First, we’re telling Certbot to use its `--webroot` plugin instead of |
| 433 | the automated `--nginx` plugin. With this plugin, Certbot writes the |
| 434 | ACME HTTP-01 challenge files to the static web document root directory |
| 435 | behind each domain. For this example, we’ve got two web roots, one of |
| 436 | which holds documents for two different second-level domains |
| 437 | (`example.com` and `example.net`) with `www` at the third level being |
| 438 | optional. This is a common sort of configuration these days, but you |
| 439 | needn’t feel that you must slavishly imitate it; the other web root is |
| 440 | for an entirely different domain, also with `www` being optional. Since |
| 441 | all of these domains are served by a single nginx instance, we need to |
| 442 | give all of this in a single command, because we want to mint a single |
| 443 | certificate that authenticates all of these domains. |
| 444 | |
| 445 | The second key option is `--dry-run`, which tells Certbot not to do |
| 446 | anything permanent. We’re just seeing if everything works as expected, |
| 447 | at this point. |
| 448 | |
| @@ -454,11 +463,11 @@ | |
| 454 | $ mkdir -p /var/www/example.com/.well-known/acme-challenge |
| 455 | $ echo hi > /var/www/example.com/.well-known/acme-challenge/test |
| 456 | |
| 457 | Then try to pull that file over HTTP — not HTTPS! — as |
| 458 | `http://example.com/.well-known/acme-challenge/test`. I’ve found that |
| 459 | using Firefox and Safari is better for this sort of thing than Chrome, |
| 460 | because Chrome is more aggressive about automatically forwarding URLs to |
| 461 | HTTPS even if you requested “`http`”. |
| 462 | |
| 463 | In extremis, you can do the test manually: |
| 464 | |
| @@ -476,17 +485,24 @@ | |
| 476 | ETag: "5c436ac2-4" |
| 477 | Accept-Ranges: bytes |
| 478 | |
| 479 | hi |
| 480 | |
| 481 | You’re looking for that “hi” line at the end and the “200 OK” response |
| 482 | here. If you get a 404 or other error response, you need to look into |
| 483 | your web server logs to find out what’s going wrong. |
| 484 | |
| 485 | Note that it’s important to do this test with HTTP/1.1 when debugging a |
| 486 | name-based virtual hosting configuration like this, if the test domain |
| 487 | is one of the secondary names, as in the example above, `foo.net`. |
| 488 | |
| 489 | If you’re still running into trouble, the log file written by Certbot |
| 490 | can be helpful. It tells you where it’s writing it early in each run. |
| 491 | |
| 492 | |
| @@ -583,10 +599,11 @@ | |
| 583 | can discuss this document [on the forum][fd]. This document’s author |
| 584 | keeps an eye on the forum and expects to keep this document updated with |
| 585 | ideas that appear in that thread. |
| 586 | |
| 587 | [2016]: https://www.mail-archive.com/[email protected]/msg22907.html |
| 588 | [cb]: https://certbot.eff.org/ |
| 589 | [cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx |
| 590 | [fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157 |
| 591 | [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security |
| 592 | [lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security) |
| 593 |
| --- www/tls-nginx.md | |
| +++ www/tls-nginx.md | |
| @@ -48,11 +48,11 @@ | |
| 48 | |
| 49 | |
| 50 | ## Fossil Remote Access Methods |
| 51 | |
| 52 | Fossil provides four major ways to access a repository it’s serving |
| 53 | remotely, three of which are straightforward to use with nginx: |
| 54 | |
| 55 | * **HTTP** — Fossil has a built-in HTTP server: `fossil server`. |
| 56 | While this method is efficient and it’s possible to use nginx to |
| 57 | proxy access to another HTTP server, this option is overkill for our |
| 58 | purposes. nginx is itself a fully featured HTTP server, so we will |
| @@ -134,36 +134,37 @@ | |
| 134 | the `/code` URI on its domains, but that the “`foo`” repo is hosted at |
| 135 | the top level of its domain. You’ll want to do something like the |
| 136 | former for a Fossil repo that’s just one piece of a larger site, but the |
| 137 | latter for a repo that is basically the whole point of the site. |
| 138 | |
| 139 | You might also want another script to automate the update, build, and |
| 140 | deployment steps for new Fossil versions: |
| 141 | |
| 142 | #!/bin/sh |
| 143 | cd $HOME/src/fossil/trunk |
| 144 | fossil up |
| 145 | make -j11 |
| 146 | killall fossil |
| 147 | sudo make install |
| 148 | fslsrv |
| 149 | |
| 150 | The `killall fossil` step is needed only on OSes that refuse to let you |
| 151 | replace a running binary on disk. |
| 152 | |
| 153 | As written, the `fslsrv` script assumes a Linux environment. It expects |
| 154 | `/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`. |
| 155 | It should not be difficult to port to systems like macOS or the BSDs. |
| 156 | |
| 157 | |
| 158 | # Configuring Let’s Encrypt, the Easy Way |
| 159 | |
| 160 | If your web serving needs are simple, [Certbot][cb] can configure nginx |
| 161 | for you and keep its certificates up to date. You can follow the Certbot |
| 162 | documentation for [nginx on Ubuntu 18.04 LTS guide][cbnu] as-is, though |
| 163 | we’d recommend one small change: to use the version of Certbot in the |
| 164 | Ubuntu package repository rather than the first-party Certbot package |
| 165 | that the guide recommends. |
| 166 | |
| 167 | The primary local configuration you need is to tell nginx how to proxy |
| 168 | certain URLs down to the Fossil instance you started above with the |
| 169 | `fslsrv` script: |
| 170 | |
| @@ -184,11 +185,17 @@ | |
| 185 | If you’re finding that you can’t get certificates to be issued or |
| 186 | renewed using the Easy Way instructions, the problem is usually that |
| 187 | your nginx configuration is too complicated for Certbot’s `--nginx` |
| 188 | plugin to understand. It attempts to rewrite your nginx configuration |
| 189 | files on the fly to achieve the renewal, and if it doesn’t put its |
| 190 | directives in the right locations, the domain verification can fail. |
| 191 | |
| 192 | Let’s Encrypt uses the [Automated Certificate Management |
| 193 | Environment][acme] protocol (ACME) to determine whether a given client |
| 194 | actually has control over the domain(s) for which it wants a certificate |
| 195 | minted. Let’s Encrypt will not blithely let you mint certificates for |
| 196 | `google.com` and `paypal.com` just because you ask for it! |
| 197 | |
| 198 | Your author’s configuration, glossed above, is complicated enough that |
| 199 | the current version of Certbot (0.28 at the time of this writing) can’t |
| 200 | cope with it. That’s the primary motivation for me to write this guide: |
| 201 | I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04 |
| @@ -306,11 +313,13 @@ | |
| 313 | making those parameters unique to your server and thus unguessable. If |
| 314 | the file doesn’t exist on your system, you can create it manually, so: |
| 315 | |
| 316 | $ sudo openssl dhparam -out /etc/letsencrypt/dhparams.pem 2048 |
| 317 | |
| 318 | Beware, this can take a long time. On a shared Linux host I tried it on |
| 319 | running OpenSSL 1.1.0g, it took about 21 seconds, but on a fast, idle |
| 320 | iMac running LibreSSL 2.6.5, it took 8 minutes and 4 seconds! |
| 321 | |
| 322 | The next section is also optional. It enables [OCSP stapling][ocsp], a |
| 323 | protocol that improves the speed and security of the TLS connection |
| 324 | negotiation. |
| 325 | |
| @@ -349,22 +358,21 @@ | |
| 358 | |
| 359 | |
| 360 | ### HTTP-Only Service |
| 361 | |
| 362 | While we’d prefer not to offer HTTP service at all, we need to do so for |
| 363 | two reasons: |
| 364 | |
| 365 | * The temporary reason is that until we get Let’s Encrypt certificates |
| 366 | minted and configured properly, we can’t use HTTPS yet at all. |
| 367 | |
| 368 | * The ongoing reason is that the Certbot [ACME][acme] HTTP-01 |
| 369 | challenge used by the Let’s Encrypt service only runs over HTTP. This is |
| 370 | not only because it has to work before HTTPS is first configured, |
| 371 | but also because it might need to work after a certificate is |
| 372 | accidentally allowed to lapse, to get that server back into a state |
| 373 | where it can speak HTTPS safely again. |
| 374 | |
| 375 | So, from the second `service { }` block, we include this file to set up |
| 376 | the minimal HTTP service we reqiure, `local/http-certbot-only`: |
| 377 | |
| 378 | listen 80; |
| @@ -384,28 +392,29 @@ | |
| 392 | ready to begin testing. |
| 393 | |
| 394 | |
| 395 | #### Why the Repetition? |
| 396 | |
| 397 | These `server { }` blocks contain several directives that have to be |
| 398 | either completely repeated or copied with only trivial changes when |
| 399 | you’re hosting multiple domains from a single server. |
| 400 | |
| 401 | You might then wonder, why haven’t I factored some of those directives |
| 402 | into the included files `local/tls-common` and |
| 403 | `local/http-certbot-only`? Why can’t the HTTP-only `server { }` block |
| 404 | above be just two lines? That is, why can I not say: |
| 405 | |
| 406 | server_name .foo.net; |
| 407 | include local/http-certbot-only; |
| 408 | |
| 409 | Then in `local/http-certbot-only` say: |
| 410 | |
| 411 | root /var/www/$host; |
| 412 | access_log /var/log/nginx/$host-http-access.log; |
| 413 | error_log /var/log/nginx/$host-http-error.log; |
| 414 | |
| 415 | Sadly, nginx doesn’t allow variable subtitution into these particular |
| 416 | directives. As I understand it, allowing that would make nginx slower, |
| 417 | so we must largely repeat these directives in each HTTP `server { }` |
| 418 | block. |
| 419 | |
| 420 | These configurations are, as shown, as small as I know how to get them. |
| @@ -429,20 +438,20 @@ | |
| 438 | |
| 439 | There are two key options here. |
| 440 | |
| 441 | First, we’re telling Certbot to use its `--webroot` plugin instead of |
| 442 | the automated `--nginx` plugin. With this plugin, Certbot writes the |
| 443 | [ACME][acme] HTTP-01 challenge files to the static web document root |
| 444 | directory behind each domain. For this example, we’ve got two web |
| 445 | roots, one of which holds documents for two different second-level |
| 446 | domains (`example.com` and `example.net`) with `www` at the third level |
| 447 | being optional. This is a common sort of configuration these days, but |
| 448 | you needn’t feel that you must slavishly imitate it; the other web root |
| 449 | is for an entirely different domain, also with `www` being optional. |
| 450 | Since all of these domains are served by a single nginx instance, we |
| 451 | need to give all of this in a single command, because we want to mint a |
| 452 | single certificate that authenticates all of these domains. |
| 453 | |
| 454 | The second key option is `--dry-run`, which tells Certbot not to do |
| 455 | anything permanent. We’re just seeing if everything works as expected, |
| 456 | at this point. |
| 457 | |
| @@ -454,11 +463,11 @@ | |
| 463 | $ mkdir -p /var/www/example.com/.well-known/acme-challenge |
| 464 | $ echo hi > /var/www/example.com/.well-known/acme-challenge/test |
| 465 | |
| 466 | Then try to pull that file over HTTP — not HTTPS! — as |
| 467 | `http://example.com/.well-known/acme-challenge/test`. I’ve found that |
| 468 | using Firefox or Safari is better for this sort of thing than Chrome, |
| 469 | because Chrome is more aggressive about automatically forwarding URLs to |
| 470 | HTTPS even if you requested “`http`”. |
| 471 | |
| 472 | In extremis, you can do the test manually: |
| 473 | |
| @@ -476,17 +485,24 @@ | |
| 485 | ETag: "5c436ac2-4" |
| 486 | Accept-Ranges: bytes |
| 487 | |
| 488 | hi |
| 489 | |
| 490 | You type the first two lines at the remote system, plus the doubled |
| 491 | “Enter” to create the blank line, and you get something back that |
| 492 | hopefully looks like the rest of the text above. |
| 493 | |
| 494 | The key bits you’re looking for here are the “hi” line at the end — the |
| 495 | document content you created above — and the “200 OK” response code. If |
| 496 | you get a 404 or other error response, you need to look into your web |
| 497 | server logs to find out what’s going wrong. |
| 498 | |
| 499 | Note that it’s important to do this test with HTTP/1.1 when debugging a |
| 500 | name-based virtual hosting configuration like this. Unless you test only |
| 501 | with the primary domain name alias for the server, this test will fail. |
| 502 | Using the example configuration above, you can only use the |
| 503 | easier-to-type HTTP/1.0 protocol to test the `foo.net` alias. |
| 504 | |
| 505 | If you’re still running into trouble, the log file written by Certbot |
| 506 | can be helpful. It tells you where it’s writing it early in each run. |
| 507 | |
| 508 | |
| @@ -583,10 +599,11 @@ | |
| 599 | can discuss this document [on the forum][fd]. This document’s author |
| 600 | keeps an eye on the forum and expects to keep this document updated with |
| 601 | ideas that appear in that thread. |
| 602 | |
| 603 | [2016]: https://www.mail-archive.com/[email protected]/msg22907.html |
| 604 | [acme]: https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment |
| 605 | [cb]: https://certbot.eff.org/ |
| 606 | [cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx |
| 607 | [fd]: https://fossil-scm.org/forum/forumpost/ae6a4ee157 |
| 608 | [hsts]: https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security |
| 609 | [lja]: https://en.wikipedia.org/wiki/Logjam_(computer_security) |
| 610 |