Deployment guide

kiwix-serve

Overview

kiwix-serve is a single, self-contained HTTP server for offline ZIM content archives. These are self-contained snapshots of Wikipedia, StackExchange, Project Gutenberg, wikis and other websites. Visitors browse the catalog, open articles and run full-text search through a built-in library and reader web UI, entirely offline. No internet connection is 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. This SecureAnyCloud image runs kiwix-serve 3.8 on Ubuntu 24.04 on Azure. It 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, reloads nginx and proves an authenticated round trip. There is no default login baked into the image. The service 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 you get:

  • 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
  • The kiwix-serve.service systemd unit, running the server as the unprivileged kiwix user, bound to loopback with a hardened service sandbox
  • The kiwix-serve-firstboot.service systemd oneshot, which 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 /healthz for load balancer probes
  • The Kiwix library and reader web UI, reachable at http://<vm-ip>/ after you sign in
  • Ubuntu 24.04 LTS base, patched at build time
  • Azure Linux Agent for seamless cloud integration and SSH key injection
  • 24/7 SecureAnyCloud support with guaranteed 24 hour response SLA

Prerequisites

  • An active Azure subscription, an SSH public key, and a VNet with a subnet in the target region
  • A subscription to the kiwix-serve 3.8 on Ubuntu 24.04 listing on the 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.

1

Deploy from the Azure Portal

Search the Azure Marketplace for kiwix, select the SecureAnyCloud publisher entry, and click Create.

Configure the NSG to 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.

HTTP Basic Auth protects the library. For public deployments, also put a TLS-terminating reverse proxy in front of port 80, so credentials and content are encrypted in transit.

2

Deploy from the Azure CLI

RG="kiwix-prod"; LOCATION="eastus"; VM_NAME="kiwix-01" IMAGE_URN="sac1647283583153:kiwix-serve:default:latest" 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
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:kiwix-serve:default:latest
az vm create -g "$RG" --name "$VM_NAME" --image "$IMAGE_URN" \
  --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
3

Connect over SSH

ssh azureuser@<vm-ip>

kiwix-serve.service and nginx.service start automatically. On the first boot, kiwix-serve-firstboot.service generates the per-VM Basic Auth password.

4

Verify the kiwix-serve service

sudo systemctl is-active kiwix-serve.service nginx.service
sudo test -f /var/lib/sac/data/kiwix-serve-firstboot.done && echo FIRSTBOOT_DONE

Both services report active, and the first-boot sentinel is present.

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

The output shows the book metadata (title, article count and size) and the ZIM file on disk.

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

The file shows 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/
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.

9

Open the library in a browser

From your workstation, open http://<vm-ip>/. The NSG must allow 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.

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.

11

Read an article

Open any article. It renders exactly as it would online, including infoboxes and images, entirely from the offline archive.

12

Search the full text

Use the search box to run a full-text search across an archive. Results list matching articles with snippets and word counts.

13

Add your own archives

Download any ZIM from the Kiwix library, place it in /var/lib/kiwix, and register it with kiwix-manage. kiwix-serve runs with --monitorLibrary, so it reloads the library automatically and needs no restart.

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. The new archive appears alongside the bundled sample.

14

Server components

Component and 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/sac/data/kiwix-serve-firstboot.done

nginx site /etc/nginx/sites-available/sac-kiwix

Basic Auth file /etc/nginx/.kiwix_htpasswd

15

Manage 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.

16

Security recommendations

  • Rotate the Basic Auth password. Regenerate /etc/nginx/.kiwix_htpasswd with openssl passwd -apr1, reload nginx, and store the password in your secrets manager.
  • Keep the HTTP listener on loopback. Leave it as shipped, expose only nginx on port 80, and put TLS in front of it with Azure Application Gateway or nginx with a real certificate.
  • Restrict the NSG. Allow port 80 only from trusted client networks.
  • Make the library public only if intended. To do so, remove the auth_basic lines from /etc/nginx/sites-available/sac-kiwix and reload nginx.
  • Add only 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.
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. The bundled sample archive contains Wikipedia content under the Creative Commons Attribution-ShareAlike 3.0 licence.

SecureAnyCloud produces this image. It 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.

SecureAnyCloud provides commercial support for this image separately from the upstream project.

Email: sales@secureanycloud.com

Website: secureanycloud.com

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 SecureAnyCloud.

View on Marketplace

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure

Launch kiwix-serve 3.8 Offline Content Server on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure