Fossil

Check-in [1a7cc263]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Merge fixes and enhancements from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rid-renumbering
Files: files | file ages | folders
SHA3-256: 1a7cc2639c11436789985d6374e624af8fc0c2bf2e76558a695c494567ce5294
User & Date: drh 2019-01-20 16:51:07
Context
2019-01-20
21:29
Automatically update the VFILE and VMERGE tables when the fingerprinting detects that a repository has been replaced by clone. check-in: b0365238 user: drh tags: rid-renumbering
16:51
Merge fixes and enhancements from trunk. check-in: 1a7cc263 user: drh tags: rid-renumbering
16:47
Fix a hyperlink error on the graph-test page. (This should have been committed to trunk to begin with.) check-in: 20431a7c user: drh tags: trunk
16:46
Fix a hyperlink error on the graph-test page. check-in: 6c388aff user: drh tags: rid-renumbering
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/stash.c.

   575    575   **  fossil stash diff ?STASHID? ?DIFF-OPTIONS?
   576    576   **  fossil stash gdiff ?STASHID? ?DIFF-OPTIONS?
   577    577   */
   578    578   void stash_cmd(void){
   579    579     const char *zCmd;
   580    580     int nCmd;
   581    581     int stashid = 0;
   582         -  int rc;
   583    582     undo_capture_command_line();
   584    583     db_must_be_within_tree();
   585    584     db_open_config(0, 0);
   586    585     db_begin_transaction();
   587    586     stash_tables_exist_and_current();
   588    587     if( g.argc<=2 ){
   589    588       zCmd = "save";

Added tools/fslsrv.

            1  +#!/bin/bash
            2  +BASEPORT=12345
            3  +FOSSIL=fossil
            4  +OLDPID=`pgrep -P 1 fossil`
            5  +PGARGS="-P 1"
            6  +
            7  +if [ "$1" = "-f" ] ; then PGARGS= ; shift ; fi
            8  +
            9  +if [ -n "$OLDPID" ]
           10  +then
           11  +    echo "Killing running Fossil server first..."
           12  +    pkill $PGARGS fossil
           13  +
           14  +    for i in $(seq 30)
           15  +    do
           16  +        if [ -n "$(pgrep $PGARGS fossil)" ]
           17  +        then
           18  +            if [ $i -eq 1 ]
           19  +            then
           20  +                echo -n "Waiting for it to die..."
           21  +            else
           22  +                echo -n .
           23  +            fi
           24  +            sleep '0.1'
           25  +        else
           26  +            break
           27  +        fi
           28  +        echo
           29  +    done
           30  +
           31  +    killall -9 fossil 2> /dev/null
           32  +fi
           33  +
           34  +if [ -x ./fossil ]
           35  +then
           36  +    # We're running from a build tree, so use that version instead
           37  +    FOSSIL=./fossil
           38  +fi
           39  +
           40  +function start_one() {
           41  +    bn=$1
           42  +    port=$(($BASEPORT + $2))
           43  +    url="$3"
           44  +
           45  +    $FOSSIL server --localhost --port $port --scgi \
           46  +            --baseurl $url --errorlog ~/log/fossil/$bn-errors.log \
           47  +            ~/museum/$bn.fossil > ~/log/fossil/$bn-stdout.log &
           48  +    echo Fossil server running for $bn, PID $!, port $port.
           49  +}
           50  +
           51  +start_one example 0 https://example.com/code
           52  +start_one foo     1 https://foo.net

Changes to www/ssl.wiki.

     1         -<title>SSL and Fossil</title>
            1  +<title>TLS and Fossil</title>
            2  +
            3  +<h2>Using TLS-Encrypted Communications with Fossil</h2>
            4  +
            5  +If you are storing sensitive information in a repository accessible over
            6  +a network whose integrity you do not fully trust, you should use TLS to
            7  +encrypt all communications with it. This is most true for repositories
            8  +accessed over the Internet, especially if they will be accessed from
            9  +edge networks you do not control, since that admits of various forms of
           10  +[https://en.wikipedia.org/wiki/Man-in-the-middle_attack|man in the
           11  +middle attack].
           12  +
           13  +TLS protects the credentials used to access the server, prevents
           14  +eavesdropping, prevents in-flight data modification, prevents server
           15  +identify spoofing, and more.
           16  +
           17  +There are two major aspects to this, both of which have to be addressed
           18  +in different ways. Those are the subjects of the next two major
           19  +sections.
           20  +
           21  +
           22  +<h2 id="client">Client-Side TLS Configuration</h2>
           23  +
           24  +Fossil itself has built-in support for TLS on the client side only. That
           25  +is to say, you can build it against [https://www.openssl.org/|the
           26  +OpenSSL library], which will allow it to clone and sync with a remote
           27  +Fossil repository via <tt>https</tt> URIs.
           28  +
           29  +The <tt>configure</tt> script will attempt to find OpenSSL on your
           30  +system automatically, but if necessary, you can specify the location
           31  +with the <tt>--with-openssl</tt> option. Type <tt>./configure
           32  +--help</tt> for details.
           33  +
           34  +Even if the Fossil build system does manage to find a workable version
           35  +of OpenSSL, a common situation is that the platform version is outdated
           36  +in some key way, enough so that you do not want to use it with Fossil.
           37  +For example, the platform version of OpenSSL might not support any of
           38  +the [https://en.wikipedia.org/wiki/Cipher_suite|cipher suites] the
           39  +remote Fossil repository's HTTPS proxy is willing to offer, so that even
           40  +though both sides are speaking TLS/SSL, they can't come to an agreement
           41  +on the cryptography.
           42  +In such cases, you may want to link Fossil to a newer version of OpenSSL
           43  +than the one provided with your client operating system. You can do this
           44  +like so:
           45  +
           46  +<pre>
           47  +    cd compat
           48  +    tar xf /path/to/openssl-*.tar.gz
           49  +    ln -fs openssl-x.y.z openssl
           50  +    ./config              # or, e.g. ./Configure darwin64-x86_64-cc
           51  +    make -j11
           52  +    cd ../..
           53  +    ./configure --with-openssl=tree
           54  +    make -j11
           55  +</pre>
           56  +
           57  +That will get you a Fossil binary statically linked to this in-tree
           58  +version of OpenSSL.
           59  +
           60  +
           61  +<h3 id="certs">Certificates</h3>
           62  +
           63  +To verify the identify of a server, TLS uses
           64  +[https://en.wikipedia.org/wiki/X.509#Certificates|X.509 certificates].
           65  +
           66  +If you are using a self-signed certificate, you'll be asked if you want
           67  +to accept the certificate the first time you communicate with the
           68  +server. Verify the certificate fingerprint is correct, then answer
           69  +"always" to remember your decision.
           70  +
           71  +If you are cloning from or syncing to Fossil servers that use a
           72  +certificate signed by a
           73  +[https://en.wikipedia.org/wiki/Certificate_authority|certificate
           74  +authority] (CA), Fossil needs to know which CAs you trust to sign those
           75  +certificates. Fossil relies on the OpenSSL library to have some way to
           76  +check a trusted list of CA signing keys.
           77  +
           78  +There are two common ways this fails:
           79  +
           80  +  #  <p>The OpenSSL library Fossil is linked to doesn't have a CA
           81  +     signing key set at all, so that it initially trusts no certificates
           82  +     at all.</p>
           83  +  #  <p>The OpenSSL library does have a CA cert set, but your Fossil server's
           84  +     TLS certificate was signed by a CA that isn't in that set.</p>
           85  +
           86  +A common reason to fall into the second trap is that you're using
           87  +certificates signed by a local private CA, as often happens in large
           88  +enterprises.  You can solve this sort of problem by getting your local
           89  +CA's signing certificate in PEM format and pointing OpenSSL at it:
           90  +
           91  +<pre>
           92  +     fossil set --global ssl-ca-location /path/to/local-ca.pem
           93  +</pre>
           94  +
           95  +The use of <tt>--global</tt> with this option is common, since you may
           96  +have multiple reposotories served under certificates signed by that same
           97  +CA.
           98  +
           99  +A common way to run into the broader first problem is that you're on
          100  +FreeBSD, which does not install a CA certificate set by default, even as
          101  +a dependency of the OpenSSL library.  If you're using a certificate
          102  +signed by one of the major public CAs, you can solve this by installing
          103  +the <tt>ca_root_nss</tt> package. That package contains the Mozilla NSS
          104  +certificate bundle, which gets installed in a location that OpenSSL
          105  +checks by default, so you don't need to change any Fossil settings.
          106  +(This is the same certificate set that ships with Firefox, by the way.)
          107  +
          108  +The same sort of thing happens with the Windows build of OpenSSL, but
          109  +for a different core reason: Windows does ship with a stock CA
          110  +certificate set, but it's not in a format that OpenSSL understands how
          111  +to use.  Rather than try to find a way to convert the data format, you
          112  +may find it acceptable to use the same Mozilla NSS cert set.  I do not
          113  +know of a way to easily get this from Mozilla themselves, but I did find
          114  +a [https://curl.haxx.se/docs/caextract.html|third party source] for the
          115  +<tt>cacert.pem</tt> file. Install it somewhere on your system, then
          116  +point Fossil at it like so:
          117  +
          118  +<pre>
          119  +     fossil set --global ssl-ca-location /path/to/cacert.pem
          120  +</pre>
          121  +
          122  +Linux platforms tend to provide such a root cert store along with the
          123  +platform OpenSSL package, either built-in or as a hard dependency.
          124  +
          125  +
          126  +<h4>Client-Side Certificates</h4>
          127  +
          128  +You can also use client side certificates to add an extra layer of
          129  +authentication, over and above Fossil's built in user management. If you
          130  +are particularly paranoid, you'll want to use this to remove the ability
          131  +of anyone on the internet from making any request to Fossil. Without
          132  +presenting a valid client side certificate, the web server won't invoke
          133  +the Fossil CGI handler.
          134  +
          135  +Configure your server to request a client side certificate, and set up a
          136  +certificate authority to sign your client certificates. For each person
          137  +who needs to access the repository, create a private key and certificate
          138  +signed with that CA.
          139  +
          140  +The PEM encoded private key and certificate should be stored in a single
          141  +file, simply by concatenating the key and certificate files. Specify the
          142  +location of this file with the <tt>ssl-identity</tt> setting, or the
          143  +<tt>--ssl-identity</tt> option to the <tt>clone</tt> command.
          144  +
          145  +If you've password protected the private key, the password will be
          146  +requested every time you connect to the server. This password is not
          147  +stored by fossil, as doing so would defeat the purpose of having a
          148  +password.
          149  +
          150  +If you attempt to connect to a server which requests a client
          151  +certificate, but don't provide one, fossil will show an error message
          152  +which explains what to do to authenticate with the server.
          153  +
          154  +
          155  +<h2 id="server">Server-Side TLS Configuration</h2>
          156  +
          157  +Fossil's built-in HTTP server feature does not currently have a built-in
          158  +way to serve via HTTP over TLS, a.k.a. HTTPS, even when you've linked
          159  +Fossil to OpenSSL. To serve a Fossil repository via HTTPS, you must put
          160  +it behind some kind of HTTPS proxy.
          161  +
          162  +
          163  +<h3 id="stunnel">stunnel Alone</h3>
          164  +
          165  +Conceptually, the simplest option is to [https://www.stunnel.org/|set up
          166  +stunnel].  A typical configuration is to run Fossil as an HTTP server
          167  +bound to localhost only, then export access to it via HTTPS with stunnel
          168  +encrypting access to Fossil instance hiding behind it.
          169  +
          170  +The difficulty comes in configuring it, which really wants a guide that
          171  +no one has written for us yet. Until that appears, you'll have to read
          172  +the stunnel documentation and that of your TLS certificate provider to
          173  +work out how to set this up.
          174  +
          175  +
          176  +<h3 id="althttpd">stunnel + althttpd</h3>
          177  +
          178  +The public SQLite and Fossil web sites can't just use stunnel + Fossil
          179  +because parts of the web site are static, served by
          180  +[https://www.sqlite.org/docsrc/file/misc/althttpd.c|a separate web
          181  +server called <tt>althttpd</tt>], written by the primary author of both
          182  +SQLite and Fossil. It is a lightweight HTTP-only web server. It handles
          183  +the static HTTP hits on <tt>sqlite.org</tt> and <tt>fossil-scm.org</tt>,
          184  +delegating HTTPS and dynamic Fossil content hits to stunnel and Fossil.
          185  +
          186  +The only documentation for althttpd currently is in its header comment.
          187  +As is typical for drh software, althttpd is a single-file C program, so
          188  +that at worst, you just have to read its code to understand it.
          189  +
          190  +
          191  +<h3 id="nginx">nginx</h3>
          192  +
          193  +If your needs are more complex than althttpd can handle or you'd prefer
          194  +to use only software available in your server operating system's package
          195  +repository, we recommend that you step up to [http://nginx.org/|nginx].
          196  +Setting this up is complex enough that we cover it [./tls-nginx.md|in a
          197  +separate document].
          198  +
          199  +
          200  +<h2 id="enforcing">Enforcing TLS Access</h2>
          201  +
          202  +To use TLS encryption in cloning and syncing to a remote Fossil
          203  +repository, be sure to use the <tt>https:</tt> URI scheme in
          204  +<tt>clone</tt> and <tt>sync</tt> commands.  If your server is configured
          205  +to serve the repository via both HTTP and HTTPS, it's easy to
          206  +accidentally use unencrypted HTTP if you forget the all-important 's'.
          207  +
          208  +There is a setting in the Fossil UI under Admin &rarr; Access called
          209  +"Redirect to HTTPS on the Login page."  This setting is not enabled by
          210  +default.  This setting does not automatically upgrade clones and syncs
          211  +done via the <tt>http</tt> URI scheme.  It only affects web UI access to
          212  +the Fossil repository.
          213  +
          214  +<b id="rloop">WARNING:</b> Never enable this setting when running Fossil
          215  +behind an HTTPS proxy with Fossil running underneath it via HTTP or
          216  +SCGI.  This will cause an infinite redirect loop any time someone tries
          217  +to log into the web UI.  Fossil sees that it's being accessed via HTTP,
          218  +so it redirects the browser to an HTTPS equivalent URL, which causes the
          219  +client to hit the HTTPS front end proxy up again for access, which
          220  +causes Fossil to see that it's being accessed via HTTP, so it redirects
          221  +the client to...'round and 'round it goes until the web browser detects
          222  +it's in a redirect loop and gives up.
     2    223   
     3         -<h2>Using SSL with Fossil</h2>
          224  +If you wish to enforce TLS-only access to a Fossil web server, it is
          225  +best done at the HTTPS front-end proxy layer, not by use of Fossil-level
          226  +settings like this one.  The [./tls-nginx.md|nginx TLS proxy guide]
          227  +shows one way to achieve this, for example.
          228  +
     4    229   
     5         -If you are storing sensitive information in your repository, you should use SSL to encrypt all communications. This will protect the credentials used to access the server, as well preventing eavesdropping of the contents of your repository.
          230  +<h2>Terminology Note</h2>
     6    231   
     7         -To host a repository with SSL, you need to use an web server which supports SSL in front of the Fossil server. You can host it using the CGI option or by proxying Fossil's built in HTTP server.
     8         -
     9         -Your fossil client must be built with SSL support. The <tt>configure</tt> script will attempt to find OpenSSL on your system, but if necessary, you can specify the location with the <tt>--with-openssl</tt> option. Type <tt>./configure --help</tt> for details.
          232  +This document is called <tt>ssl.wiki</tt> for historical reasons. The
          233  +TLS protocol was originally called SSL, and it went through several
          234  +revisions before being replaced by TLS. Years before this writing, SSL
          235  +finally became entirely obsolete due to weaknesses in the protocol fixed
          236  +in the later TLS series of protocols.
    10    237   
    11         -Make sure the URL you clone from uses the <tt>https:</tt> scheme to ensure you're using SSL. If your server is configured to serve the repository from http as well as https, it's easy to accidentally use unencrypted HTTP if you forget the all important 's'.
    12         -
    13         -
    14         -<h2>Certificates</h2>
    15         -
    16         -To verify the identify of a server, SSL uses certificates. Fossil needs to know which certificates you trust.
    17         -
    18         -If you are using a self-signed certificate, you'll be asked if you want to accept the certificate the first time you communicate with the server. Verify the certificate fingerprint is correct, then answer "always" to remember your decision.
          238  +Some people still use the term "SSL" when they actually mean "TLS," but
          239  +in the Fossil project, we always use "TLS" except when we must preserve
          240  +some sort of historical compatibility, as with this document's name in
          241  +order to avoid broken external URLs.  The Fossil TLS-related settings
          242  +also often use "`ssl`" in their names, for the same reason.
    19    243   
    20         -If you are using a certificate signed by a certificate authority, you need to specify the certificates you trust with the <tt>ssl-ca-location</tt> setting. Set this globally with the <tt>-global</tt> option for convenience.
    21         -
    22         -This should be set to the location of a file containing all the PEM encoded certificates you trust. You can obtain a certificate using a web browser, for example, Firefox, or just refer to your system's trusted CA roots which are usually stored somewhere in <tt>/etc</tt>.
    23         -
    24         -
    25         -<h2>Client side certificates</h2>
    26         -
    27         -You can also use client side certificates to add an extra layer of authentication, over and above Fossil's built in user management. If you are particularly paranoid, you'll want to use this to remove the ability of anyone on the internet from making any request to Fossil. Without presenting a valid client side certificate, the web server won't invoke the fossil CGI handler.
    28         -
    29         -Configure your server to request a client side certificate, and set up a certificate authority to sign your client certificates. For each person who needs to access the repository, create a private key and certificate signed with that CA.
    30         -
    31         -The PEM encoded private key and certificate should be stored in a single file, simply by concatenating the key and certificate files. Specify the location of this file with the <tt>ssl-identity</tt> setting, or the <tt>--ssl-identity</tt> option to the <tt>clone</tt> command.
    32         -
    33         -If you've password protected the private key, the password will be requested every time you connect to the server. This password is not stored by fossil, as doing so would defeat the purpose of having a password.
    34         -
    35         -If you attempt to connect to a server which requests a client certificate, but don't provide one, fossil will show an error message which explains what to do to authenticate with the server.
    36         -
          244  +This series of protocols is also called "HTTPS" after the URI scheme
          245  +used to specify "HTTP over TLS."

Added www/tls-nginx.md.

            1  +# Proxying Fossil via HTTPS with nginx
            2  +
            3  +One of the [many ways](./ssl.wiki) to provide TLS-encrypted HTTP access
            4  +(a.k.a. HTTPS) to Fossil is to run it behind a web proxy that supports
            5  +TLS. This document explains how to use the powerful [nginx web
            6  +server](http://nginx.org/) to do that.
            7  +
            8  +
            9  +## Benefits
           10  +
           11  +This scheme is complicated, even with the benefit of this guide and
           12  +pre-built binary packages. Why should you put up with this complexity?
           13  +Because it gives many benefits that are difficult or impossible to get
           14  +with the less complicated options:
           15  +
           16  +*   **Power** — nginx is one of the most powerful web servers in the
           17  +    world. The chance that you will run into a web serving wall that you
           18  +    can’t scale with nginx is very low.
           19  +
           20  +    To give you some idea of the sort of thing you can readily
           21  +    accomplish with nginx, your author runs a single public web server
           22  +    that provides transparent name-based virtual hosting for four
           23  +    separate domains:
           24  +
           25  +    *   One is entirely static, not involving any dynamic content or
           26  +        Fossil integration at all.
           27  +
           28  +    *   Another is served almost entirely by Fossil, with a few select
           29  +        static content exceptions punched past Fossil, which are handled
           30  +        entirely via nginx.
           31  +
           32  +    *   The other two domains are aliases for one another — e.g.
           33  +        `example.com` and `example.net` — with most of the content being
           34  +        static.  This pair of domains has three different Fossil repo
           35  +        proxies attached to various sections of the URI hierarchy.
           36  +
           37  +    All of this is done with minimal configuration repetition between
           38  +    the site configurations.
           39  +
           40  +*   **Integration** — Because nginx is so popular, it integrates with
           41  +many different technologies, and many other systems integrate with it in
           42  +turn.  This makes it great middleware, sitting between the outer web
           43  +world and interior site services like Fossil. It allows Fossil to
           44  +participate seamlessly as part of a larger web stack.
           45  +
           46  +*   **Availability** — nginx is already in most operating system binary
           47  +package repositories, so you don’t need to go out of your way to get it.
           48  +
           49  +
           50  +## Fossil Remote Access Methods
           51  +
           52  +Fossil provides four major ways to access a repository it’s serving
           53  +remotely, three of which you can use with nginx:
           54  +
           55  +*   **HTTP** — Fossil has a built-in HTTP server: `fossil server`.
           56  +    While this method is efficient and it’s possible to use nginx to
           57  +    proxy access to another HTTP server, this option is overkill for our
           58  +    purposes.  nginx is itself a fully featured HTTP server, so we will
           59  +    choose in this guide not to make nginx reinterpret Fossil’s
           60  +    implementation of HTTP.
           61  +
           62  +*   **CGI** — This method is simple but inefficient, because it launches
           63  +    a separate Fossil instance on every HTTP hit.
           64  +    
           65  +    Since Fossil is a relatively small self-contained program, and it’s
           66  +    designed to start up quickly, this method can work well in a
           67  +    surprisingly large number of cases.
           68  +
           69  +    Nevertheless, we will avoid this option in this document because
           70  +    we’re already buying into a certain amount of complexity here in
           71  +    order to gain power.  There’s no sense in throwing away any of that
           72  +    hard-won performance on CGI overhead.
           73  +
           74  +*   **SCGI** — The [SCGI protocol][scgi] provides the simplicity of CGI
           75  +    without its performance problems.
           76  +
           77  +*   **SSH** — This method exists primarily to avoid the need for HTTPS
           78  +    in the first place.  There is probably a way to get nginx to proxy
           79  +    Fossil to HTTPS via SSH, but it would be pointlessly complicated.
           80  +
           81  +SCGI it is, then.
           82  +
           83  +
           84  +# Installing
           85  +
           86  +The first step is to install the pieces we’ll be working with.  This
           87  +varies on different operating systems, so to avoid overcomplicating this
           88  +guide, we’re going to assume you’re using Ubuntu Server 18.04 LTS, a
           89  +common Tier 1 offering for [virtual private servers][vps].
           90  +
           91  +SSH into your server, then say:
           92  +
           93  +       $ sudo apt install certbot fossil nginx
           94  +
           95  +For other operating systems, simply visit [the front Certbot web
           96  +page][cb] and tell it what OS and web stack you’re using. Chances are
           97  +good that they’ve got a good guide for you already.
           98  +
           99  +
          100  +# Running Fossil in SCGI Mode
          101  +
          102  +You presumably already have a working Fossil configuration on the public
          103  +server you’re trying to set up and are just following this guide to
          104  +replace HTTP service with HTTPS.
          105  +
          106  +(You can adjust the advice in this guide to get both HTTP *and* HTTPS
          107  +service on the same site, but I strongly recommend that you do not do
          108  +that: the good excuses remaining for continuing to allow HTTP on public
          109  +web servers are running thin these days.)
          110  +
          111  +I run my Fossil SCGI server instances with a variant of [the `fslsrv`
          112  +shell script](/file/tools/fslsrv) currently hosted in the Fossil source
          113  +code repository. You’ll want to download that and make a copy of it, so
          114  +you can customize it to your particular needs.
          115  +
          116  +This script allows running multiple Fossil SCGI servers, one per
          117  +repository, each bound to a different high-numbered `localhost` port, so
          118  +that only nginx can see and proxy them out to the public.  The
          119  +“`example`” repo is on TCP port localhost:12345, and the “`foo`” repo is
          120  +on localhost:12346.
          121  +
          122  +As written, the `fslsrv` script expects repositories to be stored in the
          123  +calling user’s home directory under `~/museum`, because where else do
          124  +you keep Fossils?
          125  +
          126  +That home directory also needs to have a directory to hold log files,
          127  +`~/log/fossil/*.log`. Fossil doesn’t put out much logging, but when it
          128  +does, it’s better to have it captured than to need to re-create the
          129  +problem after the fact.
          130  +
          131  +The use of `--baseurl` in this script lets us have each Fossil
          132  +repository mounted in a different location in the URL scheme.  Here, for
          133  +example, we’re saying that the “`example`” repository is hosted under
          134  +the `/code` URI on its domains, but that the “`foo`” repo is hosted at
          135  +the top level of its domain.  You’ll want to do something like the
          136  +former for a Fossil repo that’s just one piece of a larger site, but the
          137  +latter for a repo that is basically the whole point of the site.
          138  +
          139  +This script’s automatic restart feature makes Fossil upgrades easy:
          140  +
          141  +       $ cd ~/src/fossil/trunk ; fossil up ; make ; killall fossil ;
          142  +         sudo make install ; fslsrv
          143  +
          144  +I’ve written that as a single long command because I keep it in the
          145  +history for my Fossil servers, so I can just run it again from history.
          146  +You could put it in a shell script instead.
          147  +
          148  +The `killall fossil` step is needed only on OSes that refuse to let you
          149  +replace a running binary on disk.
          150  +
          151  +As written, the `fslsrv` script assumes a Linux environment.  It expects
          152  +`/bin/bash` to exist, and it depends on non-POSIX tools like `pgrep`.
          153  +It shouldn’t be difficult to port to very different systems, like macOS
          154  +or the BSDs.
          155  +
          156  +
          157  +# Configuring Let’s Encrypt, the Easy Way
          158  +
          159  +If your web serving needs are simple, [Certbot][cb] can configure nginx
          160  +for you and keep its certificates up to date.  The details are pretty
          161  +much as in the Certbot documentation for [nginx on Ubuntu 18.04 LTS
          162  +guide][cbnu], except that where they recommend that you use the
          163  +first-party Certbot packages, we’ve found that the ones that come with
          164  +Ubuntu work just fine.
          165  +
          166  +The primary local configuration you need is to tell nginx how to proxy
          167  +certain URLs down to the Fossil instance you started above with the
          168  +`fslsrv` script:
          169  +
          170  +      location / {
          171  +           include scgi_params;
          172  +           scgi_pass 127.0.0.1:12345;
          173  +           scgi_param HTTPS "on";
          174  +           scgi_param SCRIPT_NAME "";
          175  +      }
          176  +
          177  +The TCP port number in that snippet is the key: it has to match the port
          178  +number generated by `fslsrv` from the base port number passed to the
          179  +`start_one` function.
          180  +
          181  +
          182  +# Configuring Let’s Encrypt, the Hard Way
          183  +
          184  +If you’re finding that you can’t get certificates to be issued or
          185  +renewed using the Easy Way instructions, the problem is usually that
          186  +your nginx configuration is too complicated for Certbot’s `--nginx`
          187  +plugin to understand. It attempts to rewrite your nginx configuration
          188  +files on the fly to achieve the renewal, and if it doesn’t put its
          189  +directives in the right locations, the ACME verification steps can fail.
          190  +
          191  +Your author’s configuration, glossed above, is complicated enough that
          192  +the current version of Certbot (0.28 at the time of this writing) can’t
          193  +cope with it.  That’s the primary motivation for me to write this guide:
          194  +I’m addressing the “me” years hence who needs to upgrade to Ubuntu 20.04
          195  +or 22.04 LTS and has forgotten all of this stuff. 😉
          196  +
          197  +
          198  +## Step 1: Shifting into Manual
          199  +
          200  +The first thing to do is to turn off all of the Certbot automation,
          201  +because it’ll only get in our way.  First, disable the Certbot package’s
          202  +automatic background updater:
          203  +
          204  +      $ sudo systemctl disable certbot.timer
          205  +
          206  +Next, edit `/etc/letsencrypt/renewal/example.com.conf` to disable the
          207  +nginx plugins. You’re looking for two lines setting the “install” and
          208  +“auth” plugins to “nginx”.  You can comment them out or remove them
          209  +entirely.
          210  +
          211  +
          212  +## Step 2: Configuring nginx
          213  +
          214  +On Ubuntu systems, at least, the primary user-level configuration file
          215  +is `/etc/nginx/sites-enabled/default`. For a configuration like I
          216  +described at the top of this article, I recommend that this file contain
          217  +only a list of include statements, one for each site that server hosts:
          218  +
          219  +      include local/example
          220  +      include local/foo
          221  +
          222  +Those files then each define one domain’s configuration.  Here,
          223  +`/etc/nginx/local/example` contains the configuration for
          224  +`*.example.com` and `*.example.net`; and `local/foo` contains the
          225  +configuration for `*.foo.net`.
          226  +
          227  +Here’s an example configuration:
          228  +
          229  +      server {
          230  +          server_name .foo.net;
          231  +      
          232  +          include local/tls-common;
          233  +      
          234  +          charset utf-8;
          235  +      
          236  +          access_log /var/log/nginx/foo.net-https-access.log;
          237  +           error_log /var/log/nginx/foo.net-https-error.log;
          238  +      
          239  +          # Bypass Fossil for the static Doxygen docs
          240  +          location /doc/html {
          241  +              root /var/www/foo.net;
          242  +      
          243  +              location ~* \.(html|ico|css|js|gif|jpg|png)$ {
          244  +                  expires 7d;
          245  +                  add_header Vary Accept-Encoding;
          246  +                  access_log off;
          247  +              }
          248  +          }
          249  +      
          250  +          # Redirect everything else to the Fossil instance
          251  +          location / {
          252  +              include scgi_params;
          253  +              scgi_pass 127.0.0.1:12345;
          254  +              scgi_param HTTPS "on";
          255  +              scgi_param SCRIPT_NAME "";
          256  +          }
          257  +      }
          258  +      server {
          259  +          server_name .foo.net;
          260  +          root /var/www/foo.net;
          261  +          include local/http-certbot-only;
          262  +          access_log /var/log/nginx/foo.net-http-access.log;
          263  +           error_log /var/log/nginx/foo.net-http-error.log;
          264  +      }
          265  +
          266  +Notice that we need two `server { }` blocks: one for HTTPS service, and
          267  +one for HTTP-only service:
          268  +
          269  +
          270  +### HTTP over TLS (HTTPS) Service
          271  +
          272  +The first `server { }` block includes this file, `local/tls-common`:
          273  +
          274  +      listen 443 ssl;
          275  +
          276  +      ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
          277  +      ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
          278  +
          279  +      ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
          280  +
          281  +      ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          282  +      ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SH
          283  +      ssl_session_cache shared:le_nginx_SSL:1m;
          284  +      ssl_prefer_server_ciphers on;
          285  +      ssl_session_timeout 1440m;
          286  +
          287  +These are the common TLS configuration parameters used by all domains
          288  +hosted by this server. Since all of those domains share a single TLS
          289  +certificate, we reference the same `example.com/*.pem` files written out
          290  +by Certbot here. We also reference the common server-specific
          291  +Diffie-Hellman parameter file written by the Let’s Encrypt package when
          292  +it’s initially installed.
          293  +
          294  +The `ssl_protocols` and `ssl_ciphers` lines are prone to bit-rot: as new
          295  +attacks on TLS and its associated technologies are discovered, this
          296  +configuration is likely to need to change. Even if we fully succeed in
          297  +[keeping this document up-to-date](#evolution), the nature of this guide
          298  +is to recommend static configurations for your server. You will have to
          299  +keep an eye on this sort of thing and evolve your local configuration as
          300  +the world changes around it.
          301  +
          302  +Running a TLS certificate checker against your site occasionally is a
          303  +good idea. The most thorough service I’m aware of is the [Qualys SSL
          304  +Labs Test][qslt], which gives the site I’m basing this guide on an “A”
          305  +rating at the time of this writing.
          306  +
          307  +I assume you’re taking my advice to serve only the least amount of stuff
          308  +over HTTP that you can get away with. Certbot’s ACME HTTP-01
          309  +authentication scheme is one of those few things.
          310  +
          311  +
          312  +### HTTP-Only Service
          313  +
          314  +While we’d prefer not to offer HTTP service at all, we need to do so for
          315  +two reasons, one temporary and the other going forward indefinitely.
          316  +
          317  +First, until we get Let’s Encrypt certificates minted and configured
          318  +properly, we can’t use HTTPS yet at all.
          319  +
          320  +Second, the Certbot ACME HTTP-01 challenge used by the Let’s Encrypt
          321  +service only runs over HTTP, because it has to work before HTTPS is
          322  +working, or after a certificate is accidentally allowed to lapse.  This
          323  +is the protocol Let’s Encrypt uses to determine whether we actually have
          324  +control over the domains we want our certificate to be minted for.
          325  +Let’s Encrypt will not just let you mint certificates for `google.com`
          326  +and `paypal.com`!
          327  +
          328  +So, from the second `service { }` block, we include this file to set up
          329  +the minimal HTTP service we reqiure, `local/http-certbot-only`:
          330  +
          331  +      listen 80;
          332  +      listen [::]:80;
          333  +  
          334  +      # This is expressed as a rewrite rule instead of an "if" because
          335  +      # http://wiki.nginx.org/IfIsEvil
          336  +      #rewrite ^(/.well-known/acme-challenge/.*) $1 break;
          337  +  
          338  +      # Force everything else to HTTPS with a permanent redirect.
          339  +      #return 301 https://$host$request_uri;
          340  +
          341  +As written above, this configuration does nothing other than to tell
          342  +nginx that it’s allowed to serve content via HTTP on port 80 as well.
          343  +
          344  +We’ll uncomment the `rewrite` and `return` directives below, when we’re
          345  +ready to begin testing.
          346  +
          347  +
          348  +#### Why the Repitition?
          349  +
          350  +You need to do much the same sort of thing as above for each domain name
          351  +hosted by your nginx server.
          352  +
          353  +You might being to wonder, then, why I haven’t factored some of those
          354  +directives into the included files `local/tls-common` and
          355  +`local/http-certbot-only`. For example, why can’t the second HTTP-only
          356  +`server { }` block above just be these two lines:
          357  +
          358  +      server_name .foo.net;
          359  +      include local/http-certbot-only;
          360  +
          361  +Then in `local/http-certbot-only`, we’d like to say:
          362  +
          363  +      root /var/www/$host;
          364  +      access_log /var/log/nginx/$host-http-access.log;
          365  +       error_log /var/log/nginx/$host-http-error.log;
          366  +
          367  +Sadly, nginx doesn’t allow variable subtitution into any of these
          368  +directives. As I understand it, allowing that would make nginx slower,
          369  +so we must largely repeat these directives in each HTTP `server { }`
          370  +block.
          371  +
          372  +These configurations are, as shown, as small as I know how to get them.
          373  +If you know of a way to reduce some of this repitition, [I solicit your
          374  +advice][fd].
          375  +
          376  +
          377  +## Step 3: Dry Run
          378  +
          379  +We want to first request a dry run, because Let’s Encrypt puts some
          380  +rather low limits on how often you’re allowed to request an actual
          381  +certificate.  You want to be sure everything’s working before you do
          382  +that.  You’ll run a command something like this:
          383  +
          384  +      $ sudo certbot certonly --webroot --dry-run \
          385  +         --webroot-path /var/www/example.com \
          386  +             -d example.com -d www.example.com \
          387  +             -d example.net -d www.example.net \
          388  +         --webroot-path /var/www/foo.net \
          389  +             -d foo.net -d www.foo.net
          390  +
          391  +There are two key options here.
          392  +
          393  +First, we’re telling Certbot to use its `--webroot` plugin instead of
          394  +the automated `--nginx` plugin. With this plugin, Certbot writes the
          395  +ACME HTTP-01 challenge files to the static web document root directory
          396  +behind each domain.  For this example, we’ve got two web roots, one of
          397  +which holds documents for two different second-level domains
          398  +(`example.com` and `example.net`) with `www` at the third level being
          399  +optional.  This is a common sort of configuration these days, but you
          400  +needn’t feel that you must slavishly imitate it; the other web root is
          401  +for an entirely different domain, also with `www` being optional.  Since
          402  +all of these domains are served by a single nginx instance, we need to
          403  +give all of this in a single command, because we want to mint a single
          404  +certificate that authenticates all of these domains.
          405  +
          406  +The second key option is `--dry-run`, which tells Certbot not to do
          407  +anything permanent.  We’re just seeing if everything works as expected,
          408  +at this point.
          409  +
          410  +
          411  +### Troubleshooting the Dry Run
          412  +
          413  +If that didn’t work, try creating a manual test:
          414  +
          415  +      $ mkdir -p /var/www/example.com/.well-known/acme-challenge
          416  +      $ echo hi > /var/www/example.com/.well-known/acme-challenge/test
          417  +
          418  +Then try to pull that file over HTTP — not HTTPS! — as
          419  +`http://example.com/.well-known/acme-challenge/test`. I’ve found that
          420  +using Firefox and Safari is better for this sort of thing than Chrome,
          421  +because Chrome is more aggressive about automatically forwarding URLs to
          422  +HTTPS even if you requested “`http`”.
          423  +
          424  +In extremis, you can do the test manually:
          425  +
          426  +      $ telnet foo.net 80
          427  +      GET /.well-known/acme-challenge/test HTTP/1.1
          428  +      Host: example.com
          429  +
          430  +      HTTP/1.1 200 OK
          431  +      Server: nginx/1.14.0 (Ubuntu)
          432  +      Date: Sat, 19 Jan 2019 19:43:58 GMT
          433  +      Content-Type: application/octet-stream
          434  +      Content-Length: 3
          435  +      Last-Modified: Sat, 19 Jan 2019 18:21:54 GMT
          436  +      Connection: keep-alive
          437  +      ETag: "5c436ac2-4"
          438  +      Accept-Ranges: bytes
          439  +
          440  +      hi
          441  +
          442  +You’re looking for that “hi” line at the end and the “200 OK” response
          443  +here. If you get a 404 or other error response, you need to look into
          444  +your web server logs to find out what’s going wrong.
          445  +
          446  +Note that it’s important to do this test with HTTP/1.1 when debugging a
          447  +name-based virtual hosting configuration like this, if the test domain
          448  +is one of the secondary names, as in the example above, `foo.net`.
          449  +
          450  +If you’re still running into trouble, the log file written by Certbot
          451  +can be helpful.  It tells you where it’s writing it early in each run.
          452  +
          453  +
          454  +
          455  +## Step 4: Getting Your First Certificate
          456  +
          457  +Once the dry run is working, you can drop the `--dry-run` option and
          458  +re-run the long command above.  (The one with all the `--webroot*`
          459  +flags.) This should now succeed, and it will save all of those flag
          460  +values to your Let’s Encrypt configuration file, so you don’t need to
          461  +keep giving them.
          462  +
          463  +
          464  +
          465  +## Step 5: Test It
          466  +
          467  +Edit the `local/http-certbot-only` file and uncomment the `redirect` and
          468  +`return` directives, then restart your nginx server and make sure it now
          469  +forces everything to HTTPS like it should:
          470  +
          471  +      $ sudo systemctl restart nginx
          472  +
          473  +Test ideas:
          474  +
          475  +*   Visit both Fossil and non-Fossil URLs
          476  +
          477  +*   Log into the repo, log out, and log back in
          478  +
          479  +*   Clone via `http`: ensure that it redirects to `https`, and that
          480  +    subsequent `fossil sync` commands go directly to `https` due to the
          481  +    301 permanent redirect.
          482  +
          483  +This forced redirect is why we don’t need the Fossil Admin &rarr; Access
          484  +"Redirect to HTTPS on the Login page" setting to be enabled.  Not only
          485  +is it unnecessary with this HTTPS redirect at the front-end proxy level,
          486  +it would actually [cause an infinite redirect loop if
          487  +enabled](./ssl.wiki#rloop).
          488  +
          489  +
          490  +## Step 6: Renewing Automatically
          491  +
          492  +Now that the configuration is solid, you can renew the LE cert and
          493  +restart nginx with two short commands, which are easily automated:
          494  +
          495  +      sudo certbot certonly --webroot
          496  +      sudo systemctl restart nginx
          497  +
          498  +I put those in a script in the `PATH`, then arrange to call that
          499  +periodically.  Let’s Encrypt doesn’t let you renew the certificate very
          500  +often unless forced, and when forced there’s a maximum renewal counter.
          501  +Nevertheless, some people recommend running this daily and just letting
          502  +it fail until the server lets you renew.  Others arrange to run it no
          503  +more often than it’s known to work without complaint.  Suit yourself.
          504  +
          505  +
          506  +-----------
          507  +
          508  +<a id=”evolution”></a>
          509  +**Document Evolution**
          510  +
          511  +TLS and web proxying are a constantly evolving technology. This article
          512  +replaces my [earlier effort][2016], which had whole sections that were
          513  +basically obsolete within about a year of posting it. Two years on, and
          514  +I was encouraging readers to ignore about half of that HOWTO.  I am now
          515  +writing this document about 3 years later because Let’s Encrypt
          516  +deprecated key technology that HOWTO depended on, to the point that
          517  +following that old HOWTO is more likely to confuse than enlighten.
          518  +
          519  +There is no particularly good reason to expect that this sort of thing
          520  +will not continue to happen, so this effort is expected to be a living
          521  +document.  If you do not have commit access on the `fossil-scm.org`
          522  +repository to update this document as the world changes around it, you
          523  +can discuss this document [on the forum][fd].  This document’s author
          524  +keeps an eye on the forum and expects to keep this document updated with
          525  +ideas that appear in that thread.
          526  +
          527  +[2016]: https://www.mail-archive.com/fossil-users@lists.fossil-scm.org/msg22907.html
          528  +[cb]:   https://certbot.eff.org/
          529  +[cbnu]: https://certbot.eff.org/lets-encrypt/ubuntubionic-nginx
          530  +[fd]:   https://fossil-scm.org/forum/forumpost/ae6a4ee157
          531  +[qslt]: https://www.ssllabs.com/ssltest/
          532  +[scgi]: https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface
          533  +[vps]:  https://en.wikipedia.org/wiki/Virtual_private_server