kiwix-serve 3.8 Offline Content Server on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of kiwix-serve 3.8 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. kiwix-serve is a single, self contained HTTP server that serves offline ZIM content archives, self contained snapshots of Wikipedia, StackExchange, Project Gutenberg, wikis and other websites, through a built in library and reader web UI. Visitors browse the catalog, open articles and run full text search entirely offline, with no internet connection required once the archives are in place. kiwix-serve is part of the Kiwix project and is released under the GNU General Public License v3.0 or later.
The image installs the official statically linked kiwix-tools release (version 3.8.2 at build time) to /usr/local/bin. The kiwix-serve HTTP listener is bound to loopback only and fronted by nginx on port 80 with HTTP Basic Auth, so the library is never exposed without a credential. At first boot, kiwix-serve-firstboot.service generates a unique per VM Basic Auth password (there is no default login baked into the image), reloads nginx, proves an authenticated round trip, and writes the password to /root/kiwix-serve-credentials.txt (mode 0600, root only). A small sample archive, the top hundred English Wikipedia articles, is bundled so the library works the moment the VM boots; you can add your own ZIM files at any time.
What is included:
-
kiwix-serve, kiwix-manage and kiwix-search 3.8.2 (official static musl release), pinned and sha256 verified
-
A bundled sample ZIM, the top hundred English Wikipedia articles (Wikipedia content under CC BY-SA 3.0, freely redistributable), at
/var/lib/kiwix -
kiwix-serve.servicesystemd unit running the server as the unprivilegedkiwixuser, bound to loopback with a hardened service sandbox -
kiwix-serve-firstboot.servicesystemd oneshot that generates the per VM HTTP Basic Auth password, reloads nginx, proves an authenticated round trip and writes/root/kiwix-serve-credentials.txt -
nginx on port 80 reverse proxying to the loopback bound kiwix-serve listener, with HTTP Basic Auth and an unauthenticated
/healthzfor load balancer probes -
The Kiwix library and reader web UI, reachable at
http://<vm-ip>/after signing in -
Ubuntu 24.04 LTS base with the latest security patches
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
-
An active Azure subscription, SSH public key, VNet plus subnet in the target region
-
A subscription to the kiwix-serve 3.8 on Ubuntu 24.04 listing on Azure Marketplace
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) for evaluation and small libraries. For large archives (a full Wikipedia is tens of GB) and higher traffic, use Standard_D2s_v5 or larger and resize the OS disk to fit your ZIM files.
Step 1: Deploy from the Azure Portal
Search kiwix in Marketplace, select the cloudimg publisher entry, then click Create.
NSG rules: allow TCP 22 from your management IP and TCP 80 from your client IPs. The kiwix-serve HTTP listener is bound to loopback, so only nginx on port 80 is exposed. The library is protected by HTTP Basic Auth, but for public deployments put a TLS terminating reverse proxy in front of port 80 so credentials and content are encrypted in transit.
Step 2: Deploy from the Azure CLI
RG="kiwix-prod"; LOCATION="eastus"; VM_NAME="kiwix-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/kiwix-serve/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name kx-vnet --address-prefix 10.90.0.0/16 --subnet-name kx-subnet --subnet-prefix 10.90.1.0/24
az network nsg create -g "$RG" --name kx-nsg
az network nsg rule create -g "$RG" --nsg-name kx-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 kx-nsg --name allow-http --priority 110 \
--source-address-prefixes "<your-client-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 kx-vnet --subnet kx-subnet --nsg kx-nsg --public-ip-sku Standard
Step 3: Connect via SSH
ssh azureuser@<vm-ip>
kiwix-serve.service and nginx.service start automatically, and kiwix-serve-firstboot.service generates the per VM Basic Auth password on the first boot.
Step 4: Verify the kiwix-serve Service
sudo systemctl is-active kiwix-serve.service nginx.service
sudo test -f /var/lib/cloudimg/kiwix-serve-firstboot.done && echo FIRSTBOOT_DONE
Both services should report active, and the first boot sentinel should be present.

Step 5: Inspect the Listeners
The kiwix-serve HTTP listener is bound to 127.0.0.1:8080, and nginx serves it on port 80. Nothing but nginx listens on a public interface.
sudo ss -tln | grep -E ':80 |:8080'
Step 6: Review the Bundled Library
The bundled sample archive and the library.xml manifest that kiwix-serve serves live in /var/lib/kiwix:
sudo /usr/local/bin/kiwix-manage /var/lib/kiwix/library.xml show
ls -lh /var/lib/kiwix/
You will see the book metadata (title, article count, size) and the ZIM file on disk.

Step 7: Retrieve the Access Password
The per VM HTTP Basic Auth password is generated at first boot and stored in a root only file:
sudo cat /root/kiwix-serve-credentials.txt
You will see the sign in user, the per VM password, and the endpoint URLs:
KIWIX_HTTP_USER=admin
KIWIX_BASIC_AUTH_PASSWORD=<KIWIX_BASIC_AUTH_PASSWORD>
KIWIX_URL=http://<vm-ip>/
KIWIX_HEALTHZ=http://<vm-ip>/healthz
KIWIX_LOCAL_HTTP=http://127.0.0.1:8080/

Step 8: Verify Access Control over HTTP
kiwix-serve is reached only through the authenticated nginx proxy. Confirm that an unauthenticated request is rejected, that the per VM password works, and that an article loads over HTTP:
PW=$(sudo grep '^KIWIX_BASIC_AUTH_PASSWORD=' /root/kiwix-serve-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no creds: %{http_code}\n' http://127.0.0.1/
curl -s -o /dev/null -w 'library index: %{http_code}\n' -u "admin:$PW" http://127.0.0.1/
BOOK=$(curl -s http://127.0.0.1:8080/catalog/v2/entries | grep -oE '/content/[^"<]+' | head -1 | sed 's:/content/::')
curl -sL -o /dev/null -w 'article: %{http_code}\n' -u "admin:$PW" "http://127.0.0.1/content/$BOOK"
The unauthenticated request returns 401, the authenticated library index returns 200, and the article fetch returns 200. The unauthenticated /healthz endpoint stays open for load balancer probes.

Step 9: Open the Library in a Browser
Open http://<vm-ip>/ from your workstation (assuming the NSG allows TCP 80). Your browser prompts for HTTP Basic Auth: sign in with user admin and the per VM password from /root/kiwix-serve-credentials.txt. The library welcome page lists every archive on the server:

Step 10: Browse an Archive
Click a book to open it in the built in reader. The archive's main page renders offline, with the reader navigation bar and search box at the top:

Step 11: Read an Article
Open any article and it renders exactly as it would online, including infoboxes and images, entirely from the offline archive:

Step 12: Full Text Search
Use the search box to run full text search across an archive. Results list matching articles with snippets and word counts:

Step 13: Add Your Own Archives
Download any ZIM from the Kiwix library, drop it in /var/lib/kiwix, and register it with kiwix-manage. kiwix-serve runs with --monitorLibrary, so it reloads the library automatically, no restart needed. Replace <version> with the current dated filename from the download site:
cd /var/lib/kiwix
sudo curl -fLO https://download.kiwix.org/zim/other/archlinux_en_all_maxi_<version>.zim
sudo /usr/local/bin/kiwix-manage /var/lib/kiwix/library.xml add /var/lib/kiwix/archlinux_en_all_maxi_<version>.zim
sudo chown kiwix:kiwix /var/lib/kiwix/*
Browse to the library and the new archive appears alongside the bundled sample.
Step 14: Server Components
| Component | Path |
|---|---|
| kiwix-serve binary | /usr/local/bin/kiwix-serve |
| kiwix-manage binary | /usr/local/bin/kiwix-manage |
| Archive directory | /var/lib/kiwix |
| Library manifest | /var/lib/kiwix/library.xml |
| Systemd unit | /etc/systemd/system/kiwix-serve.service |
| Firstboot script | /usr/local/sbin/kiwix-serve-firstboot.sh |
| Firstboot service | /etc/systemd/system/kiwix-serve-firstboot.service |
| Credentials file | /root/kiwix-serve-credentials.txt (mode 0600) |
| Firstboot sentinel | /var/lib/cloudimg/kiwix-serve-firstboot.done |
| nginx site | /etc/nginx/sites-available/cloudimg-kiwix |
| Basic Auth file | /etc/nginx/.kiwix_htpasswd |
Step 15: Managing the Service
sudo systemctl status kiwix-serve.service --no-pager | head -6
sudo journalctl -u kiwix-serve.service --no-pager | tail -5
To restart the service after adding archives or changing options, run sudo systemctl restart kiwix-serve.service.
Step 16: Security Recommendations
-
Rotate the Basic Auth password by regenerating
/etc/nginx/.kiwix_htpasswdwithopenssl passwd -apr1and reloading nginx, and store the password in your secrets manager -
Keep the HTTP listener on loopback as shipped; expose only nginx on port 80, and put TLS in front of it (Azure Application Gateway, or nginx with a real certificate)
-
Restrict the NSG so port 80 only reaches trusted client networks
-
Make the library public only if intended by removing the
auth_basiclines from/etc/nginx/sites-available/cloudimg-kiwixand reloading nginx -
Only add archives you have the right to redistribute; Wikipedia and StackExchange ZIMs are CC BY-SA and freely redistributable, and each book's licence and attribution are shown in the library UI
-
Back up the archive directory at
/var/lib/kiwix, or take Azure disk snapshots -
Patch the OS monthly with
sudo apt-get update && sudo apt-get upgrade && sudo reboot
Step 17: Support and Licensing
kiwix-serve is licensed under the GNU General Public License v3.0 or later. There are no per node, per CPU, or per GB fees. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Kiwix or openZIM project; Kiwix is a trademark of its respective owner and is used here only to describe the software included in the image. The bundled sample archive contains Wikipedia content under the Creative Commons Attribution ShareAlike 3.0 licence.
cloudimg provides commercial support for this image separately from the upstream project.
-
Email: support@cloudimg.co.uk
-
Website: www.cloudimg.co.uk
-
Support hours: 24/7 with guaranteed 24 hour response SLA
Deploy on Azure
Launch kiwix-serve 3.8 Offline Content Server 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