Fossil SCM
Removed a bunch of manual indents in pre blocks, MD fenced code blocks, etc. The skin does that for us now.
Commit
2a7b1de356d12a5fe5ffab37bc90e8514e2831f564e8de2ce0e1a4556394c24b
Parent
2ccdfa417aef0ab…
21 files changed
+15
-15
+2
-2
+37
-37
+106
-166
+13
-15
+10
-10
+29
-29
+15
-15
+3
-3
+9
-9
+26
-26
+2
-2
+3
-3
+6
-6
+9
-9
+46
-48
+46
-46
+40
-38
+119
-119
+1
-1
+22
-22
~
www/alerts.md
~
www/backup.md
~
www/ckout-workflows.md
~
www/containers.md
~
www/defcsp.md
~
www/embeddeddoc.wiki
~
www/image-format-vs-repo-size.md
~
www/javascript.md
~
www/loadmgmt.md
~
www/server/any/cgi.md
~
www/server/any/http-over-ssh.md
~
www/server/any/inetd.md
~
www/server/any/none.md
~
www/server/any/scgi.md
~
www/server/any/xinetd.md
~
www/server/debian/nginx.md
~
www/server/debian/service.md
~
www/server/macos/service.md
~
www/server/openbsd/fastcgi.md
~
www/server/windows/iis.md
~
www/th1.md
+15
-15
| --- www/alerts.md | ||
| +++ www/alerts.md | ||
| @@ -91,15 +91,15 @@ | ||
| 91 | 91 | |
| 92 | 92 | Save your changes. |
| 93 | 93 | |
| 94 | 94 | At the command line, say |
| 95 | 95 | |
| 96 | - $ fossil set email-send-command | |
| 96 | + $ fossil set email-send-command | |
| 97 | 97 | |
| 98 | 98 | If that gives a blank value instead of `sendmail -ti`, say |
| 99 | 99 | |
| 100 | - $ fossil set email-send-command "sendmail -ti" | |
| 100 | + $ fossil set email-send-command "sendmail -ti" | |
| 101 | 101 | |
| 102 | 102 | to force the setting. That works around a [known |
| 103 | 103 | bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be |
| 104 | 104 | squished by the time you read this. |
| 105 | 105 | |
| @@ -113,13 +113,13 @@ | ||
| 113 | 113 | |
| 114 | 114 | <a id="status"></a> |
| 115 | 115 | If you reload the Admin → Notification page, the Status section at the |
| 116 | 116 | top should show: |
| 117 | 117 | |
| 118 | - Outgoing Email: Piped to command "sendmail -ti" | |
| 119 | - Pending Alerts: 0 normal, 0 digest | |
| 120 | - Subscribers: 0 active, 0 total | |
| 118 | + Outgoing Email: Piped to command "sendmail -ti" | |
| 119 | + Pending Alerts: 0 normal, 0 digest | |
| 120 | + Subscribers: 0 active, 0 total | |
| 121 | 121 | |
| 122 | 122 | Before you move on to the next section, you might like to read up on |
| 123 | 123 | [some subtleties](#pipe) with the "pipe to a command" method that we did |
| 124 | 124 | not cover above. |
| 125 | 125 | |
| @@ -211,11 +211,11 @@ | ||
| 211 | 211 | message below, then press "Send Message" to verify that outgoing email |
| 212 | 212 | is working. |
| 213 | 213 | |
| 214 | 214 | Another method is from the command line: |
| 215 | 215 | |
| 216 | - $ fossil alerts test-message [email protected] --body README.md --subject Test | |
| 216 | + $ fossil alerts test-message [email protected] --body README.md --subject Test | |
| 217 | 217 | |
| 218 | 218 | That should send you an email with "Test" in the subject line and the |
| 219 | 219 | contents of your project's `README.md` file in the body. |
| 220 | 220 | |
| 221 | 221 | That command assumes that your project contains a "readme" file, but of |
| @@ -261,38 +261,38 @@ | ||
| 261 | 261 | If email alerts aren't working, there are several useful commands you |
| 262 | 262 | can give to figure out why. |
| 263 | 263 | |
| 264 | 264 | (Be sure to [`cd` into a repo checkout directory](#cd) first!) |
| 265 | 265 | |
| 266 | - $ fossil alerts status | |
| 266 | + $ fossil alerts status | |
| 267 | 267 | |
| 268 | 268 | This should give much the same information as you saw [above](#status). |
| 269 | 269 | One difference is that, since you've created a forum post, the |
| 270 | 270 | `pending-alerts` value should only be zero if you did in fact get the |
| 271 | 271 | requested email alert. If it's zero, check your mailer's spam folder. If |
| 272 | 272 | it's nonzero, continue with these troubleshooting steps. |
| 273 | 273 | |
| 274 | - $ fossil backoffice | |
| 274 | + $ fossil backoffice | |
| 275 | 275 | |
| 276 | 276 | That forces Fossil to run its ["back office" process](./backoffice.md). |
| 277 | 277 | Its only purpose at the time of this writing is to push out alert |
| 278 | 278 | emails, but it might do other things later. Sometimes it can get stuck |
| 279 | 279 | and needs to be kicked. For that reason, you might want to set up a |
| 280 | 280 | crontab entry to make sure it runs occasionally. |
| 281 | 281 | |
| 282 | - $ fossil alerts send | |
| 282 | + $ fossil alerts send | |
| 283 | 283 | |
| 284 | 284 | This should also kick off the backoffice processing, if there are any |
| 285 | 285 | pending alerts to send out. |
| 286 | 286 | |
| 287 | - $ fossil alert pending | |
| 287 | + $ fossil alert pending | |
| 288 | 288 | |
| 289 | 289 | Show any pending alerts. The number of lines output here should equal |
| 290 | 290 | the [status output above](#status). |
| 291 | 291 | |
| 292 | - $ fossil test-add-alerts f5900 | |
| 293 | - $ fossil alert send | |
| 292 | + $ fossil test-add-alerts f5900 | |
| 293 | + $ fossil alert send | |
| 294 | 294 | |
| 295 | 295 | Manually create an email alert and push it out immediately. |
| 296 | 296 | |
| 297 | 297 | The `f` in the first command's final parameter means you're scheduling a |
| 298 | 298 | "forum" alert. The integer is the ID of a forum post, which you can find |
| @@ -299,11 +299,11 @@ | ||
| 299 | 299 | by visiting `/timeline?showid` on your Fossil instance. |
| 300 | 300 | |
| 301 | 301 | The second command above is necessary because the `test-add-alerts` |
| 302 | 302 | command doesn't kick off a backoffice run. |
| 303 | 303 | |
| 304 | - $ fossil ale send | |
| 304 | + $ fossil ale send | |
| 305 | 305 | |
| 306 | 306 | This only does the same thing as the final command above, rather than |
| 307 | 307 | send you an ale, as you might be hoping. Sorry. |
| 308 | 308 | |
| 309 | 309 | |
| @@ -421,11 +421,11 @@ | ||
| 421 | 421 | |
| 422 | 422 | You can start this Tcl script as a daemon automatically on most Unix and |
| 423 | 423 | Unix-like systems by adding the following line to the `/etc/rc.local` |
| 424 | 424 | file of the server that hosts the repository sending email alerts: |
| 425 | 425 | |
| 426 | - /usr/bin/tclsh /home/www/fossil/email-sender.tcl & | |
| 426 | + /usr/bin/tclsh /home/www/fossil/email-sender.tcl & | |
| 427 | 427 | |
| 428 | 428 | [cj]: https://en.wikipedia.org/wiki/Chroot |
| 429 | 429 | [rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations |
| 430 | 430 | |
| 431 | 431 | |
| @@ -680,11 +680,11 @@ | ||
| 680 | 680 | far as I can see. |
| 681 | 681 | |
| 682 | 682 | If the `subscriberCodes` for a Fossil repository are ever compromised, |
| 683 | 683 | new ones can be generated as follows: |
| 684 | 684 | |
| 685 | - UPDATE subscriber SET subscriberCode=randomblob(32); | |
| 685 | + UPDATE subscriber SET subscriberCode=randomblob(32); | |
| 686 | 686 | |
| 687 | 687 | Since this then affects all new email alerts going out from Fossil, your |
| 688 | 688 | end users may never even realize that they're getting new codes, as long |
| 689 | 689 | as they don't click on the URLs in the footer of old alert messages. |
| 690 | 690 | |
| 691 | 691 |
| --- www/alerts.md | |
| +++ www/alerts.md | |
| @@ -91,15 +91,15 @@ | |
| 91 | |
| 92 | Save your changes. |
| 93 | |
| 94 | At the command line, say |
| 95 | |
| 96 | $ fossil set email-send-command |
| 97 | |
| 98 | If that gives a blank value instead of `sendmail -ti`, say |
| 99 | |
| 100 | $ fossil set email-send-command "sendmail -ti" |
| 101 | |
| 102 | to force the setting. That works around a [known |
| 103 | bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be |
| 104 | squished by the time you read this. |
| 105 | |
| @@ -113,13 +113,13 @@ | |
| 113 | |
| 114 | <a id="status"></a> |
| 115 | If you reload the Admin → Notification page, the Status section at the |
| 116 | top should show: |
| 117 | |
| 118 | Outgoing Email: Piped to command "sendmail -ti" |
| 119 | Pending Alerts: 0 normal, 0 digest |
| 120 | Subscribers: 0 active, 0 total |
| 121 | |
| 122 | Before you move on to the next section, you might like to read up on |
| 123 | [some subtleties](#pipe) with the "pipe to a command" method that we did |
| 124 | not cover above. |
| 125 | |
| @@ -211,11 +211,11 @@ | |
| 211 | message below, then press "Send Message" to verify that outgoing email |
| 212 | is working. |
| 213 | |
| 214 | Another method is from the command line: |
| 215 | |
| 216 | $ fossil alerts test-message [email protected] --body README.md --subject Test |
| 217 | |
| 218 | That should send you an email with "Test" in the subject line and the |
| 219 | contents of your project's `README.md` file in the body. |
| 220 | |
| 221 | That command assumes that your project contains a "readme" file, but of |
| @@ -261,38 +261,38 @@ | |
| 261 | If email alerts aren't working, there are several useful commands you |
| 262 | can give to figure out why. |
| 263 | |
| 264 | (Be sure to [`cd` into a repo checkout directory](#cd) first!) |
| 265 | |
| 266 | $ fossil alerts status |
| 267 | |
| 268 | This should give much the same information as you saw [above](#status). |
| 269 | One difference is that, since you've created a forum post, the |
| 270 | `pending-alerts` value should only be zero if you did in fact get the |
| 271 | requested email alert. If it's zero, check your mailer's spam folder. If |
| 272 | it's nonzero, continue with these troubleshooting steps. |
| 273 | |
| 274 | $ fossil backoffice |
| 275 | |
| 276 | That forces Fossil to run its ["back office" process](./backoffice.md). |
| 277 | Its only purpose at the time of this writing is to push out alert |
| 278 | emails, but it might do other things later. Sometimes it can get stuck |
| 279 | and needs to be kicked. For that reason, you might want to set up a |
| 280 | crontab entry to make sure it runs occasionally. |
| 281 | |
| 282 | $ fossil alerts send |
| 283 | |
| 284 | This should also kick off the backoffice processing, if there are any |
| 285 | pending alerts to send out. |
| 286 | |
| 287 | $ fossil alert pending |
| 288 | |
| 289 | Show any pending alerts. The number of lines output here should equal |
| 290 | the [status output above](#status). |
| 291 | |
| 292 | $ fossil test-add-alerts f5900 |
| 293 | $ fossil alert send |
| 294 | |
| 295 | Manually create an email alert and push it out immediately. |
| 296 | |
| 297 | The `f` in the first command's final parameter means you're scheduling a |
| 298 | "forum" alert. The integer is the ID of a forum post, which you can find |
| @@ -299,11 +299,11 @@ | |
| 299 | by visiting `/timeline?showid` on your Fossil instance. |
| 300 | |
| 301 | The second command above is necessary because the `test-add-alerts` |
| 302 | command doesn't kick off a backoffice run. |
| 303 | |
| 304 | $ fossil ale send |
| 305 | |
| 306 | This only does the same thing as the final command above, rather than |
| 307 | send you an ale, as you might be hoping. Sorry. |
| 308 | |
| 309 | |
| @@ -421,11 +421,11 @@ | |
| 421 | |
| 422 | You can start this Tcl script as a daemon automatically on most Unix and |
| 423 | Unix-like systems by adding the following line to the `/etc/rc.local` |
| 424 | file of the server that hosts the repository sending email alerts: |
| 425 | |
| 426 | /usr/bin/tclsh /home/www/fossil/email-sender.tcl & |
| 427 | |
| 428 | [cj]: https://en.wikipedia.org/wiki/Chroot |
| 429 | [rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations |
| 430 | |
| 431 | |
| @@ -680,11 +680,11 @@ | |
| 680 | far as I can see. |
| 681 | |
| 682 | If the `subscriberCodes` for a Fossil repository are ever compromised, |
| 683 | new ones can be generated as follows: |
| 684 | |
| 685 | UPDATE subscriber SET subscriberCode=randomblob(32); |
| 686 | |
| 687 | Since this then affects all new email alerts going out from Fossil, your |
| 688 | end users may never even realize that they're getting new codes, as long |
| 689 | as they don't click on the URLs in the footer of old alert messages. |
| 690 | |
| 691 |
| --- www/alerts.md | |
| +++ www/alerts.md | |
| @@ -91,15 +91,15 @@ | |
| 91 | |
| 92 | Save your changes. |
| 93 | |
| 94 | At the command line, say |
| 95 | |
| 96 | $ fossil set email-send-command |
| 97 | |
| 98 | If that gives a blank value instead of `sendmail -ti`, say |
| 99 | |
| 100 | $ fossil set email-send-command "sendmail -ti" |
| 101 | |
| 102 | to force the setting. That works around a [known |
| 103 | bug](https://fossil-scm.org/forum/forumpost/840b676410) which may be |
| 104 | squished by the time you read this. |
| 105 | |
| @@ -113,13 +113,13 @@ | |
| 113 | |
| 114 | <a id="status"></a> |
| 115 | If you reload the Admin → Notification page, the Status section at the |
| 116 | top should show: |
| 117 | |
| 118 | Outgoing Email: Piped to command "sendmail -ti" |
| 119 | Pending Alerts: 0 normal, 0 digest |
| 120 | Subscribers: 0 active, 0 total |
| 121 | |
| 122 | Before you move on to the next section, you might like to read up on |
| 123 | [some subtleties](#pipe) with the "pipe to a command" method that we did |
| 124 | not cover above. |
| 125 | |
| @@ -211,11 +211,11 @@ | |
| 211 | message below, then press "Send Message" to verify that outgoing email |
| 212 | is working. |
| 213 | |
| 214 | Another method is from the command line: |
| 215 | |
| 216 | $ fossil alerts test-message [email protected] --body README.md --subject Test |
| 217 | |
| 218 | That should send you an email with "Test" in the subject line and the |
| 219 | contents of your project's `README.md` file in the body. |
| 220 | |
| 221 | That command assumes that your project contains a "readme" file, but of |
| @@ -261,38 +261,38 @@ | |
| 261 | If email alerts aren't working, there are several useful commands you |
| 262 | can give to figure out why. |
| 263 | |
| 264 | (Be sure to [`cd` into a repo checkout directory](#cd) first!) |
| 265 | |
| 266 | $ fossil alerts status |
| 267 | |
| 268 | This should give much the same information as you saw [above](#status). |
| 269 | One difference is that, since you've created a forum post, the |
| 270 | `pending-alerts` value should only be zero if you did in fact get the |
| 271 | requested email alert. If it's zero, check your mailer's spam folder. If |
| 272 | it's nonzero, continue with these troubleshooting steps. |
| 273 | |
| 274 | $ fossil backoffice |
| 275 | |
| 276 | That forces Fossil to run its ["back office" process](./backoffice.md). |
| 277 | Its only purpose at the time of this writing is to push out alert |
| 278 | emails, but it might do other things later. Sometimes it can get stuck |
| 279 | and needs to be kicked. For that reason, you might want to set up a |
| 280 | crontab entry to make sure it runs occasionally. |
| 281 | |
| 282 | $ fossil alerts send |
| 283 | |
| 284 | This should also kick off the backoffice processing, if there are any |
| 285 | pending alerts to send out. |
| 286 | |
| 287 | $ fossil alert pending |
| 288 | |
| 289 | Show any pending alerts. The number of lines output here should equal |
| 290 | the [status output above](#status). |
| 291 | |
| 292 | $ fossil test-add-alerts f5900 |
| 293 | $ fossil alert send |
| 294 | |
| 295 | Manually create an email alert and push it out immediately. |
| 296 | |
| 297 | The `f` in the first command's final parameter means you're scheduling a |
| 298 | "forum" alert. The integer is the ID of a forum post, which you can find |
| @@ -299,11 +299,11 @@ | |
| 299 | by visiting `/timeline?showid` on your Fossil instance. |
| 300 | |
| 301 | The second command above is necessary because the `test-add-alerts` |
| 302 | command doesn't kick off a backoffice run. |
| 303 | |
| 304 | $ fossil ale send |
| 305 | |
| 306 | This only does the same thing as the final command above, rather than |
| 307 | send you an ale, as you might be hoping. Sorry. |
| 308 | |
| 309 | |
| @@ -421,11 +421,11 @@ | |
| 421 | |
| 422 | You can start this Tcl script as a daemon automatically on most Unix and |
| 423 | Unix-like systems by adding the following line to the `/etc/rc.local` |
| 424 | file of the server that hosts the repository sending email alerts: |
| 425 | |
| 426 | /usr/bin/tclsh /home/www/fossil/email-sender.tcl & |
| 427 | |
| 428 | [cj]: https://en.wikipedia.org/wiki/Chroot |
| 429 | [rdbc]: https://www.sqlite.org/howtocorrupt.html#_filesystems_with_broken_or_missing_lock_implementations |
| 430 | |
| 431 | |
| @@ -680,11 +680,11 @@ | |
| 680 | far as I can see. |
| 681 | |
| 682 | If the `subscriberCodes` for a Fossil repository are ever compromised, |
| 683 | new ones can be generated as follows: |
| 684 | |
| 685 | UPDATE subscriber SET subscriberCode=randomblob(32); |
| 686 | |
| 687 | Since this then affects all new email alerts going out from Fossil, your |
| 688 | end users may never even realize that they're getting new codes, as long |
| 689 | as they don't click on the URLs in the footer of old alert messages. |
| 690 | |
| 691 |
+2
-2
| --- www/backup.md | ||
| +++ www/backup.md | ||
| @@ -262,12 +262,12 @@ | ||
| 262 | 262 | than give up on the security afforded by use of configurable-iteration |
| 263 | 263 | PBKDF2. To avoid a conflict with the platform’s `openssl` binary, |
| 264 | 264 | Homebrew’s installation is [unlinked][hbul] by default, so you have to |
| 265 | 265 | give an explicit path to it, one of: |
| 266 | 266 | |
| 267 | - /usr/local/opt/openssl/bin/openssl ... # Intel x86 Macs | |
| 268 | - /opt/homebrew/opt/openssl/bin/openssl ... # ARM Macs (“Apple silicon”) | |
| 267 | + /usr/local/opt/openssl/bin/openssl ... # Intel x86 Macs | |
| 268 | + /opt/homebrew/opt/openssl/bin/openssl ... # ARM Macs (“Apple silicon”) | |
| 269 | 269 | |
| 270 | 270 | [lssl]: https://www.libressl.org/ |
| 271 | 271 | |
| 272 | 272 | |
| 273 | 273 | ## <a id="rest"></a> Restoring From An Encrypted Backup |
| 274 | 274 |
| --- www/backup.md | |
| +++ www/backup.md | |
| @@ -262,12 +262,12 @@ | |
| 262 | than give up on the security afforded by use of configurable-iteration |
| 263 | PBKDF2. To avoid a conflict with the platform’s `openssl` binary, |
| 264 | Homebrew’s installation is [unlinked][hbul] by default, so you have to |
| 265 | give an explicit path to it, one of: |
| 266 | |
| 267 | /usr/local/opt/openssl/bin/openssl ... # Intel x86 Macs |
| 268 | /opt/homebrew/opt/openssl/bin/openssl ... # ARM Macs (“Apple silicon”) |
| 269 | |
| 270 | [lssl]: https://www.libressl.org/ |
| 271 | |
| 272 | |
| 273 | ## <a id="rest"></a> Restoring From An Encrypted Backup |
| 274 |
| --- www/backup.md | |
| +++ www/backup.md | |
| @@ -262,12 +262,12 @@ | |
| 262 | than give up on the security afforded by use of configurable-iteration |
| 263 | PBKDF2. To avoid a conflict with the platform’s `openssl` binary, |
| 264 | Homebrew’s installation is [unlinked][hbul] by default, so you have to |
| 265 | give an explicit path to it, one of: |
| 266 | |
| 267 | /usr/local/opt/openssl/bin/openssl ... # Intel x86 Macs |
| 268 | /opt/homebrew/opt/openssl/bin/openssl ... # ARM Macs (“Apple silicon”) |
| 269 | |
| 270 | [lssl]: https://www.libressl.org/ |
| 271 | |
| 272 | |
| 273 | ## <a id="rest"></a> Restoring From An Encrypted Backup |
| 274 |
+37
-37
| --- www/ckout-workflows.md | ||
| +++ www/ckout-workflows.md | ||
| @@ -10,32 +10,32 @@ | ||
| 10 | 10 | ## <a id="mcw"></a> Multiple-Checkout Workflow |
| 11 | 11 | |
| 12 | 12 | With Fossil, it is routine to have multiple check-outs from the same |
| 13 | 13 | repository: |
| 14 | 14 | |
| 15 | - fossil clone https://example.com/repo /path/to/repo.fossil | |
| 16 | - | |
| 17 | - mkdir -p ~/src/my-project/trunk | |
| 18 | - cd ~/src/my-project/trunk | |
| 19 | - fossil open /path/to/repo.fossil # implicitly opens “trunk” | |
| 20 | - | |
| 21 | - mkdir ../release | |
| 22 | - cd ../release | |
| 23 | - fossil open /path/to/repo.fossil release | |
| 24 | - | |
| 25 | - mkdir ../my-other-branch | |
| 26 | - cd ../my-other-branch | |
| 27 | - fossil open /path/to/repo.fossil my-other-branch | |
| 28 | - | |
| 29 | - mkdir ../scratch | |
| 30 | - cd ../scratch | |
| 31 | - fossil open /path/to/repo.fossil abcd1234 | |
| 32 | - | |
| 33 | - mkdir ../test | |
| 34 | - cd ../test | |
| 35 | - fossil open /path/to/repo.fossil 2019-04-01 | |
| 36 | - | |
| 15 | + fossil clone https://example.com/repo /path/to/repo.fossil | |
| 16 | + | |
| 17 | + mkdir -p ~/src/my-project/trunk | |
| 18 | + cd ~/src/my-project/trunk | |
| 19 | + fossil open /path/to/repo.fossil # implicitly opens “trunk” | |
| 20 | + | |
| 21 | + mkdir ../release | |
| 22 | + cd ../release | |
| 23 | + fossil open /path/to/repo.fossil release | |
| 24 | + | |
| 25 | + mkdir ../my-other-branch | |
| 26 | + cd ../my-other-branch | |
| 27 | + fossil open /path/to/repo.fossil my-other-branch | |
| 28 | + | |
| 29 | + mkdir ../scratch | |
| 30 | + cd ../scratch | |
| 31 | + fossil open /path/to/repo.fossil abcd1234 | |
| 32 | + | |
| 33 | + mkdir ../test | |
| 34 | + cd ../test | |
| 35 | + fossil open /path/to/repo.fossil 2019-04-01 | |
| 36 | + | |
| 37 | 37 | Now you have five separate check-out directories: one each for: |
| 38 | 38 | |
| 39 | 39 | * trunk |
| 40 | 40 | * the latest tagged public release |
| 41 | 41 | * an alternate branch you’re working on |
| @@ -73,18 +73,18 @@ | ||
| 73 | 73 | |
| 74 | 74 | #### <a id="idiomatic"></a> The Idiomatic Fossil Way |
| 75 | 75 | |
| 76 | 76 | The most idiomatic way is as follows: |
| 77 | 77 | |
| 78 | - fossil clone https://example.com/repo /path/to/repo.fossil | |
| 79 | - mkdir work-dir | |
| 80 | - cd work-dir | |
| 81 | - fossil open /path/to/repo.fossil | |
| 82 | - ...work on trunk... | |
| 83 | - | |
| 84 | - fossil update my-other-branch | |
| 85 | - ...work on your other branch in the same directory... | |
| 78 | + fossil clone https://example.com/repo /path/to/repo.fossil | |
| 79 | + mkdir work-dir | |
| 80 | + cd work-dir | |
| 81 | + fossil open /path/to/repo.fossil | |
| 82 | + ...work on trunk... | |
| 83 | + | |
| 84 | + fossil update my-other-branch | |
| 85 | + ...work on your other branch in the same directory... | |
| 86 | 86 | |
| 87 | 87 | Basically, you replace the `cd` commands in the multiple checkouts |
| 88 | 88 | workflow above with `fossil up` commands. |
| 89 | 89 | |
| 90 | 90 | |
| @@ -91,13 +91,13 @@ | ||
| 91 | 91 | #### <a id="open"></a> Opening a Repository by URI |
| 92 | 92 | |
| 93 | 93 | In Fossil 2.12, we added a feature to simplify the single-worktree use |
| 94 | 94 | case: |
| 95 | 95 | |
| 96 | - mkdir work-dir | |
| 97 | - cd work-dir | |
| 98 | - fossil open https://example.com/repo | |
| 96 | + mkdir work-dir | |
| 97 | + cd work-dir | |
| 98 | + fossil open https://example.com/repo | |
| 99 | 99 | |
| 100 | 100 | Now you have “trunk” open in `work-dir`, with the repo file stored as |
| 101 | 101 | `repo.fossil` in that same directory. |
| 102 | 102 | |
| 103 | 103 | Users of Git may be surprised that it doesn’t create a directory for you |
| @@ -111,33 +111,33 @@ | ||
| 111 | 111 | |
| 112 | 112 | #### <a id="clone"></a> Git-Like Clone-and-Open |
| 113 | 113 | |
| 114 | 114 | In Fossil 2.14, we added a more Git-like alternative: |
| 115 | 115 | |
| 116 | - fossil clone https://fossil-scm.org/fossil | |
| 117 | - cd fossil | |
| 116 | + fossil clone https://fossil-scm.org/fossil | |
| 117 | + cd fossil | |
| 118 | 118 | |
| 119 | 119 | This results in a `fossil.fossil` repo DB file and a `fossil/` working |
| 120 | 120 | directory. |
| 121 | 121 | |
| 122 | 122 | Note that our `clone URI` behavior does not commingle the repo and |
| 123 | 123 | check-out, solving our major problem with the Git design. |
| 124 | 124 | |
| 125 | 125 | If you want the repo to be named something else, adjust the URL: |
| 126 | 126 | |
| 127 | - fossil clone https://fossil-scm.org/fossil/fsl | |
| 127 | + fossil clone https://fossil-scm.org/fossil/fsl | |
| 128 | 128 | |
| 129 | 129 | That gets you `fsl.fossil` checked out into `fsl/`. |
| 130 | 130 | |
| 131 | 131 | For sites where the repo isn’t served from a subdirectory like this, you |
| 132 | 132 | might need another form of the URL. For example, you might have your |
| 133 | 133 | repo served from `dev.example.com` and want it cloned as `my-project`: |
| 134 | 134 | |
| 135 | - fossil clone https://dev.example.com/repo/my-project | |
| 135 | + fossil clone https://dev.example.com/repo/my-project | |
| 136 | 136 | |
| 137 | 137 | The `/repo` addition is the key: whatever comes after is used as the |
| 138 | 138 | repository name. [See the docs][clone] for more details. |
| 139 | 139 | |
| 140 | 140 | [caod]: https://fossil-scm.org/forum/forumpost/3f143cec74 |
| 141 | 141 | [clone]: /help?cmd=clone |
| 142 | 142 | |
| 143 | 143 | <div style="height:50em" id="this-space-intentionally-left-blank"></div> |
| 144 | 144 |
| --- www/ckout-workflows.md | |
| +++ www/ckout-workflows.md | |
| @@ -10,32 +10,32 @@ | |
| 10 | ## <a id="mcw"></a> Multiple-Checkout Workflow |
| 11 | |
| 12 | With Fossil, it is routine to have multiple check-outs from the same |
| 13 | repository: |
| 14 | |
| 15 | fossil clone https://example.com/repo /path/to/repo.fossil |
| 16 | |
| 17 | mkdir -p ~/src/my-project/trunk |
| 18 | cd ~/src/my-project/trunk |
| 19 | fossil open /path/to/repo.fossil # implicitly opens “trunk” |
| 20 | |
| 21 | mkdir ../release |
| 22 | cd ../release |
| 23 | fossil open /path/to/repo.fossil release |
| 24 | |
| 25 | mkdir ../my-other-branch |
| 26 | cd ../my-other-branch |
| 27 | fossil open /path/to/repo.fossil my-other-branch |
| 28 | |
| 29 | mkdir ../scratch |
| 30 | cd ../scratch |
| 31 | fossil open /path/to/repo.fossil abcd1234 |
| 32 | |
| 33 | mkdir ../test |
| 34 | cd ../test |
| 35 | fossil open /path/to/repo.fossil 2019-04-01 |
| 36 | |
| 37 | Now you have five separate check-out directories: one each for: |
| 38 | |
| 39 | * trunk |
| 40 | * the latest tagged public release |
| 41 | * an alternate branch you’re working on |
| @@ -73,18 +73,18 @@ | |
| 73 | |
| 74 | #### <a id="idiomatic"></a> The Idiomatic Fossil Way |
| 75 | |
| 76 | The most idiomatic way is as follows: |
| 77 | |
| 78 | fossil clone https://example.com/repo /path/to/repo.fossil |
| 79 | mkdir work-dir |
| 80 | cd work-dir |
| 81 | fossil open /path/to/repo.fossil |
| 82 | ...work on trunk... |
| 83 | |
| 84 | fossil update my-other-branch |
| 85 | ...work on your other branch in the same directory... |
| 86 | |
| 87 | Basically, you replace the `cd` commands in the multiple checkouts |
| 88 | workflow above with `fossil up` commands. |
| 89 | |
| 90 | |
| @@ -91,13 +91,13 @@ | |
| 91 | #### <a id="open"></a> Opening a Repository by URI |
| 92 | |
| 93 | In Fossil 2.12, we added a feature to simplify the single-worktree use |
| 94 | case: |
| 95 | |
| 96 | mkdir work-dir |
| 97 | cd work-dir |
| 98 | fossil open https://example.com/repo |
| 99 | |
| 100 | Now you have “trunk” open in `work-dir`, with the repo file stored as |
| 101 | `repo.fossil` in that same directory. |
| 102 | |
| 103 | Users of Git may be surprised that it doesn’t create a directory for you |
| @@ -111,33 +111,33 @@ | |
| 111 | |
| 112 | #### <a id="clone"></a> Git-Like Clone-and-Open |
| 113 | |
| 114 | In Fossil 2.14, we added a more Git-like alternative: |
| 115 | |
| 116 | fossil clone https://fossil-scm.org/fossil |
| 117 | cd fossil |
| 118 | |
| 119 | This results in a `fossil.fossil` repo DB file and a `fossil/` working |
| 120 | directory. |
| 121 | |
| 122 | Note that our `clone URI` behavior does not commingle the repo and |
| 123 | check-out, solving our major problem with the Git design. |
| 124 | |
| 125 | If you want the repo to be named something else, adjust the URL: |
| 126 | |
| 127 | fossil clone https://fossil-scm.org/fossil/fsl |
| 128 | |
| 129 | That gets you `fsl.fossil` checked out into `fsl/`. |
| 130 | |
| 131 | For sites where the repo isn’t served from a subdirectory like this, you |
| 132 | might need another form of the URL. For example, you might have your |
| 133 | repo served from `dev.example.com` and want it cloned as `my-project`: |
| 134 | |
| 135 | fossil clone https://dev.example.com/repo/my-project |
| 136 | |
| 137 | The `/repo` addition is the key: whatever comes after is used as the |
| 138 | repository name. [See the docs][clone] for more details. |
| 139 | |
| 140 | [caod]: https://fossil-scm.org/forum/forumpost/3f143cec74 |
| 141 | [clone]: /help?cmd=clone |
| 142 | |
| 143 | <div style="height:50em" id="this-space-intentionally-left-blank"></div> |
| 144 |
| --- www/ckout-workflows.md | |
| +++ www/ckout-workflows.md | |
| @@ -10,32 +10,32 @@ | |
| 10 | ## <a id="mcw"></a> Multiple-Checkout Workflow |
| 11 | |
| 12 | With Fossil, it is routine to have multiple check-outs from the same |
| 13 | repository: |
| 14 | |
| 15 | fossil clone https://example.com/repo /path/to/repo.fossil |
| 16 | |
| 17 | mkdir -p ~/src/my-project/trunk |
| 18 | cd ~/src/my-project/trunk |
| 19 | fossil open /path/to/repo.fossil # implicitly opens “trunk” |
| 20 | |
| 21 | mkdir ../release |
| 22 | cd ../release |
| 23 | fossil open /path/to/repo.fossil release |
| 24 | |
| 25 | mkdir ../my-other-branch |
| 26 | cd ../my-other-branch |
| 27 | fossil open /path/to/repo.fossil my-other-branch |
| 28 | |
| 29 | mkdir ../scratch |
| 30 | cd ../scratch |
| 31 | fossil open /path/to/repo.fossil abcd1234 |
| 32 | |
| 33 | mkdir ../test |
| 34 | cd ../test |
| 35 | fossil open /path/to/repo.fossil 2019-04-01 |
| 36 | |
| 37 | Now you have five separate check-out directories: one each for: |
| 38 | |
| 39 | * trunk |
| 40 | * the latest tagged public release |
| 41 | * an alternate branch you’re working on |
| @@ -73,18 +73,18 @@ | |
| 73 | |
| 74 | #### <a id="idiomatic"></a> The Idiomatic Fossil Way |
| 75 | |
| 76 | The most idiomatic way is as follows: |
| 77 | |
| 78 | fossil clone https://example.com/repo /path/to/repo.fossil |
| 79 | mkdir work-dir |
| 80 | cd work-dir |
| 81 | fossil open /path/to/repo.fossil |
| 82 | ...work on trunk... |
| 83 | |
| 84 | fossil update my-other-branch |
| 85 | ...work on your other branch in the same directory... |
| 86 | |
| 87 | Basically, you replace the `cd` commands in the multiple checkouts |
| 88 | workflow above with `fossil up` commands. |
| 89 | |
| 90 | |
| @@ -91,13 +91,13 @@ | |
| 91 | #### <a id="open"></a> Opening a Repository by URI |
| 92 | |
| 93 | In Fossil 2.12, we added a feature to simplify the single-worktree use |
| 94 | case: |
| 95 | |
| 96 | mkdir work-dir |
| 97 | cd work-dir |
| 98 | fossil open https://example.com/repo |
| 99 | |
| 100 | Now you have “trunk” open in `work-dir`, with the repo file stored as |
| 101 | `repo.fossil` in that same directory. |
| 102 | |
| 103 | Users of Git may be surprised that it doesn’t create a directory for you |
| @@ -111,33 +111,33 @@ | |
| 111 | |
| 112 | #### <a id="clone"></a> Git-Like Clone-and-Open |
| 113 | |
| 114 | In Fossil 2.14, we added a more Git-like alternative: |
| 115 | |
| 116 | fossil clone https://fossil-scm.org/fossil |
| 117 | cd fossil |
| 118 | |
| 119 | This results in a `fossil.fossil` repo DB file and a `fossil/` working |
| 120 | directory. |
| 121 | |
| 122 | Note that our `clone URI` behavior does not commingle the repo and |
| 123 | check-out, solving our major problem with the Git design. |
| 124 | |
| 125 | If you want the repo to be named something else, adjust the URL: |
| 126 | |
| 127 | fossil clone https://fossil-scm.org/fossil/fsl |
| 128 | |
| 129 | That gets you `fsl.fossil` checked out into `fsl/`. |
| 130 | |
| 131 | For sites where the repo isn’t served from a subdirectory like this, you |
| 132 | might need another form of the URL. For example, you might have your |
| 133 | repo served from `dev.example.com` and want it cloned as `my-project`: |
| 134 | |
| 135 | fossil clone https://dev.example.com/repo/my-project |
| 136 | |
| 137 | The `/repo` addition is the key: whatever comes after is used as the |
| 138 | repository name. [See the docs][clone] for more details. |
| 139 | |
| 140 | [caod]: https://fossil-scm.org/forum/forumpost/3f143cec74 |
| 141 | [clone]: /help?cmd=clone |
| 142 | |
| 143 | <div style="height:50em" id="this-space-intentionally-left-blank"></div> |
| 144 |
+106
-166
| --- www/containers.md | ||
| +++ www/containers.md | ||
| @@ -13,20 +13,16 @@ | ||
| 13 | 13 | ## 1. Quick Start |
| 14 | 14 | |
| 15 | 15 | Fossil ships a `Dockerfile` at the top of its source tree, |
| 16 | 16 | [here][DF], which you can build like so: |
| 17 | 17 | |
| 18 | -``` | |
| 19 | - $ docker build -t fossil . | |
| 20 | -``` | |
| 18 | + $ docker build -t fossil . | |
| 21 | 19 | |
| 22 | 20 | If the image built successfully, you can create a container from it and |
| 23 | 21 | test that it runs: |
| 24 | 22 | |
| 25 | -``` | |
| 26 | - $ docker run --name fossil -p 9999:8080/tcp fossil | |
| 27 | -``` | |
| 23 | + $ docker run --name fossil -p 9999:8080/tcp fossil | |
| 28 | 24 | |
| 29 | 25 | This shows us remapping the internal TCP listening port as 9999 on the |
| 30 | 26 | host. This feature of OCI runtimes means there’s little point to using |
| 31 | 27 | the “`fossil server --port`” feature inside the container. We can let |
| 32 | 28 | Fossil default to 8080 internally, then remap it to wherever we want it |
| @@ -44,13 +40,11 @@ | ||
| 44 | 40 | with the `DCFLAGS` variable. (DB is short for “`docker build`”, and DC |
| 45 | 41 | is short for “`docker create`”, a sub-step of the “run” target.) |
| 46 | 42 | To get the custom port setting as in |
| 47 | 43 | second command above, say: |
| 48 | 44 | |
| 49 | -``` | |
| 50 | - $ make container-run DCFLAGS='-p 9999:8080/tcp' | |
| 51 | -``` | |
| 45 | + $ make container-run DCFLAGS='-p 9999:8080/tcp' | |
| 52 | 46 | |
| 53 | 47 | Contrast the raw “`docker`” commands above, which create an |
| 54 | 48 | _unversioned_ image called `fossil:latest` and from that a container |
| 55 | 49 | simply called `fossil`. The unversioned names are more convenient for |
| 56 | 50 | interactive use, while the versioned ones are good for CI/CD type |
| @@ -81,15 +75,13 @@ | ||
| 81 | 75 | ### <a id="repo-inside"></a> 2.1 Storing the Repo Inside the Container |
| 82 | 76 | |
| 83 | 77 | The simplest method is to stop the container if it was running, then |
| 84 | 78 | say: |
| 85 | 79 | |
| 86 | -``` | |
| 87 | - $ docker cp /path/to/my-project.fossil fossil:/museum/repo.fossil | |
| 88 | - $ docker start fossil | |
| 89 | - $ docker exec fossil chown -R 499 /museum | |
| 90 | -``` | |
| 80 | + $ docker cp /path/to/my-project.fossil fossil:/museum/repo.fossil | |
| 81 | + $ docker start fossil | |
| 82 | + $ docker exec fossil chown -R 499 /museum | |
| 91 | 83 | |
| 92 | 84 | That copies the local Fossil repo into the container where the server |
| 93 | 85 | expects to find it, so that the “start” command causes it to serve from |
| 94 | 86 | that copied-in file instead. Since it lives atop the immutable base |
| 95 | 87 | layers, it persists as part of the container proper, surviving restarts. |
| @@ -120,17 +112,15 @@ | ||
| 120 | 112 | designed to be killed off at the slightest cause, rebuilt, and |
| 121 | 113 | redeployed. If you do that with the repo inside the container, it gets |
| 122 | 114 | destroyed, too. The solution is to replace the “run” command above with |
| 123 | 115 | the following: |
| 124 | 116 | |
| 125 | -``` | |
| 126 | - $ docker run \ | |
| 127 | - --publish 9999:8080 \ | |
| 128 | - --name fossil-bind-mount \ | |
| 129 | - --volume ~/museum:/museum \ | |
| 130 | - fossil | |
| 131 | -``` | |
| 117 | + $ docker run \ | |
| 118 | + --publish 9999:8080 \ | |
| 119 | + --name fossil-bind-mount \ | |
| 120 | + --volume ~/museum:/museum \ | |
| 121 | + fossil | |
| 132 | 122 | |
| 133 | 123 | Because this bind mount maps a host-side directory (`~/museum`) into the |
| 134 | 124 | container, you don’t need to `docker cp` the repo into the container at |
| 135 | 125 | all. It still expects to find the repository as `repo.fossil` under that |
| 136 | 126 | directory, but now both the host and the container can see that repo DB. |
| @@ -151,13 +141,11 @@ | ||
| 151 | 141 | You might be aware that OCI containers allow mapping a single file into |
| 152 | 142 | the repository rather than a whole directory. Since Fossil repositories |
| 153 | 143 | are specially-formatted SQLite databases, you might be wondering why we |
| 154 | 144 | don’t say things like: |
| 155 | 145 | |
| 156 | -``` | |
| 157 | - --volume ~/museum/my-project.fossil:/museum/repo.fossil | |
| 158 | -``` | |
| 146 | + --volume ~/museum/my-project.fossil:/museum/repo.fossil | |
| 159 | 147 | |
| 160 | 148 | That lets us have a convenient file name for the project outside the |
| 161 | 149 | container while letting the configuration inside the container refer to |
| 162 | 150 | the generic “`/museum/repo.fossil`” name. Why should we have to name |
| 163 | 151 | the repo generically on the outside merely to placate the container? |
| @@ -292,21 +280,19 @@ | ||
| 292 | 280 | |
| 293 | 281 | All together, we recommend adding the following options to your |
| 294 | 282 | “`docker run`” commands, as well as to any “`docker create`” command |
| 295 | 283 | that will be followed by “`docker start`”: |
| 296 | 284 | |
| 297 | -``` | |
| 298 | - --cap-drop AUDIT_WRITE \ | |
| 299 | - --cap-drop CHOWN \ | |
| 300 | - --cap-drop FSETID \ | |
| 301 | - --cap-drop KILL \ | |
| 302 | - --cap-drop MKNOD \ | |
| 303 | - --cap-drop NET_BIND_SERVICE \ | |
| 304 | - --cap-drop NET_RAW \ | |
| 305 | - --cap-drop SETFCAP \ | |
| 306 | - --cap-drop SETPCAP | |
| 307 | -``` | |
| 285 | + --cap-drop AUDIT_WRITE \ | |
| 286 | + --cap-drop CHOWN \ | |
| 287 | + --cap-drop FSETID \ | |
| 288 | + --cap-drop KILL \ | |
| 289 | + --cap-drop MKNOD \ | |
| 290 | + --cap-drop NET_BIND_SERVICE \ | |
| 291 | + --cap-drop NET_RAW \ | |
| 292 | + --cap-drop SETFCAP \ | |
| 293 | + --cap-drop SETPCAP | |
| 308 | 294 | |
| 309 | 295 | In the next section, we’ll show a case where you create a container |
| 310 | 296 | without ever running it, making these options pointless. |
| 311 | 297 | |
| 312 | 298 | [backoffice]: ./backoffice.md |
| @@ -326,16 +312,14 @@ | ||
| 326 | 312 | modern Linux distros make this [surprisingly difficult][lsl], but Alpine’s |
| 327 | 313 | back-to-basics nature makes static builds work the way they used to, |
| 328 | 314 | back in the day. If that’s all you’re after, you can do so as easily as |
| 329 | 315 | this: |
| 330 | 316 | |
| 331 | -``` | |
| 332 | - $ docker build -t fossil . | |
| 333 | - $ docker create --name fossil-static-tmp fossil | |
| 334 | - $ docker cp fossil-static-tmp:/bin/fossil . | |
| 335 | - $ docker container rm fossil-static-tmp | |
| 336 | -``` | |
| 317 | + $ docker build -t fossil . | |
| 318 | + $ docker create --name fossil-static-tmp fossil | |
| 319 | + $ docker cp fossil-static-tmp:/bin/fossil . | |
| 320 | + $ docker container rm fossil-static-tmp | |
| 337 | 321 | |
| 338 | 322 | The result is six or seven megs, depending on the CPU architecture you |
| 339 | 323 | build for. It’s built stripped. |
| 340 | 324 | |
| 341 | 325 | [lsl]: https://stackoverflow.com/questions/3430400/linux-static-linking-is-dead |
| @@ -347,19 +331,15 @@ | ||
| 347 | 331 | |
| 348 | 332 | The default version of Fossil fetched in the build is the version in the |
| 349 | 333 | checkout directory at the time you run it. You could override it to get |
| 350 | 334 | a release build like so: |
| 351 | 335 | |
| 352 | -``` | |
| 353 | - $ docker build -t fossil --build-arg FSLVER=version-2.20 . | |
| 354 | -``` | |
| 336 | + $ docker build -t fossil --build-arg FSLVER=version-2.20 . | |
| 355 | 337 | |
| 356 | 338 | Or equivalently, using Fossil’s `Makefile` convenience target: |
| 357 | 339 | |
| 358 | -``` | |
| 359 | - $ make container-image DBFLAGS='--build-arg FSLVER=version-2.20' | |
| 360 | -``` | |
| 340 | + $ make container-image DBFLAGS='--build-arg FSLVER=version-2.20' | |
| 361 | 341 | |
| 362 | 342 | While you could instead use the generic |
| 363 | 343 | “`release`” tag here, it’s better to use a specific version number |
| 364 | 344 | since container builders cache downloaded files, hoping to |
| 365 | 345 | reuse them across builds. If you ask for “`release`” before a new |
| @@ -384,13 +364,11 @@ | ||
| 384 | 364 | 500 and went *down* one instead to reduce the chance of a conflict to as |
| 385 | 365 | close to zero as we can manage. |
| 386 | 366 | |
| 387 | 367 | To change it to something else, say: |
| 388 | 368 | |
| 389 | -``` | |
| 390 | - $ make container-image DBFLAGS='--build-arg UID=501' | |
| 391 | -``` | |
| 369 | + $ make container-image DBFLAGS='--build-arg UID=501' | |
| 392 | 370 | |
| 393 | 371 | This is particularly useful if you’re putting your repository on a |
| 394 | 372 | separate volume since the IDs “leak” out into the host environment via |
| 395 | 373 | file permissions. You may therefore wish them to mean something on both |
| 396 | 374 | sides of the container barrier rather than have “499” appear on the host |
| @@ -403,25 +381,21 @@ | ||
| 403 | 381 | for use of any OCI container system that implements the same interfaces. |
| 404 | 382 | We go into more details about this [below](#light), but |
| 405 | 383 | for now, it suffices to point out that you can switch to Podman while |
| 406 | 384 | using our `Makefile` convenience targets unchanged by saying: |
| 407 | 385 | |
| 408 | -``` | |
| 409 | 386 | $ make CENGINE=podman container-run |
| 410 | -``` | |
| 411 | 387 | |
| 412 | 388 | |
| 413 | 389 | ### 5.4 <a id="config"></a>Fossil Configuration Options |
| 414 | 390 | |
| 415 | 391 | You can use this same mechanism to enable non-default Fossil |
| 416 | 392 | configuration options in your build. For instance, to turn on |
| 417 | 393 | the JSON API and the TH1 docs extension: |
| 418 | 394 | |
| 419 | -``` | |
| 420 | - $ make container-image \ | |
| 421 | - DBFLAGS='--build-arg FSLCFG="--json --with-th1-docs"' | |
| 422 | -``` | |
| 395 | + $ make container-image \ | |
| 396 | + DBFLAGS='--build-arg FSLCFG="--json --with-th1-docs"' | |
| 423 | 397 | |
| 424 | 398 | If you also wanted [the Tcl evaluation extension](./th1.md#tclEval), |
| 425 | 399 | that brings us to [the next point](#run). |
| 426 | 400 | |
| 427 | 401 | |
| @@ -429,20 +403,20 @@ | ||
| 429 | 403 | |
| 430 | 404 | If you want a basic shell environment for temporary debugging of the |
| 431 | 405 | running container, that’s easily added. Simply change this line in the |
| 432 | 406 | `Dockerfile`… |
| 433 | 407 | |
| 434 | - FROM scratch AS run | |
| 408 | + FROM scratch AS run | |
| 435 | 409 | |
| 436 | 410 | …to this: |
| 437 | 411 | |
| 438 | - FROM busybox AS run | |
| 412 | + FROM busybox AS run | |
| 439 | 413 | |
| 440 | 414 | Rebuild and redeploy to give your Fossil container a [BusyBox]-based |
| 441 | 415 | shell environment that you can get into via: |
| 442 | 416 | |
| 443 | - $ docker exec -it -u fossil $(make container-version) sh | |
| 417 | + $ docker exec -it -u fossil $(make container-version) sh | |
| 444 | 418 | |
| 445 | 419 | That command assumes you built it via “`make container`” and are |
| 446 | 420 | therefore using its versioning scheme. |
| 447 | 421 | |
| 448 | 422 | You will likely want to remove the `PATH` override in the “RUN” stage |
| @@ -463,11 +437,10 @@ | ||
| 463 | 437 | most popular programming languages in the world, we have many options |
| 464 | 438 | for achieving this. For instance, there is a whole class of |
| 465 | 439 | “[distroless]” images that will do this efficiently by changing |
| 466 | 440 | “`STAGE 2`” in the `Dockefile` to this: |
| 467 | 441 | |
| 468 | -``` | |
| 469 | 442 | ## --------------------------------------------------------------------- |
| 470 | 443 | ## STAGE 2: Pare that back to the bare essentials, plus Python. |
| 471 | 444 | ## --------------------------------------------------------------------- |
| 472 | 445 | FROM cgr.dev/chainguard/python:latest |
| 473 | 446 | USER root |
| @@ -478,24 +451,21 @@ | ||
| 478 | 451 | RUN [ "/bin/busybox", "--install", "/bin" ] |
| 479 | 452 | RUN set -x \ |
| 480 | 453 | && echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \ |
| 481 | 454 | && echo "fossil:x:${UID}:fossil" >> /etc/group \ |
| 482 | 455 | && install -d -m 700 -o fossil -g fossil log museum |
| 483 | -``` | |
| 484 | 456 | |
| 485 | 457 | You will also have to add `busybox-static` to the APK package list in |
| 486 | 458 | STAGE 1 for the `RUN` script at the end of that stage to work, since the |
| 487 | 459 | [Chainguard Python image][cgimgs] lacks a shell, on purpose. The need to |
| 488 | 460 | install root-level binaries is why we change `USER` temporarily here. |
| 489 | 461 | |
| 490 | 462 | Build it and test that it works like so: |
| 491 | 463 | |
| 492 | -``` | |
| 493 | 464 | $ make container-run && |
| 494 | 465 | docker exec -i $(make container-version) python --version |
| 495 | 466 | 3.11.2 |
| 496 | -``` | |
| 497 | 467 | |
| 498 | 468 | The compensation for the hassle of using Chainguard over something more |
| 499 | 469 | general purpose like changing the `run` layer to Alpine and then adding |
| 500 | 470 | a “`apk add python`” command to the `Dockerfile` |
| 501 | 471 | is huge: we no longer leave a package manager sitting around inside the |
| @@ -555,11 +525,10 @@ | ||
| 555 | 525 | into this, [enable linger |
| 556 | 526 | mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).) |
| 557 | 527 | so I was able to create a unit file called |
| 558 | 528 | `~/.local/share/systemd/user/[email protected]` with these contents: |
| 559 | 529 | |
| 560 | -``` | |
| 561 | 530 | [Unit] |
| 562 | 531 | Description=Fossil email alert sender for %I |
| 563 | 532 | |
| 564 | 533 | [Service] |
| 565 | 534 | WorkingDirectory=/home/fossil/museum |
| @@ -567,20 +536,17 @@ | ||
| 567 | 536 | Restart=always |
| 568 | 537 | RestartSec=3 |
| 569 | 538 | |
| 570 | 539 | [Install] |
| 571 | 540 | WantedBy=default.target |
| 572 | -``` | |
| 573 | 541 | |
| 574 | 542 | I was then able to enable email alert forwarding for select repositories |
| 575 | 543 | after configuring them per [the docs](./alerts.md) by saying: |
| 576 | 544 | |
| 577 | -``` | |
| 578 | 545 | $ systemctl --user daemon-reload |
| 579 | 546 | $ systemctl --user enable alert-sender@myproject |
| 580 | 547 | $ systemctl --user start alert-sender@myproject |
| 581 | -``` | |
| 582 | 548 | |
| 583 | 549 | Because this is a parameterized script and we’ve set our repository |
| 584 | 550 | paths predictably, you can do this for as many repositories as you need |
| 585 | 551 | to by passing their names after the “`@`” sign in the commands above. |
| 586 | 552 | |
| @@ -606,13 +572,11 @@ | ||
| 606 | 572 | For the sake of simple examples in this section, we’ll assume you’re |
| 607 | 573 | integrating Fossil into a larger web site, such as with our [Debian + |
| 608 | 574 | nginx + TLS][DNT] plan. This is why all of the examples below create |
| 609 | 575 | the container with this option: |
| 610 | 576 | |
| 611 | -``` | |
| 612 | - --publish 127.0.0.1:9999:8080 | |
| 613 | -``` | |
| 577 | + --publish 127.0.0.1:9999:8080 | |
| 614 | 578 | |
| 615 | 579 | The assumption is that there’s a reverse proxy running somewhere that |
| 616 | 580 | redirects public web hits to localhost port 9999, which in turn goes to |
| 617 | 581 | port 8080 inside the container. This use of port |
| 618 | 582 | publishing effectively replaces the use of the |
| @@ -678,14 +642,12 @@ | ||
| 678 | 642 | tenth the size of Docker Engine. |
| 679 | 643 | |
| 680 | 644 | For our purposes here, the only thing that changes relative to the |
| 681 | 645 | examples at the top of this document are the initial command: |
| 682 | 646 | |
| 683 | -``` | |
| 684 | - $ podman build -t fossil . | |
| 685 | - $ podman run --name fossil -p 9999:8080/tcp fossil | |
| 686 | -``` | |
| 647 | + $ podman build -t fossil . | |
| 648 | + $ podman run --name fossil -p 9999:8080/tcp fossil | |
| 687 | 649 | |
| 688 | 650 | Your Linux package repo may have a `podman-docker` package which |
| 689 | 651 | provides a “`docker`” script that calls “`podman`” for you, eliminating |
| 690 | 652 | even the command name difference. With that installed, the `make` |
| 691 | 653 | commands above will work with Podman as-is. |
| @@ -692,23 +654,21 @@ | ||
| 692 | 654 | |
| 693 | 655 | The only difference that matters here is that Podman doesn’t have the |
| 694 | 656 | same [default Linux kernel capability set](#caps) as Docker, which |
| 695 | 657 | affects the `--cap-drop` flags recommended above to: |
| 696 | 658 | |
| 697 | -``` | |
| 698 | - $ podman create \ | |
| 699 | - --name fossil \ | |
| 700 | - --cap-drop CHOWN \ | |
| 701 | - --cap-drop FSETID \ | |
| 702 | - --cap-drop KILL \ | |
| 703 | - --cap-drop NET_BIND_SERVICE \ | |
| 704 | - --cap-drop SETFCAP \ | |
| 705 | - --cap-drop SETPCAP \ | |
| 706 | - --publish 127.0.0.1:9999:8080 \ | |
| 707 | - localhost/fossil | |
| 708 | - $ podman start fossil | |
| 709 | -``` | |
| 659 | + $ podman create \ | |
| 660 | + --name fossil \ | |
| 661 | + --cap-drop CHOWN \ | |
| 662 | + --cap-drop FSETID \ | |
| 663 | + --cap-drop KILL \ | |
| 664 | + --cap-drop NET_BIND_SERVICE \ | |
| 665 | + --cap-drop SETFCAP \ | |
| 666 | + --cap-drop SETPCAP \ | |
| 667 | + --publish 127.0.0.1:9999:8080 \ | |
| 668 | + localhost/fossil | |
| 669 | + $ podman start fossil | |
| 710 | 670 | |
| 711 | 671 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 712 | 672 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 713 | 673 | [Podman]: https://podman.io/ |
| 714 | 674 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| @@ -720,13 +680,11 @@ | ||
| 720 | 680 | If even the Podman stack is too big for you, the next-best option I’m |
| 721 | 681 | aware of is the `systemd-container` infrastructure on modern Linuxes, |
| 722 | 682 | available since version 239 or so. Its runtime tooling requires only |
| 723 | 683 | about 1.4 MiB of disk space: |
| 724 | 684 | |
| 725 | -``` | |
| 726 | - $ sudo apt install systemd-container btrfs-tools | |
| 727 | -``` | |
| 685 | + $ sudo apt install systemd-container btrfs-tools | |
| 728 | 686 | |
| 729 | 687 | That command assumes the primary test environment for |
| 730 | 688 | this guide, Ubuntu 22.04 LTS with `systemd` 249. For best |
| 731 | 689 | results, `/var/lib/machines` should be a btrfs volume, because |
| 732 | 690 | [`$REASONS`][mcfad]. For CentOS Stream 9 and other Red Hattish |
| @@ -742,60 +700,54 @@ | ||
| 742 | 700 | If you use [the stock `Dockerfile`][DF] to generate your |
| 743 | 701 | base image, `nspawn` won’t recognize it as containing an OS unless you |
| 744 | 702 | change the “`FROM scratch AS os`” line at the top of the second stage |
| 745 | 703 | to something like this: |
| 746 | 704 | |
| 747 | -``` | |
| 748 | - FROM gcr.io/distroless/static-debian11 AS os | |
| 749 | -``` | |
| 705 | + FROM gcr.io/distroless/static-debian11 AS os | |
| 750 | 706 | |
| 751 | 707 | Using that as a base image provides all the files `nspawn` checks for to |
| 752 | 708 | determine whether the container is sufficiently close to a Linux VM for |
| 753 | 709 | the following step to proceed: |
| 754 | 710 | |
| 755 | -``` | |
| 756 | - $ make container | |
| 757 | - $ docker container export $(make container-version) | | |
| 758 | - machinectl import-tar - myproject | |
| 759 | -``` | |
| 711 | + $ make container | |
| 712 | + $ docker container export $(make container-version) | | |
| 713 | + machinectl import-tar - myproject | |
| 760 | 714 | |
| 761 | 715 | Next, create `/etc/systemd/nspawn/myproject.nspawn`: |
| 762 | 716 | |
| 763 | 717 | ---- |
| 764 | 718 | |
| 765 | -``` | |
| 766 | -[Exec] | |
| 767 | -WorkingDirectory=/ | |
| 768 | -Parameters=bin/fossil server \ | |
| 769 | - --baseurl https://example.com/myproject \ | |
| 770 | - --create \ | |
| 771 | - --jsmode bundled \ | |
| 772 | - --localhost \ | |
| 773 | - --port 9000 \ | |
| 774 | - --scgi \ | |
| 775 | - --user admin \ | |
| 776 | - museum/repo.fossil | |
| 777 | -DropCapability= \ | |
| 778 | - CAP_AUDIT_WRITE \ | |
| 779 | - CAP_CHOWN \ | |
| 780 | - CAP_FSETID \ | |
| 781 | - CAP_KILL \ | |
| 782 | - CAP_MKNOD \ | |
| 783 | - CAP_NET_BIND_SERVICE \ | |
| 784 | - CAP_NET_RAW \ | |
| 785 | - CAP_SETFCAP \ | |
| 786 | - CAP_SETPCAP | |
| 787 | -ProcessTwo=yes | |
| 788 | -LinkJournal=no | |
| 789 | -Timezone=no | |
| 790 | - | |
| 791 | -[Files] | |
| 792 | -Bind=/home/fossil/museum/myproject:/museum | |
| 793 | - | |
| 794 | -[Network] | |
| 795 | -VirtualEthernet=no | |
| 796 | -``` | |
| 719 | + [Exec] | |
| 720 | + WorkingDirectory=/ | |
| 721 | + Parameters=bin/fossil server \ | |
| 722 | + --baseurl https://example.com/myproject \ | |
| 723 | + --create \ | |
| 724 | + --jsmode bundled \ | |
| 725 | + --localhost \ | |
| 726 | + --port 9000 \ | |
| 727 | + --scgi \ | |
| 728 | + --user admin \ | |
| 729 | + museum/repo.fossil | |
| 730 | + DropCapability= \ | |
| 731 | + CAP_AUDIT_WRITE \ | |
| 732 | + CAP_CHOWN \ | |
| 733 | + CAP_FSETID \ | |
| 734 | + CAP_KILL \ | |
| 735 | + CAP_MKNOD \ | |
| 736 | + CAP_NET_BIND_SERVICE \ | |
| 737 | + CAP_NET_RAW \ | |
| 738 | + CAP_SETFCAP \ | |
| 739 | + CAP_SETPCAP | |
| 740 | + ProcessTwo=yes | |
| 741 | + LinkJournal=no | |
| 742 | + Timezone=no | |
| 743 | + | |
| 744 | + [Files] | |
| 745 | + Bind=/home/fossil/museum/myproject:/museum | |
| 746 | + | |
| 747 | + [Network] | |
| 748 | + VirtualEthernet=no | |
| 797 | 749 | |
| 798 | 750 | ---- |
| 799 | 751 | |
| 800 | 752 | If you recognize most of that from the `Dockerfile` discussion above, |
| 801 | 753 | congratulations, you’ve been paying attention. The rest should also |
| @@ -819,22 +771,20 @@ | ||
| 819 | 771 | That being done, we also need a generic `systemd` unit file called |
| 820 | 772 | `/etc/systemd/system/[email protected]`, containing: |
| 821 | 773 | |
| 822 | 774 | ---- |
| 823 | 775 | |
| 824 | -``` | |
| 825 | -[Unit] | |
| 826 | -Description=Fossil %i Repo Service | |
| 827 | -[email protected] [email protected] | |
| 828 | -After=network.target systemd-resolved.service [email protected] [email protected] | |
| 829 | - | |
| 830 | -[Service] | |
| 831 | -ExecStart=systemd-nspawn --settings=override --read-only --machine=%i bin/fossil | |
| 832 | - | |
| 833 | -[Install] | |
| 834 | -WantedBy=multi-user.target | |
| 835 | -``` | |
| 776 | + [Unit] | |
| 777 | + Description=Fossil %i Repo Service | |
| 778 | + [email protected] [email protected] | |
| 779 | + After=network.target systemd-resolved.service [email protected] [email protected] | |
| 780 | + | |
| 781 | + [Service] | |
| 782 | + ExecStart=systemd-nspawn --settings=override --read-only --machine=%i bin/fossil | |
| 783 | + | |
| 784 | + [Install] | |
| 785 | + WantedBy=multi-user.target | |
| 836 | 786 | |
| 837 | 787 | ---- |
| 838 | 788 | |
| 839 | 789 | You shouldn’t have to change any of this because we’ve given the |
| 840 | 790 | `--setting=override` flag, meaning any setting in the nspawn file |
| @@ -843,42 +793,36 @@ | ||
| 843 | 793 | share the base configuration, varying on a per-repo level through |
| 844 | 794 | adjustments to their individual `*.nspawn` files. |
| 845 | 795 | |
| 846 | 796 | You may then start the service in the normal way: |
| 847 | 797 | |
| 848 | -``` | |
| 849 | - $ sudo systemctl enable fossil@myproject | |
| 850 | - $ sudo systemctl start fossil@myproject | |
| 851 | -``` | |
| 798 | + $ sudo systemctl enable fossil@myproject | |
| 799 | + $ sudo systemctl start fossil@myproject | |
| 852 | 800 | |
| 853 | 801 | You should then find it running on localhost port 9000 per the nspawn |
| 854 | 802 | configuration file above, suitable for proxying Fossil out to the |
| 855 | 803 | public using nginx via SCGI. If you aren’t using a front-end proxy |
| 856 | 804 | and want Fossil exposed to the world via HTTPS, you might say this instead in |
| 857 | 805 | the `*.nspawn` file: |
| 858 | 806 | |
| 859 | -``` | |
| 860 | -Parameters=bin/fossil server \ | |
| 861 | - --cert /path/to/cert.pem \ | |
| 862 | - --create \ | |
| 863 | - --jsmode bundled \ | |
| 864 | - --port 443 \ | |
| 865 | - --user admin \ | |
| 866 | - museum/repo.fossil | |
| 867 | -``` | |
| 807 | + Parameters=bin/fossil server \ | |
| 808 | + --cert /path/to/cert.pem \ | |
| 809 | + --create \ | |
| 810 | + --jsmode bundled \ | |
| 811 | + --port 443 \ | |
| 812 | + --user admin \ | |
| 813 | + museum/repo.fossil | |
| 868 | 814 | |
| 869 | 815 | You would also need to un-drop the `CAP_NET_BIND_SERVICE` capability |
| 870 | 816 | to allow Fossil to bind to this low-numbered port. |
| 871 | 817 | |
| 872 | 818 | We use the `systemd` template file feature to allow multiple Fossil |
| 873 | 819 | servers running on a single machine, each on a different TCP port, |
| 874 | 820 | as when proxying them out as subdirectories of a larger site. |
| 875 | 821 | To add another project, you must first clone the base “machine” layer: |
| 876 | 822 | |
| 877 | -``` | |
| 878 | - $ sudo machinectl clone myproject otherthing | |
| 879 | -``` | |
| 823 | + $ sudo machinectl clone myproject otherthing | |
| 880 | 824 | |
| 881 | 825 | That will not only create a clone of `/var/lib/machines/myproject` |
| 882 | 826 | as `../otherthing`, it will create a matching `otherthing.nspawn` file for you |
| 883 | 827 | as a copy of the first one. Adjust its contents to suit, then enable |
| 884 | 828 | and start it as above. |
| @@ -895,21 +839,17 @@ | ||
| 895 | 839 | |
| 896 | 840 | Fortunately, there are workarounds. |
| 897 | 841 | |
| 898 | 842 | First, the `apt install` command above becomes: |
| 899 | 843 | |
| 900 | -``` | |
| 901 | - $ sudo dnf install systemd-container | |
| 902 | -``` | |
| 844 | + $ sudo dnf install systemd-container | |
| 903 | 845 | |
| 904 | 846 | Second, you have to hack around the lack of `machinectl import-tar`: |
| 905 | 847 | |
| 906 | -``` | |
| 907 | - $ rootfs=/var/lib/machines/fossil | |
| 908 | - $ sudo mkdir -p $rootfs | |
| 909 | - $ docker container export fossil | sudo tar -xf -C $rootfs - | |
| 910 | -``` | |
| 848 | + $ rootfs=/var/lib/machines/fossil | |
| 849 | + $ sudo mkdir -p $rootfs | |
| 850 | + $ docker container export fossil | sudo tar -xf -C $rootfs - | |
| 911 | 851 | |
| 912 | 852 | The parent directory path in the `rootfs` variable is important, |
| 913 | 853 | because although we aren’t able to use `machinectl` on such systems, the |
| 914 | 854 | `systemd-nspawn` developers assume you’re using them together; when you give |
| 915 | 855 | `--machine`, it assumes the `machinectl` directory scheme. You could |
| 916 | 856 |
| --- www/containers.md | |
| +++ www/containers.md | |
| @@ -13,20 +13,16 @@ | |
| 13 | ## 1. Quick Start |
| 14 | |
| 15 | Fossil ships a `Dockerfile` at the top of its source tree, |
| 16 | [here][DF], which you can build like so: |
| 17 | |
| 18 | ``` |
| 19 | $ docker build -t fossil . |
| 20 | ``` |
| 21 | |
| 22 | If the image built successfully, you can create a container from it and |
| 23 | test that it runs: |
| 24 | |
| 25 | ``` |
| 26 | $ docker run --name fossil -p 9999:8080/tcp fossil |
| 27 | ``` |
| 28 | |
| 29 | This shows us remapping the internal TCP listening port as 9999 on the |
| 30 | host. This feature of OCI runtimes means there’s little point to using |
| 31 | the “`fossil server --port`” feature inside the container. We can let |
| 32 | Fossil default to 8080 internally, then remap it to wherever we want it |
| @@ -44,13 +40,11 @@ | |
| 44 | with the `DCFLAGS` variable. (DB is short for “`docker build`”, and DC |
| 45 | is short for “`docker create`”, a sub-step of the “run” target.) |
| 46 | To get the custom port setting as in |
| 47 | second command above, say: |
| 48 | |
| 49 | ``` |
| 50 | $ make container-run DCFLAGS='-p 9999:8080/tcp' |
| 51 | ``` |
| 52 | |
| 53 | Contrast the raw “`docker`” commands above, which create an |
| 54 | _unversioned_ image called `fossil:latest` and from that a container |
| 55 | simply called `fossil`. The unversioned names are more convenient for |
| 56 | interactive use, while the versioned ones are good for CI/CD type |
| @@ -81,15 +75,13 @@ | |
| 81 | ### <a id="repo-inside"></a> 2.1 Storing the Repo Inside the Container |
| 82 | |
| 83 | The simplest method is to stop the container if it was running, then |
| 84 | say: |
| 85 | |
| 86 | ``` |
| 87 | $ docker cp /path/to/my-project.fossil fossil:/museum/repo.fossil |
| 88 | $ docker start fossil |
| 89 | $ docker exec fossil chown -R 499 /museum |
| 90 | ``` |
| 91 | |
| 92 | That copies the local Fossil repo into the container where the server |
| 93 | expects to find it, so that the “start” command causes it to serve from |
| 94 | that copied-in file instead. Since it lives atop the immutable base |
| 95 | layers, it persists as part of the container proper, surviving restarts. |
| @@ -120,17 +112,15 @@ | |
| 120 | designed to be killed off at the slightest cause, rebuilt, and |
| 121 | redeployed. If you do that with the repo inside the container, it gets |
| 122 | destroyed, too. The solution is to replace the “run” command above with |
| 123 | the following: |
| 124 | |
| 125 | ``` |
| 126 | $ docker run \ |
| 127 | --publish 9999:8080 \ |
| 128 | --name fossil-bind-mount \ |
| 129 | --volume ~/museum:/museum \ |
| 130 | fossil |
| 131 | ``` |
| 132 | |
| 133 | Because this bind mount maps a host-side directory (`~/museum`) into the |
| 134 | container, you don’t need to `docker cp` the repo into the container at |
| 135 | all. It still expects to find the repository as `repo.fossil` under that |
| 136 | directory, but now both the host and the container can see that repo DB. |
| @@ -151,13 +141,11 @@ | |
| 151 | You might be aware that OCI containers allow mapping a single file into |
| 152 | the repository rather than a whole directory. Since Fossil repositories |
| 153 | are specially-formatted SQLite databases, you might be wondering why we |
| 154 | don’t say things like: |
| 155 | |
| 156 | ``` |
| 157 | --volume ~/museum/my-project.fossil:/museum/repo.fossil |
| 158 | ``` |
| 159 | |
| 160 | That lets us have a convenient file name for the project outside the |
| 161 | container while letting the configuration inside the container refer to |
| 162 | the generic “`/museum/repo.fossil`” name. Why should we have to name |
| 163 | the repo generically on the outside merely to placate the container? |
| @@ -292,21 +280,19 @@ | |
| 292 | |
| 293 | All together, we recommend adding the following options to your |
| 294 | “`docker run`” commands, as well as to any “`docker create`” command |
| 295 | that will be followed by “`docker start`”: |
| 296 | |
| 297 | ``` |
| 298 | --cap-drop AUDIT_WRITE \ |
| 299 | --cap-drop CHOWN \ |
| 300 | --cap-drop FSETID \ |
| 301 | --cap-drop KILL \ |
| 302 | --cap-drop MKNOD \ |
| 303 | --cap-drop NET_BIND_SERVICE \ |
| 304 | --cap-drop NET_RAW \ |
| 305 | --cap-drop SETFCAP \ |
| 306 | --cap-drop SETPCAP |
| 307 | ``` |
| 308 | |
| 309 | In the next section, we’ll show a case where you create a container |
| 310 | without ever running it, making these options pointless. |
| 311 | |
| 312 | [backoffice]: ./backoffice.md |
| @@ -326,16 +312,14 @@ | |
| 326 | modern Linux distros make this [surprisingly difficult][lsl], but Alpine’s |
| 327 | back-to-basics nature makes static builds work the way they used to, |
| 328 | back in the day. If that’s all you’re after, you can do so as easily as |
| 329 | this: |
| 330 | |
| 331 | ``` |
| 332 | $ docker build -t fossil . |
| 333 | $ docker create --name fossil-static-tmp fossil |
| 334 | $ docker cp fossil-static-tmp:/bin/fossil . |
| 335 | $ docker container rm fossil-static-tmp |
| 336 | ``` |
| 337 | |
| 338 | The result is six or seven megs, depending on the CPU architecture you |
| 339 | build for. It’s built stripped. |
| 340 | |
| 341 | [lsl]: https://stackoverflow.com/questions/3430400/linux-static-linking-is-dead |
| @@ -347,19 +331,15 @@ | |
| 347 | |
| 348 | The default version of Fossil fetched in the build is the version in the |
| 349 | checkout directory at the time you run it. You could override it to get |
| 350 | a release build like so: |
| 351 | |
| 352 | ``` |
| 353 | $ docker build -t fossil --build-arg FSLVER=version-2.20 . |
| 354 | ``` |
| 355 | |
| 356 | Or equivalently, using Fossil’s `Makefile` convenience target: |
| 357 | |
| 358 | ``` |
| 359 | $ make container-image DBFLAGS='--build-arg FSLVER=version-2.20' |
| 360 | ``` |
| 361 | |
| 362 | While you could instead use the generic |
| 363 | “`release`” tag here, it’s better to use a specific version number |
| 364 | since container builders cache downloaded files, hoping to |
| 365 | reuse them across builds. If you ask for “`release`” before a new |
| @@ -384,13 +364,11 @@ | |
| 384 | 500 and went *down* one instead to reduce the chance of a conflict to as |
| 385 | close to zero as we can manage. |
| 386 | |
| 387 | To change it to something else, say: |
| 388 | |
| 389 | ``` |
| 390 | $ make container-image DBFLAGS='--build-arg UID=501' |
| 391 | ``` |
| 392 | |
| 393 | This is particularly useful if you’re putting your repository on a |
| 394 | separate volume since the IDs “leak” out into the host environment via |
| 395 | file permissions. You may therefore wish them to mean something on both |
| 396 | sides of the container barrier rather than have “499” appear on the host |
| @@ -403,25 +381,21 @@ | |
| 403 | for use of any OCI container system that implements the same interfaces. |
| 404 | We go into more details about this [below](#light), but |
| 405 | for now, it suffices to point out that you can switch to Podman while |
| 406 | using our `Makefile` convenience targets unchanged by saying: |
| 407 | |
| 408 | ``` |
| 409 | $ make CENGINE=podman container-run |
| 410 | ``` |
| 411 | |
| 412 | |
| 413 | ### 5.4 <a id="config"></a>Fossil Configuration Options |
| 414 | |
| 415 | You can use this same mechanism to enable non-default Fossil |
| 416 | configuration options in your build. For instance, to turn on |
| 417 | the JSON API and the TH1 docs extension: |
| 418 | |
| 419 | ``` |
| 420 | $ make container-image \ |
| 421 | DBFLAGS='--build-arg FSLCFG="--json --with-th1-docs"' |
| 422 | ``` |
| 423 | |
| 424 | If you also wanted [the Tcl evaluation extension](./th1.md#tclEval), |
| 425 | that brings us to [the next point](#run). |
| 426 | |
| 427 | |
| @@ -429,20 +403,20 @@ | |
| 429 | |
| 430 | If you want a basic shell environment for temporary debugging of the |
| 431 | running container, that’s easily added. Simply change this line in the |
| 432 | `Dockerfile`… |
| 433 | |
| 434 | FROM scratch AS run |
| 435 | |
| 436 | …to this: |
| 437 | |
| 438 | FROM busybox AS run |
| 439 | |
| 440 | Rebuild and redeploy to give your Fossil container a [BusyBox]-based |
| 441 | shell environment that you can get into via: |
| 442 | |
| 443 | $ docker exec -it -u fossil $(make container-version) sh |
| 444 | |
| 445 | That command assumes you built it via “`make container`” and are |
| 446 | therefore using its versioning scheme. |
| 447 | |
| 448 | You will likely want to remove the `PATH` override in the “RUN” stage |
| @@ -463,11 +437,10 @@ | |
| 463 | most popular programming languages in the world, we have many options |
| 464 | for achieving this. For instance, there is a whole class of |
| 465 | “[distroless]” images that will do this efficiently by changing |
| 466 | “`STAGE 2`” in the `Dockefile` to this: |
| 467 | |
| 468 | ``` |
| 469 | ## --------------------------------------------------------------------- |
| 470 | ## STAGE 2: Pare that back to the bare essentials, plus Python. |
| 471 | ## --------------------------------------------------------------------- |
| 472 | FROM cgr.dev/chainguard/python:latest |
| 473 | USER root |
| @@ -478,24 +451,21 @@ | |
| 478 | RUN [ "/bin/busybox", "--install", "/bin" ] |
| 479 | RUN set -x \ |
| 480 | && echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \ |
| 481 | && echo "fossil:x:${UID}:fossil" >> /etc/group \ |
| 482 | && install -d -m 700 -o fossil -g fossil log museum |
| 483 | ``` |
| 484 | |
| 485 | You will also have to add `busybox-static` to the APK package list in |
| 486 | STAGE 1 for the `RUN` script at the end of that stage to work, since the |
| 487 | [Chainguard Python image][cgimgs] lacks a shell, on purpose. The need to |
| 488 | install root-level binaries is why we change `USER` temporarily here. |
| 489 | |
| 490 | Build it and test that it works like so: |
| 491 | |
| 492 | ``` |
| 493 | $ make container-run && |
| 494 | docker exec -i $(make container-version) python --version |
| 495 | 3.11.2 |
| 496 | ``` |
| 497 | |
| 498 | The compensation for the hassle of using Chainguard over something more |
| 499 | general purpose like changing the `run` layer to Alpine and then adding |
| 500 | a “`apk add python`” command to the `Dockerfile` |
| 501 | is huge: we no longer leave a package manager sitting around inside the |
| @@ -555,11 +525,10 @@ | |
| 555 | into this, [enable linger |
| 556 | mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).) |
| 557 | so I was able to create a unit file called |
| 558 | `~/.local/share/systemd/user/[email protected]` with these contents: |
| 559 | |
| 560 | ``` |
| 561 | [Unit] |
| 562 | Description=Fossil email alert sender for %I |
| 563 | |
| 564 | [Service] |
| 565 | WorkingDirectory=/home/fossil/museum |
| @@ -567,20 +536,17 @@ | |
| 567 | Restart=always |
| 568 | RestartSec=3 |
| 569 | |
| 570 | [Install] |
| 571 | WantedBy=default.target |
| 572 | ``` |
| 573 | |
| 574 | I was then able to enable email alert forwarding for select repositories |
| 575 | after configuring them per [the docs](./alerts.md) by saying: |
| 576 | |
| 577 | ``` |
| 578 | $ systemctl --user daemon-reload |
| 579 | $ systemctl --user enable alert-sender@myproject |
| 580 | $ systemctl --user start alert-sender@myproject |
| 581 | ``` |
| 582 | |
| 583 | Because this is a parameterized script and we’ve set our repository |
| 584 | paths predictably, you can do this for as many repositories as you need |
| 585 | to by passing their names after the “`@`” sign in the commands above. |
| 586 | |
| @@ -606,13 +572,11 @@ | |
| 606 | For the sake of simple examples in this section, we’ll assume you’re |
| 607 | integrating Fossil into a larger web site, such as with our [Debian + |
| 608 | nginx + TLS][DNT] plan. This is why all of the examples below create |
| 609 | the container with this option: |
| 610 | |
| 611 | ``` |
| 612 | --publish 127.0.0.1:9999:8080 |
| 613 | ``` |
| 614 | |
| 615 | The assumption is that there’s a reverse proxy running somewhere that |
| 616 | redirects public web hits to localhost port 9999, which in turn goes to |
| 617 | port 8080 inside the container. This use of port |
| 618 | publishing effectively replaces the use of the |
| @@ -678,14 +642,12 @@ | |
| 678 | tenth the size of Docker Engine. |
| 679 | |
| 680 | For our purposes here, the only thing that changes relative to the |
| 681 | examples at the top of this document are the initial command: |
| 682 | |
| 683 | ``` |
| 684 | $ podman build -t fossil . |
| 685 | $ podman run --name fossil -p 9999:8080/tcp fossil |
| 686 | ``` |
| 687 | |
| 688 | Your Linux package repo may have a `podman-docker` package which |
| 689 | provides a “`docker`” script that calls “`podman`” for you, eliminating |
| 690 | even the command name difference. With that installed, the `make` |
| 691 | commands above will work with Podman as-is. |
| @@ -692,23 +654,21 @@ | |
| 692 | |
| 693 | The only difference that matters here is that Podman doesn’t have the |
| 694 | same [default Linux kernel capability set](#caps) as Docker, which |
| 695 | affects the `--cap-drop` flags recommended above to: |
| 696 | |
| 697 | ``` |
| 698 | $ podman create \ |
| 699 | --name fossil \ |
| 700 | --cap-drop CHOWN \ |
| 701 | --cap-drop FSETID \ |
| 702 | --cap-drop KILL \ |
| 703 | --cap-drop NET_BIND_SERVICE \ |
| 704 | --cap-drop SETFCAP \ |
| 705 | --cap-drop SETPCAP \ |
| 706 | --publish 127.0.0.1:9999:8080 \ |
| 707 | localhost/fossil |
| 708 | $ podman start fossil |
| 709 | ``` |
| 710 | |
| 711 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 712 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 713 | [Podman]: https://podman.io/ |
| 714 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| @@ -720,13 +680,11 @@ | |
| 720 | If even the Podman stack is too big for you, the next-best option I’m |
| 721 | aware of is the `systemd-container` infrastructure on modern Linuxes, |
| 722 | available since version 239 or so. Its runtime tooling requires only |
| 723 | about 1.4 MiB of disk space: |
| 724 | |
| 725 | ``` |
| 726 | $ sudo apt install systemd-container btrfs-tools |
| 727 | ``` |
| 728 | |
| 729 | That command assumes the primary test environment for |
| 730 | this guide, Ubuntu 22.04 LTS with `systemd` 249. For best |
| 731 | results, `/var/lib/machines` should be a btrfs volume, because |
| 732 | [`$REASONS`][mcfad]. For CentOS Stream 9 and other Red Hattish |
| @@ -742,60 +700,54 @@ | |
| 742 | If you use [the stock `Dockerfile`][DF] to generate your |
| 743 | base image, `nspawn` won’t recognize it as containing an OS unless you |
| 744 | change the “`FROM scratch AS os`” line at the top of the second stage |
| 745 | to something like this: |
| 746 | |
| 747 | ``` |
| 748 | FROM gcr.io/distroless/static-debian11 AS os |
| 749 | ``` |
| 750 | |
| 751 | Using that as a base image provides all the files `nspawn` checks for to |
| 752 | determine whether the container is sufficiently close to a Linux VM for |
| 753 | the following step to proceed: |
| 754 | |
| 755 | ``` |
| 756 | $ make container |
| 757 | $ docker container export $(make container-version) | |
| 758 | machinectl import-tar - myproject |
| 759 | ``` |
| 760 | |
| 761 | Next, create `/etc/systemd/nspawn/myproject.nspawn`: |
| 762 | |
| 763 | ---- |
| 764 | |
| 765 | ``` |
| 766 | [Exec] |
| 767 | WorkingDirectory=/ |
| 768 | Parameters=bin/fossil server \ |
| 769 | --baseurl https://example.com/myproject \ |
| 770 | --create \ |
| 771 | --jsmode bundled \ |
| 772 | --localhost \ |
| 773 | --port 9000 \ |
| 774 | --scgi \ |
| 775 | --user admin \ |
| 776 | museum/repo.fossil |
| 777 | DropCapability= \ |
| 778 | CAP_AUDIT_WRITE \ |
| 779 | CAP_CHOWN \ |
| 780 | CAP_FSETID \ |
| 781 | CAP_KILL \ |
| 782 | CAP_MKNOD \ |
| 783 | CAP_NET_BIND_SERVICE \ |
| 784 | CAP_NET_RAW \ |
| 785 | CAP_SETFCAP \ |
| 786 | CAP_SETPCAP |
| 787 | ProcessTwo=yes |
| 788 | LinkJournal=no |
| 789 | Timezone=no |
| 790 | |
| 791 | [Files] |
| 792 | Bind=/home/fossil/museum/myproject:/museum |
| 793 | |
| 794 | [Network] |
| 795 | VirtualEthernet=no |
| 796 | ``` |
| 797 | |
| 798 | ---- |
| 799 | |
| 800 | If you recognize most of that from the `Dockerfile` discussion above, |
| 801 | congratulations, you’ve been paying attention. The rest should also |
| @@ -819,22 +771,20 @@ | |
| 819 | That being done, we also need a generic `systemd` unit file called |
| 820 | `/etc/systemd/system/[email protected]`, containing: |
| 821 | |
| 822 | ---- |
| 823 | |
| 824 | ``` |
| 825 | [Unit] |
| 826 | Description=Fossil %i Repo Service |
| 827 | [email protected] [email protected] |
| 828 | After=network.target systemd-resolved.service [email protected] [email protected] |
| 829 | |
| 830 | [Service] |
| 831 | ExecStart=systemd-nspawn --settings=override --read-only --machine=%i bin/fossil |
| 832 | |
| 833 | [Install] |
| 834 | WantedBy=multi-user.target |
| 835 | ``` |
| 836 | |
| 837 | ---- |
| 838 | |
| 839 | You shouldn’t have to change any of this because we’ve given the |
| 840 | `--setting=override` flag, meaning any setting in the nspawn file |
| @@ -843,42 +793,36 @@ | |
| 843 | share the base configuration, varying on a per-repo level through |
| 844 | adjustments to their individual `*.nspawn` files. |
| 845 | |
| 846 | You may then start the service in the normal way: |
| 847 | |
| 848 | ``` |
| 849 | $ sudo systemctl enable fossil@myproject |
| 850 | $ sudo systemctl start fossil@myproject |
| 851 | ``` |
| 852 | |
| 853 | You should then find it running on localhost port 9000 per the nspawn |
| 854 | configuration file above, suitable for proxying Fossil out to the |
| 855 | public using nginx via SCGI. If you aren’t using a front-end proxy |
| 856 | and want Fossil exposed to the world via HTTPS, you might say this instead in |
| 857 | the `*.nspawn` file: |
| 858 | |
| 859 | ``` |
| 860 | Parameters=bin/fossil server \ |
| 861 | --cert /path/to/cert.pem \ |
| 862 | --create \ |
| 863 | --jsmode bundled \ |
| 864 | --port 443 \ |
| 865 | --user admin \ |
| 866 | museum/repo.fossil |
| 867 | ``` |
| 868 | |
| 869 | You would also need to un-drop the `CAP_NET_BIND_SERVICE` capability |
| 870 | to allow Fossil to bind to this low-numbered port. |
| 871 | |
| 872 | We use the `systemd` template file feature to allow multiple Fossil |
| 873 | servers running on a single machine, each on a different TCP port, |
| 874 | as when proxying them out as subdirectories of a larger site. |
| 875 | To add another project, you must first clone the base “machine” layer: |
| 876 | |
| 877 | ``` |
| 878 | $ sudo machinectl clone myproject otherthing |
| 879 | ``` |
| 880 | |
| 881 | That will not only create a clone of `/var/lib/machines/myproject` |
| 882 | as `../otherthing`, it will create a matching `otherthing.nspawn` file for you |
| 883 | as a copy of the first one. Adjust its contents to suit, then enable |
| 884 | and start it as above. |
| @@ -895,21 +839,17 @@ | |
| 895 | |
| 896 | Fortunately, there are workarounds. |
| 897 | |
| 898 | First, the `apt install` command above becomes: |
| 899 | |
| 900 | ``` |
| 901 | $ sudo dnf install systemd-container |
| 902 | ``` |
| 903 | |
| 904 | Second, you have to hack around the lack of `machinectl import-tar`: |
| 905 | |
| 906 | ``` |
| 907 | $ rootfs=/var/lib/machines/fossil |
| 908 | $ sudo mkdir -p $rootfs |
| 909 | $ docker container export fossil | sudo tar -xf -C $rootfs - |
| 910 | ``` |
| 911 | |
| 912 | The parent directory path in the `rootfs` variable is important, |
| 913 | because although we aren’t able to use `machinectl` on such systems, the |
| 914 | `systemd-nspawn` developers assume you’re using them together; when you give |
| 915 | `--machine`, it assumes the `machinectl` directory scheme. You could |
| 916 |
| --- www/containers.md | |
| +++ www/containers.md | |
| @@ -13,20 +13,16 @@ | |
| 13 | ## 1. Quick Start |
| 14 | |
| 15 | Fossil ships a `Dockerfile` at the top of its source tree, |
| 16 | [here][DF], which you can build like so: |
| 17 | |
| 18 | $ docker build -t fossil . |
| 19 | |
| 20 | If the image built successfully, you can create a container from it and |
| 21 | test that it runs: |
| 22 | |
| 23 | $ docker run --name fossil -p 9999:8080/tcp fossil |
| 24 | |
| 25 | This shows us remapping the internal TCP listening port as 9999 on the |
| 26 | host. This feature of OCI runtimes means there’s little point to using |
| 27 | the “`fossil server --port`” feature inside the container. We can let |
| 28 | Fossil default to 8080 internally, then remap it to wherever we want it |
| @@ -44,13 +40,11 @@ | |
| 40 | with the `DCFLAGS` variable. (DB is short for “`docker build`”, and DC |
| 41 | is short for “`docker create`”, a sub-step of the “run” target.) |
| 42 | To get the custom port setting as in |
| 43 | second command above, say: |
| 44 | |
| 45 | $ make container-run DCFLAGS='-p 9999:8080/tcp' |
| 46 | |
| 47 | Contrast the raw “`docker`” commands above, which create an |
| 48 | _unversioned_ image called `fossil:latest` and from that a container |
| 49 | simply called `fossil`. The unversioned names are more convenient for |
| 50 | interactive use, while the versioned ones are good for CI/CD type |
| @@ -81,15 +75,13 @@ | |
| 75 | ### <a id="repo-inside"></a> 2.1 Storing the Repo Inside the Container |
| 76 | |
| 77 | The simplest method is to stop the container if it was running, then |
| 78 | say: |
| 79 | |
| 80 | $ docker cp /path/to/my-project.fossil fossil:/museum/repo.fossil |
| 81 | $ docker start fossil |
| 82 | $ docker exec fossil chown -R 499 /museum |
| 83 | |
| 84 | That copies the local Fossil repo into the container where the server |
| 85 | expects to find it, so that the “start” command causes it to serve from |
| 86 | that copied-in file instead. Since it lives atop the immutable base |
| 87 | layers, it persists as part of the container proper, surviving restarts. |
| @@ -120,17 +112,15 @@ | |
| 112 | designed to be killed off at the slightest cause, rebuilt, and |
| 113 | redeployed. If you do that with the repo inside the container, it gets |
| 114 | destroyed, too. The solution is to replace the “run” command above with |
| 115 | the following: |
| 116 | |
| 117 | $ docker run \ |
| 118 | --publish 9999:8080 \ |
| 119 | --name fossil-bind-mount \ |
| 120 | --volume ~/museum:/museum \ |
| 121 | fossil |
| 122 | |
| 123 | Because this bind mount maps a host-side directory (`~/museum`) into the |
| 124 | container, you don’t need to `docker cp` the repo into the container at |
| 125 | all. It still expects to find the repository as `repo.fossil` under that |
| 126 | directory, but now both the host and the container can see that repo DB. |
| @@ -151,13 +141,11 @@ | |
| 141 | You might be aware that OCI containers allow mapping a single file into |
| 142 | the repository rather than a whole directory. Since Fossil repositories |
| 143 | are specially-formatted SQLite databases, you might be wondering why we |
| 144 | don’t say things like: |
| 145 | |
| 146 | --volume ~/museum/my-project.fossil:/museum/repo.fossil |
| 147 | |
| 148 | That lets us have a convenient file name for the project outside the |
| 149 | container while letting the configuration inside the container refer to |
| 150 | the generic “`/museum/repo.fossil`” name. Why should we have to name |
| 151 | the repo generically on the outside merely to placate the container? |
| @@ -292,21 +280,19 @@ | |
| 280 | |
| 281 | All together, we recommend adding the following options to your |
| 282 | “`docker run`” commands, as well as to any “`docker create`” command |
| 283 | that will be followed by “`docker start`”: |
| 284 | |
| 285 | --cap-drop AUDIT_WRITE \ |
| 286 | --cap-drop CHOWN \ |
| 287 | --cap-drop FSETID \ |
| 288 | --cap-drop KILL \ |
| 289 | --cap-drop MKNOD \ |
| 290 | --cap-drop NET_BIND_SERVICE \ |
| 291 | --cap-drop NET_RAW \ |
| 292 | --cap-drop SETFCAP \ |
| 293 | --cap-drop SETPCAP |
| 294 | |
| 295 | In the next section, we’ll show a case where you create a container |
| 296 | without ever running it, making these options pointless. |
| 297 | |
| 298 | [backoffice]: ./backoffice.md |
| @@ -326,16 +312,14 @@ | |
| 312 | modern Linux distros make this [surprisingly difficult][lsl], but Alpine’s |
| 313 | back-to-basics nature makes static builds work the way they used to, |
| 314 | back in the day. If that’s all you’re after, you can do so as easily as |
| 315 | this: |
| 316 | |
| 317 | $ docker build -t fossil . |
| 318 | $ docker create --name fossil-static-tmp fossil |
| 319 | $ docker cp fossil-static-tmp:/bin/fossil . |
| 320 | $ docker container rm fossil-static-tmp |
| 321 | |
| 322 | The result is six or seven megs, depending on the CPU architecture you |
| 323 | build for. It’s built stripped. |
| 324 | |
| 325 | [lsl]: https://stackoverflow.com/questions/3430400/linux-static-linking-is-dead |
| @@ -347,19 +331,15 @@ | |
| 331 | |
| 332 | The default version of Fossil fetched in the build is the version in the |
| 333 | checkout directory at the time you run it. You could override it to get |
| 334 | a release build like so: |
| 335 | |
| 336 | $ docker build -t fossil --build-arg FSLVER=version-2.20 . |
| 337 | |
| 338 | Or equivalently, using Fossil’s `Makefile` convenience target: |
| 339 | |
| 340 | $ make container-image DBFLAGS='--build-arg FSLVER=version-2.20' |
| 341 | |
| 342 | While you could instead use the generic |
| 343 | “`release`” tag here, it’s better to use a specific version number |
| 344 | since container builders cache downloaded files, hoping to |
| 345 | reuse them across builds. If you ask for “`release`” before a new |
| @@ -384,13 +364,11 @@ | |
| 364 | 500 and went *down* one instead to reduce the chance of a conflict to as |
| 365 | close to zero as we can manage. |
| 366 | |
| 367 | To change it to something else, say: |
| 368 | |
| 369 | $ make container-image DBFLAGS='--build-arg UID=501' |
| 370 | |
| 371 | This is particularly useful if you’re putting your repository on a |
| 372 | separate volume since the IDs “leak” out into the host environment via |
| 373 | file permissions. You may therefore wish them to mean something on both |
| 374 | sides of the container barrier rather than have “499” appear on the host |
| @@ -403,25 +381,21 @@ | |
| 381 | for use of any OCI container system that implements the same interfaces. |
| 382 | We go into more details about this [below](#light), but |
| 383 | for now, it suffices to point out that you can switch to Podman while |
| 384 | using our `Makefile` convenience targets unchanged by saying: |
| 385 | |
| 386 | $ make CENGINE=podman container-run |
| 387 | |
| 388 | |
| 389 | ### 5.4 <a id="config"></a>Fossil Configuration Options |
| 390 | |
| 391 | You can use this same mechanism to enable non-default Fossil |
| 392 | configuration options in your build. For instance, to turn on |
| 393 | the JSON API and the TH1 docs extension: |
| 394 | |
| 395 | $ make container-image \ |
| 396 | DBFLAGS='--build-arg FSLCFG="--json --with-th1-docs"' |
| 397 | |
| 398 | If you also wanted [the Tcl evaluation extension](./th1.md#tclEval), |
| 399 | that brings us to [the next point](#run). |
| 400 | |
| 401 | |
| @@ -429,20 +403,20 @@ | |
| 403 | |
| 404 | If you want a basic shell environment for temporary debugging of the |
| 405 | running container, that’s easily added. Simply change this line in the |
| 406 | `Dockerfile`… |
| 407 | |
| 408 | FROM scratch AS run |
| 409 | |
| 410 | …to this: |
| 411 | |
| 412 | FROM busybox AS run |
| 413 | |
| 414 | Rebuild and redeploy to give your Fossil container a [BusyBox]-based |
| 415 | shell environment that you can get into via: |
| 416 | |
| 417 | $ docker exec -it -u fossil $(make container-version) sh |
| 418 | |
| 419 | That command assumes you built it via “`make container`” and are |
| 420 | therefore using its versioning scheme. |
| 421 | |
| 422 | You will likely want to remove the `PATH` override in the “RUN” stage |
| @@ -463,11 +437,10 @@ | |
| 437 | most popular programming languages in the world, we have many options |
| 438 | for achieving this. For instance, there is a whole class of |
| 439 | “[distroless]” images that will do this efficiently by changing |
| 440 | “`STAGE 2`” in the `Dockefile` to this: |
| 441 | |
| 442 | ## --------------------------------------------------------------------- |
| 443 | ## STAGE 2: Pare that back to the bare essentials, plus Python. |
| 444 | ## --------------------------------------------------------------------- |
| 445 | FROM cgr.dev/chainguard/python:latest |
| 446 | USER root |
| @@ -478,24 +451,21 @@ | |
| 451 | RUN [ "/bin/busybox", "--install", "/bin" ] |
| 452 | RUN set -x \ |
| 453 | && echo "fossil:x:${UID}:${UID}:User:/museum:/false" >> /etc/passwd \ |
| 454 | && echo "fossil:x:${UID}:fossil" >> /etc/group \ |
| 455 | && install -d -m 700 -o fossil -g fossil log museum |
| 456 | |
| 457 | You will also have to add `busybox-static` to the APK package list in |
| 458 | STAGE 1 for the `RUN` script at the end of that stage to work, since the |
| 459 | [Chainguard Python image][cgimgs] lacks a shell, on purpose. The need to |
| 460 | install root-level binaries is why we change `USER` temporarily here. |
| 461 | |
| 462 | Build it and test that it works like so: |
| 463 | |
| 464 | $ make container-run && |
| 465 | docker exec -i $(make container-version) python --version |
| 466 | 3.11.2 |
| 467 | |
| 468 | The compensation for the hassle of using Chainguard over something more |
| 469 | general purpose like changing the `run` layer to Alpine and then adding |
| 470 | a “`apk add python`” command to the `Dockerfile` |
| 471 | is huge: we no longer leave a package manager sitting around inside the |
| @@ -555,11 +525,10 @@ | |
| 525 | into this, [enable linger |
| 526 | mode](https://www.freedesktop.org/software/systemd/man/loginctl.html).) |
| 527 | so I was able to create a unit file called |
| 528 | `~/.local/share/systemd/user/[email protected]` with these contents: |
| 529 | |
| 530 | [Unit] |
| 531 | Description=Fossil email alert sender for %I |
| 532 | |
| 533 | [Service] |
| 534 | WorkingDirectory=/home/fossil/museum |
| @@ -567,20 +536,17 @@ | |
| 536 | Restart=always |
| 537 | RestartSec=3 |
| 538 | |
| 539 | [Install] |
| 540 | WantedBy=default.target |
| 541 | |
| 542 | I was then able to enable email alert forwarding for select repositories |
| 543 | after configuring them per [the docs](./alerts.md) by saying: |
| 544 | |
| 545 | $ systemctl --user daemon-reload |
| 546 | $ systemctl --user enable alert-sender@myproject |
| 547 | $ systemctl --user start alert-sender@myproject |
| 548 | |
| 549 | Because this is a parameterized script and we’ve set our repository |
| 550 | paths predictably, you can do this for as many repositories as you need |
| 551 | to by passing their names after the “`@`” sign in the commands above. |
| 552 | |
| @@ -606,13 +572,11 @@ | |
| 572 | For the sake of simple examples in this section, we’ll assume you’re |
| 573 | integrating Fossil into a larger web site, such as with our [Debian + |
| 574 | nginx + TLS][DNT] plan. This is why all of the examples below create |
| 575 | the container with this option: |
| 576 | |
| 577 | --publish 127.0.0.1:9999:8080 |
| 578 | |
| 579 | The assumption is that there’s a reverse proxy running somewhere that |
| 580 | redirects public web hits to localhost port 9999, which in turn goes to |
| 581 | port 8080 inside the container. This use of port |
| 582 | publishing effectively replaces the use of the |
| @@ -678,14 +642,12 @@ | |
| 642 | tenth the size of Docker Engine. |
| 643 | |
| 644 | For our purposes here, the only thing that changes relative to the |
| 645 | examples at the top of this document are the initial command: |
| 646 | |
| 647 | $ podman build -t fossil . |
| 648 | $ podman run --name fossil -p 9999:8080/tcp fossil |
| 649 | |
| 650 | Your Linux package repo may have a `podman-docker` package which |
| 651 | provides a “`docker`” script that calls “`podman`” for you, eliminating |
| 652 | even the command name difference. With that installed, the `make` |
| 653 | commands above will work with Podman as-is. |
| @@ -692,23 +654,21 @@ | |
| 654 | |
| 655 | The only difference that matters here is that Podman doesn’t have the |
| 656 | same [default Linux kernel capability set](#caps) as Docker, which |
| 657 | affects the `--cap-drop` flags recommended above to: |
| 658 | |
| 659 | $ podman create \ |
| 660 | --name fossil \ |
| 661 | --cap-drop CHOWN \ |
| 662 | --cap-drop FSETID \ |
| 663 | --cap-drop KILL \ |
| 664 | --cap-drop NET_BIND_SERVICE \ |
| 665 | --cap-drop SETFCAP \ |
| 666 | --cap-drop SETPCAP \ |
| 667 | --publish 127.0.0.1:9999:8080 \ |
| 668 | localhost/fossil |
| 669 | $ podman start fossil |
| 670 | |
| 671 | [pmmac]: https://podman.io/getting-started/installation.html#macos |
| 672 | [pmwin]: https://github.com/containers/podman/blob/main/docs/tutorials/podman-for-windows.md |
| 673 | [Podman]: https://podman.io/ |
| 674 | [rl]: https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md |
| @@ -720,13 +680,11 @@ | |
| 680 | If even the Podman stack is too big for you, the next-best option I’m |
| 681 | aware of is the `systemd-container` infrastructure on modern Linuxes, |
| 682 | available since version 239 or so. Its runtime tooling requires only |
| 683 | about 1.4 MiB of disk space: |
| 684 | |
| 685 | $ sudo apt install systemd-container btrfs-tools |
| 686 | |
| 687 | That command assumes the primary test environment for |
| 688 | this guide, Ubuntu 22.04 LTS with `systemd` 249. For best |
| 689 | results, `/var/lib/machines` should be a btrfs volume, because |
| 690 | [`$REASONS`][mcfad]. For CentOS Stream 9 and other Red Hattish |
| @@ -742,60 +700,54 @@ | |
| 700 | If you use [the stock `Dockerfile`][DF] to generate your |
| 701 | base image, `nspawn` won’t recognize it as containing an OS unless you |
| 702 | change the “`FROM scratch AS os`” line at the top of the second stage |
| 703 | to something like this: |
| 704 | |
| 705 | FROM gcr.io/distroless/static-debian11 AS os |
| 706 | |
| 707 | Using that as a base image provides all the files `nspawn` checks for to |
| 708 | determine whether the container is sufficiently close to a Linux VM for |
| 709 | the following step to proceed: |
| 710 | |
| 711 | $ make container |
| 712 | $ docker container export $(make container-version) | |
| 713 | machinectl import-tar - myproject |
| 714 | |
| 715 | Next, create `/etc/systemd/nspawn/myproject.nspawn`: |
| 716 | |
| 717 | ---- |
| 718 | |
| 719 | [Exec] |
| 720 | WorkingDirectory=/ |
| 721 | Parameters=bin/fossil server \ |
| 722 | --baseurl https://example.com/myproject \ |
| 723 | --create \ |
| 724 | --jsmode bundled \ |
| 725 | --localhost \ |
| 726 | --port 9000 \ |
| 727 | --scgi \ |
| 728 | --user admin \ |
| 729 | museum/repo.fossil |
| 730 | DropCapability= \ |
| 731 | CAP_AUDIT_WRITE \ |
| 732 | CAP_CHOWN \ |
| 733 | CAP_FSETID \ |
| 734 | CAP_KILL \ |
| 735 | CAP_MKNOD \ |
| 736 | CAP_NET_BIND_SERVICE \ |
| 737 | CAP_NET_RAW \ |
| 738 | CAP_SETFCAP \ |
| 739 | CAP_SETPCAP |
| 740 | ProcessTwo=yes |
| 741 | LinkJournal=no |
| 742 | Timezone=no |
| 743 | |
| 744 | [Files] |
| 745 | Bind=/home/fossil/museum/myproject:/museum |
| 746 | |
| 747 | [Network] |
| 748 | VirtualEthernet=no |
| 749 | |
| 750 | ---- |
| 751 | |
| 752 | If you recognize most of that from the `Dockerfile` discussion above, |
| 753 | congratulations, you’ve been paying attention. The rest should also |
| @@ -819,22 +771,20 @@ | |
| 771 | That being done, we also need a generic `systemd` unit file called |
| 772 | `/etc/systemd/system/[email protected]`, containing: |
| 773 | |
| 774 | ---- |
| 775 | |
| 776 | [Unit] |
| 777 | Description=Fossil %i Repo Service |
| 778 | [email protected] [email protected] |
| 779 | After=network.target systemd-resolved.service [email protected] [email protected] |
| 780 | |
| 781 | [Service] |
| 782 | ExecStart=systemd-nspawn --settings=override --read-only --machine=%i bin/fossil |
| 783 | |
| 784 | [Install] |
| 785 | WantedBy=multi-user.target |
| 786 | |
| 787 | ---- |
| 788 | |
| 789 | You shouldn’t have to change any of this because we’ve given the |
| 790 | `--setting=override` flag, meaning any setting in the nspawn file |
| @@ -843,42 +793,36 @@ | |
| 793 | share the base configuration, varying on a per-repo level through |
| 794 | adjustments to their individual `*.nspawn` files. |
| 795 | |
| 796 | You may then start the service in the normal way: |
| 797 | |
| 798 | $ sudo systemctl enable fossil@myproject |
| 799 | $ sudo systemctl start fossil@myproject |
| 800 | |
| 801 | You should then find it running on localhost port 9000 per the nspawn |
| 802 | configuration file above, suitable for proxying Fossil out to the |
| 803 | public using nginx via SCGI. If you aren’t using a front-end proxy |
| 804 | and want Fossil exposed to the world via HTTPS, you might say this instead in |
| 805 | the `*.nspawn` file: |
| 806 | |
| 807 | Parameters=bin/fossil server \ |
| 808 | --cert /path/to/cert.pem \ |
| 809 | --create \ |
| 810 | --jsmode bundled \ |
| 811 | --port 443 \ |
| 812 | --user admin \ |
| 813 | museum/repo.fossil |
| 814 | |
| 815 | You would also need to un-drop the `CAP_NET_BIND_SERVICE` capability |
| 816 | to allow Fossil to bind to this low-numbered port. |
| 817 | |
| 818 | We use the `systemd` template file feature to allow multiple Fossil |
| 819 | servers running on a single machine, each on a different TCP port, |
| 820 | as when proxying them out as subdirectories of a larger site. |
| 821 | To add another project, you must first clone the base “machine” layer: |
| 822 | |
| 823 | $ sudo machinectl clone myproject otherthing |
| 824 | |
| 825 | That will not only create a clone of `/var/lib/machines/myproject` |
| 826 | as `../otherthing`, it will create a matching `otherthing.nspawn` file for you |
| 827 | as a copy of the first one. Adjust its contents to suit, then enable |
| 828 | and start it as above. |
| @@ -895,21 +839,17 @@ | |
| 839 | |
| 840 | Fortunately, there are workarounds. |
| 841 | |
| 842 | First, the `apt install` command above becomes: |
| 843 | |
| 844 | $ sudo dnf install systemd-container |
| 845 | |
| 846 | Second, you have to hack around the lack of `machinectl import-tar`: |
| 847 | |
| 848 | $ rootfs=/var/lib/machines/fossil |
| 849 | $ sudo mkdir -p $rootfs |
| 850 | $ docker container export fossil | sudo tar -xf -C $rootfs - |
| 851 | |
| 852 | The parent directory path in the `rootfs` variable is important, |
| 853 | because although we aren’t able to use `machinectl` on such systems, the |
| 854 | `systemd-nspawn` developers assume you’re using them together; when you give |
| 855 | `--machine`, it assumes the `machinectl` directory scheme. You could |
| 856 |
+13
-15
| --- www/defcsp.md | ||
| +++ www/defcsp.md | ||
| @@ -23,43 +23,41 @@ | ||
| 23 | 23 | ## The Default Restrictions |
| 24 | 24 | |
| 25 | 25 | The default CSP used by Fossil is as follows: |
| 26 | 26 | |
| 27 | 27 | <pre> |
| 28 | - default-src 'self' data:; | |
| 29 | - script-src 'self' 'nonce-$nonce'; | |
| 30 | - style-src 'self' 'unsafe-inline'; | |
| 31 | - img-src * data:; | |
| 28 | +default-src 'self' data:; | |
| 29 | +script-src 'self' 'nonce-$nonce'; | |
| 30 | +style-src 'self' 'unsafe-inline'; | |
| 31 | +img-src * data:; | |
| 32 | 32 | </pre> |
| 33 | 33 | |
| 34 | 34 | The default is recommended for most installations. However, |
| 35 | 35 | the site administrators can overwrite this default CSP using the |
| 36 | 36 | [default-csp setting](/help?cmd=default-csp). For example, |
| 37 | 37 | CSP restrictions can be completely disabled by setting the default-csp to: |
| 38 | 38 | |
| 39 | -<pre> | |
| 40 | - default-src *; | |
| 41 | -</pre> | |
| 39 | + default-src *; | |
| 42 | 40 | |
| 43 | 41 | The following sections detail the maining of the default CSP setting. |
| 44 | 42 | |
| 45 | 43 | ### <a id="base"></a> default-src 'self' data: |
| 46 | 44 | |
| 47 | 45 | This policy means mixed-origin content isn’t allowed, so you can’t refer |
| 48 | 46 | to resources on other web domains. Browsers will ignore a link like the |
| 49 | 47 | one in the following Markdown under our default CSP: |
| 50 | 48 | |
| 51 | -  | |
| 49 | +  | |
| 52 | 50 | |
| 53 | 51 | If you look in the browser’s developer console, you should see a CSP |
| 54 | 52 | error when attempting to render such a page. |
| 55 | 53 | |
| 56 | 54 | The default policy does allow inline `data:` URIs, which means you could |
| 57 | 55 | [data-encode][de] your image content and put it inline within the |
| 58 | 56 | document: |
| 59 | 57 | |
| 60 | -  | |
| 58 | +  | |
| 61 | 59 | |
| 62 | 60 | That method is best used for fairly small resources. Large `data:` URIs |
| 63 | 61 | are hard to read and edit. There are secondary problems as well: if you |
| 64 | 62 | put a large image into a Fossil forum post this way, anyone subscribed |
| 65 | 63 | to email alerts will get a copy of the raw URI text, which can amount to |
| @@ -67,11 +65,11 @@ | ||
| 67 | 65 | |
| 68 | 66 | For inline images within [embedded documentation][ed], it suffices to |
| 69 | 67 | store the referred-to files in the repo and then refer to them using |
| 70 | 68 | repo-relative URLs: |
| 71 | 69 | |
| 72 | -  | |
| 70 | +  | |
| 73 | 71 | |
| 74 | 72 | This avoids bloating the doc text with `data:` URI blobs: |
| 75 | 73 | |
| 76 | 74 | There are many other cases, [covered below](#serving). |
| 77 | 75 | |
| @@ -99,11 +97,11 @@ | ||
| 99 | 97 | `<style>` tags within the document text. |
| 100 | 98 | |
| 101 | 99 | The `'unsafe-inline'` declaration allows CSS within individual HTML |
| 102 | 100 | elements: |
| 103 | 101 | |
| 104 | - <p style="margin-left: 4em">Indented text.</p> | |
| 102 | + <p style="margin-left: 4em">Indented text.</p> | |
| 105 | 103 | |
| 106 | 104 | As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'` |
| 107 | 105 | feature is suboptimal for security. However, there are |
| 108 | 106 | a few places in the Fossil-generated HTML that benefit from this |
| 109 | 107 | flexibility and the work-arounds are verbose and difficult to maintain. |
| @@ -174,11 +172,11 @@ | ||
| 174 | 172 | scheme. Any one of those hundreds of repositories could trick you into |
| 175 | 173 | visiting their repository home page, set to [an HTML-formatted embedded |
| 176 | 174 | doc page][hfed] via Admin → Configuration → Index Page, with this |
| 177 | 175 | content: |
| 178 | 176 | |
| 179 | - <script src="/doc/trunk/bad.js"></script> | |
| 177 | + <script src="/doc/trunk/bad.js"></script> | |
| 180 | 178 | |
| 181 | 179 | That script can then do anything allowed in JavaScript to *any other* |
| 182 | 180 | Chisel repository your browser can access. The possibilities for mischief |
| 183 | 181 | are *vast*. For just one example, if you have login cookies on four |
| 184 | 182 | different Chisel repositories, your attacker could harvest the login |
| @@ -198,11 +196,11 @@ | ||
| 198 | 196 | willingly run any JavaScript code they’ve provided, blind, you **must |
| 199 | 197 | not** give the `--with-th1-docs` option when configuring Fossil, because |
| 200 | 198 | that allows substitution of the [pre-defined `$nonce` TH1 |
| 201 | 199 | variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: |
| 202 | 200 | |
| 203 | - <script src="/doc/trunk/bad.js" nonce="$nonce"></script> | |
| 201 | + <script src="/doc/trunk/bad.js" nonce="$nonce"></script> | |
| 204 | 202 | |
| 205 | 203 | Even with this feature enabled, you cannot put `<script>` tags into |
| 206 | 204 | Fossil Wiki or Markdown-formatted content, because our HTML generators |
| 207 | 205 | for those formats purposely strip or disable such tags in the output. |
| 208 | 206 | Therefore, if you trust those users with check-in rights to provide |
| @@ -331,11 +329,11 @@ | ||
| 331 | 329 | |
| 332 | 330 | Because a blank setting tells Fossil to use its hard-coded default CSP, |
| 333 | 331 | you have to say something like the following to get a repository without |
| 334 | 332 | content security policy restrictions: |
| 335 | 333 | |
| 336 | - $ fossil set -R /path/to/served/repo.fossil default-csp 'default-src *' | |
| 334 | + $ fossil set -R /path/to/served/repo.fossil default-csp 'default-src *' | |
| 337 | 335 | |
| 338 | 336 | We recommend that instead of using the command line to change this |
| 339 | 337 | setting that you do it via the repository’s web interface, in |
| 340 | 338 | Admin → Settings. Write your CSP rules in the edit box marked |
| 341 | 339 | "`default-csp`". Do not add hard newlines in that box: the setting needs |
| @@ -366,11 +364,11 @@ | ||
| 366 | 364 | |
| 367 | 365 | This means that another way you can override this value is to use |
| 368 | 366 | the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1 |
| 369 | 367 | processing happens during skin processing: |
| 370 | 368 | |
| 371 | - $ fossil set th1-setup "set default_csp {default-src 'self'}" | |
| 369 | + $ fossil set th1-setup "set default_csp {default-src 'self'}" | |
| 372 | 370 | |
| 373 | 371 | After [the above](#admin-ui), this is the cleanest method. |
| 374 | 372 | |
| 375 | 373 | [thvar]: ./customskin.md#vars |
| 376 | 374 | |
| 377 | 375 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -23,43 +23,41 @@ | |
| 23 | ## The Default Restrictions |
| 24 | |
| 25 | The default CSP used by Fossil is as follows: |
| 26 | |
| 27 | <pre> |
| 28 | default-src 'self' data:; |
| 29 | script-src 'self' 'nonce-$nonce'; |
| 30 | style-src 'self' 'unsafe-inline'; |
| 31 | img-src * data:; |
| 32 | </pre> |
| 33 | |
| 34 | The default is recommended for most installations. However, |
| 35 | the site administrators can overwrite this default CSP using the |
| 36 | [default-csp setting](/help?cmd=default-csp). For example, |
| 37 | CSP restrictions can be completely disabled by setting the default-csp to: |
| 38 | |
| 39 | <pre> |
| 40 | default-src *; |
| 41 | </pre> |
| 42 | |
| 43 | The following sections detail the maining of the default CSP setting. |
| 44 | |
| 45 | ### <a id="base"></a> default-src 'self' data: |
| 46 | |
| 47 | This policy means mixed-origin content isn’t allowed, so you can’t refer |
| 48 | to resources on other web domains. Browsers will ignore a link like the |
| 49 | one in the following Markdown under our default CSP: |
| 50 | |
| 51 |  |
| 52 | |
| 53 | If you look in the browser’s developer console, you should see a CSP |
| 54 | error when attempting to render such a page. |
| 55 | |
| 56 | The default policy does allow inline `data:` URIs, which means you could |
| 57 | [data-encode][de] your image content and put it inline within the |
| 58 | document: |
| 59 | |
| 60 |  |
| 61 | |
| 62 | That method is best used for fairly small resources. Large `data:` URIs |
| 63 | are hard to read and edit. There are secondary problems as well: if you |
| 64 | put a large image into a Fossil forum post this way, anyone subscribed |
| 65 | to email alerts will get a copy of the raw URI text, which can amount to |
| @@ -67,11 +65,11 @@ | |
| 67 | |
| 68 | For inline images within [embedded documentation][ed], it suffices to |
| 69 | store the referred-to files in the repo and then refer to them using |
| 70 | repo-relative URLs: |
| 71 | |
| 72 |  |
| 73 | |
| 74 | This avoids bloating the doc text with `data:` URI blobs: |
| 75 | |
| 76 | There are many other cases, [covered below](#serving). |
| 77 | |
| @@ -99,11 +97,11 @@ | |
| 99 | `<style>` tags within the document text. |
| 100 | |
| 101 | The `'unsafe-inline'` declaration allows CSS within individual HTML |
| 102 | elements: |
| 103 | |
| 104 | <p style="margin-left: 4em">Indented text.</p> |
| 105 | |
| 106 | As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'` |
| 107 | feature is suboptimal for security. However, there are |
| 108 | a few places in the Fossil-generated HTML that benefit from this |
| 109 | flexibility and the work-arounds are verbose and difficult to maintain. |
| @@ -174,11 +172,11 @@ | |
| 174 | scheme. Any one of those hundreds of repositories could trick you into |
| 175 | visiting their repository home page, set to [an HTML-formatted embedded |
| 176 | doc page][hfed] via Admin → Configuration → Index Page, with this |
| 177 | content: |
| 178 | |
| 179 | <script src="/doc/trunk/bad.js"></script> |
| 180 | |
| 181 | That script can then do anything allowed in JavaScript to *any other* |
| 182 | Chisel repository your browser can access. The possibilities for mischief |
| 183 | are *vast*. For just one example, if you have login cookies on four |
| 184 | different Chisel repositories, your attacker could harvest the login |
| @@ -198,11 +196,11 @@ | |
| 198 | willingly run any JavaScript code they’ve provided, blind, you **must |
| 199 | not** give the `--with-th1-docs` option when configuring Fossil, because |
| 200 | that allows substitution of the [pre-defined `$nonce` TH1 |
| 201 | variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: |
| 202 | |
| 203 | <script src="/doc/trunk/bad.js" nonce="$nonce"></script> |
| 204 | |
| 205 | Even with this feature enabled, you cannot put `<script>` tags into |
| 206 | Fossil Wiki or Markdown-formatted content, because our HTML generators |
| 207 | for those formats purposely strip or disable such tags in the output. |
| 208 | Therefore, if you trust those users with check-in rights to provide |
| @@ -331,11 +329,11 @@ | |
| 331 | |
| 332 | Because a blank setting tells Fossil to use its hard-coded default CSP, |
| 333 | you have to say something like the following to get a repository without |
| 334 | content security policy restrictions: |
| 335 | |
| 336 | $ fossil set -R /path/to/served/repo.fossil default-csp 'default-src *' |
| 337 | |
| 338 | We recommend that instead of using the command line to change this |
| 339 | setting that you do it via the repository’s web interface, in |
| 340 | Admin → Settings. Write your CSP rules in the edit box marked |
| 341 | "`default-csp`". Do not add hard newlines in that box: the setting needs |
| @@ -366,11 +364,11 @@ | |
| 366 | |
| 367 | This means that another way you can override this value is to use |
| 368 | the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1 |
| 369 | processing happens during skin processing: |
| 370 | |
| 371 | $ fossil set th1-setup "set default_csp {default-src 'self'}" |
| 372 | |
| 373 | After [the above](#admin-ui), this is the cleanest method. |
| 374 | |
| 375 | [thvar]: ./customskin.md#vars |
| 376 | |
| 377 |
| --- www/defcsp.md | |
| +++ www/defcsp.md | |
| @@ -23,43 +23,41 @@ | |
| 23 | ## The Default Restrictions |
| 24 | |
| 25 | The default CSP used by Fossil is as follows: |
| 26 | |
| 27 | <pre> |
| 28 | default-src 'self' data:; |
| 29 | script-src 'self' 'nonce-$nonce'; |
| 30 | style-src 'self' 'unsafe-inline'; |
| 31 | img-src * data:; |
| 32 | </pre> |
| 33 | |
| 34 | The default is recommended for most installations. However, |
| 35 | the site administrators can overwrite this default CSP using the |
| 36 | [default-csp setting](/help?cmd=default-csp). For example, |
| 37 | CSP restrictions can be completely disabled by setting the default-csp to: |
| 38 | |
| 39 | default-src *; |
| 40 | |
| 41 | The following sections detail the maining of the default CSP setting. |
| 42 | |
| 43 | ### <a id="base"></a> default-src 'self' data: |
| 44 | |
| 45 | This policy means mixed-origin content isn’t allowed, so you can’t refer |
| 46 | to resources on other web domains. Browsers will ignore a link like the |
| 47 | one in the following Markdown under our default CSP: |
| 48 | |
| 49 |  |
| 50 | |
| 51 | If you look in the browser’s developer console, you should see a CSP |
| 52 | error when attempting to render such a page. |
| 53 | |
| 54 | The default policy does allow inline `data:` URIs, which means you could |
| 55 | [data-encode][de] your image content and put it inline within the |
| 56 | document: |
| 57 | |
| 58 |  |
| 59 | |
| 60 | That method is best used for fairly small resources. Large `data:` URIs |
| 61 | are hard to read and edit. There are secondary problems as well: if you |
| 62 | put a large image into a Fossil forum post this way, anyone subscribed |
| 63 | to email alerts will get a copy of the raw URI text, which can amount to |
| @@ -67,11 +65,11 @@ | |
| 65 | |
| 66 | For inline images within [embedded documentation][ed], it suffices to |
| 67 | store the referred-to files in the repo and then refer to them using |
| 68 | repo-relative URLs: |
| 69 | |
| 70 |  |
| 71 | |
| 72 | This avoids bloating the doc text with `data:` URI blobs: |
| 73 | |
| 74 | There are many other cases, [covered below](#serving). |
| 75 | |
| @@ -99,11 +97,11 @@ | |
| 97 | `<style>` tags within the document text. |
| 98 | |
| 99 | The `'unsafe-inline'` declaration allows CSS within individual HTML |
| 100 | elements: |
| 101 | |
| 102 | <p style="margin-left: 4em">Indented text.</p> |
| 103 | |
| 104 | As the "`unsafe-`" prefix on the name implies, the `'unsafe-inline'` |
| 105 | feature is suboptimal for security. However, there are |
| 106 | a few places in the Fossil-generated HTML that benefit from this |
| 107 | flexibility and the work-arounds are verbose and difficult to maintain. |
| @@ -174,11 +172,11 @@ | |
| 172 | scheme. Any one of those hundreds of repositories could trick you into |
| 173 | visiting their repository home page, set to [an HTML-formatted embedded |
| 174 | doc page][hfed] via Admin → Configuration → Index Page, with this |
| 175 | content: |
| 176 | |
| 177 | <script src="/doc/trunk/bad.js"></script> |
| 178 | |
| 179 | That script can then do anything allowed in JavaScript to *any other* |
| 180 | Chisel repository your browser can access. The possibilities for mischief |
| 181 | are *vast*. For just one example, if you have login cookies on four |
| 182 | different Chisel repositories, your attacker could harvest the login |
| @@ -198,11 +196,11 @@ | |
| 196 | willingly run any JavaScript code they’ve provided, blind, you **must |
| 197 | not** give the `--with-th1-docs` option when configuring Fossil, because |
| 198 | that allows substitution of the [pre-defined `$nonce` TH1 |
| 199 | variable](./th1.md#nonce) into [HTML-formatted embedded docs][hfed]: |
| 200 | |
| 201 | <script src="/doc/trunk/bad.js" nonce="$nonce"></script> |
| 202 | |
| 203 | Even with this feature enabled, you cannot put `<script>` tags into |
| 204 | Fossil Wiki or Markdown-formatted content, because our HTML generators |
| 205 | for those formats purposely strip or disable such tags in the output. |
| 206 | Therefore, if you trust those users with check-in rights to provide |
| @@ -331,11 +329,11 @@ | |
| 329 | |
| 330 | Because a blank setting tells Fossil to use its hard-coded default CSP, |
| 331 | you have to say something like the following to get a repository without |
| 332 | content security policy restrictions: |
| 333 | |
| 334 | $ fossil set -R /path/to/served/repo.fossil default-csp 'default-src *' |
| 335 | |
| 336 | We recommend that instead of using the command line to change this |
| 337 | setting that you do it via the repository’s web interface, in |
| 338 | Admin → Settings. Write your CSP rules in the edit box marked |
| 339 | "`default-csp`". Do not add hard newlines in that box: the setting needs |
| @@ -366,11 +364,11 @@ | |
| 364 | |
| 365 | This means that another way you can override this value is to use |
| 366 | the [`th1-setup` hook script](./th1-hooks.md), which runs before TH1 |
| 367 | processing happens during skin processing: |
| 368 | |
| 369 | $ fossil set th1-setup "set default_csp {default-src 'self'}" |
| 370 | |
| 371 | After [the above](#admin-ui), this is the cleanest method. |
| 372 | |
| 373 | [thvar]: ./customskin.md#vars |
| 374 | |
| 375 |
+10
-10
| --- www/embeddeddoc.wiki | ||
| +++ www/embeddeddoc.wiki | ||
| @@ -138,21 +138,21 @@ | ||
| 138 | 138 | the root of the Fossil repository using the special text "$ROOT" |
| 139 | 139 | at the beginning of a URL. For example, a Markdown hyperlink to |
| 140 | 140 | the Markdown formatting rules might be |
| 141 | 141 | written in the embedded document like this: |
| 142 | 142 | |
| 143 | -<nowiki><pre> | |
| 144 | - [Markdown formatting rules]($ROOT/wiki_rules) | |
| 145 | -</pre></nowiki> | |
| 143 | +<verbatim> | |
| 144 | +[Markdown formatting rules]($ROOT/wiki_rules) | |
| 145 | +</verbatim> | |
| 146 | 146 | |
| 147 | 147 | Depending on how the how the Fossil server is configured, that hyperlink |
| 148 | 148 | might be renderer like one of the following: |
| 149 | 149 | |
| 150 | -<nowiki><pre> | |
| 151 | - <a href="/wiki_rules">Wiki formatting rules</a> | |
| 152 | - <a href="/cgi-bin/fossil/wiki_rules">Wiki formatting rules</a> | |
| 153 | -</pre></nowiki> | |
| 150 | +<verbatim> | |
| 151 | +<a href="/wiki_rules">Wiki formatting rule</a> | |
| 152 | +<a href="/cgi-bin/fossil/wiki_rules">Wiki formatting rules</a> | |
| 153 | +</verbatim> | |
| 154 | 154 | |
| 155 | 155 | So, in other words, the "$ROOT" text is converted into whatever |
| 156 | 156 | the "<baseurl>" is for the document. |
| 157 | 157 | |
| 158 | 158 | This substitution works for HTML and Markdown documents. |
| @@ -169,13 +169,13 @@ | ||
| 169 | 169 | |
| 170 | 170 | For example, if an embedded document documented wanted to reference |
| 171 | 171 | some other document in a separate file named "www/otherdoc.md", |
| 172 | 172 | it could use a URL like this: |
| 173 | 173 | |
| 174 | -<nowiki><pre> | |
| 175 | - [Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md) | |
| 176 | -</pre></nowiki> | |
| 174 | +<verbatim> | |
| 175 | +[Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md) | |
| 176 | +</verbatim> | |
| 177 | 177 | |
| 178 | 178 | As with "$ROOT", this substitution only works for Markdown and HTML |
| 179 | 179 | documents. For Wiki documents, you would need to use a relative URL. |
| 180 | 180 | |
| 181 | 181 | <h2 id="th1">2.3 TH1 Documents</h2> |
| 182 | 182 |
| --- www/embeddeddoc.wiki | |
| +++ www/embeddeddoc.wiki | |
| @@ -138,21 +138,21 @@ | |
| 138 | the root of the Fossil repository using the special text "$ROOT" |
| 139 | at the beginning of a URL. For example, a Markdown hyperlink to |
| 140 | the Markdown formatting rules might be |
| 141 | written in the embedded document like this: |
| 142 | |
| 143 | <nowiki><pre> |
| 144 | [Markdown formatting rules]($ROOT/wiki_rules) |
| 145 | </pre></nowiki> |
| 146 | |
| 147 | Depending on how the how the Fossil server is configured, that hyperlink |
| 148 | might be renderer like one of the following: |
| 149 | |
| 150 | <nowiki><pre> |
| 151 | <a href="/wiki_rules">Wiki formatting rules</a> |
| 152 | <a href="/cgi-bin/fossil/wiki_rules">Wiki formatting rules</a> |
| 153 | </pre></nowiki> |
| 154 | |
| 155 | So, in other words, the "$ROOT" text is converted into whatever |
| 156 | the "<baseurl>" is for the document. |
| 157 | |
| 158 | This substitution works for HTML and Markdown documents. |
| @@ -169,13 +169,13 @@ | |
| 169 | |
| 170 | For example, if an embedded document documented wanted to reference |
| 171 | some other document in a separate file named "www/otherdoc.md", |
| 172 | it could use a URL like this: |
| 173 | |
| 174 | <nowiki><pre> |
| 175 | [Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md) |
| 176 | </pre></nowiki> |
| 177 | |
| 178 | As with "$ROOT", this substitution only works for Markdown and HTML |
| 179 | documents. For Wiki documents, you would need to use a relative URL. |
| 180 | |
| 181 | <h2 id="th1">2.3 TH1 Documents</h2> |
| 182 |
| --- www/embeddeddoc.wiki | |
| +++ www/embeddeddoc.wiki | |
| @@ -138,21 +138,21 @@ | |
| 138 | the root of the Fossil repository using the special text "$ROOT" |
| 139 | at the beginning of a URL. For example, a Markdown hyperlink to |
| 140 | the Markdown formatting rules might be |
| 141 | written in the embedded document like this: |
| 142 | |
| 143 | <verbatim> |
| 144 | [Markdown formatting rules]($ROOT/wiki_rules) |
| 145 | </verbatim> |
| 146 | |
| 147 | Depending on how the how the Fossil server is configured, that hyperlink |
| 148 | might be renderer like one of the following: |
| 149 | |
| 150 | <verbatim> |
| 151 | <a href="/wiki_rules">Wiki formatting rule</a> |
| 152 | <a href="/cgi-bin/fossil/wiki_rules">Wiki formatting rules</a> |
| 153 | </verbatim> |
| 154 | |
| 155 | So, in other words, the "$ROOT" text is converted into whatever |
| 156 | the "<baseurl>" is for the document. |
| 157 | |
| 158 | This substitution works for HTML and Markdown documents. |
| @@ -169,13 +169,13 @@ | |
| 169 | |
| 170 | For example, if an embedded document documented wanted to reference |
| 171 | some other document in a separate file named "www/otherdoc.md", |
| 172 | it could use a URL like this: |
| 173 | |
| 174 | <verbatim> |
| 175 | [Other Document]($ROOT/doc/$CURRENT/www/otherdoc.md) |
| 176 | </verbatim> |
| 177 | |
| 178 | As with "$ROOT", this substitution only works for Markdown and HTML |
| 179 | documents. For Wiki documents, you would need to use a relative URL. |
| 180 | |
| 181 | <h2 id="th1">2.3 TH1 Documents</h2> |
| 182 |
+29
-29
| --- www/image-format-vs-repo-size.md | ||
| +++ www/image-format-vs-repo-size.md | ||
| @@ -159,39 +159,39 @@ | ||
| 159 | 159 | uncompressed form, we want an automated method for producing the |
| 160 | 160 | uncompressed form to make Fossil happy while still having the compressed |
| 161 | 161 | form to keep our content creation applications happy. This `Makefile` |
| 162 | 162 | should[^makefile] do that for BMP, PNG, SVG, and XLSX files: |
| 163 | 163 | |
| 164 | - .SUFFIXES: .bmp .png .svg .svgz | |
| 165 | - | |
| 166 | - .svgz.svg: | |
| 167 | - gzip -dc < $< > $@ | |
| 168 | - | |
| 169 | - .svg.svgz: | |
| 170 | - gzip -9c < $< > $@ | |
| 171 | - | |
| 172 | - .bmp.png: | |
| 173 | - convert -quality 95 $< $@ | |
| 174 | - | |
| 175 | - .png.bmp: | |
| 176 | - convert $< $@ | |
| 177 | - | |
| 178 | - SS_FILES := $(wildcard spreadsheet/*) | |
| 179 | - | |
| 180 | - | |
| 181 | - all: $(SS_FILES) illus.svg image.bmp doc-big.pdf | |
| 182 | - | |
| 183 | - reconstitute: illus.svgz image.png | |
| 184 | - ( cd spreadsheet ; zip -9 ../spreadsheet.xlsx) * ) | |
| 185 | - qpdf doc-big.pdf doc-small.pdf | |
| 186 | - | |
| 187 | - | |
| 188 | - $(SS_FILES): spreadsheet.xlsx | |
| 189 | - unzip $@ -d $< | |
| 190 | - | |
| 191 | - doc-big.pdf: doc-small.pdf | |
| 192 | - qpdf --stream-data=uncompress $@ $< | |
| 164 | + .SUFFIXES: .bmp .png .svg .svgz | |
| 165 | + | |
| 166 | + .svgz.svg: | |
| 167 | + gzip -dc < $< > $@ | |
| 168 | + | |
| 169 | + .svg.svgz: | |
| 170 | + gzip -9c < $< > $@ | |
| 171 | + | |
| 172 | + .bmp.png: | |
| 173 | + convert -quality 95 $< $@ | |
| 174 | + | |
| 175 | + .png.bmp: | |
| 176 | + convert $< $@ | |
| 177 | + | |
| 178 | + SS_FILES := $(wildcard spreadsheet/*) | |
| 179 | + | |
| 180 | + | |
| 181 | + all: $(SS_FILES) illus.svg image.bmp doc-big.pdf | |
| 182 | + | |
| 183 | + reconstitute: illus.svgz image.png | |
| 184 | + ( cd spreadsheet ; zip -9 ../spreadsheet.xlsx) * ) | |
| 185 | + qpdf doc-big.pdf doc-small.pdf | |
| 186 | + | |
| 187 | + | |
| 188 | + $(SS_FILES): spreadsheet.xlsx | |
| 189 | + unzip $@ -d $< | |
| 190 | + | |
| 191 | + doc-big.pdf: doc-small.pdf | |
| 192 | + qpdf --stream-data=uncompress $@ $< | |
| 193 | 193 | |
| 194 | 194 | This `Makefile` allows you to treat the compressed version as the |
| 195 | 195 | process input, but to actually check in only the changes against the |
| 196 | 196 | uncompressed version by typing “`make`” before “`fossil ci`”. This is |
| 197 | 197 | not actually an extra step in practice, since if you’ve got a |
| 198 | 198 |
| --- www/image-format-vs-repo-size.md | |
| +++ www/image-format-vs-repo-size.md | |
| @@ -159,39 +159,39 @@ | |
| 159 | uncompressed form, we want an automated method for producing the |
| 160 | uncompressed form to make Fossil happy while still having the compressed |
| 161 | form to keep our content creation applications happy. This `Makefile` |
| 162 | should[^makefile] do that for BMP, PNG, SVG, and XLSX files: |
| 163 | |
| 164 | .SUFFIXES: .bmp .png .svg .svgz |
| 165 | |
| 166 | .svgz.svg: |
| 167 | gzip -dc < $< > $@ |
| 168 | |
| 169 | .svg.svgz: |
| 170 | gzip -9c < $< > $@ |
| 171 | |
| 172 | .bmp.png: |
| 173 | convert -quality 95 $< $@ |
| 174 | |
| 175 | .png.bmp: |
| 176 | convert $< $@ |
| 177 | |
| 178 | SS_FILES := $(wildcard spreadsheet/*) |
| 179 | |
| 180 | |
| 181 | all: $(SS_FILES) illus.svg image.bmp doc-big.pdf |
| 182 | |
| 183 | reconstitute: illus.svgz image.png |
| 184 | ( cd spreadsheet ; zip -9 ../spreadsheet.xlsx) * ) |
| 185 | qpdf doc-big.pdf doc-small.pdf |
| 186 | |
| 187 | |
| 188 | $(SS_FILES): spreadsheet.xlsx |
| 189 | unzip $@ -d $< |
| 190 | |
| 191 | doc-big.pdf: doc-small.pdf |
| 192 | qpdf --stream-data=uncompress $@ $< |
| 193 | |
| 194 | This `Makefile` allows you to treat the compressed version as the |
| 195 | process input, but to actually check in only the changes against the |
| 196 | uncompressed version by typing “`make`” before “`fossil ci`”. This is |
| 197 | not actually an extra step in practice, since if you’ve got a |
| 198 |
| --- www/image-format-vs-repo-size.md | |
| +++ www/image-format-vs-repo-size.md | |
| @@ -159,39 +159,39 @@ | |
| 159 | uncompressed form, we want an automated method for producing the |
| 160 | uncompressed form to make Fossil happy while still having the compressed |
| 161 | form to keep our content creation applications happy. This `Makefile` |
| 162 | should[^makefile] do that for BMP, PNG, SVG, and XLSX files: |
| 163 | |
| 164 | .SUFFIXES: .bmp .png .svg .svgz |
| 165 | |
| 166 | .svgz.svg: |
| 167 | gzip -dc < $< > $@ |
| 168 | |
| 169 | .svg.svgz: |
| 170 | gzip -9c < $< > $@ |
| 171 | |
| 172 | .bmp.png: |
| 173 | convert -quality 95 $< $@ |
| 174 | |
| 175 | .png.bmp: |
| 176 | convert $< $@ |
| 177 | |
| 178 | SS_FILES := $(wildcard spreadsheet/*) |
| 179 | |
| 180 | |
| 181 | all: $(SS_FILES) illus.svg image.bmp doc-big.pdf |
| 182 | |
| 183 | reconstitute: illus.svgz image.png |
| 184 | ( cd spreadsheet ; zip -9 ../spreadsheet.xlsx) * ) |
| 185 | qpdf doc-big.pdf doc-small.pdf |
| 186 | |
| 187 | |
| 188 | $(SS_FILES): spreadsheet.xlsx |
| 189 | unzip $@ -d $< |
| 190 | |
| 191 | doc-big.pdf: doc-small.pdf |
| 192 | qpdf --stream-data=uncompress $@ $< |
| 193 | |
| 194 | This `Makefile` allows you to treat the compressed version as the |
| 195 | process input, but to actually check in only the changes against the |
| 196 | uncompressed version by typing “`make`” before “`fossil ci`”. This is |
| 197 | not actually an extra step in practice, since if you’ve got a |
| 198 |
+15
-15
| --- www/javascript.md | ||
| +++ www/javascript.md | ||
| @@ -371,24 +371,24 @@ | ||
| 371 | 371 | maintain your repository’s wiki at all. Fossil’s [`wiki` command][fwc] |
| 372 | 372 | lets you manipulate wiki documents from the command line. For example, |
| 373 | 373 | consider this Vi based workflow: |
| 374 | 374 | |
| 375 | 375 | ```shell |
| 376 | - $ vi 'My Article.wiki' # begin work on new article | |
| 377 | - ...write, write, write... | |
| 378 | - :w # save changes to disk copy | |
| 379 | - :!fossil wiki create 'My Article' '%' # current file (%) to new article | |
| 380 | - ...write, write, write some more... | |
| 381 | - :w # save again | |
| 382 | - :!fossil wiki commit 'My Article' '%' # update article from disk | |
| 383 | - :q # done writing for today | |
| 384 | - | |
| 385 | - ....days later... | |
| 386 | - $ vi # work sans named file today | |
| 387 | - :r !fossil wiki export 'My Article' - # pull article text into vi buffer | |
| 388 | - ...write, write, write yet more... | |
| 389 | - :w !fossil wiki commit - # vi buffer updates article | |
| 376 | +$ vi 'My Article.wiki' # begin work on new article | |
| 377 | + ...write, write, write... | |
| 378 | +:w # save changes to disk copy | |
| 379 | +:!fossil wiki create 'My Article' '%' # current file (%) to new article | |
| 380 | + ...write, write, write some more... | |
| 381 | +:w # save again | |
| 382 | +:!fossil wiki commit 'My Article' '%' # update article from disk | |
| 383 | +:q # done writing for today | |
| 384 | + | |
| 385 | + ....days later... | |
| 386 | +$ vi # work sans named file today | |
| 387 | +:r !fossil wiki export 'My Article' - # pull article text into vi buffer | |
| 388 | + ...write, write, write yet more... | |
| 389 | +:w !fossil wiki commit - # vi buffer updates article | |
| 390 | 390 | ``` |
| 391 | 391 | |
| 392 | 392 | Extending this concept to other text editors is an exercise left to the |
| 393 | 393 | reader. |
| 394 | 394 | |
| @@ -576,11 +576,11 @@ | ||
| 576 | 576 | sufficiently motivated to build a Fossil chat gateway, connecting to |
| 577 | 577 | IRC, Jabber, etc. The messages are stored in the repository’s `chat` |
| 578 | 578 | table with monotonically increasing IDs, so a poller that did something |
| 579 | 579 | like |
| 580 | 580 | |
| 581 | - SELECT xfrom, xmsg FROM chat WHERE msgid > 1234; | |
| 581 | + SELECT xfrom, xmsg FROM chat WHERE msgid > 1234; | |
| 582 | 582 | |
| 583 | 583 | …would pull the messages submitted since the last poll. Making the |
| 584 | 584 | gateway bidirectional should be possible as well, as long as it properly |
| 585 | 585 | uses SQLite transactions. |
| 586 | 586 | |
| 587 | 587 |
| --- www/javascript.md | |
| +++ www/javascript.md | |
| @@ -371,24 +371,24 @@ | |
| 371 | maintain your repository’s wiki at all. Fossil’s [`wiki` command][fwc] |
| 372 | lets you manipulate wiki documents from the command line. For example, |
| 373 | consider this Vi based workflow: |
| 374 | |
| 375 | ```shell |
| 376 | $ vi 'My Article.wiki' # begin work on new article |
| 377 | ...write, write, write... |
| 378 | :w # save changes to disk copy |
| 379 | :!fossil wiki create 'My Article' '%' # current file (%) to new article |
| 380 | ...write, write, write some more... |
| 381 | :w # save again |
| 382 | :!fossil wiki commit 'My Article' '%' # update article from disk |
| 383 | :q # done writing for today |
| 384 | |
| 385 | ....days later... |
| 386 | $ vi # work sans named file today |
| 387 | :r !fossil wiki export 'My Article' - # pull article text into vi buffer |
| 388 | ...write, write, write yet more... |
| 389 | :w !fossil wiki commit - # vi buffer updates article |
| 390 | ``` |
| 391 | |
| 392 | Extending this concept to other text editors is an exercise left to the |
| 393 | reader. |
| 394 | |
| @@ -576,11 +576,11 @@ | |
| 576 | sufficiently motivated to build a Fossil chat gateway, connecting to |
| 577 | IRC, Jabber, etc. The messages are stored in the repository’s `chat` |
| 578 | table with monotonically increasing IDs, so a poller that did something |
| 579 | like |
| 580 | |
| 581 | SELECT xfrom, xmsg FROM chat WHERE msgid > 1234; |
| 582 | |
| 583 | …would pull the messages submitted since the last poll. Making the |
| 584 | gateway bidirectional should be possible as well, as long as it properly |
| 585 | uses SQLite transactions. |
| 586 | |
| 587 |
| --- www/javascript.md | |
| +++ www/javascript.md | |
| @@ -371,24 +371,24 @@ | |
| 371 | maintain your repository’s wiki at all. Fossil’s [`wiki` command][fwc] |
| 372 | lets you manipulate wiki documents from the command line. For example, |
| 373 | consider this Vi based workflow: |
| 374 | |
| 375 | ```shell |
| 376 | $ vi 'My Article.wiki' # begin work on new article |
| 377 | ...write, write, write... |
| 378 | :w # save changes to disk copy |
| 379 | :!fossil wiki create 'My Article' '%' # current file (%) to new article |
| 380 | ...write, write, write some more... |
| 381 | :w # save again |
| 382 | :!fossil wiki commit 'My Article' '%' # update article from disk |
| 383 | :q # done writing for today |
| 384 | |
| 385 | ....days later... |
| 386 | $ vi # work sans named file today |
| 387 | :r !fossil wiki export 'My Article' - # pull article text into vi buffer |
| 388 | ...write, write, write yet more... |
| 389 | :w !fossil wiki commit - # vi buffer updates article |
| 390 | ``` |
| 391 | |
| 392 | Extending this concept to other text editors is an exercise left to the |
| 393 | reader. |
| 394 | |
| @@ -576,11 +576,11 @@ | |
| 576 | sufficiently motivated to build a Fossil chat gateway, connecting to |
| 577 | IRC, Jabber, etc. The messages are stored in the repository’s `chat` |
| 578 | table with monotonically increasing IDs, so a poller that did something |
| 579 | like |
| 580 | |
| 581 | SELECT xfrom, xmsg FROM chat WHERE msgid > 1234; |
| 582 | |
| 583 | …would pull the messages submitted since the last poll. Making the |
| 584 | gateway bidirectional should be possible as well, as long as it properly |
| 585 | uses SQLite transactions. |
| 586 | |
| 587 |
+3
-3
| --- www/loadmgmt.md | ||
| +++ www/loadmgmt.md | ||
| @@ -52,12 +52,12 @@ | ||
| 52 | 52 | easily set it higher on a multi-core server. |
| 53 | 53 | |
| 54 | 54 | The maximum load average can also be set on the command line using |
| 55 | 55 | commands like this: |
| 56 | 56 | |
| 57 | - fossil set max-loadavg 1.5 | |
| 58 | - fossil all set max-loadavg 1.5 | |
| 57 | + fossil set max-loadavg 1.5 | |
| 58 | + fossil all set max-loadavg 1.5 | |
| 59 | 59 | |
| 60 | 60 | The second form is especially useful for changing the maximum load |
| 61 | 61 | average simultaneously on a large number of repositories. |
| 62 | 62 | |
| 63 | 63 | Note that this load-average limiting feature is only available on |
| @@ -71,11 +71,11 @@ | ||
| 71 | 71 | you are running a Fossil instance [inside a `chroot(2)` |
| 72 | 72 | jail](./chroot.md) and you have not mounted the `/proc` virtual file |
| 73 | 73 | system inside that jail. On the [self-hosting Fossil repositories][sh], |
| 74 | 74 | this was accomplished by adding a line to the `/etc/fstab` file: |
| 75 | 75 | |
| 76 | - chroot_jail_proc /home/www/proc proc ro 0 0 | |
| 76 | + chroot_jail_proc /home/www/proc proc ro 0 0 | |
| 77 | 77 | |
| 78 | 78 | The `/home/www/proc` pathname should be adjusted so that the `/proc` |
| 79 | 79 | component is at the root of the chroot jail, of course. |
| 80 | 80 | |
| 81 | 81 | To see if the load-average limiter is functional, visit the |
| 82 | 82 |
| --- www/loadmgmt.md | |
| +++ www/loadmgmt.md | |
| @@ -52,12 +52,12 @@ | |
| 52 | easily set it higher on a multi-core server. |
| 53 | |
| 54 | The maximum load average can also be set on the command line using |
| 55 | commands like this: |
| 56 | |
| 57 | fossil set max-loadavg 1.5 |
| 58 | fossil all set max-loadavg 1.5 |
| 59 | |
| 60 | The second form is especially useful for changing the maximum load |
| 61 | average simultaneously on a large number of repositories. |
| 62 | |
| 63 | Note that this load-average limiting feature is only available on |
| @@ -71,11 +71,11 @@ | |
| 71 | you are running a Fossil instance [inside a `chroot(2)` |
| 72 | jail](./chroot.md) and you have not mounted the `/proc` virtual file |
| 73 | system inside that jail. On the [self-hosting Fossil repositories][sh], |
| 74 | this was accomplished by adding a line to the `/etc/fstab` file: |
| 75 | |
| 76 | chroot_jail_proc /home/www/proc proc ro 0 0 |
| 77 | |
| 78 | The `/home/www/proc` pathname should be adjusted so that the `/proc` |
| 79 | component is at the root of the chroot jail, of course. |
| 80 | |
| 81 | To see if the load-average limiter is functional, visit the |
| 82 |
| --- www/loadmgmt.md | |
| +++ www/loadmgmt.md | |
| @@ -52,12 +52,12 @@ | |
| 52 | easily set it higher on a multi-core server. |
| 53 | |
| 54 | The maximum load average can also be set on the command line using |
| 55 | commands like this: |
| 56 | |
| 57 | fossil set max-loadavg 1.5 |
| 58 | fossil all set max-loadavg 1.5 |
| 59 | |
| 60 | The second form is especially useful for changing the maximum load |
| 61 | average simultaneously on a large number of repositories. |
| 62 | |
| 63 | Note that this load-average limiting feature is only available on |
| @@ -71,11 +71,11 @@ | |
| 71 | you are running a Fossil instance [inside a `chroot(2)` |
| 72 | jail](./chroot.md) and you have not mounted the `/proc` virtual file |
| 73 | system inside that jail. On the [self-hosting Fossil repositories][sh], |
| 74 | this was accomplished by adding a line to the `/etc/fstab` file: |
| 75 | |
| 76 | chroot_jail_proc /home/www/proc proc ro 0 0 |
| 77 | |
| 78 | The `/home/www/proc` pathname should be adjusted so that the `/proc` |
| 79 | component is at the root of the chroot jail, of course. |
| 80 | |
| 81 | To see if the load-average limiter is functional, visit the |
| 82 |
+9
-9
| --- www/server/any/cgi.md | ||
| +++ www/server/any/cgi.md | ||
| @@ -8,12 +8,12 @@ | ||
| 8 | 8 | on the CGI protocol. |
| 9 | 9 | |
| 10 | 10 | To run Fossil as CGI, create a CGI script (here called "repo") in the |
| 11 | 11 | CGI directory of your web server with content like this: |
| 12 | 12 | |
| 13 | - #!/usr/bin/fossil | |
| 14 | - repository: /home/fossil/repo.fossil | |
| 13 | + #!/usr/bin/fossil | |
| 14 | + repository: /home/fossil/repo.fossil | |
| 15 | 15 | |
| 16 | 16 | Adjust the paths appropriately. It may be necessary to set certain |
| 17 | 17 | permissions on this file or to modify an `.htaccess` file or make other |
| 18 | 18 | server-specific changes. Consult the documentation for your particular |
| 19 | 19 | web server. The following permissions are *normally* required, but, |
| @@ -57,13 +57,13 @@ | ||
| 57 | 57 | To serve multiple repositories from a directory using CGI, use the |
| 58 | 58 | "directory:" tag in the CGI script rather than "repository:". You |
| 59 | 59 | might also want to add a "notfound:" tag to tell where to redirect if |
| 60 | 60 | the particular repository requested by the URL is not found: |
| 61 | 61 | |
| 62 | - #!/usr/bin/fossil | |
| 63 | - directory: /home/fossil/repos | |
| 64 | - notfound: http://url-to-go-to-if-repo-not-found/ | |
| 62 | + #!/usr/bin/fossil | |
| 63 | + directory: /home/fossil/repos | |
| 64 | + notfound: http://url-to-go-to-if-repo-not-found/ | |
| 65 | 65 | |
| 66 | 66 | Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b> |
| 67 | 67 | will serve up the repository `/home/fossil/repos/XYZ.fossil` if it |
| 68 | 68 | exists. |
| 69 | 69 | |
| @@ -79,14 +79,14 @@ | ||
| 79 | 79 | However, Fossil in CGI mode needs it in order to generate the correct links. |
| 80 | 80 | |
| 81 | 81 | Apache can be instructed to pass this parameter further to the CGI scripts for |
| 82 | 82 | TLS connections with a stanza like |
| 83 | 83 | |
| 84 | - SetEnvIf X-Forwarded-Proto "https" HTTPS=on | |
| 85 | - | |
| 84 | + SetEnvIf X-Forwarded-Proto "https" HTTPS=on | |
| 85 | + | |
| 86 | 86 | in its config file section for CGI, provided that |
| 87 | 87 | |
| 88 | - proxy_set_header X-Forwarded-Proto $scheme; | |
| 89 | - | |
| 88 | + proxy_set_header X-Forwarded-Proto $scheme; | |
| 89 | + | |
| 90 | 90 | has been be added in the relevant proxying section of the Nginx config file. |
| 91 | 91 | |
| 92 | 92 | *[Return to the top-level Fossil server article.](../)* |
| 93 | 93 |
| --- www/server/any/cgi.md | |
| +++ www/server/any/cgi.md | |
| @@ -8,12 +8,12 @@ | |
| 8 | on the CGI protocol. |
| 9 | |
| 10 | To run Fossil as CGI, create a CGI script (here called "repo") in the |
| 11 | CGI directory of your web server with content like this: |
| 12 | |
| 13 | #!/usr/bin/fossil |
| 14 | repository: /home/fossil/repo.fossil |
| 15 | |
| 16 | Adjust the paths appropriately. It may be necessary to set certain |
| 17 | permissions on this file or to modify an `.htaccess` file or make other |
| 18 | server-specific changes. Consult the documentation for your particular |
| 19 | web server. The following permissions are *normally* required, but, |
| @@ -57,13 +57,13 @@ | |
| 57 | To serve multiple repositories from a directory using CGI, use the |
| 58 | "directory:" tag in the CGI script rather than "repository:". You |
| 59 | might also want to add a "notfound:" tag to tell where to redirect if |
| 60 | the particular repository requested by the URL is not found: |
| 61 | |
| 62 | #!/usr/bin/fossil |
| 63 | directory: /home/fossil/repos |
| 64 | notfound: http://url-to-go-to-if-repo-not-found/ |
| 65 | |
| 66 | Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b> |
| 67 | will serve up the repository `/home/fossil/repos/XYZ.fossil` if it |
| 68 | exists. |
| 69 | |
| @@ -79,14 +79,14 @@ | |
| 79 | However, Fossil in CGI mode needs it in order to generate the correct links. |
| 80 | |
| 81 | Apache can be instructed to pass this parameter further to the CGI scripts for |
| 82 | TLS connections with a stanza like |
| 83 | |
| 84 | SetEnvIf X-Forwarded-Proto "https" HTTPS=on |
| 85 | |
| 86 | in its config file section for CGI, provided that |
| 87 | |
| 88 | proxy_set_header X-Forwarded-Proto $scheme; |
| 89 | |
| 90 | has been be added in the relevant proxying section of the Nginx config file. |
| 91 | |
| 92 | *[Return to the top-level Fossil server article.](../)* |
| 93 |
| --- www/server/any/cgi.md | |
| +++ www/server/any/cgi.md | |
| @@ -8,12 +8,12 @@ | |
| 8 | on the CGI protocol. |
| 9 | |
| 10 | To run Fossil as CGI, create a CGI script (here called "repo") in the |
| 11 | CGI directory of your web server with content like this: |
| 12 | |
| 13 | #!/usr/bin/fossil |
| 14 | repository: /home/fossil/repo.fossil |
| 15 | |
| 16 | Adjust the paths appropriately. It may be necessary to set certain |
| 17 | permissions on this file or to modify an `.htaccess` file or make other |
| 18 | server-specific changes. Consult the documentation for your particular |
| 19 | web server. The following permissions are *normally* required, but, |
| @@ -57,13 +57,13 @@ | |
| 57 | To serve multiple repositories from a directory using CGI, use the |
| 58 | "directory:" tag in the CGI script rather than "repository:". You |
| 59 | might also want to add a "notfound:" tag to tell where to redirect if |
| 60 | the particular repository requested by the URL is not found: |
| 61 | |
| 62 | #!/usr/bin/fossil |
| 63 | directory: /home/fossil/repos |
| 64 | notfound: http://url-to-go-to-if-repo-not-found/ |
| 65 | |
| 66 | Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b> |
| 67 | will serve up the repository `/home/fossil/repos/XYZ.fossil` if it |
| 68 | exists. |
| 69 | |
| @@ -79,14 +79,14 @@ | |
| 79 | However, Fossil in CGI mode needs it in order to generate the correct links. |
| 80 | |
| 81 | Apache can be instructed to pass this parameter further to the CGI scripts for |
| 82 | TLS connections with a stanza like |
| 83 | |
| 84 | SetEnvIf X-Forwarded-Proto "https" HTTPS=on |
| 85 | |
| 86 | in its config file section for CGI, provided that |
| 87 | |
| 88 | proxy_set_header X-Forwarded-Proto $scheme; |
| 89 | |
| 90 | has been be added in the relevant proxying section of the Nginx config file. |
| 91 | |
| 92 | *[Return to the top-level Fossil server article.](../)* |
| 93 |
+26
-26
| --- www/server/any/http-over-ssh.md | ||
| +++ www/server/any/http-over-ssh.md | ||
| @@ -15,15 +15,15 @@ | ||
| 15 | 15 | |
| 16 | 16 | Put something like the following into the `sshd_config` file on the |
| 17 | 17 | Fossil repository server: |
| 18 | 18 | |
| 19 | 19 | ``` ssh-config |
| 20 | - Match Group fossil | |
| 21 | - X11Forwarding no | |
| 22 | - AllowTcpForwarding no | |
| 23 | - AllowAgentForwarding no | |
| 24 | - ForceCommand /home/fossil/bin/wrapper | |
| 20 | +Match Group fossil | |
| 21 | + X11Forwarding no | |
| 22 | + AllowTcpForwarding no | |
| 23 | + AllowAgentForwarding no | |
| 24 | + ForceCommand /home/fossil/bin/wrapper | |
| 25 | 25 | ``` |
| 26 | 26 | |
| 27 | 27 | This file is usually found in `/etc/ssh`, but some OSes put it |
| 28 | 28 | elsewhere. |
| 29 | 29 | |
| @@ -30,11 +30,11 @@ | ||
| 30 | 30 | The first line presumes that we will put all users who need to use our |
| 31 | 31 | Fossil repositories into the `fossil` group, as we will do |
| 32 | 32 | [below](#perms). You could instead say something like: |
| 33 | 33 | |
| 34 | 34 | ``` ssh-config |
| 35 | - Match User alice,bob,carol,dave | |
| 35 | +Match User alice,bob,carol,dave | |
| 36 | 36 | ``` |
| 37 | 37 | |
| 38 | 38 | You have to list the users allowed to use Fossil in this case because |
| 39 | 39 | your system likely has a system administrator that uses SSH for remote |
| 40 | 40 | shell access, so you want to *exclude* that user from the list. For the |
| @@ -42,11 +42,11 @@ | ||
| 42 | 42 | a `Match` block of some sort. |
| 43 | 43 | |
| 44 | 44 | You could instead list the exceptions: |
| 45 | 45 | |
| 46 | 46 | ``` ssh-config |
| 47 | - Match User !evi | |
| 47 | +Match User !evi | |
| 48 | 48 | ``` |
| 49 | 49 | |
| 50 | 50 | This would permit only [Evi the System Administrator][evi] to bypass this |
| 51 | 51 | mechanism. |
| 52 | 52 | |
| @@ -68,16 +68,16 @@ | ||
| 68 | 68 | and rewrite other parts to make this work. |
| 69 | 69 | |
| 70 | 70 | Here is a simpler variant of Andy’s original wrapper script: |
| 71 | 71 | |
| 72 | 72 | ``` sh |
| 73 | - #!/bin/bash | |
| 74 | - set -- $SSH_ORIGINAL_COMMAND | |
| 75 | - while [ $# -gt 1 ] ; do shift ; done | |
| 76 | - export REMOTE_USER="$USER" | |
| 77 | - ROOT=/home/fossil | |
| 78 | - exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" | |
| 73 | +#!/bin/bash | |
| 74 | +set -- $SSH_ORIGINAL_COMMAND | |
| 75 | +while [ $# -gt 1 ] ; do shift ; done | |
| 76 | +export REMOTE_USER="$USER" | |
| 77 | +ROOT=/home/fossil | |
| 78 | +exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" | |
| 79 | 79 | ``` |
| 80 | 80 | |
| 81 | 81 | The substantive changes are: |
| 82 | 82 | |
| 83 | 83 | 1. Move the command rewriting bits to the start. |
| @@ -104,11 +104,11 @@ | ||
| 104 | 104 | check the absolute paths for local correctness: is `/bin/basename` |
| 105 | 105 | installed on your system, for example? |
| 106 | 106 | |
| 107 | 107 | Under this scheme, you clone with a command like: |
| 108 | 108 | |
| 109 | - $ fossil clone ssh://HOST/repo.fossil | |
| 109 | + $ fossil clone ssh://HOST/repo.fossil | |
| 110 | 110 | |
| 111 | 111 | This will clone the remote `/home/fossil/museum/repo.fossil` repository |
| 112 | 112 | to your local machine under the same name and open it into a “`repo/`” |
| 113 | 113 | subdirectory. Notice that we didn’t have to give the `museum/` part of |
| 114 | 114 | the path: it’s implicit per point #3 above. |
| @@ -129,20 +129,20 @@ | ||
| 129 | 129 | repositories are stored. |
| 130 | 130 | |
| 131 | 131 | You can achieve all of this on a Linux box with: |
| 132 | 132 | |
| 133 | 133 | ``` shell |
| 134 | - sudo adduser fossil | |
| 135 | - for u in alice bob carol dave ; do | |
| 136 | - sudo adduser $u | |
| 137 | - sudo gpasswd -a fossil $u | |
| 138 | - done | |
| 139 | - sudo -i -u fossil | |
| 140 | - chmod 710 . | |
| 141 | - mkdir -m 750 bin | |
| 142 | - mkdir -m 770 museum | |
| 143 | - ln -s /usr/local/bin/fossil bin | |
| 134 | +sudo adduser fossil | |
| 135 | +for u in alice bob carol dave ; do | |
| 136 | + sudo adduser $u | |
| 137 | + sudo gpasswd -a fossil $u | |
| 138 | +done | |
| 139 | +sudo -i -u fossil | |
| 140 | +chmod 710 . | |
| 141 | +mkdir -m 750 bin | |
| 142 | +mkdir -m 770 museum | |
| 143 | +ln -s /usr/local/bin/fossil bin | |
| 144 | 144 | ``` |
| 145 | 145 | |
| 146 | 146 | You then need to copy the Fossil repositories into `~fossil/museum` and |
| 147 | 147 | make them readable and writable by group `fossil`. These repositories |
| 148 | 148 | presumably already have Fossil users configured, with the necessary |
| @@ -153,12 +153,12 @@ | ||
| 153 | 153 | Fossil only pays attention to this environment variable in certain |
| 154 | 154 | contexts, of which “`fossil http`” is not one. Run this command against |
| 155 | 155 | each repo to allow that: |
| 156 | 156 | |
| 157 | 157 | ``` shell |
| 158 | - echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | | |
| 159 | - fossil sql -R museum/repo.fossil | |
| 158 | +echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | | |
| 159 | +fossil sql -R museum/repo.fossil | |
| 160 | 160 | ``` |
| 161 | 161 | |
| 162 | 162 | Now you can configure SSH authentication for each user. Since Fossil’s |
| 163 | 163 | password-saving feature doesn’t work in this case, I suggest setting up |
| 164 | 164 | SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication |
| 165 | 165 |
| --- www/server/any/http-over-ssh.md | |
| +++ www/server/any/http-over-ssh.md | |
| @@ -15,15 +15,15 @@ | |
| 15 | |
| 16 | Put something like the following into the `sshd_config` file on the |
| 17 | Fossil repository server: |
| 18 | |
| 19 | ``` ssh-config |
| 20 | Match Group fossil |
| 21 | X11Forwarding no |
| 22 | AllowTcpForwarding no |
| 23 | AllowAgentForwarding no |
| 24 | ForceCommand /home/fossil/bin/wrapper |
| 25 | ``` |
| 26 | |
| 27 | This file is usually found in `/etc/ssh`, but some OSes put it |
| 28 | elsewhere. |
| 29 | |
| @@ -30,11 +30,11 @@ | |
| 30 | The first line presumes that we will put all users who need to use our |
| 31 | Fossil repositories into the `fossil` group, as we will do |
| 32 | [below](#perms). You could instead say something like: |
| 33 | |
| 34 | ``` ssh-config |
| 35 | Match User alice,bob,carol,dave |
| 36 | ``` |
| 37 | |
| 38 | You have to list the users allowed to use Fossil in this case because |
| 39 | your system likely has a system administrator that uses SSH for remote |
| 40 | shell access, so you want to *exclude* that user from the list. For the |
| @@ -42,11 +42,11 @@ | |
| 42 | a `Match` block of some sort. |
| 43 | |
| 44 | You could instead list the exceptions: |
| 45 | |
| 46 | ``` ssh-config |
| 47 | Match User !evi |
| 48 | ``` |
| 49 | |
| 50 | This would permit only [Evi the System Administrator][evi] to bypass this |
| 51 | mechanism. |
| 52 | |
| @@ -68,16 +68,16 @@ | |
| 68 | and rewrite other parts to make this work. |
| 69 | |
| 70 | Here is a simpler variant of Andy’s original wrapper script: |
| 71 | |
| 72 | ``` sh |
| 73 | #!/bin/bash |
| 74 | set -- $SSH_ORIGINAL_COMMAND |
| 75 | while [ $# -gt 1 ] ; do shift ; done |
| 76 | export REMOTE_USER="$USER" |
| 77 | ROOT=/home/fossil |
| 78 | exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" |
| 79 | ``` |
| 80 | |
| 81 | The substantive changes are: |
| 82 | |
| 83 | 1. Move the command rewriting bits to the start. |
| @@ -104,11 +104,11 @@ | |
| 104 | check the absolute paths for local correctness: is `/bin/basename` |
| 105 | installed on your system, for example? |
| 106 | |
| 107 | Under this scheme, you clone with a command like: |
| 108 | |
| 109 | $ fossil clone ssh://HOST/repo.fossil |
| 110 | |
| 111 | This will clone the remote `/home/fossil/museum/repo.fossil` repository |
| 112 | to your local machine under the same name and open it into a “`repo/`” |
| 113 | subdirectory. Notice that we didn’t have to give the `museum/` part of |
| 114 | the path: it’s implicit per point #3 above. |
| @@ -129,20 +129,20 @@ | |
| 129 | repositories are stored. |
| 130 | |
| 131 | You can achieve all of this on a Linux box with: |
| 132 | |
| 133 | ``` shell |
| 134 | sudo adduser fossil |
| 135 | for u in alice bob carol dave ; do |
| 136 | sudo adduser $u |
| 137 | sudo gpasswd -a fossil $u |
| 138 | done |
| 139 | sudo -i -u fossil |
| 140 | chmod 710 . |
| 141 | mkdir -m 750 bin |
| 142 | mkdir -m 770 museum |
| 143 | ln -s /usr/local/bin/fossil bin |
| 144 | ``` |
| 145 | |
| 146 | You then need to copy the Fossil repositories into `~fossil/museum` and |
| 147 | make them readable and writable by group `fossil`. These repositories |
| 148 | presumably already have Fossil users configured, with the necessary |
| @@ -153,12 +153,12 @@ | |
| 153 | Fossil only pays attention to this environment variable in certain |
| 154 | contexts, of which “`fossil http`” is not one. Run this command against |
| 155 | each repo to allow that: |
| 156 | |
| 157 | ``` shell |
| 158 | echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | |
| 159 | fossil sql -R museum/repo.fossil |
| 160 | ``` |
| 161 | |
| 162 | Now you can configure SSH authentication for each user. Since Fossil’s |
| 163 | password-saving feature doesn’t work in this case, I suggest setting up |
| 164 | SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication |
| 165 |
| --- www/server/any/http-over-ssh.md | |
| +++ www/server/any/http-over-ssh.md | |
| @@ -15,15 +15,15 @@ | |
| 15 | |
| 16 | Put something like the following into the `sshd_config` file on the |
| 17 | Fossil repository server: |
| 18 | |
| 19 | ``` ssh-config |
| 20 | Match Group fossil |
| 21 | X11Forwarding no |
| 22 | AllowTcpForwarding no |
| 23 | AllowAgentForwarding no |
| 24 | ForceCommand /home/fossil/bin/wrapper |
| 25 | ``` |
| 26 | |
| 27 | This file is usually found in `/etc/ssh`, but some OSes put it |
| 28 | elsewhere. |
| 29 | |
| @@ -30,11 +30,11 @@ | |
| 30 | The first line presumes that we will put all users who need to use our |
| 31 | Fossil repositories into the `fossil` group, as we will do |
| 32 | [below](#perms). You could instead say something like: |
| 33 | |
| 34 | ``` ssh-config |
| 35 | Match User alice,bob,carol,dave |
| 36 | ``` |
| 37 | |
| 38 | You have to list the users allowed to use Fossil in this case because |
| 39 | your system likely has a system administrator that uses SSH for remote |
| 40 | shell access, so you want to *exclude* that user from the list. For the |
| @@ -42,11 +42,11 @@ | |
| 42 | a `Match` block of some sort. |
| 43 | |
| 44 | You could instead list the exceptions: |
| 45 | |
| 46 | ``` ssh-config |
| 47 | Match User !evi |
| 48 | ``` |
| 49 | |
| 50 | This would permit only [Evi the System Administrator][evi] to bypass this |
| 51 | mechanism. |
| 52 | |
| @@ -68,16 +68,16 @@ | |
| 68 | and rewrite other parts to make this work. |
| 69 | |
| 70 | Here is a simpler variant of Andy’s original wrapper script: |
| 71 | |
| 72 | ``` sh |
| 73 | #!/bin/bash |
| 74 | set -- $SSH_ORIGINAL_COMMAND |
| 75 | while [ $# -gt 1 ] ; do shift ; done |
| 76 | export REMOTE_USER="$USER" |
| 77 | ROOT=/home/fossil |
| 78 | exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" |
| 79 | ``` |
| 80 | |
| 81 | The substantive changes are: |
| 82 | |
| 83 | 1. Move the command rewriting bits to the start. |
| @@ -104,11 +104,11 @@ | |
| 104 | check the absolute paths for local correctness: is `/bin/basename` |
| 105 | installed on your system, for example? |
| 106 | |
| 107 | Under this scheme, you clone with a command like: |
| 108 | |
| 109 | $ fossil clone ssh://HOST/repo.fossil |
| 110 | |
| 111 | This will clone the remote `/home/fossil/museum/repo.fossil` repository |
| 112 | to your local machine under the same name and open it into a “`repo/`” |
| 113 | subdirectory. Notice that we didn’t have to give the `museum/` part of |
| 114 | the path: it’s implicit per point #3 above. |
| @@ -129,20 +129,20 @@ | |
| 129 | repositories are stored. |
| 130 | |
| 131 | You can achieve all of this on a Linux box with: |
| 132 | |
| 133 | ``` shell |
| 134 | sudo adduser fossil |
| 135 | for u in alice bob carol dave ; do |
| 136 | sudo adduser $u |
| 137 | sudo gpasswd -a fossil $u |
| 138 | done |
| 139 | sudo -i -u fossil |
| 140 | chmod 710 . |
| 141 | mkdir -m 750 bin |
| 142 | mkdir -m 770 museum |
| 143 | ln -s /usr/local/bin/fossil bin |
| 144 | ``` |
| 145 | |
| 146 | You then need to copy the Fossil repositories into `~fossil/museum` and |
| 147 | make them readable and writable by group `fossil`. These repositories |
| 148 | presumably already have Fossil users configured, with the necessary |
| @@ -153,12 +153,12 @@ | |
| 153 | Fossil only pays attention to this environment variable in certain |
| 154 | contexts, of which “`fossil http`” is not one. Run this command against |
| 155 | each repo to allow that: |
| 156 | |
| 157 | ``` shell |
| 158 | echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | |
| 159 | fossil sql -R museum/repo.fossil |
| 160 | ``` |
| 161 | |
| 162 | Now you can configure SSH authentication for each user. Since Fossil’s |
| 163 | password-saving feature doesn’t work in this case, I suggest setting up |
| 164 | SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication |
| 165 |
+2
-2
| --- www/server/any/inetd.md | ||
| +++ www/server/any/inetd.md | ||
| @@ -2,11 +2,11 @@ | ||
| 2 | 2 | |
| 3 | 3 | A Fossil server can be launched on-demand by `inetd` by using the |
| 4 | 4 | [`fossil http`](/help/http) command. To do so, add a line like the |
| 5 | 5 | following to its configuration file, typically `/etc/inetd.conf`: |
| 6 | 6 | |
| 7 | - 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil | |
| 7 | + 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil | |
| 8 | 8 | |
| 9 | 9 | In this example, you are telling `inetd` that when an incoming |
| 10 | 10 | connection appears on TCP port 80 that it should launch the program |
| 11 | 11 | `/usr/bin/fossil` with the arguments shown. Obviously you will need to |
| 12 | 12 | modify the pathnames for your particular setup. The final argument is |
| @@ -17,11 +17,11 @@ | ||
| 17 | 17 | specification must be a symbolic name and cannot be numeric, add the |
| 18 | 18 | desired name and port to `/etc/services`. For example, if you want your |
| 19 | 19 | Fossil server running on TCP port 12345 instead of 80, you will need to |
| 20 | 20 | add: |
| 21 | 21 | |
| 22 | - fossil 12345/tcp # fossil server | |
| 22 | + fossil 12345/tcp # fossil server | |
| 23 | 23 | |
| 24 | 24 | and use the symbolic name “`fossil`” instead of the numeric TCP port |
| 25 | 25 | number (“12345” in the above example) in `inetd.conf`. |
| 26 | 26 | |
| 27 | 27 | Notice that we configured `inetd` to launch Fossil as root. See the |
| 28 | 28 |
| --- www/server/any/inetd.md | |
| +++ www/server/any/inetd.md | |
| @@ -2,11 +2,11 @@ | |
| 2 | |
| 3 | A Fossil server can be launched on-demand by `inetd` by using the |
| 4 | [`fossil http`](/help/http) command. To do so, add a line like the |
| 5 | following to its configuration file, typically `/etc/inetd.conf`: |
| 6 | |
| 7 | 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil |
| 8 | |
| 9 | In this example, you are telling `inetd` that when an incoming |
| 10 | connection appears on TCP port 80 that it should launch the program |
| 11 | `/usr/bin/fossil` with the arguments shown. Obviously you will need to |
| 12 | modify the pathnames for your particular setup. The final argument is |
| @@ -17,11 +17,11 @@ | |
| 17 | specification must be a symbolic name and cannot be numeric, add the |
| 18 | desired name and port to `/etc/services`. For example, if you want your |
| 19 | Fossil server running on TCP port 12345 instead of 80, you will need to |
| 20 | add: |
| 21 | |
| 22 | fossil 12345/tcp # fossil server |
| 23 | |
| 24 | and use the symbolic name “`fossil`” instead of the numeric TCP port |
| 25 | number (“12345” in the above example) in `inetd.conf`. |
| 26 | |
| 27 | Notice that we configured `inetd` to launch Fossil as root. See the |
| 28 |
| --- www/server/any/inetd.md | |
| +++ www/server/any/inetd.md | |
| @@ -2,11 +2,11 @@ | |
| 2 | |
| 3 | A Fossil server can be launched on-demand by `inetd` by using the |
| 4 | [`fossil http`](/help/http) command. To do so, add a line like the |
| 5 | following to its configuration file, typically `/etc/inetd.conf`: |
| 6 | |
| 7 | 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil |
| 8 | |
| 9 | In this example, you are telling `inetd` that when an incoming |
| 10 | connection appears on TCP port 80 that it should launch the program |
| 11 | `/usr/bin/fossil` with the arguments shown. Obviously you will need to |
| 12 | modify the pathnames for your particular setup. The final argument is |
| @@ -17,11 +17,11 @@ | |
| 17 | specification must be a symbolic name and cannot be numeric, add the |
| 18 | desired name and port to `/etc/services`. For example, if you want your |
| 19 | Fossil server running on TCP port 12345 instead of 80, you will need to |
| 20 | add: |
| 21 | |
| 22 | fossil 12345/tcp # fossil server |
| 23 | |
| 24 | and use the symbolic name “`fossil`” instead of the numeric TCP port |
| 25 | number (“12345” in the above example) in `inetd.conf`. |
| 26 | |
| 27 | Notice that we configured `inetd` to launch Fossil as root. See the |
| 28 |
+3
-3
| --- www/server/any/none.md | ||
| +++ www/server/any/none.md | ||
| @@ -28,19 +28,19 @@ | ||
| 28 | 28 | |
| 29 | 29 | You can omit the _REPOSITORY_ argument if you run one of the above |
| 30 | 30 | commands from within a Fossil checkout directory to serve that |
| 31 | 31 | repository: |
| 32 | 32 | |
| 33 | - $ fossil ui # or... | |
| 34 | - $ fossil server | |
| 33 | + $ fossil ui # or... | |
| 34 | + $ fossil server | |
| 35 | 35 | |
| 36 | 36 | You can abbreviate Fossil sub-commands as long as they are unambiguous. |
| 37 | 37 | “`server`” can currently be as short as “`ser`”. |
| 38 | 38 | |
| 39 | 39 | You can serve a directory containing multiple `*.fossil` files like so: |
| 40 | 40 | |
| 41 | - $ fossil server --port 9000 --repolist /path/to/repo/dir | |
| 41 | + $ fossil server --port 9000 --repolist /path/to/repo/dir | |
| 42 | 42 | |
| 43 | 43 | There is an [example script](/file/tools/fslsrv) in the Fossil |
| 44 | 44 | distribution that wraps `fossil server` to produce more complicated |
| 45 | 45 | effects. Feel free to take it, study it, and modify it to suit your |
| 46 | 46 | local needs. |
| 47 | 47 |
| --- www/server/any/none.md | |
| +++ www/server/any/none.md | |
| @@ -28,19 +28,19 @@ | |
| 28 | |
| 29 | You can omit the _REPOSITORY_ argument if you run one of the above |
| 30 | commands from within a Fossil checkout directory to serve that |
| 31 | repository: |
| 32 | |
| 33 | $ fossil ui # or... |
| 34 | $ fossil server |
| 35 | |
| 36 | You can abbreviate Fossil sub-commands as long as they are unambiguous. |
| 37 | “`server`” can currently be as short as “`ser`”. |
| 38 | |
| 39 | You can serve a directory containing multiple `*.fossil` files like so: |
| 40 | |
| 41 | $ fossil server --port 9000 --repolist /path/to/repo/dir |
| 42 | |
| 43 | There is an [example script](/file/tools/fslsrv) in the Fossil |
| 44 | distribution that wraps `fossil server` to produce more complicated |
| 45 | effects. Feel free to take it, study it, and modify it to suit your |
| 46 | local needs. |
| 47 |
| --- www/server/any/none.md | |
| +++ www/server/any/none.md | |
| @@ -28,19 +28,19 @@ | |
| 28 | |
| 29 | You can omit the _REPOSITORY_ argument if you run one of the above |
| 30 | commands from within a Fossil checkout directory to serve that |
| 31 | repository: |
| 32 | |
| 33 | $ fossil ui # or... |
| 34 | $ fossil server |
| 35 | |
| 36 | You can abbreviate Fossil sub-commands as long as they are unambiguous. |
| 37 | “`server`” can currently be as short as “`ser`”. |
| 38 | |
| 39 | You can serve a directory containing multiple `*.fossil` files like so: |
| 40 | |
| 41 | $ fossil server --port 9000 --repolist /path/to/repo/dir |
| 42 | |
| 43 | There is an [example script](/file/tools/fslsrv) in the Fossil |
| 44 | distribution that wraps `fossil server` to produce more complicated |
| 45 | effects. Feel free to take it, study it, and modify it to suit your |
| 46 | local needs. |
| 47 |
+6
-6
| --- www/server/any/scgi.md | ||
| +++ www/server/any/scgi.md | ||
| @@ -9,15 +9,15 @@ | ||
| 9 | 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | 11 | |
| 12 | 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | 13 | |
| 14 | - location /code/ { | |
| 15 | - include scgi_params; | |
| 16 | - scgi_param SCRIPT_NAME "/code"; | |
| 17 | - scgi_pass localhost:9000; | |
| 18 | - } | |
| 14 | + location /code/ { | |
| 15 | + include scgi_params; | |
| 16 | + scgi_param SCRIPT_NAME "/code"; | |
| 17 | + scgi_pass localhost:9000; | |
| 18 | + } | |
| 19 | 19 | |
| 20 | 20 | The `scgi_params` file comes with nginx, and it simply translates nginx |
| 21 | 21 | internal variables to `scgi_param` directives to create SCGI environment |
| 22 | 22 | variables for the proxied program; in this case, Fossil. Our explicit |
| 23 | 23 | `scgi_param` call to define `SCRIPT_NAME` adds one more variable to this |
| @@ -28,11 +28,11 @@ | ||
| 28 | 28 | |
| 29 | 29 | The final directive simply tells nginx to proxy all calls to URLs under |
| 30 | 30 | `/code` down to an SCGI program on TCP port 9000. We can temporarily |
| 31 | 31 | set Fossil up as a server on that port like so: |
| 32 | 32 | |
| 33 | - $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & | |
| 33 | + $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & | |
| 34 | 34 | |
| 35 | 35 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 36 | 36 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 37 | 37 | options discussed in that linked document — such as the ability to serve |
| 38 | 38 | a directory full of Fossil repositories rather than just a single |
| 39 | 39 |
| --- www/server/any/scgi.md | |
| +++ www/server/any/scgi.md | |
| @@ -9,15 +9,15 @@ | |
| 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | |
| 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | |
| 14 | location /code/ { |
| 15 | include scgi_params; |
| 16 | scgi_param SCRIPT_NAME "/code"; |
| 17 | scgi_pass localhost:9000; |
| 18 | } |
| 19 | |
| 20 | The `scgi_params` file comes with nginx, and it simply translates nginx |
| 21 | internal variables to `scgi_param` directives to create SCGI environment |
| 22 | variables for the proxied program; in this case, Fossil. Our explicit |
| 23 | `scgi_param` call to define `SCRIPT_NAME` adds one more variable to this |
| @@ -28,11 +28,11 @@ | |
| 28 | |
| 29 | The final directive simply tells nginx to proxy all calls to URLs under |
| 30 | `/code` down to an SCGI program on TCP port 9000. We can temporarily |
| 31 | set Fossil up as a server on that port like so: |
| 32 | |
| 33 | $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & |
| 34 | |
| 35 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 36 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 37 | options discussed in that linked document — such as the ability to serve |
| 38 | a directory full of Fossil repositories rather than just a single |
| 39 |
| --- www/server/any/scgi.md | |
| +++ www/server/any/scgi.md | |
| @@ -9,15 +9,15 @@ | |
| 9 | This can be used with a web server such as [nginx](http://nginx.org) |
| 10 | which does not support [Fossil’s CGI mode](./cgi.md). |
| 11 | |
| 12 | A basic nginx configuration to support SCGI with Fossil looks like this: |
| 13 | |
| 14 | location /code/ { |
| 15 | include scgi_params; |
| 16 | scgi_param SCRIPT_NAME "/code"; |
| 17 | scgi_pass localhost:9000; |
| 18 | } |
| 19 | |
| 20 | The `scgi_params` file comes with nginx, and it simply translates nginx |
| 21 | internal variables to `scgi_param` directives to create SCGI environment |
| 22 | variables for the proxied program; in this case, Fossil. Our explicit |
| 23 | `scgi_param` call to define `SCRIPT_NAME` adds one more variable to this |
| @@ -28,11 +28,11 @@ | |
| 28 | |
| 29 | The final directive simply tells nginx to proxy all calls to URLs under |
| 30 | `/code` down to an SCGI program on TCP port 9000. We can temporarily |
| 31 | set Fossil up as a server on that port like so: |
| 32 | |
| 33 | $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & |
| 34 | |
| 35 | The `--scgi` option switches Fossil into SCGI mode from its default, |
| 36 | which is [stand-alone HTTP server mode](./none.md). All of the other |
| 37 | options discussed in that linked document — such as the ability to serve |
| 38 | a directory full of Fossil repositories rather than just a single |
| 39 |
+9
-9
| --- www/server/any/xinetd.md | ||
| +++ www/server/any/xinetd.md | ||
| @@ -6,19 +6,19 @@ | ||
| 6 | 6 | |
| 7 | 7 | The typical configuration file is either `/etc/xinetd.conf` or a subfile |
| 8 | 8 | in the `/etc/xinetd.d` directory. You need a configuration something |
| 9 | 9 | like this for Fossil: |
| 10 | 10 | |
| 11 | - service http | |
| 12 | - { | |
| 13 | - port = 80 | |
| 14 | - socket_type = stream | |
| 15 | - wait = no | |
| 16 | - user = root | |
| 17 | - server = /usr/bin/fossil | |
| 18 | - server_args = http /home/fossil/repos/ | |
| 19 | - } | |
| 11 | + service http | |
| 12 | + { | |
| 13 | + port = 80 | |
| 14 | + socket_type = stream | |
| 15 | + wait = no | |
| 16 | + user = root | |
| 17 | + server = /usr/bin/fossil | |
| 18 | + server_args = http /home/fossil/repos/ | |
| 19 | + } | |
| 20 | 20 | |
| 21 | 21 | This example configures Fossil to serve multiple repositories under the |
| 22 | 22 | `/home/fossil/repos/` directory. |
| 23 | 23 | |
| 24 | 24 | Beyond this, see the general commentary in our article on [the `inetd` |
| 25 | 25 |
| --- www/server/any/xinetd.md | |
| +++ www/server/any/xinetd.md | |
| @@ -6,19 +6,19 @@ | |
| 6 | |
| 7 | The typical configuration file is either `/etc/xinetd.conf` or a subfile |
| 8 | in the `/etc/xinetd.d` directory. You need a configuration something |
| 9 | like this for Fossil: |
| 10 | |
| 11 | service http |
| 12 | { |
| 13 | port = 80 |
| 14 | socket_type = stream |
| 15 | wait = no |
| 16 | user = root |
| 17 | server = /usr/bin/fossil |
| 18 | server_args = http /home/fossil/repos/ |
| 19 | } |
| 20 | |
| 21 | This example configures Fossil to serve multiple repositories under the |
| 22 | `/home/fossil/repos/` directory. |
| 23 | |
| 24 | Beyond this, see the general commentary in our article on [the `inetd` |
| 25 |
| --- www/server/any/xinetd.md | |
| +++ www/server/any/xinetd.md | |
| @@ -6,19 +6,19 @@ | |
| 6 | |
| 7 | The typical configuration file is either `/etc/xinetd.conf` or a subfile |
| 8 | in the `/etc/xinetd.d` directory. You need a configuration something |
| 9 | like this for Fossil: |
| 10 | |
| 11 | service http |
| 12 | { |
| 13 | port = 80 |
| 14 | socket_type = stream |
| 15 | wait = no |
| 16 | user = root |
| 17 | server = /usr/bin/fossil |
| 18 | server_args = http /home/fossil/repos/ |
| 19 | } |
| 20 | |
| 21 | This example configures Fossil to serve multiple repositories under the |
| 22 | `/home/fossil/repos/` directory. |
| 23 | |
| 24 | Beyond this, see the general commentary in our article on [the `inetd` |
| 25 |
+46
-48
| --- www/server/debian/nginx.md | ||
| +++ www/server/debian/nginx.md | ||
| @@ -101,11 +101,11 @@ | ||
| 101 | 101 | ## <a id="deps"></a>Installing the Dependencies |
| 102 | 102 | |
| 103 | 103 | The first step is to install some non-default packages we’ll need. SSH into |
| 104 | 104 | your server, then say: |
| 105 | 105 | |
| 106 | - $ sudo apt install fossil nginx | |
| 106 | + $ sudo apt install fossil nginx | |
| 107 | 107 | |
| 108 | 108 | You can leave “`fossil`” out of that if you’re building Fossil from |
| 109 | 109 | source to get a more up-to-date version than is shipped with the host |
| 110 | 110 | OS. |
| 111 | 111 | |
| @@ -131,12 +131,12 @@ | ||
| 131 | 131 | On Debian and Ubuntu systems the primary user-level configuration file |
| 132 | 132 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 133 | 133 | file contain only a list of include statements, one for each site that |
| 134 | 134 | server hosts: |
| 135 | 135 | |
| 136 | - include local/example.com | |
| 137 | - include local/foo.net | |
| 136 | + include local/example.com | |
| 137 | + include local/foo.net | |
| 138 | 138 | |
| 139 | 139 | Those files then each define one domain’s configuration. Here, |
| 140 | 140 | `/etc/nginx/local/example.com` contains the configuration for |
| 141 | 141 | `*.example.com` and its alias `*.example.net`; and `local/foo.net` |
| 142 | 142 | contains the configuration for `*.foo.net`. |
| @@ -197,13 +197,13 @@ | ||
| 197 | 197 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 198 | 198 | try on your own site, such as static asset proxying. |
| 199 | 199 | |
| 200 | 200 | You also need a `local/code` file containing: |
| 201 | 201 | |
| 202 | - include scgi_params; | |
| 203 | - scgi_pass 127.0.0.1:12345; | |
| 204 | - scgi_param SCRIPT_NAME "/code"; | |
| 202 | + include scgi_params; | |
| 203 | + scgi_pass 127.0.0.1:12345; | |
| 204 | + scgi_param SCRIPT_NAME "/code"; | |
| 205 | 205 | |
| 206 | 206 | We separate that out because nginx refuses to inherit certain settings |
| 207 | 207 | between nested location blocks, so rather than repeat them, we extract |
| 208 | 208 | them to this separate file and include it from both locations where it’s |
| 209 | 209 | needed. You see this above where we set far-future expiration dates on |
| @@ -213,16 +213,16 @@ | ||
| 213 | 213 | Fossil-based site considerably faster. |
| 214 | 214 | |
| 215 | 215 | Similarly, the `local/generic` file referenced above helps us reduce unnecessary |
| 216 | 216 | repetition among the multiple sites this configuration hosts: |
| 217 | 217 | |
| 218 | - root /var/www/$host; | |
| 218 | + root /var/www/$host; | |
| 219 | 219 | |
| 220 | - listen 80; | |
| 221 | - listen [::]:80; | |
| 220 | + listen 80; | |
| 221 | + listen [::]:80; | |
| 222 | 222 | |
| 223 | - charset utf-8; | |
| 223 | + charset utf-8; | |
| 224 | 224 | |
| 225 | 225 | There are some configuration directives that nginx refuses to substitute |
| 226 | 226 | variables into, citing performance considerations, so there is a limit |
| 227 | 227 | to how much repetition you can squeeze out this way. One such example |
| 228 | 228 | are the `access_log` and `error_log` directives, which follow an obvious |
| @@ -246,14 +246,14 @@ | ||
| 246 | 246 | |
| 247 | 247 | However, it is still worth showing the proper method of proxying |
| 248 | 248 | Fossil’s HTTP server through nginx if only to make reading nginx |
| 249 | 249 | documentation on other sites easier: |
| 250 | 250 | |
| 251 | - location /code { | |
| 252 | - rewrite ^/code(/.*) $1 break; | |
| 253 | - proxy_pass http://127.0.0.1:12345; | |
| 254 | - } | |
| 251 | + location /code { | |
| 252 | + rewrite ^/code(/.*) $1 break; | |
| 253 | + proxy_pass http://127.0.0.1:12345; | |
| 254 | + } | |
| 255 | 255 | |
| 256 | 256 | The most common thing people get wrong when hand-rolling a configuration |
| 257 | 257 | like this is to get the slashes wrong. Fossil is sensitive to this. For |
| 258 | 258 | instance, Fossil will not collapse double slashes down to a single |
| 259 | 259 | slash, as some other HTTP servers will. |
| @@ -267,12 +267,12 @@ | ||
| 267 | 267 | a problem, but when sending [unversioned content][uv], it uses a single |
| 268 | 268 | message for the entire file. Therefore, if you will be storing files |
| 269 | 269 | larger than this limit as unversioned content, you need to raise the |
| 270 | 270 | limit. Within the `location` block: |
| 271 | 271 | |
| 272 | - # Allow large unversioned file uploads, such as PDFs | |
| 273 | - client_max_body_size 20M; | |
| 272 | + # Allow large unversioned file uploads, such as PDFs | |
| 273 | + client_max_body_size 20M; | |
| 274 | 274 | |
| 275 | 275 | [uv]: ../../unvers.wiki |
| 276 | 276 | |
| 277 | 277 | |
| 278 | 278 | ## <a id="fail2ban"></a> Integrating `fail2ban` |
| @@ -285,32 +285,32 @@ | ||
| 285 | 285 | Fossil behind an nginx proxy, we convert these failures to log file |
| 286 | 286 | form, which `fail2ban` is designed to handle. |
| 287 | 287 | |
| 288 | 288 | First, install `fail2ban`, if you haven’t already: |
| 289 | 289 | |
| 290 | - sudo apt install fail2ban | |
| 290 | + sudo apt install fail2ban | |
| 291 | 291 | |
| 292 | 292 | We’d like `fail2ban` to react to Fossil `/login` failures. The stock |
| 293 | 293 | configuration of `fail2ban` only detects a few common sorts of SSH |
| 294 | 294 | attacks by default, and its included (but disabled) nginx attack |
| 295 | 295 | detectors don’t include one that knows how to detect an attack on |
| 296 | 296 | Fossil. We have to teach it by putting the following into |
| 297 | 297 | `/etc/fail2ban/filter.d/nginx-fossil-login.conf`: |
| 298 | 298 | |
| 299 | - [Definition] | |
| 300 | - failregex = ^<HOST> - .*POST .*/login HTTP/..." 401 | |
| 299 | + [Definition] | |
| 300 | + failregex = ^<HOST> - .*POST .*/login HTTP/..." 401 | |
| 301 | 301 | |
| 302 | 302 | That teaches `fail2ban` how to recognize the errors logged by Fossil |
| 303 | 303 | [as of 2.14](/info/39d7eb0e22). (Earlier versions of Fossil returned |
| 304 | 304 | HTTP status code 200 for this, so you couldn’t distinguish a successful |
| 305 | 305 | login from a failure.) |
| 306 | 306 | |
| 307 | 307 | Then in `/etc/fail2ban/jail.local`, add this section: |
| 308 | 308 | |
| 309 | - [nginx-fossil-login] | |
| 310 | - enabled = true | |
| 311 | - logpath = /var/log/nginx/*-https-access.log | |
| 309 | + [nginx-fossil-login] | |
| 310 | + enabled = true | |
| 311 | + logpath = /var/log/nginx/*-https-access.log | |
| 312 | 312 | |
| 313 | 313 | The last line is the key: it tells `fail2ban` where we’ve put all of our |
| 314 | 314 | per-repo access logs in the nginx config above. |
| 315 | 315 | |
| 316 | 316 | There’s a [lot more you can do][dof2b], but that gets us out of scope of |
| @@ -338,44 +338,42 @@ | ||
| 338 | 338 | |
| 339 | 339 | You may wish to include something like this from each `server { }` |
| 340 | 340 | block in your configuration to enable TLS in a common, secure way: |
| 341 | 341 | |
| 342 | 342 | ``` |
| 343 | - # Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port. | |
| 344 | - listen 443 ssl; | |
| 345 | - listen [::]:443 ssl; | |
| 346 | - | |
| 347 | - # Reference the TLS cert files produced by Certbot. | |
| 348 | - ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; | |
| 349 | - ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; | |
| 350 | - | |
| 351 | - # Load the Let's Encrypt Diffie-Hellman parameters generated for | |
| 352 | - # this server. Without this, the server is vulnerable to Logjam. | |
| 353 | - ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; | |
| 354 | - | |
| 355 | - # Tighten things down further, per Qualys’ and Certbot’s advice. | |
| 356 | - ssl_session_cache shared:le_nginx_SSL:1m; | |
| 357 | - ssl_protocols TLSv1.2 TLSv1.3; | |
| 358 | - ssl_prefer_server_ciphers on; | |
| 359 | - ssl_session_timeout 1440m; | |
| 360 | - | |
| 361 | - # Offer OCSP certificate stapling. | |
| 362 | - ssl_stapling on; | |
| 363 | - ssl_stapling_verify on; | |
| 364 | - | |
| 365 | - # Enable HSTS. | |
| 366 | - include local/enable-hsts; | |
| 343 | +# Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port. | |
| 344 | +listen 443 ssl; | |
| 345 | +listen [::]:443 ssl; | |
| 346 | + | |
| 347 | +# Reference the TLS cert files produced by Certbot. | |
| 348 | +ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; | |
| 349 | +ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; | |
| 350 | + | |
| 351 | +# Load the Let's Encrypt Diffie-Hellman parameters generated for | |
| 352 | +# this server. Without this, the server is vulnerable to Logjam. | |
| 353 | +ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; | |
| 354 | + | |
| 355 | +# Tighten things down further, per Qualys’ and Certbot’s advice. | |
| 356 | +ssl_session_cache shared:le_nginx_SSL:1m; | |
| 357 | +ssl_protocols TLSv1.2 TLSv1.3; | |
| 358 | +ssl_prefer_server_ciphers on; | |
| 359 | +ssl_session_timeout 1440m; | |
| 360 | + | |
| 361 | +# Offer OCSP certificate stapling. | |
| 362 | +ssl_stapling on; | |
| 363 | +ssl_stapling_verify on; | |
| 364 | + | |
| 365 | +# Enable HSTS. | |
| 366 | +include local/enable-hsts; | |
| 367 | 367 | ``` |
| 368 | 368 | |
| 369 | 369 | The [HSTS] step is optional and should be applied only after due |
| 370 | 370 | consideration, since it has the potential to lock users out of your |
| 371 | 371 | site if you later change your mind on the TLS configuration. |
| 372 | 372 | The `local/enable-hsts` file it references is simply: |
| 373 | 373 | |
| 374 | -``` | |
| 375 | 374 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; |
| 376 | -``` | |
| 377 | 375 | |
| 378 | 376 | It’s a separate file because nginx requires that headers like this be |
| 379 | 377 | applied separately for each `location { }` block. We’ve therefore |
| 380 | 378 | factored this out so you can `include` it everywhere you need it. |
| 381 | 379 | |
| 382 | 380 |
| --- www/server/debian/nginx.md | |
| +++ www/server/debian/nginx.md | |
| @@ -101,11 +101,11 @@ | |
| 101 | ## <a id="deps"></a>Installing the Dependencies |
| 102 | |
| 103 | The first step is to install some non-default packages we’ll need. SSH into |
| 104 | your server, then say: |
| 105 | |
| 106 | $ sudo apt install fossil nginx |
| 107 | |
| 108 | You can leave “`fossil`” out of that if you’re building Fossil from |
| 109 | source to get a more up-to-date version than is shipped with the host |
| 110 | OS. |
| 111 | |
| @@ -131,12 +131,12 @@ | |
| 131 | On Debian and Ubuntu systems the primary user-level configuration file |
| 132 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 133 | file contain only a list of include statements, one for each site that |
| 134 | server hosts: |
| 135 | |
| 136 | include local/example.com |
| 137 | include local/foo.net |
| 138 | |
| 139 | Those files then each define one domain’s configuration. Here, |
| 140 | `/etc/nginx/local/example.com` contains the configuration for |
| 141 | `*.example.com` and its alias `*.example.net`; and `local/foo.net` |
| 142 | contains the configuration for `*.foo.net`. |
| @@ -197,13 +197,13 @@ | |
| 197 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 198 | try on your own site, such as static asset proxying. |
| 199 | |
| 200 | You also need a `local/code` file containing: |
| 201 | |
| 202 | include scgi_params; |
| 203 | scgi_pass 127.0.0.1:12345; |
| 204 | scgi_param SCRIPT_NAME "/code"; |
| 205 | |
| 206 | We separate that out because nginx refuses to inherit certain settings |
| 207 | between nested location blocks, so rather than repeat them, we extract |
| 208 | them to this separate file and include it from both locations where it’s |
| 209 | needed. You see this above where we set far-future expiration dates on |
| @@ -213,16 +213,16 @@ | |
| 213 | Fossil-based site considerably faster. |
| 214 | |
| 215 | Similarly, the `local/generic` file referenced above helps us reduce unnecessary |
| 216 | repetition among the multiple sites this configuration hosts: |
| 217 | |
| 218 | root /var/www/$host; |
| 219 | |
| 220 | listen 80; |
| 221 | listen [::]:80; |
| 222 | |
| 223 | charset utf-8; |
| 224 | |
| 225 | There are some configuration directives that nginx refuses to substitute |
| 226 | variables into, citing performance considerations, so there is a limit |
| 227 | to how much repetition you can squeeze out this way. One such example |
| 228 | are the `access_log` and `error_log` directives, which follow an obvious |
| @@ -246,14 +246,14 @@ | |
| 246 | |
| 247 | However, it is still worth showing the proper method of proxying |
| 248 | Fossil’s HTTP server through nginx if only to make reading nginx |
| 249 | documentation on other sites easier: |
| 250 | |
| 251 | location /code { |
| 252 | rewrite ^/code(/.*) $1 break; |
| 253 | proxy_pass http://127.0.0.1:12345; |
| 254 | } |
| 255 | |
| 256 | The most common thing people get wrong when hand-rolling a configuration |
| 257 | like this is to get the slashes wrong. Fossil is sensitive to this. For |
| 258 | instance, Fossil will not collapse double slashes down to a single |
| 259 | slash, as some other HTTP servers will. |
| @@ -267,12 +267,12 @@ | |
| 267 | a problem, but when sending [unversioned content][uv], it uses a single |
| 268 | message for the entire file. Therefore, if you will be storing files |
| 269 | larger than this limit as unversioned content, you need to raise the |
| 270 | limit. Within the `location` block: |
| 271 | |
| 272 | # Allow large unversioned file uploads, such as PDFs |
| 273 | client_max_body_size 20M; |
| 274 | |
| 275 | [uv]: ../../unvers.wiki |
| 276 | |
| 277 | |
| 278 | ## <a id="fail2ban"></a> Integrating `fail2ban` |
| @@ -285,32 +285,32 @@ | |
| 285 | Fossil behind an nginx proxy, we convert these failures to log file |
| 286 | form, which `fail2ban` is designed to handle. |
| 287 | |
| 288 | First, install `fail2ban`, if you haven’t already: |
| 289 | |
| 290 | sudo apt install fail2ban |
| 291 | |
| 292 | We’d like `fail2ban` to react to Fossil `/login` failures. The stock |
| 293 | configuration of `fail2ban` only detects a few common sorts of SSH |
| 294 | attacks by default, and its included (but disabled) nginx attack |
| 295 | detectors don’t include one that knows how to detect an attack on |
| 296 | Fossil. We have to teach it by putting the following into |
| 297 | `/etc/fail2ban/filter.d/nginx-fossil-login.conf`: |
| 298 | |
| 299 | [Definition] |
| 300 | failregex = ^<HOST> - .*POST .*/login HTTP/..." 401 |
| 301 | |
| 302 | That teaches `fail2ban` how to recognize the errors logged by Fossil |
| 303 | [as of 2.14](/info/39d7eb0e22). (Earlier versions of Fossil returned |
| 304 | HTTP status code 200 for this, so you couldn’t distinguish a successful |
| 305 | login from a failure.) |
| 306 | |
| 307 | Then in `/etc/fail2ban/jail.local`, add this section: |
| 308 | |
| 309 | [nginx-fossil-login] |
| 310 | enabled = true |
| 311 | logpath = /var/log/nginx/*-https-access.log |
| 312 | |
| 313 | The last line is the key: it tells `fail2ban` where we’ve put all of our |
| 314 | per-repo access logs in the nginx config above. |
| 315 | |
| 316 | There’s a [lot more you can do][dof2b], but that gets us out of scope of |
| @@ -338,44 +338,42 @@ | |
| 338 | |
| 339 | You may wish to include something like this from each `server { }` |
| 340 | block in your configuration to enable TLS in a common, secure way: |
| 341 | |
| 342 | ``` |
| 343 | # Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port. |
| 344 | listen 443 ssl; |
| 345 | listen [::]:443 ssl; |
| 346 | |
| 347 | # Reference the TLS cert files produced by Certbot. |
| 348 | ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; |
| 349 | ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; |
| 350 | |
| 351 | # Load the Let's Encrypt Diffie-Hellman parameters generated for |
| 352 | # this server. Without this, the server is vulnerable to Logjam. |
| 353 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; |
| 354 | |
| 355 | # Tighten things down further, per Qualys’ and Certbot’s advice. |
| 356 | ssl_session_cache shared:le_nginx_SSL:1m; |
| 357 | ssl_protocols TLSv1.2 TLSv1.3; |
| 358 | ssl_prefer_server_ciphers on; |
| 359 | ssl_session_timeout 1440m; |
| 360 | |
| 361 | # Offer OCSP certificate stapling. |
| 362 | ssl_stapling on; |
| 363 | ssl_stapling_verify on; |
| 364 | |
| 365 | # Enable HSTS. |
| 366 | include local/enable-hsts; |
| 367 | ``` |
| 368 | |
| 369 | The [HSTS] step is optional and should be applied only after due |
| 370 | consideration, since it has the potential to lock users out of your |
| 371 | site if you later change your mind on the TLS configuration. |
| 372 | The `local/enable-hsts` file it references is simply: |
| 373 | |
| 374 | ``` |
| 375 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; |
| 376 | ``` |
| 377 | |
| 378 | It’s a separate file because nginx requires that headers like this be |
| 379 | applied separately for each `location { }` block. We’ve therefore |
| 380 | factored this out so you can `include` it everywhere you need it. |
| 381 | |
| 382 |
| --- www/server/debian/nginx.md | |
| +++ www/server/debian/nginx.md | |
| @@ -101,11 +101,11 @@ | |
| 101 | ## <a id="deps"></a>Installing the Dependencies |
| 102 | |
| 103 | The first step is to install some non-default packages we’ll need. SSH into |
| 104 | your server, then say: |
| 105 | |
| 106 | $ sudo apt install fossil nginx |
| 107 | |
| 108 | You can leave “`fossil`” out of that if you’re building Fossil from |
| 109 | source to get a more up-to-date version than is shipped with the host |
| 110 | OS. |
| 111 | |
| @@ -131,12 +131,12 @@ | |
| 131 | On Debian and Ubuntu systems the primary user-level configuration file |
| 132 | for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this |
| 133 | file contain only a list of include statements, one for each site that |
| 134 | server hosts: |
| 135 | |
| 136 | include local/example.com |
| 137 | include local/foo.net |
| 138 | |
| 139 | Those files then each define one domain’s configuration. Here, |
| 140 | `/etc/nginx/local/example.com` contains the configuration for |
| 141 | `*.example.com` and its alias `*.example.net`; and `local/foo.net` |
| 142 | contains the configuration for `*.foo.net`. |
| @@ -197,13 +197,13 @@ | |
| 197 | configuration for SCGI][scgii], showing off a few ideas you might want to |
| 198 | try on your own site, such as static asset proxying. |
| 199 | |
| 200 | You also need a `local/code` file containing: |
| 201 | |
| 202 | include scgi_params; |
| 203 | scgi_pass 127.0.0.1:12345; |
| 204 | scgi_param SCRIPT_NAME "/code"; |
| 205 | |
| 206 | We separate that out because nginx refuses to inherit certain settings |
| 207 | between nested location blocks, so rather than repeat them, we extract |
| 208 | them to this separate file and include it from both locations where it’s |
| 209 | needed. You see this above where we set far-future expiration dates on |
| @@ -213,16 +213,16 @@ | |
| 213 | Fossil-based site considerably faster. |
| 214 | |
| 215 | Similarly, the `local/generic` file referenced above helps us reduce unnecessary |
| 216 | repetition among the multiple sites this configuration hosts: |
| 217 | |
| 218 | root /var/www/$host; |
| 219 | |
| 220 | listen 80; |
| 221 | listen [::]:80; |
| 222 | |
| 223 | charset utf-8; |
| 224 | |
| 225 | There are some configuration directives that nginx refuses to substitute |
| 226 | variables into, citing performance considerations, so there is a limit |
| 227 | to how much repetition you can squeeze out this way. One such example |
| 228 | are the `access_log` and `error_log` directives, which follow an obvious |
| @@ -246,14 +246,14 @@ | |
| 246 | |
| 247 | However, it is still worth showing the proper method of proxying |
| 248 | Fossil’s HTTP server through nginx if only to make reading nginx |
| 249 | documentation on other sites easier: |
| 250 | |
| 251 | location /code { |
| 252 | rewrite ^/code(/.*) $1 break; |
| 253 | proxy_pass http://127.0.0.1:12345; |
| 254 | } |
| 255 | |
| 256 | The most common thing people get wrong when hand-rolling a configuration |
| 257 | like this is to get the slashes wrong. Fossil is sensitive to this. For |
| 258 | instance, Fossil will not collapse double slashes down to a single |
| 259 | slash, as some other HTTP servers will. |
| @@ -267,12 +267,12 @@ | |
| 267 | a problem, but when sending [unversioned content][uv], it uses a single |
| 268 | message for the entire file. Therefore, if you will be storing files |
| 269 | larger than this limit as unversioned content, you need to raise the |
| 270 | limit. Within the `location` block: |
| 271 | |
| 272 | # Allow large unversioned file uploads, such as PDFs |
| 273 | client_max_body_size 20M; |
| 274 | |
| 275 | [uv]: ../../unvers.wiki |
| 276 | |
| 277 | |
| 278 | ## <a id="fail2ban"></a> Integrating `fail2ban` |
| @@ -285,32 +285,32 @@ | |
| 285 | Fossil behind an nginx proxy, we convert these failures to log file |
| 286 | form, which `fail2ban` is designed to handle. |
| 287 | |
| 288 | First, install `fail2ban`, if you haven’t already: |
| 289 | |
| 290 | sudo apt install fail2ban |
| 291 | |
| 292 | We’d like `fail2ban` to react to Fossil `/login` failures. The stock |
| 293 | configuration of `fail2ban` only detects a few common sorts of SSH |
| 294 | attacks by default, and its included (but disabled) nginx attack |
| 295 | detectors don’t include one that knows how to detect an attack on |
| 296 | Fossil. We have to teach it by putting the following into |
| 297 | `/etc/fail2ban/filter.d/nginx-fossil-login.conf`: |
| 298 | |
| 299 | [Definition] |
| 300 | failregex = ^<HOST> - .*POST .*/login HTTP/..." 401 |
| 301 | |
| 302 | That teaches `fail2ban` how to recognize the errors logged by Fossil |
| 303 | [as of 2.14](/info/39d7eb0e22). (Earlier versions of Fossil returned |
| 304 | HTTP status code 200 for this, so you couldn’t distinguish a successful |
| 305 | login from a failure.) |
| 306 | |
| 307 | Then in `/etc/fail2ban/jail.local`, add this section: |
| 308 | |
| 309 | [nginx-fossil-login] |
| 310 | enabled = true |
| 311 | logpath = /var/log/nginx/*-https-access.log |
| 312 | |
| 313 | The last line is the key: it tells `fail2ban` where we’ve put all of our |
| 314 | per-repo access logs in the nginx config above. |
| 315 | |
| 316 | There’s a [lot more you can do][dof2b], but that gets us out of scope of |
| @@ -338,44 +338,42 @@ | |
| 338 | |
| 339 | You may wish to include something like this from each `server { }` |
| 340 | block in your configuration to enable TLS in a common, secure way: |
| 341 | |
| 342 | ``` |
| 343 | # Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port. |
| 344 | listen 443 ssl; |
| 345 | listen [::]:443 ssl; |
| 346 | |
| 347 | # Reference the TLS cert files produced by Certbot. |
| 348 | ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; |
| 349 | ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; |
| 350 | |
| 351 | # Load the Let's Encrypt Diffie-Hellman parameters generated for |
| 352 | # this server. Without this, the server is vulnerable to Logjam. |
| 353 | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; |
| 354 | |
| 355 | # Tighten things down further, per Qualys’ and Certbot’s advice. |
| 356 | ssl_session_cache shared:le_nginx_SSL:1m; |
| 357 | ssl_protocols TLSv1.2 TLSv1.3; |
| 358 | ssl_prefer_server_ciphers on; |
| 359 | ssl_session_timeout 1440m; |
| 360 | |
| 361 | # Offer OCSP certificate stapling. |
| 362 | ssl_stapling on; |
| 363 | ssl_stapling_verify on; |
| 364 | |
| 365 | # Enable HSTS. |
| 366 | include local/enable-hsts; |
| 367 | ``` |
| 368 | |
| 369 | The [HSTS] step is optional and should be applied only after due |
| 370 | consideration, since it has the potential to lock users out of your |
| 371 | site if you later change your mind on the TLS configuration. |
| 372 | The `local/enable-hsts` file it references is simply: |
| 373 | |
| 374 | add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; |
| 375 | |
| 376 | It’s a separate file because nginx requires that headers like this be |
| 377 | applied separately for each `location { }` block. We’ve therefore |
| 378 | factored this out so you can `include` it everywhere you need it. |
| 379 | |
| 380 |
+46
-46
| --- www/server/debian/service.md | ||
| +++ www/server/debian/service.md | ||
| @@ -53,22 +53,22 @@ | ||
| 53 | 53 | |
| 54 | 54 | To do this, write the following in |
| 55 | 55 | `~/.local/share/systemd/user/fossil.service`: |
| 56 | 56 | |
| 57 | 57 | ```dosini |
| 58 | - [Unit] | |
| 59 | - Description=Fossil user server | |
| 60 | - After=network-online.target | |
| 61 | - | |
| 62 | - [Service] | |
| 63 | - WorkingDirectory=/home/fossil/museum | |
| 64 | - ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil | |
| 65 | - Restart=always | |
| 66 | - RestartSec=3 | |
| 67 | - | |
| 68 | - [Install] | |
| 69 | - WantedBy=multi-user.target | |
| 58 | +[Unit] | |
| 59 | +Description=Fossil user server | |
| 60 | +After=network-online.target | |
| 61 | + | |
| 62 | +[Service] | |
| 63 | +WorkingDirectory=/home/fossil/museum | |
| 64 | +ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil | |
| 65 | +Restart=always | |
| 66 | +RestartSec=3 | |
| 67 | + | |
| 68 | +[Install] | |
| 69 | +WantedBy=multi-user.target | |
| 70 | 70 | ``` |
| 71 | 71 | |
| 72 | 72 | Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which |
| 73 | 73 | user and group to run this service as, because we’ve installed it |
| 74 | 74 | under the account we’re logged into, which `systemd` will use as the |
| @@ -90,15 +90,15 @@ | ||
| 90 | 90 | |
| 91 | 91 | Because we’ve set this up as a user service, the commands you give to |
| 92 | 92 | manipulate the service vary somewhat from the sort you’re more likely to |
| 93 | 93 | find online: |
| 94 | 94 | |
| 95 | - $ systemctl --user daemon-reload | |
| 96 | - $ systemctl --user enable fossil | |
| 97 | - $ systemctl --user start fossil | |
| 98 | - $ systemctl --user status fossil -l | |
| 99 | - $ systemctl --user stop fossil | |
| 95 | + $ systemctl --user daemon-reload | |
| 96 | + $ systemctl --user enable fossil | |
| 97 | + $ systemctl --user start fossil | |
| 98 | + $ systemctl --user status fossil -l | |
| 99 | + $ systemctl --user stop fossil | |
| 100 | 100 | |
| 101 | 101 | That is, we don’t need to talk to `systemd` with `sudo` privileges, but |
| 102 | 102 | we do need to tell it to look at the user configuration rather than the |
| 103 | 103 | system-level configuration. |
| 104 | 104 | |
| @@ -109,11 +109,11 @@ | ||
| 109 | 109 | On some `systemd` based OSes, user services only run while that user is |
| 110 | 110 | logged in interactively. This is common on systems aiming to provide |
| 111 | 111 | desktop environments, where this is the behavior you often want. To |
| 112 | 112 | allow background services to continue to run after logout, say: |
| 113 | 113 | |
| 114 | - $ sudo loginctl enable-linger $USER | |
| 114 | + $ sudo loginctl enable-linger $USER | |
| 115 | 115 | |
| 116 | 116 | You can paste the command just like that into your terminal, since |
| 117 | 117 | `$USER` will expand to your login name. |
| 118 | 118 | |
| 119 | 119 | [scgi]: ../any/scgi.md |
| @@ -165,20 +165,20 @@ | ||
| 165 | 165 | |
| 166 | 166 | We first need to define the privileged socket listener by writing |
| 167 | 167 | `/etc/systemd/system/fossil.socket`: |
| 168 | 168 | |
| 169 | 169 | ```dosini |
| 170 | - [Unit] | |
| 171 | - Description=Fossil socket | |
| 172 | - | |
| 173 | - [Socket] | |
| 174 | - Accept=yes | |
| 175 | - ListenStream=80 | |
| 176 | - NoDelay=true | |
| 177 | - | |
| 178 | - [Install] | |
| 179 | - WantedBy=sockets.target | |
| 170 | +[Unit] | |
| 171 | +Description=Fossil socket | |
| 172 | + | |
| 173 | +[Socket] | |
| 174 | +Accept=yes | |
| 175 | +ListenStream=80 | |
| 176 | +NoDelay=true | |
| 177 | + | |
| 178 | +[Install] | |
| 179 | +WantedBy=sockets.target | |
| 180 | 180 | ``` |
| 181 | 181 | |
| 182 | 182 | Note the change of configuration directory from the `~/.local` directory |
| 183 | 183 | to the system level. We need to start this socket listener at the root |
| 184 | 184 | level because of the low-numbered TCP port restriction we brought up |
| @@ -190,21 +190,21 @@ | ||
| 190 | 190 | |
| 191 | 191 | Next, create the service definition file in that same directory as |
| 192 | 192 | `[email protected]`: |
| 193 | 193 | |
| 194 | 194 | ```dosini |
| 195 | - [Unit] | |
| 196 | - Description=Fossil socket server | |
| 197 | - After=network-online.target | |
| 198 | - | |
| 199 | - [Service] | |
| 200 | - WorkingDirectory=/home/fossil/museum | |
| 201 | - ExecStart=/home/fossil/bin/fossil http repo.fossil | |
| 202 | - StandardInput=socket | |
| 203 | - | |
| 204 | - [Install] | |
| 205 | - WantedBy=multi-user.target | |
| 195 | +[Unit] | |
| 196 | +Description=Fossil socket server | |
| 197 | +After=network-online.target | |
| 198 | + | |
| 199 | +[Service] | |
| 200 | +WorkingDirectory=/home/fossil/museum | |
| 201 | +ExecStart=/home/fossil/bin/fossil http repo.fossil | |
| 202 | +StandardInput=socket | |
| 203 | + | |
| 204 | +[Install] | |
| 205 | +WantedBy=multi-user.target | |
| 206 | 206 | ``` |
| 207 | 207 | |
| 208 | 208 | Notice that we haven’t told `systemd` which user and group to run Fossil |
| 209 | 209 | under. Since this is a system-level service definition, that means it |
| 210 | 210 | will run as root, which then causes Fossil to [automatically drop into a |
| @@ -217,34 +217,34 @@ | ||
| 217 | 217 | handles that single client’s request and then immediately shuts down. |
| 218 | 218 | |
| 219 | 219 | Next, you need to tell `systemd` to reload its system-level |
| 220 | 220 | configuration files and enable the listening socket: |
| 221 | 221 | |
| 222 | - $ sudo systemctl daemon-reload | |
| 223 | - $ sudo systemctl enable fossil.socket | |
| 222 | + $ sudo systemctl daemon-reload | |
| 223 | + $ sudo systemctl enable fossil.socket | |
| 224 | 224 | |
| 225 | 225 | And now you can manipulate the socket listener: |
| 226 | 226 | |
| 227 | - $ sudo systemctl start fossil.socket | |
| 228 | - $ sudo systemctl status -l fossil.socket | |
| 229 | - $ sudo systemctl stop fossil.socket | |
| 227 | + $ sudo systemctl start fossil.socket | |
| 228 | + $ sudo systemctl status -l fossil.socket | |
| 229 | + $ sudo systemctl stop fossil.socket | |
| 230 | 230 | |
| 231 | 231 | Notice that we’re working with the *socket*, not the *service*. The fact |
| 232 | 232 | that we’ve given them the same base name and marked the service as an |
| 233 | 233 | instantiated service with the “`@`” notation allows `systemd` to |
| 234 | 234 | automatically start an instance of the service each time a hit comes in |
| 235 | 235 | on the socket that `systemd` is monitoring on Fossil’s behalf. To see |
| 236 | 236 | this service instantiation at work, visit a long-running Fossil page |
| 237 | 237 | (e.g. `/tarball`) and then give a command like this: |
| 238 | 238 | |
| 239 | - $ sudo systemctl --full | grep fossil | |
| 239 | + $ sudo systemctl --full | grep fossil | |
| 240 | 240 | |
| 241 | 241 | This will show information about the `fossil` socket and service |
| 242 | 242 | instances, which should show your `/tarball` hit handler, if it’s still |
| 243 | 243 | running: |
| 244 | 244 | |
| 245 | - [email protected]:80-127.0.0.1:38304.service | |
| 245 | + [email protected]:80-127.0.0.1:38304.service | |
| 246 | 246 | |
| 247 | 247 | You can feed that service instance description to a `systemctl kill` |
| 248 | 248 | command to stop that single instance without restarting the whole |
| 249 | 249 | `fossil` service, for example. |
| 250 | 250 | |
| 251 | 251 |
| --- www/server/debian/service.md | |
| +++ www/server/debian/service.md | |
| @@ -53,22 +53,22 @@ | |
| 53 | |
| 54 | To do this, write the following in |
| 55 | `~/.local/share/systemd/user/fossil.service`: |
| 56 | |
| 57 | ```dosini |
| 58 | [Unit] |
| 59 | Description=Fossil user server |
| 60 | After=network-online.target |
| 61 | |
| 62 | [Service] |
| 63 | WorkingDirectory=/home/fossil/museum |
| 64 | ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil |
| 65 | Restart=always |
| 66 | RestartSec=3 |
| 67 | |
| 68 | [Install] |
| 69 | WantedBy=multi-user.target |
| 70 | ``` |
| 71 | |
| 72 | Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which |
| 73 | user and group to run this service as, because we’ve installed it |
| 74 | under the account we’re logged into, which `systemd` will use as the |
| @@ -90,15 +90,15 @@ | |
| 90 | |
| 91 | Because we’ve set this up as a user service, the commands you give to |
| 92 | manipulate the service vary somewhat from the sort you’re more likely to |
| 93 | find online: |
| 94 | |
| 95 | $ systemctl --user daemon-reload |
| 96 | $ systemctl --user enable fossil |
| 97 | $ systemctl --user start fossil |
| 98 | $ systemctl --user status fossil -l |
| 99 | $ systemctl --user stop fossil |
| 100 | |
| 101 | That is, we don’t need to talk to `systemd` with `sudo` privileges, but |
| 102 | we do need to tell it to look at the user configuration rather than the |
| 103 | system-level configuration. |
| 104 | |
| @@ -109,11 +109,11 @@ | |
| 109 | On some `systemd` based OSes, user services only run while that user is |
| 110 | logged in interactively. This is common on systems aiming to provide |
| 111 | desktop environments, where this is the behavior you often want. To |
| 112 | allow background services to continue to run after logout, say: |
| 113 | |
| 114 | $ sudo loginctl enable-linger $USER |
| 115 | |
| 116 | You can paste the command just like that into your terminal, since |
| 117 | `$USER` will expand to your login name. |
| 118 | |
| 119 | [scgi]: ../any/scgi.md |
| @@ -165,20 +165,20 @@ | |
| 165 | |
| 166 | We first need to define the privileged socket listener by writing |
| 167 | `/etc/systemd/system/fossil.socket`: |
| 168 | |
| 169 | ```dosini |
| 170 | [Unit] |
| 171 | Description=Fossil socket |
| 172 | |
| 173 | [Socket] |
| 174 | Accept=yes |
| 175 | ListenStream=80 |
| 176 | NoDelay=true |
| 177 | |
| 178 | [Install] |
| 179 | WantedBy=sockets.target |
| 180 | ``` |
| 181 | |
| 182 | Note the change of configuration directory from the `~/.local` directory |
| 183 | to the system level. We need to start this socket listener at the root |
| 184 | level because of the low-numbered TCP port restriction we brought up |
| @@ -190,21 +190,21 @@ | |
| 190 | |
| 191 | Next, create the service definition file in that same directory as |
| 192 | `[email protected]`: |
| 193 | |
| 194 | ```dosini |
| 195 | [Unit] |
| 196 | Description=Fossil socket server |
| 197 | After=network-online.target |
| 198 | |
| 199 | [Service] |
| 200 | WorkingDirectory=/home/fossil/museum |
| 201 | ExecStart=/home/fossil/bin/fossil http repo.fossil |
| 202 | StandardInput=socket |
| 203 | |
| 204 | [Install] |
| 205 | WantedBy=multi-user.target |
| 206 | ``` |
| 207 | |
| 208 | Notice that we haven’t told `systemd` which user and group to run Fossil |
| 209 | under. Since this is a system-level service definition, that means it |
| 210 | will run as root, which then causes Fossil to [automatically drop into a |
| @@ -217,34 +217,34 @@ | |
| 217 | handles that single client’s request and then immediately shuts down. |
| 218 | |
| 219 | Next, you need to tell `systemd` to reload its system-level |
| 220 | configuration files and enable the listening socket: |
| 221 | |
| 222 | $ sudo systemctl daemon-reload |
| 223 | $ sudo systemctl enable fossil.socket |
| 224 | |
| 225 | And now you can manipulate the socket listener: |
| 226 | |
| 227 | $ sudo systemctl start fossil.socket |
| 228 | $ sudo systemctl status -l fossil.socket |
| 229 | $ sudo systemctl stop fossil.socket |
| 230 | |
| 231 | Notice that we’re working with the *socket*, not the *service*. The fact |
| 232 | that we’ve given them the same base name and marked the service as an |
| 233 | instantiated service with the “`@`” notation allows `systemd` to |
| 234 | automatically start an instance of the service each time a hit comes in |
| 235 | on the socket that `systemd` is monitoring on Fossil’s behalf. To see |
| 236 | this service instantiation at work, visit a long-running Fossil page |
| 237 | (e.g. `/tarball`) and then give a command like this: |
| 238 | |
| 239 | $ sudo systemctl --full | grep fossil |
| 240 | |
| 241 | This will show information about the `fossil` socket and service |
| 242 | instances, which should show your `/tarball` hit handler, if it’s still |
| 243 | running: |
| 244 | |
| 245 | [email protected]:80-127.0.0.1:38304.service |
| 246 | |
| 247 | You can feed that service instance description to a `systemctl kill` |
| 248 | command to stop that single instance without restarting the whole |
| 249 | `fossil` service, for example. |
| 250 | |
| 251 |
| --- www/server/debian/service.md | |
| +++ www/server/debian/service.md | |
| @@ -53,22 +53,22 @@ | |
| 53 | |
| 54 | To do this, write the following in |
| 55 | `~/.local/share/systemd/user/fossil.service`: |
| 56 | |
| 57 | ```dosini |
| 58 | [Unit] |
| 59 | Description=Fossil user server |
| 60 | After=network-online.target |
| 61 | |
| 62 | [Service] |
| 63 | WorkingDirectory=/home/fossil/museum |
| 64 | ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil |
| 65 | Restart=always |
| 66 | RestartSec=3 |
| 67 | |
| 68 | [Install] |
| 69 | WantedBy=multi-user.target |
| 70 | ``` |
| 71 | |
| 72 | Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which |
| 73 | user and group to run this service as, because we’ve installed it |
| 74 | under the account we’re logged into, which `systemd` will use as the |
| @@ -90,15 +90,15 @@ | |
| 90 | |
| 91 | Because we’ve set this up as a user service, the commands you give to |
| 92 | manipulate the service vary somewhat from the sort you’re more likely to |
| 93 | find online: |
| 94 | |
| 95 | $ systemctl --user daemon-reload |
| 96 | $ systemctl --user enable fossil |
| 97 | $ systemctl --user start fossil |
| 98 | $ systemctl --user status fossil -l |
| 99 | $ systemctl --user stop fossil |
| 100 | |
| 101 | That is, we don’t need to talk to `systemd` with `sudo` privileges, but |
| 102 | we do need to tell it to look at the user configuration rather than the |
| 103 | system-level configuration. |
| 104 | |
| @@ -109,11 +109,11 @@ | |
| 109 | On some `systemd` based OSes, user services only run while that user is |
| 110 | logged in interactively. This is common on systems aiming to provide |
| 111 | desktop environments, where this is the behavior you often want. To |
| 112 | allow background services to continue to run after logout, say: |
| 113 | |
| 114 | $ sudo loginctl enable-linger $USER |
| 115 | |
| 116 | You can paste the command just like that into your terminal, since |
| 117 | `$USER` will expand to your login name. |
| 118 | |
| 119 | [scgi]: ../any/scgi.md |
| @@ -165,20 +165,20 @@ | |
| 165 | |
| 166 | We first need to define the privileged socket listener by writing |
| 167 | `/etc/systemd/system/fossil.socket`: |
| 168 | |
| 169 | ```dosini |
| 170 | [Unit] |
| 171 | Description=Fossil socket |
| 172 | |
| 173 | [Socket] |
| 174 | Accept=yes |
| 175 | ListenStream=80 |
| 176 | NoDelay=true |
| 177 | |
| 178 | [Install] |
| 179 | WantedBy=sockets.target |
| 180 | ``` |
| 181 | |
| 182 | Note the change of configuration directory from the `~/.local` directory |
| 183 | to the system level. We need to start this socket listener at the root |
| 184 | level because of the low-numbered TCP port restriction we brought up |
| @@ -190,21 +190,21 @@ | |
| 190 | |
| 191 | Next, create the service definition file in that same directory as |
| 192 | `[email protected]`: |
| 193 | |
| 194 | ```dosini |
| 195 | [Unit] |
| 196 | Description=Fossil socket server |
| 197 | After=network-online.target |
| 198 | |
| 199 | [Service] |
| 200 | WorkingDirectory=/home/fossil/museum |
| 201 | ExecStart=/home/fossil/bin/fossil http repo.fossil |
| 202 | StandardInput=socket |
| 203 | |
| 204 | [Install] |
| 205 | WantedBy=multi-user.target |
| 206 | ``` |
| 207 | |
| 208 | Notice that we haven’t told `systemd` which user and group to run Fossil |
| 209 | under. Since this is a system-level service definition, that means it |
| 210 | will run as root, which then causes Fossil to [automatically drop into a |
| @@ -217,34 +217,34 @@ | |
| 217 | handles that single client’s request and then immediately shuts down. |
| 218 | |
| 219 | Next, you need to tell `systemd` to reload its system-level |
| 220 | configuration files and enable the listening socket: |
| 221 | |
| 222 | $ sudo systemctl daemon-reload |
| 223 | $ sudo systemctl enable fossil.socket |
| 224 | |
| 225 | And now you can manipulate the socket listener: |
| 226 | |
| 227 | $ sudo systemctl start fossil.socket |
| 228 | $ sudo systemctl status -l fossil.socket |
| 229 | $ sudo systemctl stop fossil.socket |
| 230 | |
| 231 | Notice that we’re working with the *socket*, not the *service*. The fact |
| 232 | that we’ve given them the same base name and marked the service as an |
| 233 | instantiated service with the “`@`” notation allows `systemd` to |
| 234 | automatically start an instance of the service each time a hit comes in |
| 235 | on the socket that `systemd` is monitoring on Fossil’s behalf. To see |
| 236 | this service instantiation at work, visit a long-running Fossil page |
| 237 | (e.g. `/tarball`) and then give a command like this: |
| 238 | |
| 239 | $ sudo systemctl --full | grep fossil |
| 240 | |
| 241 | This will show information about the `fossil` socket and service |
| 242 | instances, which should show your `/tarball` hit handler, if it’s still |
| 243 | running: |
| 244 | |
| 245 | [email protected]:80-127.0.0.1:38304.service |
| 246 | |
| 247 | You can feed that service instance description to a `systemctl kill` |
| 248 | command to stop that single instance without restarting the whole |
| 249 | `fossil` service, for example. |
| 250 | |
| 251 |
+40
-38
| --- www/server/macos/service.md | ||
| +++ www/server/macos/service.md | ||
| @@ -18,11 +18,11 @@ | ||
| 18 | 18 | socket activation. |
| 19 | 19 | |
| 20 | 20 | For more information on `launchd`, the single best resource we’ve found |
| 21 | 21 | is [launchd.info](https://launchd.info). The next best is: |
| 22 | 22 | |
| 23 | - $ man launchd.plist | |
| 23 | + $ man launchd.plist | |
| 24 | 24 | |
| 25 | 25 | [la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/ |
| 26 | 26 | [ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html |
| 27 | 27 | [wpa]: https://en.wikipedia.org/wiki/Launchd |
| 28 | 28 | |
| @@ -32,42 +32,43 @@ | ||
| 32 | 32 | |
| 33 | 33 | To configure `launchd` to start Fossil as a standalone HTTP server, |
| 34 | 34 | write the following as `com.example.dev.FossilHTTP.plist`: |
| 35 | 35 | |
| 36 | 36 | ```xml |
| 37 | - <?xml version="1.0" encoding="UTF-8"?> | |
| 38 | - <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 39 | - <plist version="1.0"> | |
| 40 | - <dict> | |
| 41 | - <key>Label</key> | |
| 42 | - <string>com.example.dev.FossilHTTP</string> | |
| 43 | - <key>ProgramArguments</key> | |
| 44 | - <array> | |
| 45 | - <string>/usr/local/bin/fossil</string> | |
| 46 | - <string>server</string> | |
| 47 | - <string>--port</string> | |
| 48 | - <string>9000</string> | |
| 49 | - <string>repo.fossil</string> | |
| 50 | - </array> | |
| 51 | - <key>WorkingDirectory</key> | |
| 52 | - <string>/Users/you/museum</string> | |
| 53 | - <key>KeepAlive</key> | |
| 54 | - <true/> | |
| 55 | - <key>RunAtLoad</key> | |
| 56 | - <true/> | |
| 57 | - <key>StandardErrorPath</key> | |
| 58 | - <string>/tmp/fossil-error.log</string> | |
| 59 | - <key>StandardOutPath</key> | |
| 60 | - <string>/tmp/fossil-info.log</string> | |
| 61 | - <key>UserName</key> | |
| 62 | - <string>you</string> | |
| 63 | - <key>GroupName</key> | |
| 64 | - <string>staff</string> | |
| 65 | - <key>InitGroups</key> | |
| 66 | - <true/> | |
| 67 | - </dict> | |
| 68 | - </plist> | |
| 37 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 38 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" | |
| 39 | + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 40 | +<plist version="1.0"> | |
| 41 | +<dict> | |
| 42 | + <key>Label</key> | |
| 43 | + <string>com.example.dev.FossilHTTP</string> | |
| 44 | + <key>ProgramArguments</key> | |
| 45 | + <array> | |
| 46 | + <string>/usr/local/bin/fossil</string> | |
| 47 | + <string>server</string> | |
| 48 | + <string>--port</string> | |
| 49 | + <string>9000</string> | |
| 50 | + <string>repo.fossil</string> | |
| 51 | + </array> | |
| 52 | + <key>WorkingDirectory</key> | |
| 53 | + <string>/Users/you/museum</string> | |
| 54 | + <key>KeepAlive</key> | |
| 55 | + <true/> | |
| 56 | + <key>RunAtLoad</key> | |
| 57 | + <true/> | |
| 58 | + <key>StandardErrorPath</key> | |
| 59 | + <string>/tmp/fossil-error.log</string> | |
| 60 | + <key>StandardOutPath</key> | |
| 61 | + <string>/tmp/fossil-info.log</string> | |
| 62 | + <key>UserName</key> | |
| 63 | + <string>you</string> | |
| 64 | + <key>GroupName</key> | |
| 65 | + <string>staff</string> | |
| 66 | + <key>InitGroups</key> | |
| 67 | + <true/> | |
| 68 | +</dict> | |
| 69 | +</plist> | |
| 69 | 70 | ``` |
| 70 | 71 | |
| 71 | 72 | In this example, we’re assuming your development organization uses the |
| 72 | 73 | domain name “`dev.example.org`”, that your short macOS login name is |
| 73 | 74 | “`you`”, and that you store your Fossils in “`~/museum`”. Adjust these |
| @@ -81,29 +82,30 @@ | ||
| 81 | 82 | if you leave the user and group configuration at the tail end of that |
| 82 | 83 | plist file out, Fossil will remain running as root! |
| 83 | 84 | |
| 84 | 85 | Install that file and set it to start with: |
| 85 | 86 | |
| 86 | - $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ | |
| 87 | - /Library/LaunchDaemons/ | |
| 88 | - $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist | |
| 87 | + $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ | |
| 88 | + /Library/LaunchDaemons/ | |
| 89 | + $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist | |
| 89 | 90 | |
| 90 | 91 | Because we set the `RunAtLoad` key, this will also launch the daemon. |
| 91 | 92 | |
| 92 | 93 | Stop the daemon with: |
| 93 | 94 | |
| 94 | - $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist | |
| 95 | + $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist | |
| 95 | 96 | |
| 96 | 97 | |
| 97 | 98 | ## Socket Listener |
| 98 | 99 | |
| 99 | 100 | Another useful method to serve a Fossil repo via `launchd` is by setting |
| 100 | 101 | up a socket listener: |
| 101 | 102 | |
| 102 | 103 | ```xml |
| 103 | 104 | <?xml version="1.0" encoding="UTF-8"?> |
| 104 | -<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 105 | +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" | |
| 106 | + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| 105 | 107 | <plist version="1.0"> |
| 106 | 108 | <dict> |
| 107 | 109 | <key>Label</key> |
| 108 | 110 | <string>com.example.dev.FossilSocket</string> |
| 109 | 111 | <key>ProgramArguments</key> |
| 110 | 112 |
| --- www/server/macos/service.md | |
| +++ www/server/macos/service.md | |
| @@ -18,11 +18,11 @@ | |
| 18 | socket activation. |
| 19 | |
| 20 | For more information on `launchd`, the single best resource we’ve found |
| 21 | is [launchd.info](https://launchd.info). The next best is: |
| 22 | |
| 23 | $ man launchd.plist |
| 24 | |
| 25 | [la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/ |
| 26 | [ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html |
| 27 | [wpa]: https://en.wikipedia.org/wiki/Launchd |
| 28 | |
| @@ -32,42 +32,43 @@ | |
| 32 | |
| 33 | To configure `launchd` to start Fossil as a standalone HTTP server, |
| 34 | write the following as `com.example.dev.FossilHTTP.plist`: |
| 35 | |
| 36 | ```xml |
| 37 | <?xml version="1.0" encoding="UTF-8"?> |
| 38 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 39 | <plist version="1.0"> |
| 40 | <dict> |
| 41 | <key>Label</key> |
| 42 | <string>com.example.dev.FossilHTTP</string> |
| 43 | <key>ProgramArguments</key> |
| 44 | <array> |
| 45 | <string>/usr/local/bin/fossil</string> |
| 46 | <string>server</string> |
| 47 | <string>--port</string> |
| 48 | <string>9000</string> |
| 49 | <string>repo.fossil</string> |
| 50 | </array> |
| 51 | <key>WorkingDirectory</key> |
| 52 | <string>/Users/you/museum</string> |
| 53 | <key>KeepAlive</key> |
| 54 | <true/> |
| 55 | <key>RunAtLoad</key> |
| 56 | <true/> |
| 57 | <key>StandardErrorPath</key> |
| 58 | <string>/tmp/fossil-error.log</string> |
| 59 | <key>StandardOutPath</key> |
| 60 | <string>/tmp/fossil-info.log</string> |
| 61 | <key>UserName</key> |
| 62 | <string>you</string> |
| 63 | <key>GroupName</key> |
| 64 | <string>staff</string> |
| 65 | <key>InitGroups</key> |
| 66 | <true/> |
| 67 | </dict> |
| 68 | </plist> |
| 69 | ``` |
| 70 | |
| 71 | In this example, we’re assuming your development organization uses the |
| 72 | domain name “`dev.example.org`”, that your short macOS login name is |
| 73 | “`you`”, and that you store your Fossils in “`~/museum`”. Adjust these |
| @@ -81,29 +82,30 @@ | |
| 81 | if you leave the user and group configuration at the tail end of that |
| 82 | plist file out, Fossil will remain running as root! |
| 83 | |
| 84 | Install that file and set it to start with: |
| 85 | |
| 86 | $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ |
| 87 | /Library/LaunchDaemons/ |
| 88 | $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist |
| 89 | |
| 90 | Because we set the `RunAtLoad` key, this will also launch the daemon. |
| 91 | |
| 92 | Stop the daemon with: |
| 93 | |
| 94 | $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist |
| 95 | |
| 96 | |
| 97 | ## Socket Listener |
| 98 | |
| 99 | Another useful method to serve a Fossil repo via `launchd` is by setting |
| 100 | up a socket listener: |
| 101 | |
| 102 | ```xml |
| 103 | <?xml version="1.0" encoding="UTF-8"?> |
| 104 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 105 | <plist version="1.0"> |
| 106 | <dict> |
| 107 | <key>Label</key> |
| 108 | <string>com.example.dev.FossilSocket</string> |
| 109 | <key>ProgramArguments</key> |
| 110 |
| --- www/server/macos/service.md | |
| +++ www/server/macos/service.md | |
| @@ -18,11 +18,11 @@ | |
| 18 | socket activation. |
| 19 | |
| 20 | For more information on `launchd`, the single best resource we’ve found |
| 21 | is [launchd.info](https://launchd.info). The next best is: |
| 22 | |
| 23 | $ man launchd.plist |
| 24 | |
| 25 | [la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/ |
| 26 | [ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html |
| 27 | [wpa]: https://en.wikipedia.org/wiki/Launchd |
| 28 | |
| @@ -32,42 +32,43 @@ | |
| 32 | |
| 33 | To configure `launchd` to start Fossil as a standalone HTTP server, |
| 34 | write the following as `com.example.dev.FossilHTTP.plist`: |
| 35 | |
| 36 | ```xml |
| 37 | <?xml version="1.0" encoding="UTF-8"?> |
| 38 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" |
| 39 | "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 40 | <plist version="1.0"> |
| 41 | <dict> |
| 42 | <key>Label</key> |
| 43 | <string>com.example.dev.FossilHTTP</string> |
| 44 | <key>ProgramArguments</key> |
| 45 | <array> |
| 46 | <string>/usr/local/bin/fossil</string> |
| 47 | <string>server</string> |
| 48 | <string>--port</string> |
| 49 | <string>9000</string> |
| 50 | <string>repo.fossil</string> |
| 51 | </array> |
| 52 | <key>WorkingDirectory</key> |
| 53 | <string>/Users/you/museum</string> |
| 54 | <key>KeepAlive</key> |
| 55 | <true/> |
| 56 | <key>RunAtLoad</key> |
| 57 | <true/> |
| 58 | <key>StandardErrorPath</key> |
| 59 | <string>/tmp/fossil-error.log</string> |
| 60 | <key>StandardOutPath</key> |
| 61 | <string>/tmp/fossil-info.log</string> |
| 62 | <key>UserName</key> |
| 63 | <string>you</string> |
| 64 | <key>GroupName</key> |
| 65 | <string>staff</string> |
| 66 | <key>InitGroups</key> |
| 67 | <true/> |
| 68 | </dict> |
| 69 | </plist> |
| 70 | ``` |
| 71 | |
| 72 | In this example, we’re assuming your development organization uses the |
| 73 | domain name “`dev.example.org`”, that your short macOS login name is |
| 74 | “`you`”, and that you store your Fossils in “`~/museum`”. Adjust these |
| @@ -81,29 +82,30 @@ | |
| 82 | if you leave the user and group configuration at the tail end of that |
| 83 | plist file out, Fossil will remain running as root! |
| 84 | |
| 85 | Install that file and set it to start with: |
| 86 | |
| 87 | $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ |
| 88 | /Library/LaunchDaemons/ |
| 89 | $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist |
| 90 | |
| 91 | Because we set the `RunAtLoad` key, this will also launch the daemon. |
| 92 | |
| 93 | Stop the daemon with: |
| 94 | |
| 95 | $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist |
| 96 | |
| 97 | |
| 98 | ## Socket Listener |
| 99 | |
| 100 | Another useful method to serve a Fossil repo via `launchd` is by setting |
| 101 | up a socket listener: |
| 102 | |
| 103 | ```xml |
| 104 | <?xml version="1.0" encoding="UTF-8"?> |
| 105 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" |
| 106 | "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
| 107 | <plist version="1.0"> |
| 108 | <dict> |
| 109 | <key>Label</key> |
| 110 | <string>com.example.dev.FossilSocket</string> |
| 111 | <key>ProgramArguments</key> |
| 112 |
+119
-119
| --- www/server/openbsd/fastcgi.md | ||
| +++ www/server/openbsd/fastcgi.md | ||
| @@ -18,52 +18,52 @@ | ||
| 18 | 18 | |
| 19 | 19 | Use the OpenBSD package manager `pkg_add` to install Fossil, making sure |
| 20 | 20 | to select the statically linked binary. |
| 21 | 21 | |
| 22 | 22 | ```console |
| 23 | - $ doas pkg_add fossil | |
| 24 | - quirks-3.325 signed on 2020-06-12T06:24:53Z | |
| 25 | - Ambiguous: choose package for fossil | |
| 26 | - 0: <None> | |
| 27 | - 1: fossil-2.10v0 | |
| 28 | - 2: fossil-2.10v0-static | |
| 29 | - Your choice: 2 | |
| 30 | - fossil-2.10v0-static: ok | |
| 23 | +$ doas pkg_add fossil | |
| 24 | +quirks-3.325 signed on 2020-06-12T06:24:53Z | |
| 25 | +Ambiguous: choose package for fossil | |
| 26 | + 0: <None> | |
| 27 | + 1: fossil-2.10v0 | |
| 28 | + 2: fossil-2.10v0-static | |
| 29 | +Your choice: 2 | |
| 30 | +fossil-2.10v0-static: ok | |
| 31 | 31 | ``` |
| 32 | 32 | |
| 33 | 33 | This installs Fossil into the chroot. To facilitate local use, create a |
| 34 | 34 | symbolic link of the fossil executable into `/usr/local/bin`. |
| 35 | 35 | |
| 36 | 36 | ```console |
| 37 | - $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil | |
| 37 | +$ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil | |
| 38 | 38 | ``` |
| 39 | 39 | |
| 40 | 40 | As a privileged user, create the file `/var/www/cgi-bin/scm` with the |
| 41 | 41 | following contents to make the CGI script that `httpd` will execute in |
| 42 | 42 | response to `fsl.domain.tld` requests; all paths are relative to the |
| 43 | 43 | `/var/www` chroot. |
| 44 | 44 | |
| 45 | 45 | ```sh |
| 46 | - #!/bin/fossil | |
| 47 | - directory: /htdocs/fsl.domain.tld | |
| 48 | - notfound: https://domain.tld | |
| 49 | - repolist | |
| 50 | - errorlog: /logs/fossil.log | |
| 46 | +#!/bin/fossil | |
| 47 | +directory: /htdocs/fsl.domain.tld | |
| 48 | +notfound: https://domain.tld | |
| 49 | +repolist | |
| 50 | +errorlog: /logs/fossil.log | |
| 51 | 51 | ``` |
| 52 | 52 | |
| 53 | 53 | The `directory` directive instructs Fossil to serve all repositories |
| 54 | 54 | found in `/var/www/htdocs/fsl.domain.tld`, while `errorlog` sets logging |
| 55 | 55 | to be saved to `/var/www/logs/fossil.log`; create the repository |
| 56 | 56 | directory and log file—making the latter owned by the `www` user, and |
| 57 | 57 | the script executable. |
| 58 | 58 | |
| 59 | 59 | ```console |
| 60 | - $ doas mkdir /var/www/htdocs/fsl.domain.tld | |
| 61 | - $ doas touch /var/www/logs/fossil.log | |
| 62 | - $ doas chown www /var/www/logs/fossil.log | |
| 63 | - $ doas chmod 660 /var/www/logs/fossil.log | |
| 64 | - $ doas chmod 755 /var/www/cgi-bin/scm | |
| 60 | +$ doas mkdir /var/www/htdocs/fsl.domain.tld | |
| 61 | +$ doas touch /var/www/logs/fossil.log | |
| 62 | +$ doas chown www /var/www/logs/fossil.log | |
| 63 | +$ doas chmod 660 /var/www/logs/fossil.log | |
| 64 | +$ doas chmod 755 /var/www/cgi-bin/scm | |
| 65 | 65 | ``` |
| 66 | 66 | |
| 67 | 67 | ## <a id="chroot"></a>Setup chroot |
| 68 | 68 | |
| 69 | 69 | Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible |
| @@ -75,41 +75,41 @@ | ||
| 75 | 75 | startup script to recreate the device files at boot, create a template |
| 76 | 76 | of the needed ``/dev`` tree to automatically populate the memory |
| 77 | 77 | filesystem. |
| 78 | 78 | |
| 79 | 79 | ```console |
| 80 | - $ doas mkdir /var/www/dev | |
| 81 | - $ doas install -d -g daemon /template/dev | |
| 82 | - $ cd /template/dev | |
| 83 | - $ doas /dev/MAKEDEV urandom | |
| 84 | - $ doas mknod -m 666 null c 2 2 | |
| 85 | - $ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev | |
| 86 | - $ ls -l | |
| 87 | - total 0 | |
| 88 | - crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null | |
| 89 | - lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom | |
| 90 | - crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom | |
| 80 | +$ doas mkdir /var/www/dev | |
| 81 | +$ doas install -d -g daemon /template/dev | |
| 82 | +$ cd /template/dev | |
| 83 | +$ doas /dev/MAKEDEV urandom | |
| 84 | +$ doas mknod -m 666 null c 2 2 | |
| 85 | +$ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev | |
| 86 | +$ ls -l | |
| 87 | +total 0 | |
| 88 | +crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null | |
| 89 | +lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom | |
| 90 | +crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom | |
| 91 | 91 | ``` |
| 92 | 92 | |
| 93 | 93 | [mfs]: https://man.openbsd.org/mount_mfs.8 |
| 94 | 94 | |
| 95 | 95 | To make the mountable memory filesystem permanent, open `/etc/fstab` as |
| 96 | 96 | a privileged user and add the following line to automate creation of the |
| 97 | 97 | filesystem at startup: |
| 98 | 98 | |
| 99 | 99 | ```console |
| 100 | - swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0 | |
| 100 | +swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0 | |
| 101 | 101 | ``` |
| 102 | 102 | |
| 103 | 103 | The same user that executes the fossil binary must have writable access |
| 104 | 104 | to the repository directory that resides within the chroot; on OpenBSD |
| 105 | 105 | this is `www`. In addition, grant repository directory ownership to the |
| 106 | 106 | user who will push to, pull from, and create repositories. |
| 107 | 107 | |
| 108 | 108 | ```console |
| 109 | - $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld | |
| 110 | - $ doas chmod 770 /var/www/htdocs/fsl.domain.tld | |
| 109 | +$ doas chown -R user:www /var/www/htdocs/fsl.domain.tld | |
| 110 | +$ doas chmod 770 /var/www/htdocs/fsl.domain.tld | |
| 111 | 111 | ``` |
| 112 | 112 | |
| 113 | 113 | ## <a id="httpdconfig"></a>Configure httpd |
| 114 | 114 | |
| 115 | 115 | On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for |
| @@ -123,46 +123,46 @@ | ||
| 123 | 123 | [LE]: https://letsencrypt.org |
| 124 | 124 | [acme]: https://man.openbsd.org/acme-client.1 |
| 125 | 125 | [httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5 |
| 126 | 126 | |
| 127 | 127 | ```apache |
| 128 | - server "fsl.domain.tld" { | |
| 129 | - listen on * port http | |
| 130 | - root "/htdocs/fsl.domain.tld" | |
| 131 | - location "/.well-known/acme-challenge/*" { | |
| 132 | - root "/acme" | |
| 133 | - request strip 2 | |
| 134 | - } | |
| 135 | - location * { | |
| 136 | - block return 301 "https://$HTTP_HOST$REQUEST_URI" | |
| 137 | - } | |
| 138 | - location "/*" { | |
| 139 | - fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } | |
| 140 | - } | |
| 141 | - } | |
| 142 | - | |
| 143 | - server "fsl.domain.tld" { | |
| 144 | - listen on * tls port https | |
| 145 | - root "/htdocs/fsl.domain.tld" | |
| 146 | - tls { | |
| 147 | - certificate "/etc/ssl/domain.tld.fullchain.pem" | |
| 148 | - key "/etc/ssl/private/domain.tld.key" | |
| 149 | - } | |
| 150 | - hsts { | |
| 151 | - max-age 15768000 | |
| 152 | - preload | |
| 153 | - subdomains | |
| 154 | - } | |
| 155 | - connection max request body 104857600 | |
| 156 | - location "/*" { | |
| 157 | - fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } | |
| 158 | - } | |
| 159 | - location "/.well-known/acme-challenge/*" { | |
| 160 | - root "/acme" | |
| 161 | - request strip 2 | |
| 162 | - } | |
| 163 | - } | |
| 128 | +server "fsl.domain.tld" { | |
| 129 | + listen on * port http | |
| 130 | + root "/htdocs/fsl.domain.tld" | |
| 131 | + location "/.well-known/acme-challenge/*" { | |
| 132 | + root "/acme" | |
| 133 | + request strip 2 | |
| 134 | + } | |
| 135 | + location * { | |
| 136 | + block return 301 "https://$HTTP_HOST$REQUEST_URI" | |
| 137 | + } | |
| 138 | + location "/*" { | |
| 139 | + fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } | |
| 140 | + } | |
| 141 | +} | |
| 142 | + | |
| 143 | +server "fsl.domain.tld" { | |
| 144 | + listen on * tls port https | |
| 145 | + root "/htdocs/fsl.domain.tld" | |
| 146 | + tls { | |
| 147 | + certificate "/etc/ssl/domain.tld.fullchain.pem" | |
| 148 | + key "/etc/ssl/private/domain.tld.key" | |
| 149 | + } | |
| 150 | + hsts { | |
| 151 | + max-age 15768000 | |
| 152 | + preload | |
| 153 | + subdomains | |
| 154 | + } | |
| 155 | + connection max request body 104857600 | |
| 156 | + location "/*" { | |
| 157 | + fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } | |
| 158 | + } | |
| 159 | + location "/.well-known/acme-challenge/*" { | |
| 160 | + root "/acme" | |
| 161 | + request strip 2 | |
| 162 | + } | |
| 163 | +} | |
| 164 | 164 | ``` |
| 165 | 165 | |
| 166 | 166 | [The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server |
| 167 | 167 | is 1 MiB. Fossil chunks its sync protocol such that this is not |
| 168 | 168 | normally a problem, but when sending [unversioned content][uv], it uses |
| @@ -187,57 +187,57 @@ | ||
| 187 | 187 | ensure you have a zone record for the subdomain with your registrar or |
| 188 | 188 | nameserver. Then open `/etc/acme-client.conf` as a privileged user to |
| 189 | 189 | configure the request. |
| 190 | 190 | |
| 191 | 191 | ```dosini |
| 192 | - authority letsencrypt { | |
| 193 | - api url "https://acme-v02.api.letsencrypt.org/directory" | |
| 194 | - account key "/etc/acme/letsencrypt-privkey.pem" | |
| 195 | - } | |
| 196 | - | |
| 197 | - authority letsencrypt-staging { | |
| 198 | - api url "https://acme-staging.api.letsencrypt.org/directory" | |
| 199 | - account key "/etc/acme/letsencrypt-staging-privkey.pem" | |
| 200 | - } | |
| 201 | - | |
| 202 | - domain domain.tld { | |
| 203 | - alternative names { www.domain.tld fsl.domain.tld } | |
| 204 | - domain key "/etc/ssl/private/domain.tld.key" | |
| 205 | - domain certificate "/etc/ssl/domain.tld.crt" | |
| 206 | - domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem" | |
| 207 | - sign with letsencrypt | |
| 208 | - } | |
| 192 | +authority letsencrypt { | |
| 193 | + api url "https://acme-v02.api.letsencrypt.org/directory" | |
| 194 | + account key "/etc/acme/letsencrypt-privkey.pem" | |
| 195 | +} | |
| 196 | + | |
| 197 | +authority letsencrypt-staging { | |
| 198 | + api url "https://acme-staging.api.letsencrypt.org/directory" | |
| 199 | + account key "/etc/acme/letsencrypt-staging-privkey.pem" | |
| 200 | +} | |
| 201 | + | |
| 202 | +domain domain.tld { | |
| 203 | + alternative names { www.domain.tld fsl.domain.tld } | |
| 204 | + domain key "/etc/ssl/private/domain.tld.key" | |
| 205 | + domain certificate "/etc/ssl/domain.tld.crt" | |
| 206 | + domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem" | |
| 207 | + sign with letsencrypt | |
| 208 | +} | |
| 209 | 209 | ``` |
| 210 | 210 | |
| 211 | 211 | Start `httpd` with the new configuration file, and issue the certificate |
| 212 | 212 | request. |
| 213 | 213 | |
| 214 | 214 | ```console |
| 215 | - $ doas rcctl start httpd | |
| 216 | - $ doas acme-client -vv domain.tld | |
| 217 | - acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating) | |
| 218 | - acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key | |
| 219 | - acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key | |
| 220 | - acme-client: https://acme-v01.api.letsencrypt.org/directory: directories | |
| 221 | - acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248 | |
| 222 | - ... | |
| 223 | - N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes) | |
| 224 | - acme-client: /etc/ssl/domain.tld.crt: created | |
| 225 | - acme-client: /etc/ssl/domain.tld.fullchain.pem: created | |
| 215 | +$ doas rcctl start httpd | |
| 216 | +$ doas acme-client -vv domain.tld | |
| 217 | +acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating) | |
| 218 | +acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key | |
| 219 | +acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key | |
| 220 | +acme-client: https://acme-v01.api.letsencrypt.org/directory: directories | |
| 221 | +acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248 | |
| 222 | +... | |
| 223 | +N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes) | |
| 224 | +acme-client: /etc/ssl/domain.tld.crt: created | |
| 225 | +acme-client: /etc/ssl/domain.tld.fullchain.pem: created | |
| 226 | 226 | ``` |
| 227 | 227 | |
| 228 | 228 | A successful result will output the public certificate, full chain of |
| 229 | 229 | trust, and private key into the `/etc/ssl` directory as specified in |
| 230 | 230 | `acme-client.conf`. |
| 231 | 231 | |
| 232 | 232 | ```console |
| 233 | - $ doas ls -lR /etc/ssl | |
| 234 | - -r--r--r-- 1 root wheel 2.3K Mar 2 01:31:03 2018 domain.tld.crt | |
| 235 | - -r--r--r-- 1 root wheel 3.9K Mar 2 01:31:03 2018 domain.tld.fullchain.pem | |
| 233 | +$ doas ls -lR /etc/ssl | |
| 234 | +-r--r--r-- 1 root wheel 2.3K Mar 2 01:31:03 2018 domain.tld.crt | |
| 235 | +-r--r--r-- 1 root wheel 3.9K Mar 2 01:31:03 2018 domain.tld.fullchain.pem | |
| 236 | 236 | |
| 237 | - /etc/ssl/private: | |
| 238 | - -r-------- 1 root wheel 3.2K Mar 2 01:31:03 2018 domain.tld.key | |
| 237 | +/etc/ssl/private: | |
| 238 | +-r-------- 1 root wheel 3.2K Mar 2 01:31:03 2018 domain.tld.key | |
| 239 | 239 | ``` |
| 240 | 240 | |
| 241 | 241 | Make sure to reopen `/etc/httpd.conf` to uncomment the second server |
| 242 | 242 | block responsible for serving HTTPS requests before proceeding. |
| 243 | 243 | |
| @@ -249,36 +249,36 @@ | ||
| 249 | 249 | execute the above Fossil CGI script—before checking that the syntax of |
| 250 | 250 | the `httpd.conf` configuration file is correct, and (re)starting the |
| 251 | 251 | server (if still running from requesting a Let's Encrypt certificate). |
| 252 | 252 | |
| 253 | 253 | ```console |
| 254 | - $ doas rcctl enable slowcgi | |
| 255 | - $ doas rcctl start slowcgi | |
| 256 | - slowcgi(ok) | |
| 257 | - $ doas httpd -vnf /etc/httpd.conf | |
| 258 | - configuration OK | |
| 259 | - $ doas rcctl start httpd | |
| 260 | - httpd(ok) | |
| 254 | +$ doas rcctl enable slowcgi | |
| 255 | +$ doas rcctl start slowcgi | |
| 256 | +slowcgi(ok) | |
| 257 | +$ doas httpd -vnf /etc/httpd.conf | |
| 258 | +configuration OK | |
| 259 | +$ doas rcctl start httpd | |
| 260 | +httpd(ok) | |
| 261 | 261 | ``` |
| 262 | 262 | |
| 263 | 263 | ## <a id="clientconfig"></a>Configure Client |
| 264 | 264 | |
| 265 | 265 | To facilitate creating new repositories and pushing them to the server, |
| 266 | 266 | add the following function to your `~/.cshrc` or `~/.zprofile` or the |
| 267 | 267 | config file for whichever shell you are using on your development box. |
| 268 | 268 | |
| 269 | 269 | ```sh |
| 270 | - finit() { | |
| 271 | - fossil init $1.fossil && \ | |
| 272 | - chmod 664 $1.fossil && \ | |
| 273 | - fossil open $1.fossil && \ | |
| 274 | - fossil user password $USER $PASSWD && \ | |
| 275 | - fossil remote-url https://$USER:[email protected]/$1 && \ | |
| 276 | - rsync --perms $1.fossil [email protected]:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \ | |
| 277 | - chmod 644 $1.fossil && \ | |
| 278 | - fossil ui | |
| 279 | - } | |
| 270 | +finit() { | |
| 271 | + fossil init $1.fossil && \ | |
| 272 | + chmod 664 $1.fossil && \ | |
| 273 | + fossil open $1.fossil && \ | |
| 274 | + fossil user password $USER $PASSWD && \ | |
| 275 | + fossil remote-url https://$USER:[email protected]/$1 && \ | |
| 276 | + rsync --perms $1.fossil [email protected]:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \ | |
| 277 | + chmod 644 $1.fossil && \ | |
| 278 | + fossil ui | |
| 279 | +} | |
| 280 | 280 | ``` |
| 281 | 281 | |
| 282 | 282 | This enables a new repository to be made with `finit repo`, which will |
| 283 | 283 | create the fossil repository file `repo.fossil` in the current working |
| 284 | 284 | directory; by default, the repository user is set to the environment |
| 285 | 285 |
| --- www/server/openbsd/fastcgi.md | |
| +++ www/server/openbsd/fastcgi.md | |
| @@ -18,52 +18,52 @@ | |
| 18 | |
| 19 | Use the OpenBSD package manager `pkg_add` to install Fossil, making sure |
| 20 | to select the statically linked binary. |
| 21 | |
| 22 | ```console |
| 23 | $ doas pkg_add fossil |
| 24 | quirks-3.325 signed on 2020-06-12T06:24:53Z |
| 25 | Ambiguous: choose package for fossil |
| 26 | 0: <None> |
| 27 | 1: fossil-2.10v0 |
| 28 | 2: fossil-2.10v0-static |
| 29 | Your choice: 2 |
| 30 | fossil-2.10v0-static: ok |
| 31 | ``` |
| 32 | |
| 33 | This installs Fossil into the chroot. To facilitate local use, create a |
| 34 | symbolic link of the fossil executable into `/usr/local/bin`. |
| 35 | |
| 36 | ```console |
| 37 | $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil |
| 38 | ``` |
| 39 | |
| 40 | As a privileged user, create the file `/var/www/cgi-bin/scm` with the |
| 41 | following contents to make the CGI script that `httpd` will execute in |
| 42 | response to `fsl.domain.tld` requests; all paths are relative to the |
| 43 | `/var/www` chroot. |
| 44 | |
| 45 | ```sh |
| 46 | #!/bin/fossil |
| 47 | directory: /htdocs/fsl.domain.tld |
| 48 | notfound: https://domain.tld |
| 49 | repolist |
| 50 | errorlog: /logs/fossil.log |
| 51 | ``` |
| 52 | |
| 53 | The `directory` directive instructs Fossil to serve all repositories |
| 54 | found in `/var/www/htdocs/fsl.domain.tld`, while `errorlog` sets logging |
| 55 | to be saved to `/var/www/logs/fossil.log`; create the repository |
| 56 | directory and log file—making the latter owned by the `www` user, and |
| 57 | the script executable. |
| 58 | |
| 59 | ```console |
| 60 | $ doas mkdir /var/www/htdocs/fsl.domain.tld |
| 61 | $ doas touch /var/www/logs/fossil.log |
| 62 | $ doas chown www /var/www/logs/fossil.log |
| 63 | $ doas chmod 660 /var/www/logs/fossil.log |
| 64 | $ doas chmod 755 /var/www/cgi-bin/scm |
| 65 | ``` |
| 66 | |
| 67 | ## <a id="chroot"></a>Setup chroot |
| 68 | |
| 69 | Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible |
| @@ -75,41 +75,41 @@ | |
| 75 | startup script to recreate the device files at boot, create a template |
| 76 | of the needed ``/dev`` tree to automatically populate the memory |
| 77 | filesystem. |
| 78 | |
| 79 | ```console |
| 80 | $ doas mkdir /var/www/dev |
| 81 | $ doas install -d -g daemon /template/dev |
| 82 | $ cd /template/dev |
| 83 | $ doas /dev/MAKEDEV urandom |
| 84 | $ doas mknod -m 666 null c 2 2 |
| 85 | $ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev |
| 86 | $ ls -l |
| 87 | total 0 |
| 88 | crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null |
| 89 | lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom |
| 90 | crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom |
| 91 | ``` |
| 92 | |
| 93 | [mfs]: https://man.openbsd.org/mount_mfs.8 |
| 94 | |
| 95 | To make the mountable memory filesystem permanent, open `/etc/fstab` as |
| 96 | a privileged user and add the following line to automate creation of the |
| 97 | filesystem at startup: |
| 98 | |
| 99 | ```console |
| 100 | swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0 |
| 101 | ``` |
| 102 | |
| 103 | The same user that executes the fossil binary must have writable access |
| 104 | to the repository directory that resides within the chroot; on OpenBSD |
| 105 | this is `www`. In addition, grant repository directory ownership to the |
| 106 | user who will push to, pull from, and create repositories. |
| 107 | |
| 108 | ```console |
| 109 | $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld |
| 110 | $ doas chmod 770 /var/www/htdocs/fsl.domain.tld |
| 111 | ``` |
| 112 | |
| 113 | ## <a id="httpdconfig"></a>Configure httpd |
| 114 | |
| 115 | On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for |
| @@ -123,46 +123,46 @@ | |
| 123 | [LE]: https://letsencrypt.org |
| 124 | [acme]: https://man.openbsd.org/acme-client.1 |
| 125 | [httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5 |
| 126 | |
| 127 | ```apache |
| 128 | server "fsl.domain.tld" { |
| 129 | listen on * port http |
| 130 | root "/htdocs/fsl.domain.tld" |
| 131 | location "/.well-known/acme-challenge/*" { |
| 132 | root "/acme" |
| 133 | request strip 2 |
| 134 | } |
| 135 | location * { |
| 136 | block return 301 "https://$HTTP_HOST$REQUEST_URI" |
| 137 | } |
| 138 | location "/*" { |
| 139 | fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | server "fsl.domain.tld" { |
| 144 | listen on * tls port https |
| 145 | root "/htdocs/fsl.domain.tld" |
| 146 | tls { |
| 147 | certificate "/etc/ssl/domain.tld.fullchain.pem" |
| 148 | key "/etc/ssl/private/domain.tld.key" |
| 149 | } |
| 150 | hsts { |
| 151 | max-age 15768000 |
| 152 | preload |
| 153 | subdomains |
| 154 | } |
| 155 | connection max request body 104857600 |
| 156 | location "/*" { |
| 157 | fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } |
| 158 | } |
| 159 | location "/.well-known/acme-challenge/*" { |
| 160 | root "/acme" |
| 161 | request strip 2 |
| 162 | } |
| 163 | } |
| 164 | ``` |
| 165 | |
| 166 | [The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server |
| 167 | is 1 MiB. Fossil chunks its sync protocol such that this is not |
| 168 | normally a problem, but when sending [unversioned content][uv], it uses |
| @@ -187,57 +187,57 @@ | |
| 187 | ensure you have a zone record for the subdomain with your registrar or |
| 188 | nameserver. Then open `/etc/acme-client.conf` as a privileged user to |
| 189 | configure the request. |
| 190 | |
| 191 | ```dosini |
| 192 | authority letsencrypt { |
| 193 | api url "https://acme-v02.api.letsencrypt.org/directory" |
| 194 | account key "/etc/acme/letsencrypt-privkey.pem" |
| 195 | } |
| 196 | |
| 197 | authority letsencrypt-staging { |
| 198 | api url "https://acme-staging.api.letsencrypt.org/directory" |
| 199 | account key "/etc/acme/letsencrypt-staging-privkey.pem" |
| 200 | } |
| 201 | |
| 202 | domain domain.tld { |
| 203 | alternative names { www.domain.tld fsl.domain.tld } |
| 204 | domain key "/etc/ssl/private/domain.tld.key" |
| 205 | domain certificate "/etc/ssl/domain.tld.crt" |
| 206 | domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem" |
| 207 | sign with letsencrypt |
| 208 | } |
| 209 | ``` |
| 210 | |
| 211 | Start `httpd` with the new configuration file, and issue the certificate |
| 212 | request. |
| 213 | |
| 214 | ```console |
| 215 | $ doas rcctl start httpd |
| 216 | $ doas acme-client -vv domain.tld |
| 217 | acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating) |
| 218 | acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key |
| 219 | acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key |
| 220 | acme-client: https://acme-v01.api.letsencrypt.org/directory: directories |
| 221 | acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248 |
| 222 | ... |
| 223 | N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes) |
| 224 | acme-client: /etc/ssl/domain.tld.crt: created |
| 225 | acme-client: /etc/ssl/domain.tld.fullchain.pem: created |
| 226 | ``` |
| 227 | |
| 228 | A successful result will output the public certificate, full chain of |
| 229 | trust, and private key into the `/etc/ssl` directory as specified in |
| 230 | `acme-client.conf`. |
| 231 | |
| 232 | ```console |
| 233 | $ doas ls -lR /etc/ssl |
| 234 | -r--r--r-- 1 root wheel 2.3K Mar 2 01:31:03 2018 domain.tld.crt |
| 235 | -r--r--r-- 1 root wheel 3.9K Mar 2 01:31:03 2018 domain.tld.fullchain.pem |
| 236 | |
| 237 | /etc/ssl/private: |
| 238 | -r-------- 1 root wheel 3.2K Mar 2 01:31:03 2018 domain.tld.key |
| 239 | ``` |
| 240 | |
| 241 | Make sure to reopen `/etc/httpd.conf` to uncomment the second server |
| 242 | block responsible for serving HTTPS requests before proceeding. |
| 243 | |
| @@ -249,36 +249,36 @@ | |
| 249 | execute the above Fossil CGI script—before checking that the syntax of |
| 250 | the `httpd.conf` configuration file is correct, and (re)starting the |
| 251 | server (if still running from requesting a Let's Encrypt certificate). |
| 252 | |
| 253 | ```console |
| 254 | $ doas rcctl enable slowcgi |
| 255 | $ doas rcctl start slowcgi |
| 256 | slowcgi(ok) |
| 257 | $ doas httpd -vnf /etc/httpd.conf |
| 258 | configuration OK |
| 259 | $ doas rcctl start httpd |
| 260 | httpd(ok) |
| 261 | ``` |
| 262 | |
| 263 | ## <a id="clientconfig"></a>Configure Client |
| 264 | |
| 265 | To facilitate creating new repositories and pushing them to the server, |
| 266 | add the following function to your `~/.cshrc` or `~/.zprofile` or the |
| 267 | config file for whichever shell you are using on your development box. |
| 268 | |
| 269 | ```sh |
| 270 | finit() { |
| 271 | fossil init $1.fossil && \ |
| 272 | chmod 664 $1.fossil && \ |
| 273 | fossil open $1.fossil && \ |
| 274 | fossil user password $USER $PASSWD && \ |
| 275 | fossil remote-url https://$USER:[email protected]/$1 && \ |
| 276 | rsync --perms $1.fossil [email protected]:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \ |
| 277 | chmod 644 $1.fossil && \ |
| 278 | fossil ui |
| 279 | } |
| 280 | ``` |
| 281 | |
| 282 | This enables a new repository to be made with `finit repo`, which will |
| 283 | create the fossil repository file `repo.fossil` in the current working |
| 284 | directory; by default, the repository user is set to the environment |
| 285 |
| --- www/server/openbsd/fastcgi.md | |
| +++ www/server/openbsd/fastcgi.md | |
| @@ -18,52 +18,52 @@ | |
| 18 | |
| 19 | Use the OpenBSD package manager `pkg_add` to install Fossil, making sure |
| 20 | to select the statically linked binary. |
| 21 | |
| 22 | ```console |
| 23 | $ doas pkg_add fossil |
| 24 | quirks-3.325 signed on 2020-06-12T06:24:53Z |
| 25 | Ambiguous: choose package for fossil |
| 26 | 0: <None> |
| 27 | 1: fossil-2.10v0 |
| 28 | 2: fossil-2.10v0-static |
| 29 | Your choice: 2 |
| 30 | fossil-2.10v0-static: ok |
| 31 | ``` |
| 32 | |
| 33 | This installs Fossil into the chroot. To facilitate local use, create a |
| 34 | symbolic link of the fossil executable into `/usr/local/bin`. |
| 35 | |
| 36 | ```console |
| 37 | $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil |
| 38 | ``` |
| 39 | |
| 40 | As a privileged user, create the file `/var/www/cgi-bin/scm` with the |
| 41 | following contents to make the CGI script that `httpd` will execute in |
| 42 | response to `fsl.domain.tld` requests; all paths are relative to the |
| 43 | `/var/www` chroot. |
| 44 | |
| 45 | ```sh |
| 46 | #!/bin/fossil |
| 47 | directory: /htdocs/fsl.domain.tld |
| 48 | notfound: https://domain.tld |
| 49 | repolist |
| 50 | errorlog: /logs/fossil.log |
| 51 | ``` |
| 52 | |
| 53 | The `directory` directive instructs Fossil to serve all repositories |
| 54 | found in `/var/www/htdocs/fsl.domain.tld`, while `errorlog` sets logging |
| 55 | to be saved to `/var/www/logs/fossil.log`; create the repository |
| 56 | directory and log file—making the latter owned by the `www` user, and |
| 57 | the script executable. |
| 58 | |
| 59 | ```console |
| 60 | $ doas mkdir /var/www/htdocs/fsl.domain.tld |
| 61 | $ doas touch /var/www/logs/fossil.log |
| 62 | $ doas chown www /var/www/logs/fossil.log |
| 63 | $ doas chmod 660 /var/www/logs/fossil.log |
| 64 | $ doas chmod 755 /var/www/cgi-bin/scm |
| 65 | ``` |
| 66 | |
| 67 | ## <a id="chroot"></a>Setup chroot |
| 68 | |
| 69 | Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible |
| @@ -75,41 +75,41 @@ | |
| 75 | startup script to recreate the device files at boot, create a template |
| 76 | of the needed ``/dev`` tree to automatically populate the memory |
| 77 | filesystem. |
| 78 | |
| 79 | ```console |
| 80 | $ doas mkdir /var/www/dev |
| 81 | $ doas install -d -g daemon /template/dev |
| 82 | $ cd /template/dev |
| 83 | $ doas /dev/MAKEDEV urandom |
| 84 | $ doas mknod -m 666 null c 2 2 |
| 85 | $ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev |
| 86 | $ ls -l |
| 87 | total 0 |
| 88 | crw-rw-rw- 1 root daemon 2, 2 Jun 20 08:56 null |
| 89 | lrwxr-xr-x 1 root daemon 7 Jun 18 06:30 random@ -> urandom |
| 90 | crw-r--r-- 1 root wheel 45, 0 Jun 18 06:30 urandom |
| 91 | ``` |
| 92 | |
| 93 | [mfs]: https://man.openbsd.org/mount_mfs.8 |
| 94 | |
| 95 | To make the mountable memory filesystem permanent, open `/etc/fstab` as |
| 96 | a privileged user and add the following line to automate creation of the |
| 97 | filesystem at startup: |
| 98 | |
| 99 | ```console |
| 100 | swap /var/www/dev mfs rw,-s=1048576,-P=/template/dev 0 0 |
| 101 | ``` |
| 102 | |
| 103 | The same user that executes the fossil binary must have writable access |
| 104 | to the repository directory that resides within the chroot; on OpenBSD |
| 105 | this is `www`. In addition, grant repository directory ownership to the |
| 106 | user who will push to, pull from, and create repositories. |
| 107 | |
| 108 | ```console |
| 109 | $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld |
| 110 | $ doas chmod 770 /var/www/htdocs/fsl.domain.tld |
| 111 | ``` |
| 112 | |
| 113 | ## <a id="httpdconfig"></a>Configure httpd |
| 114 | |
| 115 | On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for |
| @@ -123,46 +123,46 @@ | |
| 123 | [LE]: https://letsencrypt.org |
| 124 | [acme]: https://man.openbsd.org/acme-client.1 |
| 125 | [httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5 |
| 126 | |
| 127 | ```apache |
| 128 | server "fsl.domain.tld" { |
| 129 | listen on * port http |
| 130 | root "/htdocs/fsl.domain.tld" |
| 131 | location "/.well-known/acme-challenge/*" { |
| 132 | root "/acme" |
| 133 | request strip 2 |
| 134 | } |
| 135 | location * { |
| 136 | block return 301 "https://$HTTP_HOST$REQUEST_URI" |
| 137 | } |
| 138 | location "/*" { |
| 139 | fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | server "fsl.domain.tld" { |
| 144 | listen on * tls port https |
| 145 | root "/htdocs/fsl.domain.tld" |
| 146 | tls { |
| 147 | certificate "/etc/ssl/domain.tld.fullchain.pem" |
| 148 | key "/etc/ssl/private/domain.tld.key" |
| 149 | } |
| 150 | hsts { |
| 151 | max-age 15768000 |
| 152 | preload |
| 153 | subdomains |
| 154 | } |
| 155 | connection max request body 104857600 |
| 156 | location "/*" { |
| 157 | fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } |
| 158 | } |
| 159 | location "/.well-known/acme-challenge/*" { |
| 160 | root "/acme" |
| 161 | request strip 2 |
| 162 | } |
| 163 | } |
| 164 | ``` |
| 165 | |
| 166 | [The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server |
| 167 | is 1 MiB. Fossil chunks its sync protocol such that this is not |
| 168 | normally a problem, but when sending [unversioned content][uv], it uses |
| @@ -187,57 +187,57 @@ | |
| 187 | ensure you have a zone record for the subdomain with your registrar or |
| 188 | nameserver. Then open `/etc/acme-client.conf` as a privileged user to |
| 189 | configure the request. |
| 190 | |
| 191 | ```dosini |
| 192 | authority letsencrypt { |
| 193 | api url "https://acme-v02.api.letsencrypt.org/directory" |
| 194 | account key "/etc/acme/letsencrypt-privkey.pem" |
| 195 | } |
| 196 | |
| 197 | authority letsencrypt-staging { |
| 198 | api url "https://acme-staging.api.letsencrypt.org/directory" |
| 199 | account key "/etc/acme/letsencrypt-staging-privkey.pem" |
| 200 | } |
| 201 | |
| 202 | domain domain.tld { |
| 203 | alternative names { www.domain.tld fsl.domain.tld } |
| 204 | domain key "/etc/ssl/private/domain.tld.key" |
| 205 | domain certificate "/etc/ssl/domain.tld.crt" |
| 206 | domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem" |
| 207 | sign with letsencrypt |
| 208 | } |
| 209 | ``` |
| 210 | |
| 211 | Start `httpd` with the new configuration file, and issue the certificate |
| 212 | request. |
| 213 | |
| 214 | ```console |
| 215 | $ doas rcctl start httpd |
| 216 | $ doas acme-client -vv domain.tld |
| 217 | acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating) |
| 218 | acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key |
| 219 | acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key |
| 220 | acme-client: https://acme-v01.api.letsencrypt.org/directory: directories |
| 221 | acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248 |
| 222 | ... |
| 223 | N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes) |
| 224 | acme-client: /etc/ssl/domain.tld.crt: created |
| 225 | acme-client: /etc/ssl/domain.tld.fullchain.pem: created |
| 226 | ``` |
| 227 | |
| 228 | A successful result will output the public certificate, full chain of |
| 229 | trust, and private key into the `/etc/ssl` directory as specified in |
| 230 | `acme-client.conf`. |
| 231 | |
| 232 | ```console |
| 233 | $ doas ls -lR /etc/ssl |
| 234 | -r--r--r-- 1 root wheel 2.3K Mar 2 01:31:03 2018 domain.tld.crt |
| 235 | -r--r--r-- 1 root wheel 3.9K Mar 2 01:31:03 2018 domain.tld.fullchain.pem |
| 236 | |
| 237 | /etc/ssl/private: |
| 238 | -r-------- 1 root wheel 3.2K Mar 2 01:31:03 2018 domain.tld.key |
| 239 | ``` |
| 240 | |
| 241 | Make sure to reopen `/etc/httpd.conf` to uncomment the second server |
| 242 | block responsible for serving HTTPS requests before proceeding. |
| 243 | |
| @@ -249,36 +249,36 @@ | |
| 249 | execute the above Fossil CGI script—before checking that the syntax of |
| 250 | the `httpd.conf` configuration file is correct, and (re)starting the |
| 251 | server (if still running from requesting a Let's Encrypt certificate). |
| 252 | |
| 253 | ```console |
| 254 | $ doas rcctl enable slowcgi |
| 255 | $ doas rcctl start slowcgi |
| 256 | slowcgi(ok) |
| 257 | $ doas httpd -vnf /etc/httpd.conf |
| 258 | configuration OK |
| 259 | $ doas rcctl start httpd |
| 260 | httpd(ok) |
| 261 | ``` |
| 262 | |
| 263 | ## <a id="clientconfig"></a>Configure Client |
| 264 | |
| 265 | To facilitate creating new repositories and pushing them to the server, |
| 266 | add the following function to your `~/.cshrc` or `~/.zprofile` or the |
| 267 | config file for whichever shell you are using on your development box. |
| 268 | |
| 269 | ```sh |
| 270 | finit() { |
| 271 | fossil init $1.fossil && \ |
| 272 | chmod 664 $1.fossil && \ |
| 273 | fossil open $1.fossil && \ |
| 274 | fossil user password $USER $PASSWD && \ |
| 275 | fossil remote-url https://$USER:[email protected]/$1 && \ |
| 276 | rsync --perms $1.fossil [email protected]:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \ |
| 277 | chmod 644 $1.fossil && \ |
| 278 | fossil ui |
| 279 | } |
| 280 | ``` |
| 281 | |
| 282 | This enables a new repository to be made with `finit repo`, which will |
| 283 | create the fossil repository file `repo.fossil` in the current working |
| 284 | directory; by default, the repository user is set to the environment |
| 285 |
+1
-1
| --- www/server/windows/iis.md | ||
| +++ www/server/windows/iis.md | ||
| @@ -32,11 +32,11 @@ | ||
| 32 | 32 | You will need to have the Fossil HTTP server running in the background, |
| 33 | 33 | serving some local repository, bound to localhost on a fixed |
| 34 | 34 | high-numbered TCP port. For the purposes of testing, simply start it by |
| 35 | 35 | hand in your command shell of choice: |
| 36 | 36 | |
| 37 | - fossil serve --port 9000 --localhost repo.fossil | |
| 37 | + fossil serve --port 9000 --localhost repo.fossil | |
| 38 | 38 | |
| 39 | 39 | That command assumes you’ve got `fossil.exe` in your `%PATH%` and you’re |
| 40 | 40 | in a directory holding `repo.fossil`. See [the platform-independent |
| 41 | 41 | instructions](../any/none.md) for further details. |
| 42 | 42 | |
| 43 | 43 |
| --- www/server/windows/iis.md | |
| +++ www/server/windows/iis.md | |
| @@ -32,11 +32,11 @@ | |
| 32 | You will need to have the Fossil HTTP server running in the background, |
| 33 | serving some local repository, bound to localhost on a fixed |
| 34 | high-numbered TCP port. For the purposes of testing, simply start it by |
| 35 | hand in your command shell of choice: |
| 36 | |
| 37 | fossil serve --port 9000 --localhost repo.fossil |
| 38 | |
| 39 | That command assumes you’ve got `fossil.exe` in your `%PATH%` and you’re |
| 40 | in a directory holding `repo.fossil`. See [the platform-independent |
| 41 | instructions](../any/none.md) for further details. |
| 42 | |
| 43 |
| --- www/server/windows/iis.md | |
| +++ www/server/windows/iis.md | |
| @@ -32,11 +32,11 @@ | |
| 32 | You will need to have the Fossil HTTP server running in the background, |
| 33 | serving some local repository, bound to localhost on a fixed |
| 34 | high-numbered TCP port. For the purposes of testing, simply start it by |
| 35 | hand in your command shell of choice: |
| 36 | |
| 37 | fossil serve --port 9000 --localhost repo.fossil |
| 38 | |
| 39 | That command assumes you’ve got `fossil.exe` in your `%PATH%` and you’re |
| 40 | in a directory holding `repo.fossil`. See [the platform-independent |
| 41 | instructions](../any/none.md) for further details. |
| 42 | |
| 43 |
+22
-22
| --- www/th1.md | ||
| +++ www/th1.md | ||
| @@ -54,15 +54,15 @@ | ||
| 54 | 54 | C/C++ programmers because TH1 does look a lot like C/C++, but the semantics |
| 55 | 55 | of TH1 are closer to FORTH or Lisp than they are to C. |
| 56 | 56 | |
| 57 | 57 | Consider the `if` command in TH1. |
| 58 | 58 | |
| 59 | - if {$current eq "dev"} { | |
| 60 | - puts "hello" | |
| 61 | - } else { | |
| 62 | - puts "world" | |
| 63 | - } | |
| 59 | + if {$current eq "dev"} { | |
| 60 | + puts "hello" | |
| 61 | + } else { | |
| 62 | + puts "world" | |
| 63 | + } | |
| 64 | 64 | |
| 65 | 65 | The example above is a single command. The first token, and the name |
| 66 | 66 | of the command, is `if`. |
| 67 | 67 | The second token is `$current eq "dev"` - an expression. (The outer {...} |
| 68 | 68 | are removed from each token by the command parser.) The third token |
| @@ -83,16 +83,16 @@ | ||
| 83 | 83 | block delimiters as in C. This is how we can have a command that extends |
| 84 | 84 | over multiple lines. It is also why the `else` keyword must be cuddled |
| 85 | 85 | up with the closing brace for the `if` clause's scriptlet. The following |
| 86 | 86 | is invalid Tcl/TH1: |
| 87 | 87 | |
| 88 | - if {$current eq "dev"} { | |
| 89 | - puts "hello" | |
| 90 | - } | |
| 91 | - else { | |
| 92 | - puts "world" | |
| 93 | - } | |
| 88 | + if {$current eq "dev"} { | |
| 89 | + puts "hello" | |
| 90 | + } | |
| 91 | + else { | |
| 92 | + puts "world" | |
| 93 | + } | |
| 94 | 94 | |
| 95 | 95 | If you try to run this under either Tcl or TH1, the interpreter will |
| 96 | 96 | tell you that there is no `else` command, because with the newline on |
| 97 | 97 | the third line, you terminated the `if` command. |
| 98 | 98 | |
| @@ -99,13 +99,13 @@ | ||
| 99 | 99 | Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the |
| 100 | 100 | end of a line to allow a command to extend over multiple lines without |
| 101 | 101 | being considered two separate commands. Here's an example from one of |
| 102 | 102 | Fossil's test scripts: |
| 103 | 103 | |
| 104 | - return [lindex [regexp -line -inline -nocase -- \ | |
| 105 | - {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ | |
| 106 | - $repository "" info trunk]]] end] | |
| 104 | + return [lindex [regexp -line -inline -nocase -- \ | |
| 105 | + {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ | |
| 106 | + $repository "" info trunk]]] end] | |
| 107 | 107 | |
| 108 | 108 | Those backslashes allow the command to wrap nicely within a standard |
| 109 | 109 | terminal width while telling the interpreter to consider those three |
| 110 | 110 | lines as a single command. |
| 111 | 111 | |
| @@ -298,16 +298,16 @@ | ||
| 298 | 298 | always true. |
| 299 | 299 | |
| 300 | 300 | Examples: |
| 301 | 301 | |
| 302 | 302 | ``` |
| 303 | - capexpr {j o r} True if any one of j, o, or r are available | |
| 304 | - capexpr {oh} True if both o and h are available | |
| 305 | - capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of | |
| 306 | - 4, 5 or 6 is available for the user | |
| 307 | - capexpr L True if the user is logged in | |
| 308 | - capexpr !L True if the user is not logged in | |
| 303 | +capexpr {j o r} True if any one of j, o, or r are available | |
| 304 | +capexpr {oh} True if both o and h are available | |
| 305 | +capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of | |
| 306 | + 4, 5 or 6 is available for the user | |
| 307 | +capexpr L True if the user is logged in | |
| 308 | +capexpr !L True if the user is not logged in | |
| 309 | 309 | ``` |
| 310 | 310 | |
| 311 | 311 | The `L` pseudo-capability is intended only to be used on its own or with |
| 312 | 312 | the `!` prefix for implementing login/logout menus via the `mainmenu` |
| 313 | 313 | site configuration option: |
| @@ -683,15 +683,15 @@ | ||
| 683 | 683 | To be clear, only one of the document classes identified by each STRING |
| 684 | 684 | needs to be searchable in order for that argument to be true. But all |
| 685 | 685 | arguments must be true for this routine to return true. Hence, to see |
| 686 | 686 | if ALL document classes are searchable: |
| 687 | 687 | |
| 688 | - if {[searchable c d t w]} {...} | |
| 688 | + if {[searchable c d t w]} {...} | |
| 689 | 689 | |
| 690 | 690 | But to see if ANY document class is searchable: |
| 691 | 691 | |
| 692 | - if {[searchable cdtw]} {...} | |
| 692 | + if {[searchable cdtw]} {...} | |
| 693 | 693 | |
| 694 | 694 | This command is useful for enabling or disabling a "Search" entry on the |
| 695 | 695 | menu bar. |
| 696 | 696 | |
| 697 | 697 | <a id="setParameter"></a>TH1 setParameter Command |
| 698 | 698 |
| --- www/th1.md | |
| +++ www/th1.md | |
| @@ -54,15 +54,15 @@ | |
| 54 | C/C++ programmers because TH1 does look a lot like C/C++, but the semantics |
| 55 | of TH1 are closer to FORTH or Lisp than they are to C. |
| 56 | |
| 57 | Consider the `if` command in TH1. |
| 58 | |
| 59 | if {$current eq "dev"} { |
| 60 | puts "hello" |
| 61 | } else { |
| 62 | puts "world" |
| 63 | } |
| 64 | |
| 65 | The example above is a single command. The first token, and the name |
| 66 | of the command, is `if`. |
| 67 | The second token is `$current eq "dev"` - an expression. (The outer {...} |
| 68 | are removed from each token by the command parser.) The third token |
| @@ -83,16 +83,16 @@ | |
| 83 | block delimiters as in C. This is how we can have a command that extends |
| 84 | over multiple lines. It is also why the `else` keyword must be cuddled |
| 85 | up with the closing brace for the `if` clause's scriptlet. The following |
| 86 | is invalid Tcl/TH1: |
| 87 | |
| 88 | if {$current eq "dev"} { |
| 89 | puts "hello" |
| 90 | } |
| 91 | else { |
| 92 | puts "world" |
| 93 | } |
| 94 | |
| 95 | If you try to run this under either Tcl or TH1, the interpreter will |
| 96 | tell you that there is no `else` command, because with the newline on |
| 97 | the third line, you terminated the `if` command. |
| 98 | |
| @@ -99,13 +99,13 @@ | |
| 99 | Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the |
| 100 | end of a line to allow a command to extend over multiple lines without |
| 101 | being considered two separate commands. Here's an example from one of |
| 102 | Fossil's test scripts: |
| 103 | |
| 104 | return [lindex [regexp -line -inline -nocase -- \ |
| 105 | {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ |
| 106 | $repository "" info trunk]]] end] |
| 107 | |
| 108 | Those backslashes allow the command to wrap nicely within a standard |
| 109 | terminal width while telling the interpreter to consider those three |
| 110 | lines as a single command. |
| 111 | |
| @@ -298,16 +298,16 @@ | |
| 298 | always true. |
| 299 | |
| 300 | Examples: |
| 301 | |
| 302 | ``` |
| 303 | capexpr {j o r} True if any one of j, o, or r are available |
| 304 | capexpr {oh} True if both o and h are available |
| 305 | capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of |
| 306 | 4, 5 or 6 is available for the user |
| 307 | capexpr L True if the user is logged in |
| 308 | capexpr !L True if the user is not logged in |
| 309 | ``` |
| 310 | |
| 311 | The `L` pseudo-capability is intended only to be used on its own or with |
| 312 | the `!` prefix for implementing login/logout menus via the `mainmenu` |
| 313 | site configuration option: |
| @@ -683,15 +683,15 @@ | |
| 683 | To be clear, only one of the document classes identified by each STRING |
| 684 | needs to be searchable in order for that argument to be true. But all |
| 685 | arguments must be true for this routine to return true. Hence, to see |
| 686 | if ALL document classes are searchable: |
| 687 | |
| 688 | if {[searchable c d t w]} {...} |
| 689 | |
| 690 | But to see if ANY document class is searchable: |
| 691 | |
| 692 | if {[searchable cdtw]} {...} |
| 693 | |
| 694 | This command is useful for enabling or disabling a "Search" entry on the |
| 695 | menu bar. |
| 696 | |
| 697 | <a id="setParameter"></a>TH1 setParameter Command |
| 698 |
| --- www/th1.md | |
| +++ www/th1.md | |
| @@ -54,15 +54,15 @@ | |
| 54 | C/C++ programmers because TH1 does look a lot like C/C++, but the semantics |
| 55 | of TH1 are closer to FORTH or Lisp than they are to C. |
| 56 | |
| 57 | Consider the `if` command in TH1. |
| 58 | |
| 59 | if {$current eq "dev"} { |
| 60 | puts "hello" |
| 61 | } else { |
| 62 | puts "world" |
| 63 | } |
| 64 | |
| 65 | The example above is a single command. The first token, and the name |
| 66 | of the command, is `if`. |
| 67 | The second token is `$current eq "dev"` - an expression. (The outer {...} |
| 68 | are removed from each token by the command parser.) The third token |
| @@ -83,16 +83,16 @@ | |
| 83 | block delimiters as in C. This is how we can have a command that extends |
| 84 | over multiple lines. It is also why the `else` keyword must be cuddled |
| 85 | up with the closing brace for the `if` clause's scriptlet. The following |
| 86 | is invalid Tcl/TH1: |
| 87 | |
| 88 | if {$current eq "dev"} { |
| 89 | puts "hello" |
| 90 | } |
| 91 | else { |
| 92 | puts "world" |
| 93 | } |
| 94 | |
| 95 | If you try to run this under either Tcl or TH1, the interpreter will |
| 96 | tell you that there is no `else` command, because with the newline on |
| 97 | the third line, you terminated the `if` command. |
| 98 | |
| @@ -99,13 +99,13 @@ | |
| 99 | Occasionally in Tcl/TH1 scripts, you may need to use a backslash at the |
| 100 | end of a line to allow a command to extend over multiple lines without |
| 101 | being considered two separate commands. Here's an example from one of |
| 102 | Fossil's test scripts: |
| 103 | |
| 104 | return [lindex [regexp -line -inline -nocase -- \ |
| 105 | {^uuid:\s+([0-9A-F]{40}) } [eval [getFossilCommand \ |
| 106 | $repository "" info trunk]]] end] |
| 107 | |
| 108 | Those backslashes allow the command to wrap nicely within a standard |
| 109 | terminal width while telling the interpreter to consider those three |
| 110 | lines as a single command. |
| 111 | |
| @@ -298,16 +298,16 @@ | |
| 298 | always true. |
| 299 | |
| 300 | Examples: |
| 301 | |
| 302 | ``` |
| 303 | capexpr {j o r} True if any one of j, o, or r are available |
| 304 | capexpr {oh} True if both o and h are available |
| 305 | capexpr {@2 @3 4 5 6} 2 or 3 available for anonymous or one of |
| 306 | 4, 5 or 6 is available for the user |
| 307 | capexpr L True if the user is logged in |
| 308 | capexpr !L True if the user is not logged in |
| 309 | ``` |
| 310 | |
| 311 | The `L` pseudo-capability is intended only to be used on its own or with |
| 312 | the `!` prefix for implementing login/logout menus via the `mainmenu` |
| 313 | site configuration option: |
| @@ -683,15 +683,15 @@ | |
| 683 | To be clear, only one of the document classes identified by each STRING |
| 684 | needs to be searchable in order for that argument to be true. But all |
| 685 | arguments must be true for this routine to return true. Hence, to see |
| 686 | if ALL document classes are searchable: |
| 687 | |
| 688 | if {[searchable c d t w]} {...} |
| 689 | |
| 690 | But to see if ANY document class is searchable: |
| 691 | |
| 692 | if {[searchable cdtw]} {...} |
| 693 | |
| 694 | This command is useful for enabling or disabling a "Search" entry on the |
| 695 | menu bar. |
| 696 | |
| 697 | <a id="setParameter"></a>TH1 setParameter Command |
| 698 |