Developer Tools Azure

Fossil on Ubuntu 24.04 on Azure User Guide

| Product: Fossil on Ubuntu 24.04 LTS on Azure

Overview

Fossil is a simple, high reliability, distributed version control system. Unlike most version control tools it bundles everything a small project needs into one self contained executable: distributed source control, a bug tracker, a wiki, a forum, a chatroom, technotes and an integrated web interface, all backed by a single SQLite database file that is the entire repository. There is nothing else to install and nothing external to run.

The cloudimg image installs Fossil 2.28 and puts it behind an nginx reverse proxy that binds the server to loopback, rate limits inbound requests and caps the request size. Fossil has a real administrator login, and this image is secure by default: anonymous and unauthenticated visitors are read only, so they can browse the timeline, read the wiki and tickets and clone the repository, but cannot commit, edit the wiki or file tickets. The administrator password is not baked into the image. A fresh empty repository and a unique random admin password are generated on each virtual machine's first boot by fossil-firstboot.service and written to a root only file at /root/fossil-info.txt.

What is included:

  • Fossil 2.28 single official binary (/usr/local/bin/fossil)
  • A single SQLite repository at /var/lib/fossil/repo.fossil (no separate database to maintain)
  • fossil.service running as the fossil user, bound to loopback 127.0.0.1:8081
  • nginx.service reverse proxy on TCP 80, TLS ready, rate limited (10 requests per second, burst 40)
  • fossil-firstboot.service generating a fresh repository and a per VM admin password on first boot
  • Anonymous write disabled: unauthenticated and anonymous users are read only
  • Ubuntu 24.04 LTS base, latest patches, unattended security upgrades enabled
  • 24/7 cloudimg support, 24h response SLA

Prerequisites

An active Azure subscription, an SSH key, and a VNet with a subnet. Recommended VM size: Standard_B2s (Fossil is very light; 4 GB RAM is plenty).

Step 1: Deploy from the Azure Portal

Search the Azure Marketplace for Fossil, choose the plan, and create the VM. In the networking step attach an NSG that allows inbound TCP 22 (SSH) and TCP 80 (the web UI) from your client networks only. Put a TLS reverse proxy in front of port 80 for production.

Step 2: Deploy from the Azure CLI

RG="fossil-prod"; LOCATION="eastus"; VM_NAME="fossil-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/fossil-scm-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name fossil-vnet --address-prefix 10.104.0.0/16 --subnet-name fossil-subnet --subnet-prefix 10.104.1.0/24
az network nsg create -g "$RG" --name fossil-nsg
az network nsg rule create -g "$RG" --nsg-name fossil-nsg --name allow-ssh --priority 100 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name fossil-nsg --name allow-web --priority 110 \
  --source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
  --size Standard_B2s --storage-sku StandardSSD_LRS \
  --admin-username azureuser --ssh-key-values "$SSH_KEY" \
  --vnet-name fossil-vnet --subnet fossil-subnet --nsg fossil-nsg --public-ip-sku Standard

Step 3: Connect via SSH

ssh azureuser@<vm-ip>

fossil.service, nginx.service and fossil-firstboot.service all start automatically on first boot.

Step 4: Verify the Service

sudo systemctl is-active fossil nginx fossil-firstboot
sudo test -f /var/lib/cloudimg/fossil-firstboot.done && echo FIRSTBOOT_DONE
sudo ss -tlnp | grep -E ':80 |:8081 '

Expected output — all services are active, nginx is bound to the public port 80 and Fossil is bound to loopback 127.0.0.1:8081 only:

active
active
active
FIRSTBOOT_DONE
LISTEN 0 10  127.0.0.1:8081 0.0.0.0:*  users:(("fossil",...))
LISTEN 0 511 0.0.0.0:80     0.0.0.0:*  users:(("nginx",...))

Fossil, nginx and the firstboot service all active, with nginx bound to public port 80 and Fossil bound to loopback 127.0.0.1:8081 only

Step 5: Secure by Default

Fossil binds only to loopback and is fronted by nginx, which rate limits requests and caps the request size. On first boot a fresh empty repository and a per VM admin password are generated and written to a root only note:

sudo cat /root/fossil-info.txt
sudo ss -tlnp | grep 8081
grep -E 'limit_req|client_max_body_size' /etc/nginx/conf.d/cloudimg-fossil-ratelimit.conf /etc/nginx/sites-available/cloudimg-fossil

The note contains the per VM admin password (unique to this machine, never baked into the image) and the resolved URL:

FOSSIL_ADMIN_USER=admin
FOSSIL_ADMIN_PASSWORD=<FOSSIL_ADMIN_PASSWORD>
FOSSIL_URL=http://<vm-ip>/

The per VM admin password note masked, Fossil bound to loopback only, and the nginx rate limit and request size cap configuration

Anonymous write is disabled. The nobody user (every unauthenticated visitor) and the anonymous user (captcha login) are given read only Fossil capabilities, while the admin user has the setup capability and is the only writer:

sudo runuser -u fossil -- env HOME=/var/lib/fossil fossil user list -R /var/lib/fossil/repo.fossil
for u in admin nobody anonymous; do
  echo "$u: $(sudo runuser -u fossil -- env HOME=/var/lib/fossil fossil user capabilities $u -R /var/lib/fossil/repo.fossil)"
done

The capability string ghjorz is read only (clone, hyperlinks, read wiki, check out, read tickets, download); it contains none of the check in, wiki write, ticket write or unversioned write capabilities:

admin: s
nobody: ghjorz
anonymous: ghjorz

The Fossil repository users and their capabilities: admin holds the setup capability while nobody and anonymous are read only

Step 6: Log In as the Administrator

Read the per VM admin password from the root only note, then confirm it authenticates. A valid admin session can reach the /setup page (HTTP 200); an anonymous request is redirected to the login page:

ADMIN_PW="<FOSSIL_ADMIN_PASSWORD>"
curl -s -c /tmp/fossil-cookies --data-urlencode "u=admin" --data-urlencode "p=$ADMIN_PW" http://127.0.0.1/login -o /dev/null
echo "admin  /setup -> HTTP $(curl -s -b /tmp/fossil-cookies -o /dev/null -w '%{http_code}' http://127.0.0.1/setup)"
echo "anon   /setup -> HTTP $(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/setup)"
rm -f /tmp/fossil-cookies

Expected output — the admin session reaches the setup page while the anonymous request is redirected:

admin  /setup -> HTTP 200
anon   /setup -> HTTP 302

In a browser, open http://<vm-ip>/ and click Login. Sign in as admin with the password from /root/fossil-info.txt. For production, put TLS in front of port 80 (see Step 13) so the password is never sent in the clear.

The Fossil login page served behind nginx, where the admin user signs in; anonymous visitors are read only

Step 7: Browse the Timeline

The timeline is the home of the repository. It shows every check in, wiki edit, ticket change and forum post in reverse chronological order, with branch tags and links to each artifact:

curl -s -o /dev/null -w 'timeline -> HTTP %{http_code}\n' http://127.0.0.1/timeline

The Fossil repository timeline showing the initial check in on the trunk branch, logged in as admin

Step 8: Use the Wiki

Fossil has a built in wiki. Pages can be written in Fossil wiki markup or in Markdown. Open the Wiki tab to browse and edit pages; anonymous visitors can read them but only authenticated users with the wiki capability can edit:

A wiki page rendered as Markdown, with the Edit, Help and History actions available to the logged in admin

Step 9: Track Bugs with Tickets

The built in ticket system is a full bug tracker. Open the Tickets tab, choose the All Tickets report to list every ticket, or click New Ticket to file one. Each ticket has a type, status, priority and full change history:

The All Tickets report listing a ticket with its type, status and title, with the color key for ticket states

Step 10: Clone and Work with the Repository

From a workstation that has Fossil installed, clone the repository over HTTP using the admin credentials (replace <vm-ip> with your VM's address), open a working checkout, then add files and commit. Because Fossil is distributed, every clone is a full copy of the repository, its wiki and its tickets:

fossil clone http://admin@<vm-ip>/ myrepo.fossil
mkdir myrepo && cd myrepo
fossil open ../myrepo.fossil
echo "hello" > README.md
fossil add README.md
fossil commit -m "Add README"

Step 11: Server Components

Component Path
Fossil binary /usr/local/bin/fossil
Repository (single SQLite file) /var/lib/fossil/repo.fossil
Systemd unit /etc/systemd/system/fossil.service
Firstboot script /usr/local/sbin/fossil-firstboot.sh
nginx site /etc/nginx/sites-available/cloudimg-fossil
Per VM info note /root/fossil-info.txt (mode 0600)
Sentinel /var/lib/cloudimg/fossil-firstboot.done
fossil version
ls /usr/local/bin/fossil /var/lib/fossil/repo.fossil

Fossil reporting version 2.28, the installed component paths, and the timeline serving 200 while the admin setup page is gated

Step 12: Managing the Service

sudo systemctl restart fossil.service
sudo journalctl -u fossil.service --no-pager -n 20

The fossil command line administers the repository directly. For example, list the users, add a developer with commit rights, or change the admin password:

sudo runuser -u fossil -- env HOME=/var/lib/fossil fossil user list -R /var/lib/fossil/repo.fossil

Step 13: Add TLS (Optional)

For production, terminate TLS at nginx. Point a DNS A record for <your-domain> at your VM's public address (<vm-ip>), then use the packaged nginx with a certificate from Let's Encrypt:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>

certbot installs the certificate, rewrites the nginx server block to listen on 443 and sets up automatic renewal. Serving Fossil over HTTPS also means the login password is no longer sent in the clear.

Step 14: Security Recommendations

  • Restrict the NSG so ports 80 and 22 only reach trusted networks.
  • Terminate TLS at nginx (Step 13) so the admin password and repository content travel encrypted.
  • Keep anonymous read only. The image ships with the nobody and anonymous users restricted to read only capabilities; only grant write capabilities to named users you trust.
  • Keep the rate limit in /etc/nginx/conf.d/cloudimg-fossil-ratelimit.conf; Fossil has no built in denial of service mitigation, so the reverse proxy limit is what protects it.
  • Back up /var/lib/fossil/repo.fossil to Azure Blob; the whole repository, including its wiki and tickets, is that one file.
  • Patch the OS monthly with sudo apt-get update && sudo apt-get upgrade; unattended security upgrades are already enabled.

Step 15: Support and Licensing

Fossil is distributed under the 2 clause BSD license — no per CPU or per user fee. cloudimg provides commercial support separately.

  • Email: support@cloudimg.co.uk
  • Website: www.cloudimg.co.uk
  • Support hours: 24/7, 24h response SLA

Deploy on Azure

Launch Fossil on Ubuntu 24.04 with 24/7 support from cloudimg.

View on Marketplace

Need Help?

Our support team is available 24/7. support@cloudimg.co.uk