Fossil on Ubuntu 24.04 on Azure User Guide
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.servicerunning as thefossiluser, bound to loopback127.0.0.1:8081nginx.servicereverse proxy on TCP 80, TLS ready, rate limited (10 requests per second, burst 40)fossil-firstboot.servicegenerating 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",...))

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>/

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

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.

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

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:

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:

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

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
nobodyandanonymoususers 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.fossilto 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