Fossil

Check-in [8ce8828d0c]
Login

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

Overview
Comment:OpenBSD server docs: Add instructions to make fossil.log owned by 'www' user, and repository directory group writeable; remove unnecessary 'directory index' option in httpd.conf; and fix redundant double backticks.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 8ce8828d0c1d38d518c6857267023040c63853a5bcd958c48073aceb633058ae
User & Date: jamsek 2020-06-27 12:45:32
Context
2020-06-27
14:48
Add the obscure() shell function. Corresponding unobscure() is not provided. (check-in: f7e572b040 user: drh tags: trunk)
12:45
OpenBSD server docs: Add instructions to make fossil.log owned by 'www' user, and repository directory group writeable; remove unnecessary 'directory index' option in httpd.conf; and fix redundant double backticks. (check-in: 8ce8828d0c user: jamsek tags: trunk)
10:48
Attempt to fix broken link on the documentation index. (check-in: 02a7c72bf9 user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to www/server/openbsd/httpd.md.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

56
57
58
59
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
185
186
187
188
189
190
191

192
193
194

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
...
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282

[`httpd`][httpd] is the default web server that is included in the base
install on OpenBSD. It's minimal and lightweight but secure and capable,
and provides a clean interface for setting up a Fossil server using
FastCGI.

This article will detail the steps required to setup a TLS-enabled
``httpd`` configuration that serves multiple Fossil repositories out of
a single directory within a chroot, and allow ``ssh`` access to create
new repositories remotely.

**NOTE:** The following instructions assume an OpenBSD 6.7 installation.

[httpd]: https://www.openbsd.org/papers/httpd-asiabsdcon2015.pdf

## <a name="fslinstall"></a>Install Fossil

Use the OpenBSD package manager ``pkg_add`` to install Fossil, making
sure to select the statically linked binary.

```console
    $ doas pkg_add fossil
    quirks-3.325 signed on 2020-06-12T06:24:53Z
    Ambiguous: choose package for fossil
          0: <None>
          1: fossil-2.10v0
          2: fossil-2.10v0-static
    Your choice: 2
    fossil-2.10v0-static: ok
```

This installs Fossil into the chroot. To facilitate local use, create a
symbolic link of the fossil executable into ``/usr/local/bin``.

```console
    $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil
```

As a privileged user, create the file ``/var/www/cgi-bin/scm`` with the
following contents to make the CGI script that ``httpd`` will execute in
response to ``fsl.domain.tld`` requests; all paths are relative to the
``/var/www`` chroot.

```sh
    #!/bin/fossil
    directory: /htdocs/fsl.domain.tld
    notfound: https://domain.tld
    repolist
    errorlog: /logs/fossil.log
```

The ``directory`` directive instructs Fossil to serve all repositories
found in ``/var/www/htdocs/fsl.domain.tld``, while ``errorlog`` sets
logging to be saved to ``/var/www/logs/fossil.log``; create the

repository directory and log file, and make the script executable.

```console
    $ doas mkdir /var/www/htdocs/fsl.domain.tld
    $ doas touch /var/www/logs/fossil.log

    $ doas chmod 755 /var/www/cgi-bin/scm
```

## <a name="chroot"></a>Setup chroot

Fossil needs both ``/dev/random`` and ``/dev/null``, which aren't
accessible from within the chroot, so need to be constructed; ``/var``,
however, is mounted with the ``nodev`` option. Rather than removing
this default setting, create a small memory filesystem with
[`mount_mfs(8)`][mfs] upon which ``/var/www/dev`` will be mounted so
that the ``random`` and ``null`` device files can be created.

```console
    $ doas mkdir /var/www/dev
    $ doas mount_mfs -s 1M /dev/sd0b /var/www/dev
    $ doas cd /var/www/dev
    $ doas /dev/MAKEDEV urandom
    $ doas mknod -m 666 null c 2 2
................................................................................
    crw-rw-rw-  1 root  daemon    2,   2 Jun 20 08:56 null
    lrwxr-xr-x  1 root  daemon         7 Jun 18 06:30 random@ -> urandom
    crw-r--r--  1 root  wheel    45,   0 Jun 18 06:30 urandom
```

[mfs]: https://man.openbsd.org/mount_mfs.8

To make the mountable memory filesystem permanent, open ``/etc/fstab``
as a privileged user and add the following line to automate creation of
the filesystem at startup:

```console
    swap /var/www/dev mfs rw,-s=1048576 0 0
```

The same user that executes the fossil binary must have writable access
to the repository directory that resides within the chroot; on OpenBSD
this is ``www``. In addition, grant repository directory ownership to
the user who will push to, pull from, and create repositories.

```console
   $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld

```

## <a name="httpdconfig"></a>Configure httpd

On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for
``httpd``. To setup the server to serve all Fossil repositores within
the directory specified in the CGI script, and automatically redirect
standard HTTP requests to HTTPS—apart from [Let's Encrypt][LE]
challenges issued in response to [acme-client(1)][acme] certificate
requests—create ``/etc/httpd.conf`` as a privileged user with the
following contents.

[LE]: https://letsencrypt.org
[acme]: https://man.openbsd.org/acme-client.1
[httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5

```apache
................................................................................
            }
            hsts {
                    max-age 15768000
                    preload
                    subdomains
            }
            connection max request body 104857600
            directory index "index.cgi"
            location  "/*" {
                    fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" }
            }
            location "/.well-known/acme-challenge/*" {
                    root "/acme"
                    request strip 2
            }
    }
```

**NOTE:** If not already in possession of a HTTPS certificate, comment
out the ``https`` server block and proceed to securing a free
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
[Start httpd](#starthttpd).

## <a name="letsencrypt"></a>Let's Encrypt Certificate

In order for ``httpd`` to serve HTTPS, secure a free certificate from
Let's Encrypt using ``acme-client``. Before issuing the
request, however, ensure you have a zone record for the subdomain with
your registrar or nameserver. Then open ``/etc/acme-client.conf`` as a
privileged user to configure the request.

```dosini
    authority letsencrypt {
            api url "https://acme-v02.api.letsencrypt.org/directory"
            account key "/etc/acme/letsencrypt-privkey.pem"
    }

................................................................................
            domain key "/etc/ssl/private/domain.tld.key"
            domain certificate "/etc/ssl/domain.tld.crt"
            domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem"
            sign with letsencrypt
    }
```


Issue the certificate request.

```console

    $ doas acme-client -vv domain.tld
    acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating)
    acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key
    acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key
    acme-client: https://acme-v01.api.letsencrypt.org/directory: directories
    acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248
    ...
    N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes)
    acme-client: /etc/ssl/domain.tld.crt: created
    acme-client: /etc/ssl/domain.tld.fullchain.pem: created
```

A successful result will output the public certificate, full chain of
trust, and private key into the ``/etc/ssl`` directory as specified in
``acme-client.conf``.

```console
   $ doas ls -lR /etc/ssl
   -r--r--r--   1 root  wheel   2.3K Mar  2 01:31:03 2018 domain.tld.crt
   -r--r--r--   1 root  wheel   3.9K Mar  2 01:31:03 2018 domain.tld.fullchain.pem

   /etc/ssl/private:
   -r--------  1 root  wheel   3.2K Mar  2 01:31:03 2018 domain.tld.key
```

Make sure to reopen ``/etc/httpd.conf`` to uncomment the second server
block responsible for serving HTTPS requests before proceeding.

## <a name="starthttpd"></a>Start httpd

With ``httpd`` configured to serve Fossil repositories out of
``/var/www/htdocs/fsl.domain.tld``, and the certificates and key in
place, enable and start ``slowcgi``—OpenBSD's FastCGI wrapper server
that will execute the above Fossil CGI script—before checking the syntax
of the ``httpd.conf`` configuration file is correct, and starting the
server.

```console
    $ doas rcctl enable slowcgi
    $ doas rcctl start slowcgi
    slowcgi(ok)
    $ doas httpd -vnf /etc/httpd.conf
    configuration OK
................................................................................
    $ doas rcctl start httpd
    httpd(ok)
```

## <a name="clientconfig"></a>Configure Client

To facilitate creating new repositories and pushing them to the server,
add the following function to your ``~/.cshrc`` or ``~/.zprofile`` or
the config file for whichever shell you are using on your development
box.

```sh
    finit() {
            fossil init $1.fossil && \
            chmod 664 $1.fossil && \
            fossil open $1.fossil && \
            fossil user password $USER $PASSWD && \
................................................................................
            fossil remote-url https://$USER:$PASSWD@fsl.domain.tld/$1 && \
            rsync --perms $1.fossil $USER@fsl.domain.tld:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \
            chmod 644 $1.fossil && \
            fossil ui
    }
```

This enables a new repository to be made with ``finit repo``, which will
create the fossil repository file ``repo.fossil`` in the current working
directory; by default, the repository user is set to the environment
variable ``$USER``. It then opens the repository and sets the user
password to the ``$PASSWD`` environment variable (which you can either
set with ``export PASSWD 'password'`` on the command line or add to a
*secured* shell environment file), and the ``remote-url`` to
https://fsl.domain.tld/repo with the credentials of ``$USER`` who is
authenticated with ``$PASSWD``. Finally, it ``rsync``'s the file to the
server before opening the local repository in your browser where you
can adjust settings such as anonymous user access, and set pertinent
repository details. Thereafter, you can add files with ``fossil add``,
and commit with ``fossil ci -m 'commit message'`` where Fossil, by
default, will push to the ``remote-url``. It's suggested you read
the [Fossil documentation][documentation]; with a sane and consistent
development model, the system is much more efficient and cohesive than
``git``—so the learning curve is not steep at all.

[documentation]: https://fossil-scm.org/home/doc/trunk/www/permutedindex.html

*[Return to the top-level Fossil server article.](../)*







|
|








|
|













|





|
|
|
|









|
|
|
>
|




>





|
|
|
|
|
|







 







|
|
|







|
|



>





|
|


|







 







<











|

|



|
|
|
|
|







 







>
|


>













|
|










|


|

|
|
|
|
|
|







 







|
|
<







 







|
|

|
|
|
|
|
|
|
|
|
|
|
|

|




2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
144
145
146
147
148
149
150

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
242
243
244
245
246
247
248
249
250

251
252
253
254
255
256
257
...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285

[`httpd`][httpd] is the default web server that is included in the base
install on OpenBSD. It's minimal and lightweight but secure and capable,
and provides a clean interface for setting up a Fossil server using
FastCGI.

This article will detail the steps required to setup a TLS-enabled
`httpd` configuration that serves multiple Fossil repositories out of
a single directory within a chroot, and allow `ssh` access to create
new repositories remotely.

**NOTE:** The following instructions assume an OpenBSD 6.7 installation.

[httpd]: https://www.openbsd.org/papers/httpd-asiabsdcon2015.pdf

## <a name="fslinstall"></a>Install Fossil

Use the OpenBSD package manager `pkg_add` to install Fossil, making sure
to select the statically linked binary.

```console
    $ doas pkg_add fossil
    quirks-3.325 signed on 2020-06-12T06:24:53Z
    Ambiguous: choose package for fossil
          0: <None>
          1: fossil-2.10v0
          2: fossil-2.10v0-static
    Your choice: 2
    fossil-2.10v0-static: ok
```

This installs Fossil into the chroot. To facilitate local use, create a
symbolic link of the fossil executable into `/usr/local/bin`.

```console
    $ doas ln -s /var/www/bin/fossil /usr/local/bin/fossil
```

As a privileged user, create the file `/var/www/cgi-bin/scm` with the
following contents to make the CGI script that `httpd` will execute in
response to `fsl.domain.tld` requests; all paths are relative to the
`/var/www` chroot.

```sh
    #!/bin/fossil
    directory: /htdocs/fsl.domain.tld
    notfound: https://domain.tld
    repolist
    errorlog: /logs/fossil.log
```

The `directory` directive instructs Fossil to serve all repositories
found in `/var/www/htdocs/fsl.domain.tld`, while `errorlog` sets logging
to be saved to `/var/www/logs/fossil.log`; create the repository
directory and log file—making the latter owned by the `www` user, and
the script executable.

```console
    $ doas mkdir /var/www/htdocs/fsl.domain.tld
    $ doas touch /var/www/logs/fossil.log
    $ doas chown www /var/www/logs/fossil.log
    $ doas chmod 755 /var/www/cgi-bin/scm
```

## <a name="chroot"></a>Setup chroot

Fossil needs both `/dev/random` and `/dev/null`, which aren't accessible
from within the chroot, so need to be constructed; `/var`, however, is
mounted with the `nodev` option. Rather than removing this default
setting, create a small memory filesystem with [`mount_mfs(8)`][mfs]
upon which `/var/www/dev` will be mounted so that the `random` and
`null` device files can be created.

```console
    $ doas mkdir /var/www/dev
    $ doas mount_mfs -s 1M /dev/sd0b /var/www/dev
    $ doas cd /var/www/dev
    $ doas /dev/MAKEDEV urandom
    $ doas mknod -m 666 null c 2 2
................................................................................
    crw-rw-rw-  1 root  daemon    2,   2 Jun 20 08:56 null
    lrwxr-xr-x  1 root  daemon         7 Jun 18 06:30 random@ -> urandom
    crw-r--r--  1 root  wheel    45,   0 Jun 18 06:30 urandom
```

[mfs]: https://man.openbsd.org/mount_mfs.8

To make the mountable memory filesystem permanent, open `/etc/fstab` as
a privileged user and add the following line to automate creation of the
filesystem at startup:

```console
    swap /var/www/dev mfs rw,-s=1048576 0 0
```

The same user that executes the fossil binary must have writable access
to the repository directory that resides within the chroot; on OpenBSD
this is `www`. In addition, grant repository directory ownership to the
user who will push to, pull from, and create repositories.

```console
   $ doas chown -R user:www /var/www/htdocs/fsl.domain.tld
   $ doas chmod 775 /var/www/htdocs/fsl.domain.tld
```

## <a name="httpdconfig"></a>Configure httpd

On OpenBSD, [httpd.conf(5)][httpd] is the configuration file for
`httpd`. To setup the server to serve all Fossil repositores within the
directory specified in the CGI script, and automatically redirect
standard HTTP requests to HTTPS—apart from [Let's Encrypt][LE]
challenges issued in response to [acme-client(1)][acme] certificate
requests—create `/etc/httpd.conf` as a privileged user with the
following contents.

[LE]: https://letsencrypt.org
[acme]: https://man.openbsd.org/acme-client.1
[httpd.conf(5)]: https://man.openbsd.org/httpd.conf.5

```apache
................................................................................
            }
            hsts {
                    max-age 15768000
                    preload
                    subdomains
            }
            connection max request body 104857600

            location  "/*" {
                    fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" }
            }
            location "/.well-known/acme-challenge/*" {
                    root "/acme"
                    request strip 2
            }
    }
```

**NOTE:** If not already in possession of a HTTPS certificate, comment
out the `https` server block and proceed to securing a free
[Let's Encrypt Certificate](#letsencrypt); otherwise skip to
[Start `httpd`](#starthttpd).

## <a name="letsencrypt"></a>Let's Encrypt Certificate

In order for `httpd` to serve HTTPS, secure a free certificate from
Let's Encrypt using `acme-client`. Before issuing the request, however,
ensure you have a zone record for the subdomain with your registrar or
nameserver. Then open `/etc/acme-client.conf` as a privileged user to
configure the request.

```dosini
    authority letsencrypt {
            api url "https://acme-v02.api.letsencrypt.org/directory"
            account key "/etc/acme/letsencrypt-privkey.pem"
    }

................................................................................
            domain key "/etc/ssl/private/domain.tld.key"
            domain certificate "/etc/ssl/domain.tld.crt"
            domain full chain certificate "/etc/ssl/domain.tld.fullchain.pem"
            sign with letsencrypt
    }
```

Start `httpd` with the new configuration file, and issue the certificate
request.

```console
    $ doas rcctl start httpd
    $ doas acme-client -vv domain.tld
    acme-client: /etc/acme/letsencrypt-privkey.pem: account key exists (not creating)
    acme-client: /etc/acme/letsencrypt-privkey.pem: loaded RSA account key
    acme-client: /etc/ssl/private/domain.tld.key: generated RSA domain key
    acme-client: https://acme-v01.api.letsencrypt.org/directory: directories
    acme-client: acme-v01.api.letsencrypt.org: DNS: 172.65.32.248
    ...
    N(Q????Z???j?j?>W#????b???? H????eb??T??*? DNosz(???n{L}???D???4[?B] (1174 bytes)
    acme-client: /etc/ssl/domain.tld.crt: created
    acme-client: /etc/ssl/domain.tld.fullchain.pem: created
```

A successful result will output the public certificate, full chain of
trust, and private key into the `/etc/ssl` directory as specified in
`acme-client.conf`.

```console
   $ doas ls -lR /etc/ssl
   -r--r--r--   1 root  wheel   2.3K Mar  2 01:31:03 2018 domain.tld.crt
   -r--r--r--   1 root  wheel   3.9K Mar  2 01:31:03 2018 domain.tld.fullchain.pem

   /etc/ssl/private:
   -r--------  1 root  wheel   3.2K Mar  2 01:31:03 2018 domain.tld.key
```

Make sure to reopen `/etc/httpd.conf` to uncomment the second server
block responsible for serving HTTPS requests before proceeding.

## <a name="starthttpd"></a>Start `httpd`

With `httpd` configured to serve Fossil repositories out of
`/var/www/htdocs/fsl.domain.tld`, and the certificates and key in place,
enable and start `slowcgi`—OpenBSD's FastCGI wrapper server that will
execute the above Fossil CGI script—before checking that the syntax of
the `httpd.conf` configuration file is correct, and (re)starting the
server (if still running from requesting a Let's Encrypt certificate).

```console
    $ doas rcctl enable slowcgi
    $ doas rcctl start slowcgi
    slowcgi(ok)
    $ doas httpd -vnf /etc/httpd.conf
    configuration OK
................................................................................
    $ doas rcctl start httpd
    httpd(ok)
```

## <a name="clientconfig"></a>Configure Client

To facilitate creating new repositories and pushing them to the server,
add the following function to your `~/.cshrc` or `~/.zprofile` or the
config file for whichever shell you are using on your development box.


```sh
    finit() {
            fossil init $1.fossil && \
            chmod 664 $1.fossil && \
            fossil open $1.fossil && \
            fossil user password $USER $PASSWD && \
................................................................................
            fossil remote-url https://$USER:$PASSWD@fsl.domain.tld/$1 && \
            rsync --perms $1.fossil $USER@fsl.domain.tld:/var/www/htdocs/fsl.domain.tld/ >/dev/null && \
            chmod 644 $1.fossil && \
            fossil ui
    }
```

This enables a new repository to be made with `finit repo`, which will
create the fossil repository file `repo.fossil` in the current working
directory; by default, the repository user is set to the environment
variable `$USER`. It then opens the repository and sets the user
password to the `$PASSWD` environment variable (which you can either set
with `export PASSWD 'password'` on the command line or add to a
*secured* shell environment file), and the `remote-url` to
`https://fsl.domain.tld/repo` with the credentials of `$USER` who is
authenticated with `$PASSWD`. Finally, it `rsync`'s the file to the
server before opening the local repository in your browser where you can
adjust settings such as anonymous user access, and set pertinent
repository details. Thereafter, you can add files with `fossil add`, and
commit with `fossil ci -m 'commit message'` where Fossil, by default,
will push to the `remote-url`. It's suggested you read the
[Fossil documentation][documentation]; with a sane and consistent
development model, the system is much more efficient and cohesive than
`git`—so the learning curve is not steep at all.

[documentation]: https://fossil-scm.org/home/doc/trunk/www/permutedindex.html

*[Return to the top-level Fossil server article.](../)*