diff options
Diffstat (limited to 'www/server')
29 files changed, 2916 insertions, 0 deletions
diff --git a/www/server/any/althttpd.md b/www/server/any/althttpd.md new file mode 100644 index 0000000..7797103 --- /dev/null +++ b/www/server/any/althttpd.md @@ -0,0 +1,42 @@ +# Serving via althttpd + +[Althttpd][althttpd] +is a light-weight web server that has been used to implement the SQLite and +Fossil websites for well over a decade. Althttpd strives for simplicity, +security, ease of configuration, and low resource usage. + +To set up a Fossil server as CGI on a host running the althttpd web +server, follow these steps. +<ol> +<li>Get the althttpd webserver running on the host. This is easily +done by following the [althttpd documentation][althttpd]. + +<li>Create a CGI script for your Fossil repository. The script will +be typically be two lines of code that look something like this: + +~~~ + #!/usr/bin/fossil + repository: /home/yourlogin/fossils/project.fossil +~~~ + +Modify the filenames to conform to your system, of course. The +CGI script accepts [other options][cgi] besides the +repository:" line. You can add in other options as you desire, +but the single "repository:" line is normally all that is needed +to get started. + +<li>Make the CGI script executable. + +<li>Verify that the fossil repository file and the directory that contains +the repository are both writable by whatever user the web server is +running and. +</ol> + +And you are done. Visit the URL that corresponds to the CGI script +you created to start using your Fossil server. + +*[Return to the top-level Fossil server article.](../)* + + +[althttpd]: https://sqlite.org/althttpd/ +[cgi]: ../../cgi.wiki diff --git a/www/server/any/cgi.md b/www/server/any/cgi.md new file mode 100644 index 0000000..79ede92 --- /dev/null +++ b/www/server/any/cgi.md @@ -0,0 +1,117 @@ +# Serving via CGI + +A Fossil server can be run from most ordinary web servers as a CGI +program. This feature allows Fossil to seamlessly integrate into a +larger website. The [self-hosting Fossil repository web +site](../../selfhost.wiki) is implemented using CGI. See the +[How CGI Works](../../aboutcgi.wiki) page for background information +on the CGI protocol. + +To run Fossil as CGI, create a CGI script (here called "repo") in the +CGI directory of your web server with content like this: + + #!/usr/bin/fossil + repository: /home/fossil/repo.fossil + +Adjust the paths appropriately. It may be necessary to set certain +permissions on this file or to modify an `.htaccess` file or make other +server-specific changes. Consult the documentation for your particular +web server. The following permissions are *normally* required, but, +again, may be different for a particular configuration: + +* The Fossil binary (`/usr/bin/fossil` in the example above) + must be readable/executable. + +* *All* directories leading up to the Fossil binary must be readable + by the process which executes the CGI. + +* The CGI script must be executable for the user under which it will + run, which often differs from the one running the web server. + Consult your site's documentation or the web server’s system + administrator. + +* *All* directories leading to the CGI script must be readable by the + web server. + +* The repository file *and* the directory containing it must be + writable by the same account which executes the Fossil binary. + (This might differ from the user the web server normally runs + under.) The directory holding the repository file(s) needs to be + writable so that SQLite can write its journal files. When using + another access control system, such as AppArmor or SELinux, it may + be necessary to explicitly permit that account to read and write + the necessary files. Also verify a possible _systemd_ sandboxing of + the web server service, especially the combination of _ProtectSystem_, + _ProtectHome_, and _ReadWriteDirectories_/_ReadWritePaths_. + +* Fossil must be able to create temporary files in a + [directory that varies by host OS](../../env-opts.md#temp). When the + CGI process is operating [within a chroot](../../chroot.md), + ensure that this directory exists and is readable/writeable by the + user who executes the Fossil binary. + +Once the CGI script is set up correctly, and assuming your server is +also set correctly, you should be able to access your repository with a +URL like: <b>http://mydomain.org/cgi-bin/repo</b> This is assuming you +are running a web server like Apache that uses a “`cgi-bin`” directory +for scripts like our “`repo`” example. + +To serve multiple repositories from a directory using CGI, use the +"directory:" tag in the CGI script rather than "repository:". You +might also want to add a "notfound:" tag to tell where to redirect if +the particular repository requested by the URL is not found: + + #!/usr/bin/fossil + directory: /home/fossil/repos + notfound: http://url-to-go-to-if-repo-not-found/ + +Once deployed, a URL like: <b>http://mydomain.org/cgi-bin/repo/XYZ</b> +will serve up the repository `/home/fossil/repos/XYZ.fossil` if it +exists. + +Additional options available to the CGI script are [documented +separately](../../cgi.wiki). + +#### CGI with Apache behind an Nginx proxy + +For the case where the Fossil repositories live on a computer, itself behind +an Internet-facing machine that employs Nginx to reverse proxy HTTP(S) requests +and take care of the TLS part of the connections in a transparent manner for +the downstream web servers, the CGI parameter `HTTPS=on` might not be set. +However, Fossil in CGI mode needs it in order to generate the correct links. + +Apache can be instructed to pass this parameter further to the CGI scripts for +TLS connections with a stanza like + + SetEnvIf X-Forwarded-Proto "https" HTTPS=on + +in its config file section for CGI, provided that + + proxy_set_header X-Forwarded-Proto $scheme; + +has been be added in the relevant proxying section of the Nginx config file. + +*[Return to the top-level Fossil server article.](../)* + +#### Apache mod_cgi and `CONTENT_LENGTH` + +At some point in its 2.4.x family, Apache's `mod_cgi` stopped relaying +the Content-Length header in the HTTP reply from CGIs back to clients. +However, Fossil clients prior to 2024-04-17 depended on seeing the +Content-Length header and were unable to handle HTTP replies without +one. The change in Apache behavior caused "fossil clone" and "fossil +sync" to stop working. There are two possible fixes to this problem: + + 1. Restore legacy behavior in Apache by adding + the following to the Apache configuration, scoped to the `<Directory>` + entry or entries in which fossil is being served via CGI: + <blockquote><pre> + <Directory ...> + SetEnv ap_trust_cgilike_cl "yes" + </Directory> + </pre></blockquote> + + 2. Upgrade your Fossil client to any trunk check-in after 2024-04-17, + as Fossil was upgraded to be able to deal with the missing + Content-Length field by + [check-in a8e33fb161f45b65](/info/a8e33fb161f45b65). diff --git a/www/server/any/http-over-ssh.md b/www/server/any/http-over-ssh.md new file mode 100644 index 0000000..8bc6fdb --- /dev/null +++ b/www/server/any/http-over-ssh.md @@ -0,0 +1,173 @@ +# Forcing Use of Fossil’s RBAC over SSH + +Andy Bradford posted a [clever solution][sshfc] to the problem of +Fossil’s RBAC system [being ignored](../../caps/#webonly) over `ssh://` +URLs: use OpenSSH’s `ForceCommand` feature to route the sync transfer +protocol data over `fossil http` rather than `fossil test-http`. + +The setup for this is complicated, but it’s a worthy option when you +need encrypted communications between the client and server, you already +have SSH set up, and [the HTTPS alternative](../../ssl.wiki) is +unworkable for some reason. + + +## 1. Force remote Fossil access through a wrapper script <a id="sshd"></a> + +Put something like the following into the `sshd_config` file on the +Fossil repository server: + +``` ssh-config +Match Group fossil + X11Forwarding no + AllowTcpForwarding no + AllowAgentForwarding no + ForceCommand /home/fossil/bin/wrapper +``` + +This file is usually found in `/etc/ssh`, but some OSes put it +elsewhere. + +The first line presumes that we will put all users who need to use our +Fossil repositories into the `fossil` group, as we will do +[below](#perms). You could instead say something like: + +``` ssh-config +Match User alice,bob,carol,dave +``` + +You have to list the users allowed to use Fossil in this case because +your system likely has a system administrator that uses SSH for remote +shell access, so you want to *exclude* that user from the list. For the +same reason, you don’t want to put the `ForceCommand` directive outside +a `Match` block of some sort. + +You could instead list the exceptions: + +``` ssh-config +Match User !evi +``` + +This would permit only [Evi the System Administrator][evi] to bypass this +mechanism. + +[evi]: https://en.wikipedia.org/wiki/Evi_Nemeth + +If you have a user that needs both interactive SSH shell access *and* +Fossil access, exclude that user from the `Match` rule and use Fossil’s +normal `ssh://` URL scheme for those cases. This user will bypass the +Fossil RBAC, but they effectively have Setup capability on those +repositories anyway by having full read/write access to the DB files via +the shell. + + +## 2. Rewrite the sync command with that wrapper <a id="wrapper"></a> + +When Fossil syncs over SSH, it attempts to launch a remote Fossil +instance with certain parameters in order to set up the HTTP-based sync +protocol over that SSH tunnel. We need to preserve some of this command +and rewrite other parts to make this work. + +Here is a simpler variant of Andy’s original wrapper script: + +``` sh +#!/bin/bash +set -- $SSH_ORIGINAL_COMMAND +while [ $# -gt 1 ] ; do shift ; done +export REMOTE_USER="$USER" +ROOT=/home/fossil +exec "$ROOT/bin/fossil" http "$ROOT/museum/$(/bin/basename "$1")" +``` + +The substantive changes are: + +1. Move the command rewriting bits to the start. + +2. Be explicit about executable paths. You might extend this idea by + using chroot, BSD jails, Linux containers, etc. + +3. Restrict the Fossil repositories to a single flat subdirectory under + the `fossil` user’s home directory. This scheme is easier to secure + than one allowing subdirectories, since you’d need to take care of + `../` and such to prevent a sandbox escape. + +4. Don’t take the user name via the SSH command; to this author’s mind, + the user should not get to override their Fossil user name on the + remote server, as that permits impersonation. The identity you + present to the SSH server must be the same identity that the Fossil + repository you’re working with knows you by. Since the users + selected by “`Match`” block above are dedicated to using only Fossil + in this setup, this restriction shouldn’t present a practical problem. + +The script’s shebang line assumes `/bin/sh` is POSIX-compliant, but that +is not the case everywhere. If the script fails to run on your system, +try changing this line to point at `bash`, `dash`, `ksh`, or `zsh`. Also +check the absolute paths for local correctness: is `/bin/basename` +installed on your system, for example? + +Under this scheme, you clone with a command like: + + $ fossil clone ssh://HOST/repo.fossil + +This will clone the remote `/home/fossil/museum/repo.fossil` repository +to your local machine under the same name and open it into a “`repo/`” +subdirectory. Notice that we didn’t have to give the `museum/` part of +the path: it’s implicit per point #3 above. + +This presumes your local user name matches the remote user name. Unlike +with `http[s]://` URLs, you don’t have to provide the `USER@` part to +get authenticated access +since this scheme doesn’t permit anonymous cloning. Only +if these two user names are different do you need to add the `USER@` bit to the +URL. + + +## 3. Set permissions <a id="perms"></a> + +This scheme assumes that the users covered by the `Match` rule can read +the wrapper script from where you placed it and execute it, and that +they have read/write access on the directory where the Fossil +repositories are stored. + +You can achieve all of this on a Linux box with: + +``` shell +sudo adduser fossil +for u in alice bob carol dave ; do + sudo adduser $u + sudo gpasswd -a fossil $u +done +sudo -i -u fossil +chmod 710 . +mkdir -m 750 bin +mkdir -m 770 museum +ln -s /usr/local/bin/fossil bin +``` + +You then need to copy the Fossil repositories into `~fossil/museum` and +make them readable and writable by group `fossil`. These repositories +presumably already have Fossil users configured, with the necessary +[user capabilities](../../caps/), the point of this article being to +show you how to make Fossil-over-SSH pay attention to those caps. + +You must also permit use of `REMOTE_USER` on each shared repository. +Fossil only pays attention to this environment variable in certain +contexts, of which “`fossil http`” is not one. Run this command against +each repo to allow that: + +``` shell +echo "INSERT OR REPLACE INTO config VALUES ('remote_user_ok',1,strftime('%s','now'));" | +fossil sql -R museum/repo.fossil +``` + +Now you can configure SSH authentication for each user. Since Fossil’s +password-saving feature doesn’t work in this case, I suggest setting up +SSH keys via `~USER/.ssh/authorized_keys` since the SSH authentication +occurs on each sync, which Fossil’s default-enabled autosync setting +makes frequent. + +Equivalent commands for other OSes should be readily discerned from the +script above. + +[sshfc]: forum:/forumpost/0d7d6c3df41fcdfd + +<div style="height:50em" id="this-space-intentionally-left-blank"></div> diff --git a/www/server/any/index.md b/www/server/any/index.md new file mode 100644 index 0000000..ccf2d94 --- /dev/null +++ b/www/server/any/index.md @@ -0,0 +1,11 @@ +# Portable Fossil Service Options + +- [Fossil as a standalone HTTP server](./none.md) +- [SCGI under your web server of choice](./scgi.md) +- [CGI under your web server of choice](./cgi.md) +- [CGI under `althttpd`](./althttpd.md) +- [Behind `stunnel` to get TLS encryption](./stunnel.md) +- [`inetd`](./inetd.md) +- [`xinetd`](./xinetd.md) + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/any/inetd.md b/www/server/any/inetd.md new file mode 100644 index 0000000..35766c7 --- /dev/null +++ b/www/server/any/inetd.md @@ -0,0 +1,52 @@ +# Serving via inetd + +A Fossil server can be launched on-demand by `inetd` by using the +[`fossil http`](/help/http) command. To do so, add a line like the +following to its configuration file, typically `/etc/inetd.conf`: + + 80 stream tcp nowait.1000 root /usr/bin/fossil /usr/bin/fossil http /home/fossil/repo.fossil + +In this example, you are telling `inetd` that when an incoming +connection appears on TCP port 80 that it should launch the program +`/usr/bin/fossil` with the arguments shown. Obviously you will need to +modify the pathnames for your particular setup. The final argument is +either the name of the fossil repository to be served or a directory +containing multiple repositories. + +If you use a non-standard TCP port on systems where the port +specification must be a symbolic name and cannot be numeric, add the +desired name and port to `/etc/services`. For example, if you want your +Fossil server running on TCP port 12345 instead of 80, you will need to +add: + + fossil 12345/tcp # fossil server + +and use the symbolic name “`fossil`” instead of the numeric TCP port +number (“12345” in the above example) in `inetd.conf`. + +Notice that we configured `inetd` to launch Fossil as root. See the +top-level section on “[The Fossil Chroot +Jail](../../chroot.md)” for the consequences of this and +alternatives to it. + +You can instead configure `inetd` to bind to a higher-numbered TCP port, +allowing Fossil to be run as a normal user. In that case, Fossil will +not put itself into a chroot jail, because it assumes you have set up +file permissions and such on the server appropriate for that user. + +The `inetd` daemon must be enabled for this to work, and it must be +restarted whenever its configuration file changes. + +This is a more complicated method than the [standalone HTTP server +method](./none.md), but it has the advantage of only using system +resources when an actual connection is attempted. If no one ever +connects to that port, a Fossil server will not (automatically) run. It +has the disadvantage of requiring "root" access, which may not be +available to you, either due to local IT policy or because of +restrictions at your shared Internet hosting service. + +For further details, see the relevant section in your system's +documentation. The FreeBSD Handbook covers `inetd` in [this +chapter](https://www.freebsd.org/doc/en/books/handbook/network-inetd.html). + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/any/none.md b/www/server/any/none.md new file mode 100644 index 0000000..2208091 --- /dev/null +++ b/www/server/any/none.md @@ -0,0 +1,56 @@ +# Standalone HTTP Server + +The easiest way to set up a Fossil server is to use either the +[`server`](/help/server) or [`ui`](/help/ui) command: + +* **fossil server** _REPOSITORY_ +* **fossil ui** _REPOSITORY_ + +The _REPOSITORY_ argument is either the name of the repository file or a +directory containing many repositories named “`*.fossil`”. Both of these +commands start a Fossil server, usually on TCP port 8080, though a +higher numbered port will be used instead if 8080 is already occupied. + +You can access these using URLs of the form **http://localhost:8080/**, +or if _REPOSITORY_ is a directory, URLs of the form +**http://localhost:8080/**_repo_**/** where _repo_ is the base name of +the repository file without the “`.fossil`” suffix. + +There are several key differences between “`ui`” and “`server`”: + +* “`ui`” always binds the server to the loopback IP address (127.0.0.1) + so that it cannot serve to other machines. + +* Anyone who visits this URL is treated as the all-powerful Setup + user, which is why the first difference exists. + +* “`ui`” launches a local web browser pointed at this URL. + +You can omit the _REPOSITORY_ argument if you run one of the above +commands from within a Fossil checkout directory to serve that +repository: + + $ fossil ui # or... + $ fossil server + +You can abbreviate Fossil sub-commands as long as they are unambiguous. +“`server`” can currently be as short as “`ser`”. + +You can serve a directory containing multiple `*.fossil` files like so: + + $ fossil server --port 9000 --repolist /path/to/repo/dir + +As a security precaution, when the “`server`” or +“`ui`” commands are run as `root` Fossil will drop into +a [chroot](../../chroot.md) with the directory where the repository is located +as the new root of the filesystem. + +There is an [example script](/file/tools/fslsrv) in the Fossil +distribution that wraps `fossil server` to produce more complicated +effects. Feel free to take it, study it, and modify it to suit your +local needs. + +See the [online documentation](/help/server) for more information on the +options and arguments you can give to these commands. + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/any/scgi.md b/www/server/any/scgi.md new file mode 100644 index 0000000..4c02158 --- /dev/null +++ b/www/server/any/scgi.md @@ -0,0 +1,72 @@ +# Serving via SCGI + +There is an alternative to running Fossil as a [standalone HTTP +server](./none.md), which is to run it in SimpleCGI (a.k.a. SCGI) mode, +which uses the same [`fossil server`](/help/server) command as for HTTP +service. Simply add the `--scgi` command-line option and the stand-alone +server will speak the SCGI protocol rather than raw HTTP. + +This can be used with a web server such as [nginx](http://nginx.org) +which does not support [Fossil’s CGI mode](./cgi.md). + +A basic nginx configuration to support SCGI with Fossil looks like this: + + location /code/ { + include scgi_params; + scgi_param SCRIPT_NAME "/code"; + scgi_pass localhost:9000; + } + +The `scgi_params` file comes with nginx, and it simply translates nginx +internal variables to `scgi_param` directives to create SCGI environment +variables for the proxied program; in this case, Fossil. Our explicit +`scgi_param` call to define `SCRIPT_NAME` adds one more variable to this +set, which is necessary for this configuration to work properly, because +our repo isn’t at the root of the URL hierarchy. Without it, when Fossil +generates absolute URLs, they’ll be missing the `/code` part at the +start, which will typically cause [404 errors][404]. + +The final directive simply tells nginx to proxy all calls to URLs under +`/code` down to an SCGI program on TCP port 9000. We can temporarily +set Fossil up as a server on that port like so: + + $ fossil server /path/to/repo.fossil --scgi --localhost --port 9000 & + +The `--scgi` option switches Fossil into SCGI mode from its default, +which is [stand-alone HTTP server mode](./none.md). All of the other +options discussed in that linked document — such as the ability to serve +a directory full of Fossil repositories rather than just a single +repository — work the same way in SCGI mode. + +The `--localhost` option is simply good security: we’re using nginx to +expose Fossil service to the outside world, so there is no good reason +to allow outsiders to contact this Fossil SCGI server directly. + +Giving an explicit non-default TCP port number via `--port` is a good +idea to avoid conflicts with use of Fossil’s default TCP service port, +8080, which may conflict with local uses of `fossil ui` and such. + +We characterized the SCGI service start command above as “temporary” +because running Fossil in the background like that means it won’t start +back up on a reboot of the server. A simple solution to that is to add +that command to `/etc/rc.local` on systems that have it. However, you +might want to consider setting Fossil up as an OS service instead, so +that you get the benefits of the platform’s service management +framework: + +* [Linux (systemd)](../debian/service.md) +* [Windows service](../windows/service.md) +* [macOS (launchd)](../macos/service.md) +* [xinetd](../any/xinetd.md) +* [inetd](../any/inetd.md) + +We go into more detail on nginx service setup with Fossil in our +[Debian/Ubuntu specific guide](../debian/nginx.md), which also +gets you TLS service. + +Similarly, our [OpenBSD specific guide](../openbsd/fastcgi.md) details how +to setup a Fossil server using httpd and FastCGI on OpenBSD. + +*[Return to the top-level Fossil server article.](../)* + +[404]: https://en.wikipedia.org/wiki/HTTP_404 diff --git a/www/server/any/stunnel.md b/www/server/any/stunnel.md new file mode 100644 index 0000000..c8824a7 --- /dev/null +++ b/www/server/any/stunnel.md @@ -0,0 +1,81 @@ +# Serving via stunnel + +[`stunnel`](https://www.stunnel.org/) is a TLS/SSL proxy for programs +that themselves serve only via HTTP, such as Fossil. (Fossil *can* speak +HTTPS, but only as a client.) `stunnel` decodes the HTTPS data from the +outside world as HTTP before passing it to Fossil, and it encodes the +HTTP replies from Fossil as HTTPS before sending them to the remote host +that made the request. + +You can run `stunnel` in one of two modes: socket listener — much like +in our [`inetd` doc](./inetd.md) — and as an HTTP reverse proxy. We’ll +cover both cases here, separately. + + +## <a id="sa"></a>Socket Activation + +The following `stunnel.conf` configuration configures it to run Fossil +in socket listener mode, launching Fossil only when an HTTPS hit comes +in, then shutting it back down as soon as the transaction is complete: + +```dosini + [fossil] + accept = 443 + TIMEOUTclose = 0 + exec = /usr/bin/fossil + execargs = /usr/bin/fossil http /home/fossil/ubercool.fossil --https + cert = /etc/letsencrypt/live/ubercool-project.org/fullchain.pem + key = /etc/letsencrypt/live/ubercool-project.org/privkey.pem + ciphers = ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES128-SHA:DES-CBC3-SHA + options = CIPHER_SERVER_PREFERENCE +``` + +This configuration shows the TLS certificate generated by the [Let’s +Encrypt](https://letsencrypt.org) [Certbot](https://certbot.eff.org) in +[certonly mode](https://certbot.eff.org/lets-encrypt/debianbuster-other). +There are other ways to get TLS certificates, but this is a popular and +free option. + +You will need to adjust the site names and paths in this example. Where +this file goes varies by OS type, so check the man pages on your system +to find out where it should be locally. + +See the `stunnel` documentation for further details about this +configuration file. + +It is important that the [`fossil http`](/help/http) command in that +configuration include the `--https` option to let Fossil know to use +“`https://`” instead of “`http://`” in generated hyperlinks. + + + +## <a id="proxy"></a>Reverse Proxy + +You can instead have Fossil running in the background in [standalone +HTTP server mode](./none.md), bound to a high random TCP port number on +localhost via the `--localhost` and `--port` flags, then configure +`stunnel` to reverse proxy public HTTPS connections down to it via HTTP. + +The configuration is the same as the above except that you drop the +`exec` and `execargs` directives and add this instead: + +```dosini + connect = 9000 +``` + +That tells `stunnel` to connect to an already-running process listening +on the given TCP port number. + +There are a few advantages to this mode: + +1. At the cost of some server memory and a tiny bit of idle CPU time, + Fossil remains running so that hits can be served a smidge faster + than in socket listener mode, where the Fossil binary has to be + loaded and re-initialized on each HTTPS hit. + +2. The socket listener mode doesn’t work on all platforms that + `stunnel` runs on, particularly [on Windows](../windows/stunnel.md). + +*[Return to the top-level Fossil server article.](../)* + +<div style="height:50em" id="this-space-intentionally-left-blank"></div> diff --git a/www/server/any/xinetd.md b/www/server/any/xinetd.md new file mode 100644 index 0000000..9e93502 --- /dev/null +++ b/www/server/any/xinetd.md @@ -0,0 +1,27 @@ +# Serving via xinetd + +Some operating systems have replaced the old Unix `inetd` daemon with +`xinetd`, which has a similar mission but with a very different +configuration file format. + +The typical configuration file is either `/etc/xinetd.conf` or a subfile +in the `/etc/xinetd.d` directory. You need a configuration something +like this for Fossil: + + service http + { + port = 80 + socket_type = stream + wait = no + user = root + server = /usr/bin/fossil + server_args = http /home/fossil/repos/ + } + +This example configures Fossil to serve multiple repositories under the +`/home/fossil/repos/` directory. + +Beyond this, see the general commentary in our article on [the `inetd` +method](./inetd.md) as they also apply to service via `xinetd`. + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/debian/index.md b/www/server/debian/index.md new file mode 100644 index 0000000..220d177 --- /dev/null +++ b/www/server/debian/index.md @@ -0,0 +1,6 @@ +# Debian/Ubuntu Specific Fossil Service Options + +- [SCGI under nginx](./nginx.md) +- [`systemd`](./service.md) + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/debian/nginx.md b/www/server/debian/nginx.md new file mode 100644 index 0000000..0140b37 --- /dev/null +++ b/www/server/debian/nginx.md @@ -0,0 +1,395 @@ +# Serving via nginx on Debian and Ubuntu + +This document is an extension of [the platform-independent SCGI +instructions][scgii], which may suffice for your purposes if your needs +are simple. + +Here, we add more detailed information on nginx itself, plus details +about running it on Debian type OSes. This document was originally +written for and tested on Debian 10 (Buster) and Ubuntu 20.04, which +were common Tier 1 OS offerings for [virtual private servers][vps] +at the time. The same configuration appears to run on Ubuntu 22.04 +LTS without change. This material may not work for older OSes. It is +known in particular to not work as given for Debian 9 and older! + +We also cover [adding TLS](#tls) to the basic configuration, because several +details depend on the host OS and web stack details. Besides, TLS is +widely considered part of the baseline configuration these days. + +[scgii]: ../any/scgi.md +[vps]: https://en.wikipedia.org/wiki/Virtual_private_server + + +## <a id="benefits"></a>Benefits + +This scheme is considerably more complicated than the [standalone HTTP +server](../any/none.md) and [CGI options](../any/cgi.md). Even with the +benefit of this guide and pre-built binary packages, it requires quite a +bit of work to set it up. Why should you put up with this complexity? +Because it gives many benefits that are difficult or impossible to get +with the less complicated options: + +* **Power** — nginx is one of the most powerful web servers in the + world. The chance that you will run into a web serving wall that you + can’t scale with nginx is very low. + + To give you some idea of the sort of thing you can readily + accomplish with nginx, your author runs a single public web server + that provides transparent name-based virtual hosting for four + separate domains: + + * <p>One is entirely static, not involving any dynamic content or + Fossil integration at all.</p> + + * <p>Another is served almost entirely by Fossil, with a few select + static content exceptions punched past Fossil, which are handled + entirely via nginx.</p> + + * <p>The other two domains are aliases for one another — e.g. + `example.com` and `example.net` — with most of the content being + static. This pair of domains has several unrelated Fossil repo + proxies attached to various sections of the URI hierarchy.</p> + + By using nginx, I was able to do all of the above with minimal + repetition between the site configurations. + +* **Integration** — Because nginx is so popular, it integrates with +many different technologies, and many other systems integrate with it in +turn. This makes it great middleware, sitting between the outer web +world and interior site services like Fossil. It allows Fossil to +participate seamlessly as part of a larger web stack. + +* **Availability** — nginx is already in most operating system binary +package repositories, so you don’t need to go out of your way to get it. + + +## <a id="modes"></a>Fossil Service Modes + +Fossil provides four major ways to access a repository it’s serving +remotely, three of which are straightforward to use with nginx: + +* **HTTP** — Fossil has [a built-in HTTP server](../any/none.md). + While this method is efficient and it’s + possible to use nginx to proxy access to another HTTP server, we + don’t see any particularly good reason to make nginx reinterpret + Fossil’s own implementation of HTTP when we have a better option. + (But see [below](#http).) + +* **SSH** — This method exists primarily to avoid the need for HTTPS, + but we *want* HTTPS. (We’ll get to that [below](#tls).) + There is probably a way to get nginx to proxy Fossil to HTTPS via + SSH, but it would be pointlessly complicated. + +* **CGI** — This method is simple but inefficient, because it launches + a separate Fossil instance on every HTTP hit. + Since Fossil is a relatively small self-contained program, and it’s + designed to start up quickly, this method can work well in a + surprisingly large number of cases. + Nevertheless, we will avoid this option in this document because + we’re already buying into a certain amount of complexity here in + order to gain power. There’s no sense in throwing away any of that + hard-won performance on CGI overhead. + +* **SCGI** — The [SCGI protocol][scgip] provides the simplicity of CGI + without its performance problems. + +SCGI it is, then. + +[scgip]: https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface + + +## <a id="deps"></a>Installing the Dependencies + +The first step is to install some non-default packages we’ll need. SSH into +your server, then say: + + $ sudo apt install fossil nginx + +You can leave “`fossil`” out of that if you’re building Fossil from +source to get a more up-to-date version than is shipped with the host +OS. + + +## <a id="scgi"></a>Running Fossil in SCGI Mode + +For the following nginx configuration to work, it needs to contact a +background Fossil instance speaking the SCGI protocol. There are +[many ways](../) to set that up, such as [with `systemd`](./service.md) +on mainstream Linux distros. Another way is to [containerize][ctz] your +repository servers, then use the [`fslsrv` wrapper for Podman][fspm] to +generate `systemd` units for use by the front-end proxy. + +However you do it, you need to match up the TCP port numbers between it +and those in the nginx configuration below. + +[ctz]: ../../containers.md +[fspm]: https://tangentsoft.com/fossil/dir/bin + + +## <a id="config"></a>Configuration + +On Debian and Ubuntu systems the primary user-level configuration file +for nginx is `/etc/nginx/sites-enabled/default`. I recommend that this +file contain only a list of include statements, one for each site that +server hosts: + + include local/example.com + include local/foo.net + +Those files then each define one domain’s configuration. Here, +`/etc/nginx/local/example.com` contains the configuration for +`*.example.com` and its alias `*.example.net`; and `local/foo.net` +contains the configuration for `*.foo.net`. + +The configuration for our `example.com` web site, stored in +`/etc/nginx/sites-enabled/local/example.com` is: + +---- + + server { + server_name .example.com .example.net ""; + include local/generic; + include local/code; + + access_log /var/log/nginx/example.com-https-access.log; + error_log /var/log/nginx/example.com-https-error.log; + + # Bypass Fossil for the static documentation generated from + # our source code by Doxygen, so it merges into the embedded + # doc URL hierarchy at Fossil’s $ROOT/doc without requiring that + # these generated files actually be stored in the repo. This + # also lets us set aggressive caching on these docs, since + # they rarely change. + location /code/doc/html { + root /var/www/example.com/code/doc/html; + + location ~* \.(html|ico|css|js|gif|jpg|png)$ { + add_header Vary Accept-Encoding; + access_log off; + expires 7d; + } + } + + # Redirect everything under /code to the Fossil instance + location /code { + include local/code; + + # Extended caching for URLs that include unique IDs + location ~ "/(artifact|doc|file|raw)/[0-9a-f]{40,64}" { + add_header Cache-Control "public, max-age=31536000, immutable"; + include local/code; + access_log off; + } + + # Lesser caching for URLs likely to be quasi-static + location ~* \.(css|gif|ico|js|jpg|png)$ { + add_header Vary Accept-Encoding; + include local/code; + access_log off; + expires 7d; + } + } + } + +---- + +As you can see, this is a pure extension of [the basic nginx service +configuration for SCGI][scgii], showing off a few ideas you might want to +try on your own site, such as static asset proxying. + +You also need a `local/code` file containing: + + include scgi_params; + scgi_pass 127.0.0.1:12345; + scgi_param SCRIPT_NAME "/code"; + +We separate that out because nginx refuses to inherit certain settings +between nested location blocks, so rather than repeat them, we extract +them to this separate file and include it from both locations where it’s +needed. You see this above where we set far-future expiration dates on +files served by Fossil via URLs that contain hashes that change when the +content changes. It tells your browser that the content of these URLs +can never change without the URL itself changing, which makes your +Fossil-based site considerably faster. + +Similarly, the `local/generic` file referenced above helps us reduce unnecessary +repetition among the multiple sites this configuration hosts: + + root /var/www/$host; + + listen 80; + listen [::]:80; + + charset utf-8; + +There are some configuration directives that nginx refuses to substitute +variables into, citing performance considerations, so there is a limit +to how much repetition you can squeeze out this way. One such example +are the `access_log` and `error_log` directives, which follow an obvious +pattern from one host to the next. Sadly, you must tolerate some +repetition across `server { }` blocks when setting up multiple domains +on a single server. + +The configuration for `foo.net` is similar. + +See [the nginx docs](https://nginx.org/en/docs/) for more ideas. + + +## <a id="http"></a>Proxying HTTP Anyway + +[Above](#modes), we argued that proxying SCGI is a better option than +making nginx reinterpret Fossil’s own implementation of HTTP. If you +want Fossil to speak HTTP, just [set Fossil up as a standalone +server](../any/none.md). And if you want nginx to [provide TLS +encryption for Fossil](#tls), proxying HTTP instead of SCGI provides no +benefit. + +However, it is still worth showing the proper method of proxying +Fossil’s HTTP server through nginx if only to make reading nginx +documentation on other sites easier: + + location /code { + rewrite ^/code(/.*) $1 break; + proxy_pass http://127.0.0.1:12345; + } + +The most common thing people get wrong when hand-rolling a configuration +like this is to get the slashes wrong. Fossil is sensitive to this. For +instance, Fossil will not collapse double slashes down to a single +slash, as some other HTTP servers will. + + +## <a id="large-uv"></a> Allowing Large Unversioned Files + +By default, nginx only accepts HTTP messages [up to a +meg](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size) +in size. Fossil chunks its sync protocol such that this is not normally +a problem, but when sending [unversioned content][uv], it uses a single +message for the entire file. Therefore, if you will be storing files +larger than this limit as unversioned content, you need to raise the +limit. Within the `location` block: + + # Allow large unversioned file uploads, such as PDFs + client_max_body_size 20M; + +[uv]: ../../unvers.wiki + + +## <a id="fail2ban"></a> Integrating `fail2ban` + +One of the nice things that falls out of proxying Fossil behind nginx is +that it makes it easier to configure `fail2ban` to recognize attacks on +Fossil and automatically block them. Fossil logs the sorts of errors we +want to detect, but it does so in places like the repository’s admin +log, a SQL table, which `fail2ban` doesn’t know how to query. By putting +Fossil behind an nginx proxy, we convert these failures to log file +form, which `fail2ban` is designed to handle. + +First, install `fail2ban`, if you haven’t already: + + sudo apt install fail2ban + +We’d like `fail2ban` to react to Fossil `/login` failures. The stock +configuration of `fail2ban` only detects a few common sorts of SSH +attacks by default, and its included (but disabled) nginx attack +detectors don’t include one that knows how to detect an attack on +Fossil. We have to teach it by putting the following into +`/etc/fail2ban/filter.d/nginx-fossil-login.conf`: + + [Definition] + failregex = ^<HOST> - .*POST .*/login HTTP/..." 401 + +That teaches `fail2ban` how to recognize the errors logged by Fossil. + +Then in `/etc/fail2ban/jail.local`, add this section: + + [nginx-fossil-login] + enabled = true + logpath = /var/log/nginx/*-https-access.log + +The last line is the key: it tells `fail2ban` where we’ve put all of our +per-repo access logs in the nginx config above. + +There’s a [lot more you can do][dof2b], but that gets us out of scope of +this guide. + + +[dof2b]: https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04 + + +## <a id="tls"></a> Adding TLS (HTTPS) Support + +One of the [many ways](../../ssl.wiki) to provide TLS-encrypted HTTP +access (a.k.a. HTTPS) to Fossil is to run it behind a web proxy that +supports TLS. Because one such option is nginx, it’s best to delegate +TLS to it if you were already using nginx for some other reason, such as +static content serving, with only part of the site being served by +Fossil. + +The simplest way by far to do this is to use [Let’s Encrypt][LE]’s +[Certbot][CB], which can configure nginx for you and keep its +certificates up to date. You need but follow their [nginx on Ubuntu 20 +guide][CBU]. We had trouble with this in the past, but either Certbot +has gotten smarter or our nginx configurations have gotten simpler, so +we have removed the manual instructions we used to have here. + +You may wish to include something like this from each `server { }` +block in your configuration to enable TLS in a common, secure way: + +``` +# Tell nginx to accept TLS-encrypted HTTPS on the standard TCP port. +listen 443 ssl; +listen [::]:443 ssl; + +# Reference the TLS cert files produced by Certbot. +ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; + +# Load the Let's Encrypt Diffie-Hellman parameters generated for +# this server. Without this, the server is vulnerable to Logjam. +ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + +# Tighten things down further, per Qualys’ and Certbot’s advice. +ssl_session_cache shared:le_nginx_SSL:1m; +ssl_protocols TLSv1.2 TLSv1.3; +ssl_prefer_server_ciphers on; +ssl_session_timeout 1440m; + +# Offer OCSP certificate stapling. +ssl_stapling on; +ssl_stapling_verify on; + +# Enable HSTS. +include local/enable-hsts; +``` + +The [HSTS] step is optional and should be applied only after due +consideration, since it has the potential to lock users out of your +site if you later change your mind on the TLS configuration. +The `local/enable-hsts` file it references is simply: + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + +It’s a separate file because nginx requires that headers like this be +applied separately for each `location { }` block. We’ve therefore +factored this out so you can `include` it everywhere you need it. + +The [OCSP] step is optional, but recommended. + +You may find [Qualys’ SSL Server Test][QSLT] helpful in verifying that +you have set all this up correctly, and that the configuration is +strong. We’ve found their [best practices doc][QSLC] to be helpful. As +of this writing, the above configuration yields an A+ rating when run on +Ubuntu 22.04.01 LTS. + +[CB]: https://certbot.eff.org/ +[CBU]: https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal +[LE]: https://letsencrypt.org/ +[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/ +[OCSP]: https://en.wikipedia.org/wiki/OCSP_stapling +[QSLC]: https://github.com/ssllabs/research/wiki/SSL-and-TLS-Deployment-Best-Practices +[QSLT]: https://www.ssllabs.com/ssltest/ + +<div style="height:50em" id="this-space-intentionally-left-blank"></div> + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/debian/service.md b/www/server/debian/service.md new file mode 100644 index 0000000..f056ff1 --- /dev/null +++ b/www/server/debian/service.md @@ -0,0 +1,259 @@ +# Serving via systemd on Debian and Ubuntu + +[`systemd`][sdhome] is the service management framework in all major +in-support versions of Linux. There are multiple ways to run Fossil +under `systemd`. + +[sdhome]: https://www.freedesktop.org/wiki/Software/systemd/ +[wpa]: https://en.wikipedia.org/wiki/Systemd#Adoption + + +## Containerized Service + +Two of the methods for running [containerized Fossil][cntdoc] integrate +with `systemd`, potentially obviating the more direct methods below: + +* If you take [the Podman method][podman] of running containerized + Fossil, it opens the `podman generate systemd` option for you, as + exemplified in [the `fslsrv` script][fslsrv] used on this author’s + public Fossil-based web site. That script pulls its container images + from [my Docker Hub repo][dhrepo] to avoid the need for my public + Fossil server to have build tools and a copy of the Fossil source + tree. You’re welcome to use my images as-is, or you may use these + tools to bounce custom builds up through a separate container image + repo you manage. + +* If you’re willing to give up [a lot of features][nsweak] relative to + Podman, and you’re willing to tolerate a lot more manual + administrivia, [the nspawn method][nspawn] has a lot less overhead, + being a direct feature of `systemd` itself. + +Both of these options provide [better security][cntsec] than running +Fossil directly under `systemd`, among [other benefits][cntdoc]. + +[cntdoc]: ../../containers.md +[cntsec]: ../../containers.md#security +[dhrepo]: https://hub.docker.com/r/tangentsoft/fossil +[fslsrv]: https://tangentsoft.com/fossil/dir?name=bin +[nspawn]: ../../containers.md#nspawn +[nsweak]: ../../containers.md#nspawn-weaknesses +[podman]: ../../containers.md#podman + + +## User Service + +A fun thing you can easily do with `systemd` that you can’t directly do +with older technologies like `inetd` and `xinetd` is to set a server up +as a “user” service. + +You can’t listen on TCP port 80 with this method due to security +restrictions on TCP ports in every OS where `systemd` runs, but you can +create a listener socket on a high-numbered (≥ 1024) TCP port, +suitable for sharing a Fossil repo to a workgroup on a private LAN. + +To do this, write the following in +`~/.local/share/systemd/user/fossil.service`: + +> ```dosini +[Unit] +Description=Fossil user server +After=network-online.target + +[Service] +WorkingDirectory=/home/fossil/museum +ExecStart=/home/fossil/bin/fossil server --port 9000 repo.fossil +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target +``` + +Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which +user and group to run this service as, because we’ve installed it +under the account we’re logged into, which `systemd` will use as the +service’s owner. + +The result is essentially [the standalone server method](../any/none.md) +coupled with an intelligent service manager that will start it +automatically in the background on system boot, perform automatic +service restarts with back-off logic, and more, making this much more +robust than the by-hand launches of `fossil` in the platform-independent +Fossil server instructions. The service will stay up until we +explicitly tell it to shut down. + +This scheme couples well with [the generic SCGI instructions][scgi] as +it requires a way to run the underlying repository server in the +background. Given that its service port is then proxied by SCGI, it +follows that it doesn’t need to run as a system service. A user service +works perfectly well for this. + +Because we’ve set this up as a user service, the commands you give to +manipulate the service vary somewhat from the sort you’re more likely to +find online: + + $ systemctl --user daemon-reload + $ systemctl --user enable fossil + $ systemctl --user start fossil + $ systemctl --user status fossil -l + $ systemctl --user stop fossil + +That is, we don’t need to talk to `systemd` with `sudo` privileges, but +we do need to tell it to look at the user configuration rather than the +system-level configuration. + +This scheme isolates the permissions needed by the Fossil server, which +reduces the amount of damage it can do if there is ever a +remotely-triggerable security flaw found in Fossil. + +On some `systemd` based OSes, user services only run while that user is +logged in interactively. This is common on systems aiming to provide +desktop environments, where this is the behavior you often want. To +allow background services to continue to run after logout, say: + + $ sudo loginctl enable-linger $USER + +You can paste the command just like that into your terminal, since +`$USER` will expand to your login name. + +[scgi]: ../any/scgi.md + + + +### System Service Alternative + +There are some common reasons that you’d have good cause to install +Fossil as a system-level service rather than the prior user-level one: + +* You’re using [the new `fossil server --cert` feature][sslsrv] to get + TLS service and want it to listen directly on port 443, rather than be + proxied, as one had to do before Fossil got the ability to act as a + TLS server itself. That requires root privileges, so you can’t run + it as a user-level service. + +* You’re proxying Fossil with [nginx](./nginx.md) or similar, allowing + it to bind to high-numbered ports, but because it starts as a system + service, you can’t get Fossil into the same dependency chain to + ensure things start up and shut down in the proper order unless it + *also* runs as a system service. + +* You want to make use of Fossil’s [chroot jail feature][cjail], which + requires the server to start as root. + +There are just a small set of changes required: + +1. Install the unit file to one of the persistent system-level unit + file directories. Typically, these are: + + /etc/systemd/system + /lib/systemd/system + +2. Add `User` and `Group` directives to the `[Service]` section so + Fossil runs as a normal user, preferably one with access only to + the Fossil repo files, rather than running as `root`. + +[sslsrv]: ../../ssl-server.md +[cjail]: ../../chroot.md + + +## Socket Activation + +Another useful method to serve a Fossil repo via `systemd` is via a +socket listener, which `systemd` calls “[socket activation][sa],” +roughly equivalent to [the ancient `inetd` method](../any/inetd.md). +It’s more complicated, but it has some nice properties. + +We first need to define the privileged socket listener by writing +`/etc/systemd/system/fossil.socket`: + +> ```dosini +[Unit] +Description=Fossil socket + +[Socket] +Accept=yes +ListenStream=80 +NoDelay=true + +[Install] +WantedBy=sockets.target +``` + +Note the change of configuration directory from the `~/.local` directory +to the system level. We need to start this socket listener at the root +level because of the low-numbered TCP port restriction we brought up +above. + +This configuration says more or less the same thing as the socket part +of an `inetd` entry [exemplified elsewhere in this +documentation](../any/inetd.md). + +Next, create the service definition file in that same directory as +`fossil@.service`: + +> ```dosini +[Unit] +Description=Fossil socket server +After=network-online.target + +[Service] +WorkingDirectory=/home/fossil/museum +ExecStart=/home/fossil/bin/fossil http repo.fossil +StandardInput=socket + +[Install] +WantedBy=multi-user.target +``` + +Notice that we haven’t told `systemd` which user and group to run Fossil +under. Since this is a system-level service definition, that means it +will run as root, which then causes Fossil to [automatically drop into a +`chroot(2)` jail](../../chroot.md) rooted at the `WorkingDirectory` +we’ve configured above, shortly after each `fossil http` call starts. + +The `Restart*` directives we had in the user service configuration above +are unnecessary for this method, since Fossil isn’t supposed to remain +running under it. Each HTTP hit starts one Fossil instance, which +handles that single client’s request and then immediately shuts down. + +Next, you need to tell `systemd` to reload its system-level +configuration files and enable the listening socket: + + $ sudo systemctl daemon-reload + $ sudo systemctl enable fossil.socket + +And now you can manipulate the socket listener: + + $ sudo systemctl start fossil.socket + $ sudo systemctl status -l fossil.socket + $ sudo systemctl stop fossil.socket + +Notice that we’re working with the *socket*, not the *service*. The fact +that we’ve given them the same base name and marked the service as an +instantiated service with the “`@`” notation allows `systemd` to +automatically start an instance of the service each time a hit comes in +on the socket that `systemd` is monitoring on Fossil’s behalf. To see +this service instantiation at work, visit a long-running Fossil page +(e.g. `/tarball`) and then give a command like this: + + $ sudo systemctl --full | grep fossil + +This will show information about the `fossil` socket and service +instances, which should show your `/tarball` hit handler, if it’s still +running: + + fossil@20-127.0.0.1:80-127.0.0.1:38304.service + +You can feed that service instance description to a `systemctl kill` +command to stop that single instance without restarting the whole +`fossil` service, for example. + +In all of this, realize that we’re able to manipulate a single socket +listener or single service instance at a time, rather than reload the +whole externally-facing network configuration as with the far more +primitive `inetd` service. + +[sa]: http://0pointer.de/blog/projects/socket-activation.html + + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/index.html b/www/server/index.html new file mode 100644 index 0000000..c15d42f --- /dev/null +++ b/www/server/index.html @@ -0,0 +1,316 @@ +<div class='fossil-doc' data-title="How To Configure A Fossil Server"> + +<style type="text/css"> + .doc > .content th.fep { + font-family: "Helvetica Neue", "Arial Narrow", "Myriad Pro", "Avenir Next Condensed"; + font-stretch: condensed; + min-width: 3em; + padding: 0.4em; + white-space: nowrap; + } + + .doc > .content th.host { + font-family: "Helvetica Neue", "Arial Narrow", "Myriad Pro", "Avenir Next Condensed"; + font-stretch: condensed; + padding: 0.4em; + text-align: right; + } + + .doc > .content td.doc { + text-align: center; + } +</style> + + +<h2>No Server Required</h2> + +<p>Fossil does not require a central server, but <a +href="whyuseaserver.wiki">a server can be useful</a>.</p> + +<p>A Fossil server does not require much memory, CPU, or disk space +and can run comfortably on a generic $5/month virtual host +or on a small device like a Raspberry Pi, or it can co-exist +on a host running other services without getting in the way. + +<p>This article is a quick-reference guide for setting up your own +Fossil server, with links to more detailed instructions specific to +particular systems, should you want extra help.</p> + + +<h2 id="prep">Repository Prep</h2> + +<p>Prior to serving a Fossil repository to others, consider running <a +href="$ROOT/help/ui"><tt>fossil ui</tt></a> locally and taking these +minimum recommended preparation steps:</p> + +<ol> + <li><p>Fossil creates only one user in a <a + href="$ROOT/help/new">new repository</a> and gives it the <a + href="../caps/admin-v-setup.md#apsu">all-powerful Setup capability</a>. + The 10-digit random password generated for that user is fairly strong + against remote attack, even without explicit password guess rate + limiting, but because that user has so much power, you may want to + give it a much stronger password under Admin → Users.</a></li> + + <li><p>Run the Admin → Security-Audit tool to verify that other + security-related permissions and settings are as you want them. + Consider clicking the “Take it private” link on that page to lock down + the security on that site to a level appropriate to a private + repository, even if you will eventually want some public service. It's + better to start from a secure position and open up service + feature-by-feature as necessary than it is to start from a fully open + position and lock down features one by one to achieve a secure + stance.</p></li> +</ol> + +<p>With the repository secured, it is safe to upload a copy of the +repository file to your server and proceed with server setup, below. +Further configuration steps can wait until <a href="#postsetup">after +the server is running</a>.</p> + + +<h2 id="methods">Activation Methods</h2> + +<p>There are basically five ways to run a Fossil server:</p> + +<ol> + <li><a href="any/cgi.md">CGI</a> + <li><a href="#slist">Socket listener</a> + <li><a href="any/none.md">Stand-alone HTTP server</a> + <li><a href="any/scgi.md">SCGI</a> + <li><a href="#ssh">SSH</a> +</ol> + +<p>All of these methods can serve either a single repository or a +directory hierarchy containing multiple repositories.</p> + +<p>You are not restricted to a single server setup. The same Fossil +repository can be served using two or more of the above techniques at +the same time. These methods use clean, well-defined, standard +interfaces (CGI, SCGI, and HTTP) which allow you to easily migrate from +one method to another in response to changes in hosting providers or +administrator preferences.</p> + +<h3 id="cgi">CGI</h3> + +<p>Most ordinary web servers can <a href="any/cgi.md">run Fossil as a +CGI script</a>. This method is known to work with Apache, +<tt>lighttpd</tt>, and <a +href="any/althttpd.md"><tt>althttpd</tt></a>. The Fossil server +administrator places a <a href="$ROOT/help/cgi">short CGI script</a> in +the web server's document hierarchy and when a client requests the URL +that corresponds to that script, Fossil runs and generates the +response.</p> + +<p>CGI is a good choice for merging Fossil into an existing web site, +particularly on hosts that have CGI set up and working. +The Fossil <a href="../selfhost.wiki">self-hosting repositories</a> are +implemented with CGI underneath <tt>althttpd</tt>.</p> + +<h3 id="slist">Socket Listener</h3> + +<p>Socket listener daemons such as +<a id="inetd" href="any/inetd.md"><tt>inetd</tt></a>, <a id="xinetd" +href="any/xinetd.md"><tt>xinetd</tt></a>, <a id="stunnel" +href="any/stunnel.md"><tt>stunnel</tt></a>, <a +href="macos/service.md"><tt>launchd</tt></a>, and <a +href="debian/service.md"><tt>systemd</tt></a> +can be configured to invoke the the +<a href="$ROOT/help/http"><tt>fossil http</tt></a> command to handle +each incoming HTTP request. The "<tt>fossil http</tt>" command reads +the HTTP request off of standard input, computes an appropriate +reply, and writes the reply on standard output. There is a separate +invocation of the "<tt>fossil http</tt>" command for each HTTP request. +The socket listener daemon takes care of relaying content to and from +the client, and (in the case of <a href="any/stunnel.md">stunnel</a>) +handling TLS decryption and encryption. + +<h3 id="standalone">Stand-alone HTTP Server</h3> + +<p>This is the <a href="any/none.md">easiest method</a>. +A stand-alone server uses the +<a href="$ROOT/help/server"><tt>fossil server</tt></a> command to run a +process that listens for incoming HTTP requests on a socket and then +dispatches a copy of itself to deal with each incoming request. You can +expose Fossil directly to the clients in this way or you can interpose a +<a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> +layer between the clients and Fossil.</p> + +<h3 id="scgi">SCGI</h3> + +<p>The Fossil standalone server can also handle <a href="any/scgi.md">SCGI</a>. +When the <a href="$ROOT/help/server"><tt>fossil server</tt></a> command is +run with the extra <tt>--scgi</tt> option, it listens for incoming +SCGI requests rather than HTTP requests. This allows Fossil to +respond to requests from web servers <a href="debian/nginx.md">such as +nginx</a> that don't support CGI. SCGI is a simpler protocol to proxy +than HTTP, since the HTTP doesn't have to be re-interpreted in terms of +the proxy's existing HTTP implementation, but it's more complex to set +up because you also have to set up an SCGI-to-HTTP proxy for it. It is +worth taking on this difficulty only when you need to integrate Fossil +into an existing web site already being served by an SCGI-capable web +server.</p> + +<h3 id="ssh">SSH</h3> + +<p>Fossil supports <tt>ssh://</tt> URLs, but there are <a +href="../caps/#webonly">practical limitations</a> with the default +behavior. You can get the full power of <a href="../caps/">Fossil's RBAC +system</a> over SSH <a href="any/http-over-ssh.md">with a bit of clever +configuration</a>.</p> + +<h2 id="matrix">Activation Tutorials</h2> + +<p>We've broken the configuration for each method out into a series of +sub-articles. Some of these are generic, while others depend on +particular operating systems or front-end software:</p> + +<div class="indent"><table> + <tr> + <th class="host">⇩ OS / Method ⇨</th> + <th class="fep">direct</th> + <th class="fep">inetd</th> + <th class="fep">stunnel</th> + <th class="fep">CGI</th> + <th class="fep">SCGI</th> + <th class="fep">FastCGI</th> + <th class="fep">althttpd</th> + <th class="fep">proxy</th> + <th class="fep">service</th> + </tr> + + <tr> + <th class="host"><a href="any/">Any</a></th> + <td class="doc"><a href="any/none.md">✅</a></td> + <td class="doc"><a href="any/inetd.md">✅</a></td> + <td class="doc"><a href="any/stunnel.md">✅</a></td> + <td class="doc"><a href="any/cgi.md">✅</a></td> + <td class="doc"><a href="any/scgi.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="any/althttpd.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc">❌</td> + </tr> + + <tr> + <th class="host"><a href="debian/">Debian/Ubuntu</a></th> + <td class="doc"><a href="any/none.md">✅</a></td> + <td class="doc"><a href="any/inetd.md">✅</a></td> + <td class="doc"><a href="any/stunnel.md">✅</a></td> + <td class="doc"><a href="any/cgi.md">✅</a></td> + <td class="doc"><a href="any/scgi.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="any/althttpd.md">✅</a></td> + <td class="doc"><a href="debian/nginx.md">✅</a></td> + <td class="doc"><a href="debian/service.md">✅</a></td> + </tr> + + <tr> + <th class="host"><a href="macos/">macOS</a></th> + <td class="doc"><a href="any/none.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="any/stunnel.md">✅</a></td> + <td class="doc"><a href="any/cgi.md">✅</a></td> + <td class="doc"><a href="any/scgi.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="any/althttpd.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="macos/service.md">✅</a></td> + </tr> + + <tr> + <th class="host"><a href="openbsd/">OpenBSD</a></th> + <td class="doc"><a href="any/none.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="any/stunnel.md">✅</a></td> + <td class="doc"><a href="any/cgi.md">✅</a></td> + <td class="doc"><a href="any/scgi.md">✅</a></td> + <td class="doc"><a href="openbsd/fastcgi.md">✅</a></td> + <td class="doc"><a href="any/althttpd.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="openbsd/service.wiki">✅</a></td> + </tr> + + <tr> + <th class="host"><a href="windows/">Windows</a></th> + <td class="doc"><a href="windows/none.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc"><a href="windows/stunnel.md">✅</a></td> + <td class="doc"><a href="windows/cgi.md">✅</a></td> + <td class="doc">❌</td> + <td class="doc">❌</td> + <td class="doc">❌</td> + <td class="doc"><a href="windows/iis.md">✅</a></td> + <td class="doc"><a href="windows/service.md">✅</a></td> + </tr> +</table></div> + +<p>Where there is a check mark in the "<b>Any</b>" row, the method for that is +generic enough that it works across OSes that Fossil is known to work +on. The check marks below that usually just link to this generic +documentation.</p> + +<p>The method in the "<b>proxy</b>" column is for the platform's default +web server configured as a <a +href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a> for +Fossil's built-in HTTP server: <a href="debian/nginx.md">nginx</a>, <a +href="windows/iis.md">IIS</a>, Apache, etc.</p> + +<p>We welcome <a href="../contribute.wiki">contributions</a> to fill gaps +(<font size="-2">❌</font>) in the table above.</p> +</noscript> + + +<h2 id="postsetup">Post-Activation Configuration</h2> + +<p>After the server is up and running, log into it as the Setup user and +visit the Admin menu to finish configuring that repository for +service:</p> + +<ol> + <li><p>Add user accounts for your other team members. Use <a + href="../caps/index.md#ucat">categories</a> to define access policies + rather than redundantly give each new user the same <a + href="../caps/index.md#ucap">individual capabilities</a>.</p></li> + + <li><p>Test access to the repository from each category of non-Setup + user that you created. You may have to give your user categories some + overlooked capabilities, particularly if you followed <a + href="#prep">our earlier advice</a> to take the repository private + prior to setting up the server.</p></li> + + <li><p>Modify the repository's look and feel by <a + href="../customskin.md">customizing the skin</a>.</p></li> + + <li><p>If the repository includes <a + href="../embeddeddoc.wiki">embedded documentation</a>, consider + activating the search feature (Admin → Search) so that visitors can do + full-text search on your documentation.</p></li> + + <li><p>Now that others can be making changes to the repository, + consider monitoring them via <a href="../alerts.md">email alerts</a> + or the <a href="$ROOT/help/www/timeline.rss">timeline RSS + feed</a>.</p></li> + + <li><p>Turn on the various logging features.</p></li> +</ol> + +<p>Reload the Admin → Security-Audit page occasionally during this +process to double check that you have not mistakenly configured the +server in a way that might expose information that you want to keep +private.</p> + + +<h2 id="more">Further Details</h2> + +<ul> + <li><a id="chroot" href="../chroot.md" >The Server Chroot Jail</a> + <li><a id="loadmgmt" href="../loadmgmt.md" >Managing Server Load</a> + <li><a id="bkofc" href="../backoffice.md" >The Backoffice</a> + <li><a id="tls" href="../ssl.wiki" >Securing a Repository with TLS</a> + <li><a id="ext" href="../serverext.wiki">CGI Server Extensions</a> + <li><a id="about" href="../aboutcgi.wiki" >How CGI Works In Fossil</a> + <li><a id="sync" href="../sync.wiki" >The Fossil Sync Protocol</a> +</ul> + +</div> diff --git a/www/server/macos/index.md b/www/server/macos/index.md new file mode 100644 index 0000000..52c9ef9 --- /dev/null +++ b/www/server/macos/index.md @@ -0,0 +1,5 @@ +# macOS Specific Fossil Service Options + +- [Running Fossil under `launchd`](./service.md) + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/macos/service.md b/www/server/macos/service.md new file mode 100644 index 0000000..b1358fa --- /dev/null +++ b/www/server/macos/service.md @@ -0,0 +1,181 @@ +# Serving via launchd on macOS + +[`launchd`][ldhome] is the default service management framework on macOS +[since the release of Tiger in 2005][wpa]. If you want a Fossil server +to launch in the background on a Mac, it’s the way Apple wants you to do +it. `launchd` is to macOS as `systemd` is to most modern Linux desktop +systems. (Indeed, `systemd` arguably reinvented the perfectly good, +pre-existing `launchd` wheel.) + +Unlike in [our `systemd` article](../debian/service.md), we’re not going +to show the per-user method here, because those so-called +[LaunchAgents][la] only start when a user is logged into the GUI, and +they stop when that user logs out. This does not strike us as proper +“server” behavior, so we’ll stick to system-level LaunchDaemons instead. + +However, we will still give two different configurations, just as in the +`systemd` article: one for a standalone HTTP server, and one using +socket activation. + +For more information on `launchd`, the single best resource we’ve found +is [launchd.info](https://launchd.info). The next best is: + + $ man launchd.plist + +[la]: http://www.grivet-tools.com/blog/2014/launchdaemons-vs-launchagents/ +[ldhome]: https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html +[wpa]: https://en.wikipedia.org/wiki/Launchd + + + +## Standalone HTTP Server + +To configure `launchd` to start Fossil as a standalone HTTP server, +write the following as `com.example.dev.FossilHTTP.plist`: + +```xml +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>Label</key> + <string>com.example.dev.FossilHTTP</string> + <key>ProgramArguments</key> + <array> + <string>/usr/local/bin/fossil</string> + <string>server</string> + <string>--port</string> + <string>9000</string> + <string>repo.fossil</string> + </array> + <key>WorkingDirectory</key> + <string>/Users/you/museum</string> + <key>KeepAlive</key> + <true/> + <key>RunAtLoad</key> + <true/> + <key>StandardErrorPath</key> + <string>/tmp/fossil-error.log</string> + <key>StandardOutPath</key> + <string>/tmp/fossil-info.log</string> + <key>UserName</key> + <string>you</string> + <key>GroupName</key> + <string>staff</string> + <key>InitGroups</key> + <true/> +</dict> +</plist> +``` + +In this example, we’re assuming your development organization uses the +domain name “`dev.example.org`”, that your short macOS login name is +“`you`”, and that you store your Fossils in “`~/museum`”. Adjust these +elements of the plist file to suit your local situation. + +You might be wondering about the use of `UserName`: isn’t Fossil +supposed to drop privileges and enter [a `chroot(2)` +jail](../../chroot.md) when it’s started as root like this? Why do we +need to give it a user name? Won’t Fossil use the owner of the +repository file to set that? All I can tell you is that in testing here, +if you leave the user and group configuration at the tail end of that +plist file out, Fossil will remain running as root! + +Install that file and set it to start with: + + $ sudo install -o root -g wheel -m 644 com.example.dev.FossilHTTP.plist \ + /Library/LaunchDaemons/ + $ sudo launchctl load -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist + +Because we set the `RunAtLoad` key, this will also launch the daemon. + +Stop the daemon with: + + $ sudo launchctl unload -w /Library/LaunchDaemons/com.example.dev.FossilHTTP.plist + + +## Socket Listener + +Another useful method to serve a Fossil repo via `launchd` is by setting +up a socket listener: + +```xml +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" + "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>Label</key> + <string>com.example.dev.FossilSocket</string> + <key>ProgramArguments</key> + <array> + <string>/usr/local/bin/fossil</string> + <string>http</string> + <string>repo.fossil</string> + </array> + <key>Sockets</key> + <dict> + <key>Listeners</key> + <dict> + <key>SockServiceName</key> + <string>9001</string> + <key>SockType</key> + <string>stream</string> + <key>SockProtocol</key> + <string>TCP</string> + <key>SockFamily</key> + <string>IPv4</string> + </dict> + </dict> + <key>inetdCompatibility</key> + <dict> + <key>Wait</key> + <false/> + </dict> + <key>WorkingDirectory</key> + <string>/Users/you/museum</string> + <key>UserName</key> + <string>you</string> + <key>GroupName</key> + <string>staff</string> + <key>InitGroups</key> + <true/> +</dict> +</plist> +``` + +Save it as “`com.example.dev.FossilSocket.plist`” and install and load +it into `launchd` as above. + +This version differs in several key ways: + +1. We’re calling Fossil as `fossil http` rather than `fossil server` to + make it serve a single request and then shut down immediately. + +2. We’ve told `launchd` to listen on our TCP port number instead of + passing it to `fossil`. + +3. We’re running the daemon in `inetd` compatibility mode of `launchd` + with “wait” mode off, which tells it to attach the connected socket + to the `fossil` process’s stdio handles. + +4. We’ve removed the `Standard*Path` keys because they interfere with + our use of stdio handles for HTTP I/O. You might therefore want to + start with the first method and then switch over to this one only + once you’ve got the daemon launching debugged, since once you tie up + stdio this way, you won’t be able to get logging information from + Fossil via that path. (Fossil does have some internal logging + mechanisms, but you can’t get at them until Fossil is launching!) + +5. We’ve removed the `KeepAlive` and `RunAtLoad` keys because those + options aren’t appropriate to this type of service. + +6. Because we’re running it via a socket listener instead of as a + standalone HTTP server, the Fossil service only takes system + resources when it’s actually handling an HTTP hit. If your Fossil + server is mostly idle, this method will be a bit more efficient than + the first option. + + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/openbsd/fastcgi.md b/www/server/openbsd/fastcgi.md new file mode 100644 index 0000000..70db94b --- /dev/null +++ b/www/server/openbsd/fastcgi.md @@ -0,0 +1,302 @@ +# Serving via httpd on OpenBSD + +[`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 id="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 660 /var/www/logs/fossil.log +$ doas chmod 755 /var/www/cgi-bin/scm +``` + +## <a id="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 and then mount it on to +`/var/www/dev` with [`mount_mfs(8)`][mfs] so that the `random` and +`null` device files can be created. In order to avoid necessitating a +startup script to recreate the device files at boot, create a template +of the needed ``/dev`` tree to automatically populate the memory +filesystem. + +```console +$ doas mkdir /var/www/dev +$ doas install -d -g daemon /template/dev +$ cd /template/dev +$ doas /dev/MAKEDEV urandom +$ doas mknod -m 666 null c 2 2 +$ doas mount_mfs -s 1M -P /template/dev /dev/sd0b /var/www/dev +$ ls -l +total 0 +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,-P=/template/dev 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 770 /var/www/htdocs/fsl.domain.tld +``` + +## <a id="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 +server "fsl.domain.tld" { + listen on * port http + root "/htdocs/fsl.domain.tld" + location "/.well-known/acme-challenge/*" { + root "/acme" + request strip 2 + } + location * { + block return 301 "https://$HTTP_HOST$REQUEST_URI" + } + location "/*" { + fastcgi { param SCRIPT_FILENAME "/cgi-bin/scm" } + } +} + +server "fsl.domain.tld" { + listen on * tls port https + root "/htdocs/fsl.domain.tld" + tls { + certificate "/etc/ssl/domain.tld.fullchain.pem" + key "/etc/ssl/private/domain.tld.key" + } + 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 + } +} +``` + +[The default limit][dlim] for HTTP messages in OpenBSD’s `httpd` server +is 1 MiB. Fossil chunks its sync protocol such that this is not +normally a problem, but when sending [unversioned content][uv], it uses +a single message for the entire file. Therefore, if you will be storing +files larger than this limit as unversioned content, you need to raise +the limit as we’ve done above with the “`connection max request body`” +setting, raising the limit to 100 MiB. + +[dlim]: https://man.openbsd.org/httpd.conf.5#connection +[uv]: ../../unvers.wiki + +**NOTE:** If not already in possession of an 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 id="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" +} + +authority letsencrypt-staging { + api url "https://acme-staging.api.letsencrypt.org/directory" + account key "/etc/acme/letsencrypt-staging-privkey.pem" +} + +domain domain.tld { + alternative names { www.domain.tld fsl.domain.tld } + 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 id="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 id="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.](../)* diff --git a/www/server/openbsd/index.md b/www/server/openbsd/index.md new file mode 100644 index 0000000..ea4f95f --- /dev/null +++ b/www/server/openbsd/index.md @@ -0,0 +1,6 @@ +# Debian/Ubuntu Specific Fossil Service Options + +- [Serving Fossil under OpenBSD’s `httpd` via FastCGI](./fastcgi.md) +- [Running Fossil as a service on OpenBSD](./service.wiki) + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/openbsd/service.wiki b/www/server/openbsd/service.wiki new file mode 100644 index 0000000..8729eb0 --- /dev/null +++ b/www/server/openbsd/service.wiki @@ -0,0 +1,118 @@ +<title>Serving via rc on OpenBSD</title> + +OpenBSD provides [https://man.openbsd.org/rc.subr.8|rc.subr(8)], +a framework for writing [https://man.openbsd.org/rc.8|rc(8)] scripts. + +<h2>Creating the daemon</h2> + +Create the file /etc/rc.d/fossil with contents like the following. + +<pre> +#!/bin/ksh +daemon="/usr/local/bin/fossil" # fossil executable +daemon_user="_fossil" # user to run fossil as +daemon_flags="server /home/_fossil/example --repolist --port 8888" # fossil command + +. /etc/rc.d/rc.subr +# pexp="$daemon server .*" # See below. +rc_reload=NO # Unsupported by Fossil; 'rcctl reload fossil' kills the process. +rc_bg=YES # Run in the background, since fossil serve does not daemonize itself +rc_cmd $1 +</pre> + +<h3>pexp</h3> + +You may need to uncomment the "pexp=". rc.subr typically +finds the daemon process based by matching the process name and argument list. +Without the "pexp=" line, rc.subr would look for this exact command: + +<pre> +/usr/local/bin/fossil server /home/_fossil/example --repolist --port 8888 +</pre> + +Depending on the arguments and their order, fossil may rewrite the arguments +for display in the process listing ([https://man.openbsd.org/ps.1|ps(1)]), +so rc.subr may fail to find the process through the default match. The example +above does not get rewritten, but the same commands in a different order can +be rewritten. +For example, when I switch the order of the arguments in "daemon_flags", + +<pre> +/usr/local/bin/fossil server --repolist --port 8888 /home/_fossil/example +</pre> + +the process command is changed to this. + +<pre> +/usr/local/bin/fossil server /home/_fossil/example /home/_fossil/example 8888 /home/_fossil/example +</pre> + +The commented "pexp=" line instructs rc.subr to choose the process whose +command and arguments text starts with this: + +<pre> +/usr/local/bin/fossil server +</pre> + +<h2>Enabling the daemon</h2> + +Once you have created /etc/rc.d/fossil, run these commands. + +<pre> +rcctl enable fossil # add fossil to pkg_scripts in /etc/rc.conf.local +rcctl start fossil # start the daemon now +</pre> + +The daemon should now be running and set to start at boot. + +<h2>Multiple daemons</h2> + +You may want to serve multiple fossil instances with different options. +For example, + + * If different users own different repositories, you may want different users + to serve different repositories. + * You may want to serve different repositories on different ports so you can + control them differently with, for example, HTTP reverse proxies or + [https://man.openbsd.org/pf.4|pf(4)]. + +To run multiple fossil daemons, create multiple files in /etc/rc.d, and +enable each of them. Here are two approaches for creating +the files in /etc/rc.d: Symbolic links and copies. + +<h3>Symbolic links</h3> + +Suppose you want to run one fossil daemon as user "user1" on port 8881 +and another as user "user2" on port 8882. Create the files with +[https://man.openbsd.org/ln.1|ln(1)], and configure them to run different +fossil commands. + +<pre> +cd /etc/rc.d +ln -s fossil fossil1 +ln -s fossil fossil2 +rcctl enable fossil1 fossil2 +rcctl set fossil1 user user1 +rcctl set fossil2 user user2 +rcctl set fossil1 flags 'server /home/user1/repo1.fossil --port 8881' +rcctl set fossil2 flags 'server /home/user2/repo2.fossil --port 8882' +rcctl start fossil1 fossil2 +</pre> + +<h3>Copies</h3> + +You may want to run fossil daemons that are too different to configure +just with [https://man.openbsd.org/rcctl.8|rcctl(8)]. +In particular, you can't change the "pexp" with rcctl. + +If you want to run fossil commands that are more different, +you may prefer to create separate files in /etc/rc.d. +Replace "ln -s" above with "cp" to accomplish this. + +<pre> +cp /etc/rc.d/fossil /etc/rc.d/fossil-user1 +cp /etc/rc.d/fossil /etc/rc.d/fossil-user2 +</pre> + +You can still use commands like "rcctl set fossil-user1 flags", but you +can also edit the "/etc/rc.d/fossil-user1" file. diff --git a/www/server/whyuseaserver.wiki b/www/server/whyuseaserver.wiki new file mode 100644 index 0000000..cdd9823 --- /dev/null +++ b/www/server/whyuseaserver.wiki @@ -0,0 +1,95 @@ +<title>Benefits of a Fossil Server</title> + +<h2>No Server Required</h2> + +Fossil does not require a central server. +Data sharing and synchronization can be entirely peer-to-peer. +Fossil uses +[https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type | +conflict-free replicated data types] +to ensure that (in the limit) all participating peers see the same content. + +<h2>But, a Server Can Be Useful</h2> + +Fossil does not require a server, but a server can be very useful. +Here are a few reasons to set up a Fossil server for your project: + + 1. <b>A server works as a complete project website.</b> + + Fossil does more than just version control. It also supports + [../tickets.wiki|trouble-tickets], + [../wikitheory.wiki|wiki], + a [../chat.md|developer chat room], and a [../forum.wiki|forum]. + The [../embeddeddoc.wiki|embedded documentation] + feature provides a great mechanism for providing project documentation. + The [../unvers.wiki|unversioned files] feature is a convenient way + to host builds and downloads on the project website. + + 2. <b>A server gives developers a common point of rendezvous for + syncing their work.</b> + + It is possible for developers to synchronize peer-to-peer but + that requires the developers coordinate the sync, which in turn + requires that the developers both want to sync at the same moment. + A server alleviates this time dependency by allowing each developer + to sync whenever it is convenient. For example, a developer may + choose to automatically sync + after each commit and before each update. Developers all stay + in sync with each other without having to interrupt each other + constantly to set up a peer-to-peer sync. + + 3. <b>A server provides project leaders with up-to-date status.</b> + + Project coordinators and BDFLs can click on a link or two at the + central Fossil server for a project and quickly tell what is + going on. They can do this from anywhere — even from their phones + — without needing to actually sync to the device they are using. + + 4. <b>A server provides automatic off-site backups.</b> + + A Fossil server is an automatic remote backup for all the work + going into a project. ([../backup.md | Within limits].) + You can even set up multiple servers at + multiple sites with automatic synchronization between them for + added redundancy. Such a setup means that no work is lost due + to a single machine failure. + + 5. <b>A server consolidates [https://www.sqlite.org/howtocorrupt.html + | SQLite corruption risk mitigation] to a single point.</b> + + The concerns in section 1 of that document assume you have direct + access to the central DB files, which isn't the case when the + server is remote and secure against tampering. + + Section 2 is about file locking, which concerns disappear when Fossil's + on the other side of an HTTP boundary and your server is set up + properly. + + Sections 3.1, 4 thru 6, and 8 apply to all Fossil configurations, + but setting up a server lets you address the risks + in a single place. Once a given commit is + sync'd to the server, you can be reasonably sure any client-side + corruption can be fixed with a fresh clone. Ultimately, this + is an argument for off-machine backups, which returns us to reason + #4 above. + + Sections 3.2 and the entirety of section 7 are no concern with + Fossil at all, since it's primarily written by the creator and + primary maintainer of SQLite, so you can be certain Fossil doesn't + actively pursue coding strategies known to risk database corruption. + + For another take on this topic, see the article + "[https://sqlite.org/useovernet.html | SQLite Over a Network, + Caveats and Considerations]". Fossil runs in rollback mode by + default per recommendation #3 at the end of that article, and a + Fossil server operates as a network proxy for the underlying + SQLite repository DB per recommendation #2. This <i>may</i> permit + you to safely switch it into WAL mode (<b>fossil rebuild --wal</b>) + depending on the underlying storage used by the server itself. + + 6. <b>A server allows [../caps/ | Fossil's RBAC system] to work.</b> + + The role-based access control (RBAC) system in Fossil only works + when the remote system is on the other side of an HTTP barrier. + ([../caps/#webonly | Details].) If you want its benefits, you need + a Fossil server setup of some kind. diff --git a/www/server/windows/cgi-bin-perm.png b/www/server/windows/cgi-bin-perm.png Binary files differnew file mode 100644 index 0000000..92ec090 --- /dev/null +++ b/www/server/windows/cgi-bin-perm.png diff --git a/www/server/windows/cgi-exec-perm.png b/www/server/windows/cgi-exec-perm.png Binary files differnew file mode 100644 index 0000000..5cfc2e3 --- /dev/null +++ b/www/server/windows/cgi-exec-perm.png diff --git a/www/server/windows/cgi-install-iis.png b/www/server/windows/cgi-install-iis.png Binary files differnew file mode 100644 index 0000000..ef6eb67 --- /dev/null +++ b/www/server/windows/cgi-install-iis.png diff --git a/www/server/windows/cgi-script-map.png b/www/server/windows/cgi-script-map.png Binary files differnew file mode 100644 index 0000000..bccc2fb --- /dev/null +++ b/www/server/windows/cgi-script-map.png diff --git a/www/server/windows/cgi.md b/www/server/windows/cgi.md new file mode 100644 index 0000000..768c76f --- /dev/null +++ b/www/server/windows/cgi.md @@ -0,0 +1,115 @@ +# Serving via IIS + CGI + +## This Is Not the Method You Are Looking For + +Setting up CGI service under IIS is surprisingly complicated compared to +running Fossil as a CGI under most other operating systems. We recommend +that you use the simpler [reverse proxying method](./iis.md) instead +unless there is some compelling reason why that method cannot work for +you, such as its dependence on non-stock IIS extensions. (Keep in mind +that both extensions it requires are by Microsoft, not third parties!) + +Once you’ve got this scheme working, it gives the same benefits as those +listed at the top of the linked-to document. + +There is a small benefit you get from using CGI over reverse proxying on +other OSes, which is that the Fossil program only runs briefly in order +to serve each HTTP hit. Once the request is done, that Fossil instance +shuts back down, releasing all of its resources. You don’t need to keep +a background Fossil HTTP server running full-time to provide CGI-based +Fossil service. + +You lose a lot of that benefit on Windows: + +1. It only matters to start with on servers that are highly RAM + constrained. (Roughly ≤ 128 MiB.) Our configuration steps below + assume you’re using the Windows and IIS GUIs, which have RAM + requirements well in excess of this, making Fossil’s resource + requirements a drop in the bucket next to them. On the [Azure + B1s][b1s] virtual machine I used to prepare these instructions, the + Windows Server Manager GUI kept filling the VM’s 1 GiB of RAM + during feature installation and crashing. I had to upgrade the VM’s + RAM to 2 GiB just to get useful work done! + +2. Process creation on Windows is [much more expensive][cp] than on the + other OSes Fossil runs on, so the benefits of firing up a Fossil + executable to process each HTTP request are partially swamped by the + overhead of doing so. + +Therefore, unless you’re willing to replace all of the GUI configuration +steps below with command line equivalents, or shut the GUI down entirely +after configuring IIS, CGI is a much less compelling option on Windows. + +**WARNING:** The following tutorial appears to fail with the current +(2019-08-17) version of Fossil, [apparently][fbug] due to an inability +of Fossil to detect that it’s being run in CGI mode. + +[b1s]: https://azure.microsoft.com/en-us/blog/introducing-b-series-our-new-burstable-vm-size/ +[cp]: https://stackoverflow.com/a/48244/142454 +[fbug]: https://fossil-scm.org/forum/forumpost/de18dc32c0 + + +## Install IIS with CGI Support + +The steps for this are identical to those for the [reverse proxying IIS +setup](./iis.md#install) except that you need to enable CGI in the last +step, since it isn’t installed by default. For Windows Server, the path +is: + + + +The path is similar on the consumer-focused versions of Windows, once +you get to that last step. + + +## Setup + +1. Install the Fossil executable to `c:\inetpub\wwwroot\bin` on the web + server. We can’t use an executable you might already have because IIS + runs under a separate user account, so we need to give that + executable special permissions, and that’s easiest to do under the + IIS tree: + +  + +2. In IIS Manager (a.k.a. `INETMGR`) drill down into the Sites folder + in the left-side pane and right-click your web site’s + configuration. (e.g. “Default Web Site”) + +3. On that menu say “Add Virtual Directory.” Give it the alias “`cgi`” + and point it at a suitable directory, such as + “`c:\inetpub\wwwroot\cgi`”. + +4. Double-click the “Handler Mappings” icon, then in the right-side + pane, click “Add Script Map...” Apply the following settings: + +  + + The Executable path must point to the path we set up in step 1, not + to some other `fossil.exe` you may have elsewhere on your system. + You will need to change the default “`*.dll`” filter in the Open + dialog to “`*.exe`” in order to see it when browsing via the “`...`” + button. + +5. Create a file called `repo.fslcgi` within the CGI directory you + chose in step 3, with a single line like this: + + repository: c:\Users\SOMEONE\museum\repo.fossil + + Give the actual path to the repository, of course. + +6. Up at the top level of IIS Manager, double-click the “ISAPI and CGI + Restrictions” icon, then click “Add...” in the right-side pane. + Give the script you just created permission to execute: + +  + +7. In the right-side pane, click “Restart” to apply this configuration, + then test it by visiting the newly-available URL in a browser: + + http://localhost/cgi/repo.fslcgi + +For more complicated setups such as “directory” mode, see [the generic +CGI instructions](../any/cgi.md). + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/windows/iis.md b/www/server/windows/iis.md new file mode 100644 index 0000000..9107da1 --- /dev/null +++ b/www/server/windows/iis.md @@ -0,0 +1,134 @@ +# Serving via IIS + +## Why Bother? + +The first part of the scheme below sets Fossil up as an HTTP server, so +you might be wondering why you wouldn’t just modify that to make it +listen on all network interfaces on TCP port 80, so you can avoid the +need for IIS entirely. For simple use cases, you can indeed do without +IIS, but there are several use cases where adding it is helpful: + +1. Proxying Fossil with IIS lets you [add TLS encryption][tls], which + [Fossil does not currently speak](../../ssl.wiki) in its server role. + +2. The URL rewriting we do below allows Fossil to be part of a larger + site already being served with IIS. + +3. You can have a mixed-mode site, with Fossil acting as a powerful + dynamic content management service and IIS as a fast static content + server. The pure-Fossil alternative requires that you check all of + your static content into Fossil as versioned or unversioned + artifacts. + +This article shows how you can get any combination of those benefits by +using IIS as a reverse proxy for `fossil server`. + +There are other ways to use IIS to serve Fossil, such as [via +CGI](./cgi.md). + + +## Background Fossil Service Setup + +You will need to have the Fossil HTTP server running in the background, +serving some local repository, bound to localhost on a fixed +high-numbered TCP port. For the purposes of testing, simply start it by +hand in your command shell of choice: + + fossil serve --port 9000 --localhost repo.fossil + +That command assumes you’ve got `fossil.exe` in your `%PATH%` and you’re +in a directory holding `repo.fossil`. See [the platform-independent +instructions](../any/none.md) for further details. + +For a more robust setup, we recommend that you [install Fossil as a +Windows service](./service.md), which will allow Fossil to start at +system boot, before anyone has logged in interactively. + + +## <a id="install"></a>Install IIS + +IIS might not be installed in your system yet, so follow the path +appropriate to your host OS. We’ve tested only the latest Microsoft +OSes as of the time of this writing, but the basic process should be +similar on older OSes. + + +### Windows Server 2019 + +1. Start “Server Manager” +2. Tell it you want to “Add roles and features” +3. Select “Role-based or feature-based installation” +4. Select your local server +5. In the Server Roles section, enable “Web Server (IIS)” + +### Windows + +1. Open Control Panel +2. Go to “Programs” +3. Select “Turn Windows features on or off” in the left-side pane +4. In the “Windows Features” dialog, enable “Internet Information + Services” + +The default set of IIS features there will suffice for this tutorial, +but you might want to enable additional features. + + +## Setting up the Proxy + +The stock IIS setup doesn’t have reverse proxying features, but they’re +easily added through extensions. You will need to install the +[Application Request Routing][arr] and [URL Rewrite][ure] extensions. In +my testing here, URL Rewrite showed up immediately after installing it, +but I had to reboot the server to get ARR to show up. (Yay Windows.) + +You can install these things through the direct links above, or you can +do it via the Web Platform Installer feature of IIS Manager (a.k.a. +`INETMGR`). + +Set these extensions up in IIS Manager like so: + +1. Double-click the “Application Request Routing Cache” icon. + +2. Right-click in the window that results, and select “Server Proxy + Settings...” + +3. Check the “Enable Proxy” box in the dialog. Click the “Apply” text + in the right-side pane. + +4. Return to the top server-level configuration area of IIS Manager and + double-click the “URL Rewrite” icon. Alternately, you might find + “URL Rewrite” in the right-side pane from within the ARR settings. + +5. Right click in the window that results, and click “Add Rule(s)...” + Tell it you want a “Blank rule” under “Inbound rules”. + +6. In the dialog that results, create a new rule called “Fossil repo + proxy.” Set the “Pattern” to “`^(.*)$`” and “Rewrite URL” set to + “`http://localhost:9000/{R:1}`”. That tells it to take everything in + the path part of the URL and send it down to localhost:9000, where + `fossil server` is listening. + +7. Click “Apply” in the right-side pane, then get back to the top level + configuration for the server, and click “Restart” in that same pane. + +At this point, if you go to `http://localhost/` in your browser, you +should see your Fossil repository’s web interface instead of the default +IIS web site, as before you did all of the above. + +This is a very simple configuration. You can do more complicated and +interesting things with this, such as redirecting only `/code` URLs to +Fossil by setting the Pattern in step 6 to “`^/code(.*)$`”. (You would +also need to pass `--baseurl http://example.com/code` in the `fossil +server` command to make this work properly.) IIS would then directly +serve all other URLs. You could also intermix ASP.NET applications in +the URL scheme in this way. + +See the documentation on [URL Rewrite rules][urr] for more ideas. + +*[Return to the top-level Fossil server article.](../)* + + +[arr]: https://www.iis.net/downloads/microsoft/application-request-routing +[tls]: https://docs.microsoft.com/en-us/iis/manage/configuring-security/understanding-iis-url-authorization +[ure]: https://www.iis.net/downloads/microsoft/url-rewrite +[urr]: https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/creating-rewrite-rules-for-the-url-rewrite-module diff --git a/www/server/windows/index.md b/www/server/windows/index.md new file mode 100644 index 0000000..a30b00a --- /dev/null +++ b/www/server/windows/index.md @@ -0,0 +1,8 @@ +# Using Windows as a Fossil Server + +- [Fossil server command](./none.md) +- [Fossil as CGI (IIS)](./iis.md) +- [Fossil as a Service](./service.md) +- [Using stunnel with Fossil on Windows](./stunnel.md) + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/windows/none.md b/www/server/windows/none.md new file mode 100644 index 0000000..eab222d --- /dev/null +++ b/www/server/windows/none.md @@ -0,0 +1,69 @@ +# Serving as a Standalone Server on Windows + +On Windows, this method works more or less identically to how it’s +documented in [the generic instructions](../any/none.md). + +...but only while `fossil.exe` is actually running, which is the source +of much trouble on Windows. This problem has two halves: + + +## No App Startup Without Desktop + +The easy methods for starting a program in Windows at system start all +require an interactive desktop. There is no *easy* way to start an arbitrary +program on Windows at boot before anyone has logged in. In Unix +terms, Windows has no simple equivalent to [the `/etc/rc.local` file][rcl]. + +You can partially get around the first problem by setting your `fossil +server` call up as one of the user’s interactive startup items. Windows +10 has its own [idiosyncratic way of doing this][si10], and in older +systems you have [several alternatives to this][si7]. Regardless of the +actual mechanism, these will cause the Fossil standalone HTTP server to +start on an *interactive desktop login* only. While you’re sitting at +the Windows login screen, the Fossil server is *down*. + +[rcl]: http://nixdoc.net/man-pages/FreeBSD/man8/rc.local.8.html +[si10]: https://www.tenforums.com/tutorials/2944-add-delete-enable-disable-startup-items-windows-10-a.html +[si7]: https://www.wikihow.com/Change-Startup-Programs-in-Windows-7 + + + +## No Simple Background Mode + +Windows also lacks a direct equivalent of the Bourne shell’s “`&`” control operator to +run a program in the background, which you can give in Unix’s `rc.local` +file, which is just a normal Bourne shell script. + +By “background,” I mean +“not attached to any interactive user’s login session.” When the +`rc.local` script exits in Unix, any program it backgrounded *stays +running*. There is no simple and direct equivalent to this mechanism in +Windows. + +If you set `fossil server` to run on interactive login, as above, it +will shut right back down again when that user logs back out. + +With Windows 10, it’s especially problematic because you can no longer +make the OS put off updates arbitrarily: your Fossil server will go down +every time Windows Update decides it needs to reboot your computer, and +then Fossil service will *stay* down until someone logs back into that +machine interactively. + + +## Better Solutions + +Because of these problems, we only recommend setting `fossil server` up +on Windows this way when +you’re a solo developer or you work in a small office where everyone +arrives more or less at the same time each day, and everyone goes home +about the same time each day, so that one user can keep the Fossil +server up through the working day. + +If your needs go at all beyond this, you should expect proper “server” +behavior, which you can get on Windows by [registering Fossil as a +Windows service](./service.md), which solves the interactive startup and +shutdown problems above, at a bit of complexity over the Startup Items +method. You may also want to consider putting that service behind [an +IIS front-end proxy](./iis.md) to add additional web serving features. + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/windows/service.md b/www/server/windows/service.md new file mode 100644 index 0000000..e2cb3f2 --- /dev/null +++ b/www/server/windows/service.md @@ -0,0 +1,120 @@ +# Fossil as a Windows Service + +If you need Fossil to start automatically on Windows, it is suggested to install +Fossil as a Windows Service. + +## Assumptions + +1. You have Administrative access to a Windows 2012r2 or above server. +2. You have PowerShell 5.1 or above installed. + +## Place Fossil on Server + +However you obtained your copy of Fossil, it is recommended that you follow +Windows conventions and place it within `\Program Files\FossilSCM`, the +proper location for the official 64-bit binary. +This way Fossil is at an expected location and you will have minimal issues with +Windows interfering in your ability to run Fossil as a service. You will need +Administrative rights to place fossil at the recommended location. If you will +only be running Fossil as a service, you do not need to add this location to the +path, though you may do so if you wish. + +## Installing Fossil as a Service + +Luckily the hard work to use Fossil as a Windows Service has been done by the +Fossil team. We simply have to install it with the proper command line options. +Fossil on Windows has a command `fossil winsrv` to allow installing Fossil as a +service on Windows. This command is only documented on the windows executable +of Fossil. You must also run the command as administrator for it to be +successful. + +### Fossil winsrv Example + +The simplest form of the command is: + +``` +fossil winsrv create --repository D:/Path/to/Repo.fossil +``` + +This will create a windows service named 'Fossil-DSCM' running under the local +system account and accessible on port 8080 by default. `fossil winsrv` can also +start, stop, and delete the service. For all available options, please execute +`fossil help winsrv` on a windows install of Fossil. + +If you wish to serve a directory of repositories, the `fossil winsrv` command +requires a slightly different set of options vs. `fossil server`: + +``` +fossil winsrv create --repository D:/Path/to/Repos --repolist +``` + +### Choice of Directory Considerations + +When the Fossil server will be used at times that files may be locked +during virus scanning, it is prudent to arrange that its directory used +for temporary files is exempted from such scanning. Ordinarily, this +will be a subdirectory named "fossil" in the temporary directory given +by the Windows GetTempPath(...) API, [namely](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw#remarks) +the value of the first existing environment variable from `%TMP%`, `%TEMP%`, +`%USERPROFILE%`, and `%SystemRoot%`; you can look for their actual values in +your system by accessing the `/test-env` webpage. +Excluding this subdirectory will avoid certain rare failures where the +fossil.exe process is unable to use the directory normally during a scan. + +### <a id='PowerShell'></a>Advanced service installation using PowerShell + +As great as `fossil winsrv` is, it does not have one to one reflection of all of +the `fossil server` [options](/help/server). When you need to use some of +the more advanced options, such as `--https`, `--skin`, or `--extroot`, you will +need to use PowerShell to configure and install the Windows service. + +PowerShell provides the [New-Service](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-5.1) +command, which we can use to install and configure Fossil as a service. The +below should all be entered as a single line in an Administrative PowerShell +console. + +```PowerShell +New-Service -Name fossil -DisplayName fossil -BinaryPathName '"C:\Program Files\FossilSCM\fossil.exe" server --port 8080 --repolist "D:/Path/to/Repos"' -StartupType Automatic +``` + +Please note the use of forward slashes in the repolist path passed to Fossil. +Windows will accept either back slashes or forward slashes in path names, but +Fossil has a preference for forward slashes. The use of `--repolist` will make +this a multiple repository server. If you want to serve only a single +repository, then leave off the `--repolist` parameter and provide the full path +to the proper repository file. Other options are listed in the +[fossil server](/help/server) documentation. + +The service will be installed by default to use the Local Service account. +Since Fossil only needs access to local files, this is fine and causes no +issues. The service will not be running once installed. You will need to start +it to proceed (the `-StartupType Automatic` parameter to `New-Service` will +result in the service auto-starting on boot). This can be done by entering + +```PowerShell +Start-Service -Name fossil +``` + +in the PowerShell console. + +Congratulations, you now have a base http accessible Fossil server running on +Windows. + +### Removing the Windows Service + +If you want to remove the Fossil service, execute the following from an +Administrative PowerShell or Command Prompt console: + +``` +sc.exe delete fossil +``` + +If you have Powershell version 6.0 or later, you can use: + +```PowerShell +Remove-Service -Name fossil +``` + +with the same effect. + +*[Return to the top-level Fossil server article.](../)* diff --git a/www/server/windows/stunnel.md b/www/server/windows/stunnel.md new file mode 100644 index 0000000..5a7e8d1 --- /dev/null +++ b/www/server/windows/stunnel.md @@ -0,0 +1,156 @@ +# Using stunnel with Fossil on Windows + +While there are many ways to configure Fossil as a server using various web +servers (Apache, IIS, nginx, etc.), this document will focus on setting up a +minimal Fossil server using only Fossil's native [server +capabilities](../any/none.md) and [stunnel](https://www.stunnel.org/) +to provide a TLS proxy. It is recommended for public repositories to go to the +extra step of configuring stunnel to provide a proper HTTPS setup. + +## Assumptions + +1. You have Administrative access to a Windows 2012r2 or above server. +2. You have PowerShell 5.1 or above installed. +3. You have acquired a certificate either from a Public CA or an Internal CA. + +## Configure Fossil Service for https + +Due to the need for the `--https` option for successfully using Fossil with +stunnel, we will use [Advanced service installation using PowerShell](./service.md#PowerShell). +We will need to change the command to install the Fossil Service to configure +it properly for use with stunnel as an https proxy. Run the following: + +```PowerShell +New-Service -Name fossil-secure -DisplayName fossil-secure -BinaryPathName '"C:\Program Files\FossilSCM\fossil.exe" server --localhost --port 9000 --https --repolist "D:/Path/to/Repos"' -StartupType Automatic +``` + +The use of `--localhost` means Fossil will only listen for traffic on the local +host on the designated port - 9000 in this case - and will not respond to +network traffic. Using `--https` will tell Fossil to generate HTTPS URLs rather +than HTTP ones. + +`New-Service` does not automatically start a service on install, so you will +need to enter the following to avoid rebooting the server: + +```PowerShell +Start-Service -Name fossil-secure +``` + +To remove the service, run the following in a Powershell or cmd console: + +``` +sc.exe delete fossil +``` + +or (in a Powershell console) + +```PowerShell +Remove-Service -Name fossil +``` + +if your version of Powershell is 6.0 or above. + +## Install stunnel 5.55 + +Download stunnel from the [downloads](https://www.stunnel.org/downloads.html) +page. Select the latest stunnel windows package (at the time of writing this is +`stunnel-5.55-win64-installer.exe`). Execute the installer and make sure you +install openSSL tools when you install stunnel. You will need this to convert +your certificate from PFX to PEM format. + +Even though the installer says it is for win64, it installs stunnel by default +to `\Program Files (x86)\stunnel`. + +## Get your certificate ready for Stunnel + +Whether you use a Public Certificate Authority or Internal Certificate +Authority, the next step is exporting the certificate from Windows into a format +useable by Stunnel. + +### Export Certificate from Windows + +If your certificate is installed via Windows Certificate Management, you will +need to export the certificate into a usable format. You can do this either +using the Windows Certificate Management Console, or PowerShell. + +#### Certificate Management Console + +Start `mmc.exe` as an Administrator. Select 'File>Add/Remove Snapin', select +'Certificates' from the list, and click 'Add'. Select 'Computer Account', +'Next', 'Local Computer', and then 'Finish'. In the Console Root, expand +'Certificates', then 'Personal', and select 'Certificates'. In the middle pane +find and select your certificate. Right click the certificate and select +'All Tasks>Export'. You want to export as PFX the Private Key, include all +certificates in the certification path, and use a password only to secure the +file. Enter a path and file name to a working directory and complete the +export. + +Continue with [Convert Certificate from PFX to PEM](#convert). + +#### PowerShell + +If you know the Friendly +Name of the Certificate this is relatively easy. Since you need to export +the private key as well, you must run the following from an Administrative +PowerShell console. + +```PowerShell +$passwd = ConvertTo-SecureString -string "yourpassword" -Force -AsPlainText + +Get-ChildItem Cert:\LocalMachine\My | Where{$_.FriendlyName -eq "FriendlyName"} | +Export-PfxCertificate -FilePath fossil-scm.pfx -Password $passwd +``` + +You will now have your certificate stored as a PFX file. + +<a id="convert"></a> +### Convert Certificate from PFX to PEM + +For this step you will need the openssl tools that were installed with stunnel. + +```PowerShell +# Add stunnel\bin directory to path for this session. +$env:PATH += ";${env:ProgramFiles(x86)}\stunnel\bin" +# Export Private Key +openssl.exe pkcs12 -in fossil-scm.pfx -out fossil-scm.key -nocerts -nodes +# Export the Certificate +openssl.exe pkcs12 -in fossil-scm.pfx -out fossil-scm.pem -nokeys +``` + +Now move `fossil-scm.key` and `fossil-scm.pem` to your stunnel config directory +(by default this should be located at `\Program Files (x86)\stunne\config`). + +## stunnel Configuration + +Use the reverse proxy configuration given in the generic [Serving via +stunnel document](../any/stunnel.md#proxy). On Windows, the +`stunnel.conf` file is located at `\Program Files (x86)\stunnel\config`. + +You will need to modify it to point at the PEM and key files generated +above. + +After completing the above configuration restart the stunnel service in Windows +with the following: + +```PowerShell +Restart-Service -Name stunnel +``` + +## Open up port 443 in the Windows Firewall + +The following instructions are for the [Windows Advanced +Firewall](https://docs.microsoft.com/en-us/windows/security/threat-protection/windows-firewall/windows-firewall-with-advanced-security). +If you are using a different Firewall, please consult your Firewall +documentation for how to open port 443 for inbound traffic. + +The following command should be entered all on one line. + +```PowerShell +New-NetFirewallRule -DisplayName "Allow Fossil Inbound" -Description "Allow Fossil inbound on port 443 using Stunnel as TLS Proxy." + -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow -Program "C:\Program Files (x86)\Stunnel\bin\stunnel.exe" +``` + +You should now be able to access your new Fossil Server via HTTPS. + + +*[Return to the top-level Fossil server article.](../)* |
