Setting up a Fossil server on FreeBSD

Posted on January 7, 2021

A few months ago I had to learn a little bit about AWS. The reason for doing so vanished, and now I have some elementary solutions searching for a problem. I found a problem recently when I desired to have a self-hosted code repository. Really, I convinced myself I had a problem so I would have something to occupy my time.

The obvious questions to be suggested to my title are “why FreeBSD?” and “why Fossil?” I believe there is a lot of value in exploring alternative resources. I chose FreeBSD because I’ve been interested for a while in learning about the BSDs. The Fossil home page gives a concise rundown of Fossil’s potential benefits over other version control systems. If you are currently hosting your stuff on Github or Gitlab, or self-hosting a Gitlab instance or stand-alone git server, and everything is going well, then cool. If you are using Subversion or something else, then keep on truckin’. Fossil looks interesting, well-made, and a bit different, which is reason enough for me to toy with it. The only thing I will evangelize is against technological monoculture, and even then it’s a “Christmas and Easter only” level of commitment.

I set up my FreeBSD EC2 instance on AWS. I just followed the basic tutorial except I used Colin Percival’s ZFS-on-root EC2 images. My installation went well and I could SSH into my new instance. Percival’s images are for FreeBSD 12.0 and I wanted to update to the latest minor version 12.2. So the only two things I installed via pkg install were tmux and beadm. I used beadm to create a boot environment as a backup in case the update failed. Chapter 12 of Michael W. Lucas’s Absolute FreeBSD covers a little on using beadm for this purpose, and of course the man pages are valuable. To do the actual update, I start tmux and followed the FreeBSD Handbook. With tmux, if my connection drops halfway through the update I can reconnect and reattach without losing any progress. The only conflict I had to resolve was a single file which seemed to govern dynamic zfs volume growth. I didn’t do anything fancier than side with the more recent revision since they seemed pretty identical to me. My choice didn’t seem immediately stupid, but I might be surprised later.

My ultimate goal is to set up a working Fossil server inside of a FreeBSD jail using vnet. I have had a lot of difficulty managing this from first principles, and I don’t feel alone in having difficulty setting up vnet jails. I finally found a jail orchestrator my feeble mind could understand: Pot. In addition to the github page, there are some more docs available here. I didn’t do anything fancier than follow the Getting Started Guide. The recommended values already in pot.conf worked well for me. SO I just uncommented the lines for POT_ZFS_ROOT, POT_FS_ROOT, POT_EXTIF, POT_NETWORK, and POT_GATEWAY. The only change I had to make was setting POT_EXTIF to the interface on my box. From there, I followed the public bridge segment of the Networking Guide. After running pot vnet-start, I’m ready to create my jail which will house my fossil server.

pot create -p fossil -t single -b 12.2 -N public-bridge -i auto

Then I start the jail with pot start fossil. I can install fossil to the jail with pkg -j fossil install -y fossil. Alternatively, I could set up a terminal inside the jail with pot term fossil and do the normal pkg install fossil from within there, but I keep reading that is best practice to administrate a jail from the host. But then I disregard that and log in to set up the appropriate files and start the services. I created two fossil repos, created some readmes and committed. So the directory structure within the jail looks like

/
    /fossils/
        - test-repo.fossil
        - test-repo-2.fossil
    /test-repo/
        - README.txt
    /test-repo-2/
        - README.txt

Setting up this layout is easy, and you can follow the Quick Start Guide to get the street-fighting knowledge of Fossil needed for this post. As an example, we can creaste a third repository. cd into /fossils, and run fossil init test-repo-3.fossil to initiate. As the guide says, the location and name of repository filename is just a convention. However, we are centralizing all the fossil files in a single directory and consistently supplying a .fossil suffix so a single fossil server process can serve multiple repositories. Then we go back to root and create the directory /test-repo-3 into which we cd. Check out the repository with

fossil open ../fossils/test-repo-3.fossil

Let’s create a dummy readme with echo "test 3" > README.txt. fossil extras will display all local changes. So we stage the change with fossil add README.txt and can commit the change with fossil commit -m "Added a dummy README file. Then our jail’s directory structure should look like.

/
    /fossils/
        - test-repo.fossil
        - test-repo-2.fossil
    /test-repo/
        - README.txt
    /test-repo-2/
        - README.txt
    /test-repo-3/
        - README.txt

So now we need to configure the network. I want requests on port 80 to transfer to the jail’s port 80. It doesn’t seem like I can make these changes dynamically so I shutdown the jail with pot stop fossil. Then I set up my desired configuration with

pot export-ports -p fossil -e 80:80

After restarting the jail with pot start fossil, I can enter pot show fossil which displays some basic info along with my new redirect rule. I log back in with pot term fossil and then start the server with

fossil server --repolist -P 80 fossils/ &

The --repolist flag specifies we are serving multiple repositories, -P 80 tells the server to listen on port 80, and fossils/ is where the list of repositories resides.

At this point I can view repositories on my web browser by going to my hosts public IP. This is far far from an ideal setup. The server should start automatically on jail setup. I should create a reverse proxy so the fossil jail never directly accesses a public network. I should enable https. I should also create a reverse proxy so I can do things like also set up a private Gitlab instance or host this blog. There are a lot of shortcomings but the advantage of being a hobbyist is never having to pretend you’re competent.