
This article provides a guide demonstrating how to deploy Kiwix Server on Ubuntu VPS.
What is Kiwix Server?
Kiwix Server allows you to host offline copies of websites and knowledge bases and make them available through a normal web browser.
It is commonly used for hosting offline copies of:
- Wikipedia
- Wiktionary
- Project Gutenberg
- Stack Exchange
- Educational resources
- Documentation collections
- Other content distributed in ZIM format
This guide will deploy Kiwix Server on Ubuntu VPS using Docker, stores ZIM archives outside the container, places Kiwix behind Nginx, and secures the public interface with Letβs Encrypt SSL.
Requirements
Before you can deploy Kiwix Server on Ubuntu VPS, ensure you have the recommended starting configuration:
- Ubuntu 22.04 or Ubuntu 24.04
- 2 CPU cores
- 2-4 GB RAM
- 20 GB or more disk space
- Root or sudo access
- Public IPv4 and/or IPv6
- Optional domain such as
wiki.example.com
Storage is normally the most important resource. Large Wikipedia ZIM files may require tens or hundreds of gigabytes.
Compare Ubuntu VPS Plans
How to Deploy Kiwix Server on Ubuntu VPS
To deploy Kiwix Server on Ubuntu VPS, follow the steps outlined below:
-
Β Update Ubuntu
SSH the VPS as root and update the package repository:
sudo apt update
Install available updates:
sudo apt upgrade -y
Install the required utilities:
sudo apt install -y \ curl \ wget \ ca-certificates \ gnupg \ nginx
-
Install Docker
Install Docker using Dockerβs installation script:
curl -fsSL https://get.docker.com | sudo sh
Enable Docker at boot and start it immediately:
sudo systemctl enable --now docker
Verify the installation:
docker --version
Check the Docker service:
sudo systemctl status docker --no-pager
-
Create the Kiwix Directory Structure
Create the main Kiwix directory:
sudo mkdir -p /srv/kiwix/zim
Optionally create a directory for configuration files:
sudo mkdir -p /srv/kiwix/config
Verify:
ls -ld /srv/kiwix /srv/kiwix/zim
The primary ZIM storage location will be:
/srv/kiwix/zim
-
Download ZIM Content
Kiwix serves content stored in
.zimarchives.Change into the ZIM directory:
cd /srv/kiwix/zim
Download the desired ZIM file:
sudo wget "ZIM_DOWNLOAD_URL"
Replace:
ZIM_DOWNLOAD_URL
with the actual download URL.
Verify the file:
ls -lh /srv/kiwix/zim
Check available disk space:
df -h /srv/kiwix
For especially large libraries, also check the current directory size:
du -sh /srv/kiwix/zim
-
Pull the Kiwix Server Container
Download the Kiwix Server image:
sudo docker pull ghcr.io/kiwix/kiwix-serve:latest
Verify that the image is present:
See Also: How to Configure RouterOS on MikroTik CHR VPS Server
sudo docker images | grep kiwix
-
Test Kiwix Server
Run a temporary test container:
sudo docker run --rm \ -p 8080:8080 \ -v /srv/kiwix/zim:/data:ro \ ghcr.io/kiwix/kiwix-serve:latest \ '*.zim'
Then browse to:
http://SERVER_IP:8080
If the Kiwix library interface appears, the application is working.
Stop the temporary container with:
Ctrl+C
-
Start the Production Kiwix Container
For production, bind Kiwix only to localhost:
sudo docker run -d \ --name kiwix \ --restart unless-stopped \ -p 127.0.0.1:8080:8080 \ -v /srv/kiwix/zim:/data:ro \ ghcr.io/kiwix/kiwix-serve:latest \ '*.zim'
This configuration prevents port
8080from being exposed directly to the Internet.Check the container:
sudo docker ps
View logs:
sudo docker logs kiwix
Test locally:
curl -I http://127.0.0.1:8080/
Confirm the listening socket:
sudo ss -lntp | grep 8080
You should see Kiwix listening through Docker on:
127.0.0.1:8080
-
Configure DNS
Create an
Arecord for the Kiwix hostname.Example:
wiki.example.com -> 203.0.113.10
If the server also uses IPv6, optionally create an
AAAArecord.Verify DNS:
dig +short wiki.example.com
Alternatively:
getent hosts wiki.example.com
-
Configure Nginx
Create an Nginx virtual host:
sudo nano /etc/nginx/sites-available/kiwix
Add:
server { listen 80; listen [::]:80; server_name wiki.example.com; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 60s; proxy_send_timeout 300s; proxy_read_timeout 300s; } }Replace:
wiki.example.com
with your actual hostname.
Enable the site:
sudo ln -s /etc/nginx/sites-available/kiwix /etc/nginx/sites-enabled/kiwix
Optionally remove the default site:
sudo rm -f /etc/nginx/sites-enabled/default
Test the Nginx configuration:
sudo nginx -t
Start and enable Nginx:
sudo systemctl enable --now nginx
Reload it:
sudo systemctl reload nginx
-
Configure UFW
Check whether UFW is installed and active:
sudo ufw status
Allow SSH:
sudo ufw allow OpenSSH
Allow HTTP and HTTPS:
sudo ufw allow 'Nginx Full'
Enable the firewall if it is not already active:
sudo ufw enable
Check the resulting configuration:
sudo ufw status
There is no reason to open port
8080, because Kiwix listens only on localhost. -
Test the Website
Browse to:
See Also: How to Migrate from HostGator to Rad Web Hosting (in 4 Easy Steps)
http://wiki.example.com
You can also test from the shell:
curl -I http://wiki.example.com
If it does not work, check Nginx:
sudo systemctl status nginx --no-pager
Check Kiwix:
sudo docker ps
Check Kiwix logs:
sudo docker logs --tail 100 kiwix
Check the Nginx error log:
sudo tail -n 100 /var/log/nginx/error.log
-
Enable HTTPS with Letβs Encrypt
Install Certbot:
sudo apt install -y certbot python3-certbot-nginx
Request a certificate:
sudo certbot --nginx -d wiki.example.com
Follow the prompts.
Afterward, test:
https://wiki.example.com
Verify automatic renewal:
sudo certbot renew --dry-run
-
Verify Automatic Startup
Check Docker:
sudo systemctl is-enabled docker
Check Nginx:
sudo systemctl is-enabled nginx
Because the Kiwix container was created with:
--restart unless-stopped
it should automatically return after Docker starts.
You can test this with:
sudo reboot
After reconnecting:
sudo docker ps
Then verify locally:
curl -I http://127.0.0.1:8080
And externally:
curl -I https://wiki.example.com
-
Add More ZIM Archives
Download additional ZIM files into:
/srv/kiwix/zim
For example:
cd /srv/kiwix/zim sudo wget "ANOTHER_ZIM_URL"
Restart Kiwix:
sudo docker restart kiwix
Because Kiwix was started with:
*.zim
all matching ZIM files in the mounted directory will be loaded.
Verify:
sudo docker logs --tail 50 kiwix
-
Replace or Update ZIM Content
Download the newer archive:
cd /srv/kiwix/zim sudo wget "NEW_ZIM_URL"
Remove the obsolete version when appropriate:
sudo rm old-version.zim
Restart Kiwix:
sudo docker restart kiwix
Verify:
sudo docker logs --tail 50 kiwix
-
Update Kiwix Server
Pull the latest container image:
sudo docker pull ghcr.io/kiwix/kiwix-serve:latest
Stop the existing container:
sudo docker stop kiwix
Remove it:
sudo docker rm kiwix
Recreate it:
sudo docker run -d \ --name kiwix \ --restart unless-stopped \ -p 127.0.0.1:8080:8080 \ -v /srv/kiwix/zim:/data:ro \ ghcr.io/kiwix/kiwix-serve:latest \ '*.zim'
The ZIM files remain intact because they live outside the container.
-
Optional Docker Compose Deployment
Create:
sudo nano /srv/kiwix/compose.yml
Add:
services: kiwix: image: ghcr.io/kiwix/kiwix-serve:latest container_name: kiwix restart: unless-stopped ports: - "127.0.0.1:8080:8080" volumes: - /srv/kiwix/zim:/data:ro command: - "*.zim"Start:
cd /srv/kiwix sudo docker compose up -d
Check status:
sudo docker compose ps
View logs:
sudo docker compose logs -f
Update later with:
cd /srv/kiwix sudo docker compose pull sudo docker compose up -d
-
Optional Kiwix Tuning
Additional Kiwix options can be supplied through the container command.
See Also: How to Install and Run Docker Engine on AlmaLinux VPS (5 Minute Quick-Start Guide)
For example:
command: - "--threads=8" - "--ipConnectionLimit=20" - "--blockexternal" - "*.zim"
Useful options include:
--threads=N
Controls worker threads.
--ipConnectionLimit=N
Limits simultaneous connections from each client IP.
--blockexternal
Prevents Kiwix users from directly navigating to external resources referenced by ZIM content.
For a small VPS, begin with the defaults and tune only if necessary.
-
Backups
Important paths include:
/srv/kiwix/ /etc/nginx/ /etc/letsencrypt/
Check ZIM storage usage:
du -sh /srv/kiwix/zim
Because publicly available ZIM archives can normally be downloaded again, some administrators exclude very large ZIM files from conventional backups.
Custom or privately generated ZIM archives should generally be backed up.
-
Troubleshooting
Check all containers:
sudo docker ps -a
Check Kiwix logs:
sudo docker logs --tail 100 kiwix
Test the backend:
curl -I http://127.0.0.1:8080
Check the port:
sudo ss -lntp | grep 8080
Test Nginx:
sudo nginx -t
Check Nginx:
sudo systemctl status nginx --no-pager
Check its error log:
sudo tail -n 100 /var/log/nginx/error.log
Check disk space:
df -h
List the ZIM library:
ls -lh /srv/kiwix/zim
Restart Kiwix:
sudo docker restart kiwix
Final Ubuntu Architecture
Internet
|
| HTTPS :443
v
+----------------------+
| Nginx |
| Let's Encrypt SSL |
+----------+-----------+
|
| HTTP
| 127.0.0.1:8080
v
+----------------------+
| Kiwix Server |
| Docker Container |
+----------+-----------+
|
| Read-only mount
v
+----------------------+
| /srv/kiwix/zim |
| |
| Wikipedia.zim |
| Wiktionary.zim |
| Gutenberg.zim |
| Other ZIM archives |
+----------------------+
This provides a simple, maintainable Kiwix deployment in which Docker runs the application while Nginx handles the public web interface and TLS.
Conclusion
You now know how to deploy Kiwix Server on Ubuntu VPS.









