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.servicesystemd unit, running the server as the unprivilegedkiwixuser, bound to loopback with a hardened service sandbox - The
kiwix-serve-firstboot.servicesystemd 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
/healthzfor 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.
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.
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 StandardConnect 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.
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_DONEBoth services report active, and the first-boot sentinel is present.
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'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.
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.txtThe 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/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.
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.
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.
Read an article
Open any article. It renders exactly as it would online, including infoboxes and images, entirely from the offline archive.
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.
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.
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
Manage the service
sudo systemctl status kiwix-serve.service --no-pager | head -6 sudo journalctl -u kiwix-serve.service --no-pager | tail -5To restart the service after adding archives or changing options, run sudo systemctl restart kiwix-serve.service.
Security recommendations
- Rotate the Basic Auth password. Regenerate
/etc/nginx/.kiwix_htpasswdwithopenssl 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_basiclines from/etc/nginx/sites-available/sac-kiwixand 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.
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
Overview
kiwix-serve is a single, self-contained HTTP server that publishes offline content archives in the open ZIM format through a built-in library and reader web interface. A single ZIM file can hold an entire offline copy of Wikipedia, Wiktionary, Stack Exchange, Project Gutenberg, a wiki, a documentation set or any other web content. You browse and full-text search it from a normal web browser with no internet connection required.
This image runs kiwix-serve 3.8.2, from the official statically linked kiwix-tools release, on Ubuntu 24.04 LTS.
The server runs as an unprivileged kiwix system account under a systemd service that starts it on boot and restarts it on failure. It reads the ZIM library from /var/lib/kiwix. It binds to the loopback address 127.0.0.1:8080 by design, so it is never exposed directly.
An nginx reverse proxy on port 80 fronts kiwix-serve and enforces HTTP Basic Authentication. kiwix-serve has no authentication of its own, so this image is secure by default. On the first boot of every deployed instance, a one-shot service generates a fresh per-instance Basic Auth password. It writes the password to /root/kiwix-serve-credentials.txt (mode 0600, readable only by root).
No password is baked into the image, and two instances launched from the same AMI never share one. A lightweight unauthenticated /healthz endpoint is available for load balancers and monitoring.
The image ships with a small sample archive, Wikipedia 100 (the 100 most-read English Wikipedia articles, wikipedia_en_100_mini), so the library has real content to browse on first boot. The article text and media are Wikipedia content under the Creative Commons Attribution-ShareAlike licence and remain freely redistributable. The publisher and licence are shown on every book card and article. You can add your own ZIM archives at any time.
The default security group for this listing opens port 22 (SSH) and port 80 (HTTP) only.
Prerequisites
- An AWS account subscribed to this product in AWS Marketplace
- An EC2 key pair in your target region for SSH access
- A security group that allows inbound TCP 22 (SSH) from your IP and TCP 80 (HTTP) from your users
- Recommended instance type:
m5.largeor larger
Connecting to your instance
SSH in as the default login user for your operating system variant, using the key pair you launched with.
For the Ubuntu 24.04 variant, the login user is ubuntu. For example: ssh -i your-key.pem ubuntu@<instance-public-ip>
Step 1 - Launch from the AWS Marketplace console
- Open the product page in AWS Marketplace, choose Continue to Subscribe, then choose Continue to Configuration.
- Select the kiwix-serve 3.8.2 on Ubuntu 24.04 delivery option and your region, then choose Continue to Launch.
- Choose your instance type, VPC/subnet, key pair and the security group described above, then launch.
Step 2 - Launch from the AWS CLI
Replace the AMI ID with the one shown on the product's launch page for your region. Use your own key pair and security group.
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=kiwix-serve}]'Step 3 - Connect to your instance
ssh -i your-key.pem ubuntu@<instance-public-ip>Step 4 - Confirm the services are running
kiwix-serve and nginx both start on boot. Confirm that they are active:
systemctl is-active kiwix-serve.service nginx.serviceBoth services report active. Check the installed version:
/usr/local/bin/kiwix-serve --versionkiwix-tools 3.8.2 libkiwix 14.2.0kiwix-serve binds to loopback only, and nginx listens on port 80:
sudo ss -ltnp | grep -E '127.0.0.1:8080|:80 'LISTEN 0 128 127.0.0.1:8080 0.0.0.0:* users:(("kiwix-serve",pid=2664,fd=3)) LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",...))Step 5 - Retrieve the per-instance credentials
This instance generates the Basic Auth password on its first boot and stores it in a root-only file. Read it over SSH:
sudo cat /root/kiwix-serve-credentials.txt# kiwix-serve - Per-VM Credentials
# Generated on first boot by kiwix-serve-firstboot.service
# KIWIX_HTTP_USER=admin KIWIX_BASIC_AUTH_PASSWORD=<generated-per-instance> KIWIX_URL=http://<instance-public-ip>/ KIWIX_HEALTHZ=http://<instance-public-ip>/healthz KIWIX_LOCAL_HTTP=http://127.0.0.1:8080/The unauthenticated health-check endpoint answers without a password, so load balancers and monitoring can probe it:
curl -s -o /dev/null -w 'healthz -> HTTP %{http_code}\n' http://127.0.0.1/healthzhealthz -> HTTP 200Any other request without valid credentials is refused with HTTP 401, which shows that the library is not open:
curl -s -o /dev/null -w 'library (no auth) -> HTTP %{http_code}\n' http://127.0.0.1/library (no auth) -> HTTP 401Step 6 - Open the library
Browse to http://<instance-public-ip>/ and sign in with the username (admin) and the per-instance password from the credentials file. The library welcome page lists the bundled Wikipedia 100 archive as a book card showing its title, description and language.
Click the book card to open it in the reader. The reader shows the archive's visual article index. The top bar has the book title, a random-article button and a search box. Everything is served locally from the ZIM with no internet connection.
Step 7 - Read an article
Open any article to read it in the built-in viewer. It includes formatting, images and infoboxes, and looks exactly as it does on the live site, but is served entirely offline.
Step 8 - Search the archive
Type a term into the reader's search box for instant suggestions. Press Enter for a full-text search across the whole archive. Results are ranked by relevance, with a short snippet from each matching article. This confirms that the ZIM is indexed and searchable.
You can also check the content catalog over the loopback interface:
curl -s -o /dev/null -w 'catalog -> HTTP %{http_code}\n' http://127.0.0.1:8080/catalog/v2/entriescatalog -> HTTP 200Step 9 - Add your own ZIM content
Download any ZIM archive from the Kiwix library into /var/lib/kiwix, then register it with kiwix-manage. The library includes Wikipedia in many languages, Wiktionary, WikiHow, medical and educational libraries, and more.
The running server watches the library and picks up the new archive automatically, so no restart is needed.
# Example: download a ZIM and register it (replace the URL and filename with your own).
sudo curl -fSL -o /var/lib/kiwix/your-content.zim \
https://download.kiwix.org/zim/other/your-content.zim
sudo kiwix-manage /var/lib/kiwix/library.xml add /var/lib/kiwix/your-content.zim
sudo chown kiwix:kiwix /var/lib/kiwix/your-content.zim /var/lib/kiwix/library.xmlTo remove the bundled sample later, delete its file and rebuild the library the same way.
Larger archives (full Wikipedia is tens of gigabytes) need a larger root volume. Resize the EBS volume and grow the filesystem before you download.
Step 10 - Make the library public (optional)
Basic Auth protects the library by default. To serve it openly, for example on a trusted private network, remove the two auth_basic directives from the nginx site and reload nginx. Then confirm that your security group allows the traffic.
sudo nano /etc/nginx/sites-available/sac-kiwix
# remove the two auth_basic lines
sudo nginx -t sudo systemctl reload nginxTo restrict access to specific clients instead, keep Basic Auth, narrow the inbound rule on port 80 in your security group to your own CIDR (your-cidr), or do both.
Step 11 - Service management
kiwix-serve and nginx are managed by systemd:
sudo systemctl status kiwix-serve
sudo systemctl status nginx
sudo journalctl -u kiwix-serve -eBackup and maintenance
- Content lives in
/var/lib/kiwix(the ZIM files andlibrary.xml). Back up that directory to preserve your library. ZIM files are self-contained and portable. - Credentials are in
/root/kiwix-serve-credentials.txt. To rotate the Basic Auth password, regenerate the nginx htpasswd entry for theadminuser and reload nginx. - OS updates: the image ships fully patched with unattended security updates enabled. Apply the latest packages at any time with your normal patch process, and reboot if a new kernel is installed.
Notes on licensing and trademarks
kiwix-serve is distributed under the GNU General Public License version 3. The bundled sample archive is Wikipedia content under the Creative Commons Attribution-ShareAlike 3.0 licence and is freely redistributable with attribution, which the reader preserves on every book card and article. SecureAnyCloud is not affiliated with or endorsed by the Kiwix or openZIM project. All product and company names are trademarks or registered trademarks of their respective holders.
Support
24/7 SecureAnyCloud support backs this image. It covers deployment, first-boot behaviour, the nginx authentication proxy, and adding or replacing ZIM content. Contact support through the details on the SecureAnyCloud listing page.
Deploy on AWS
Launch kiwix-serve on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com