WonderCMS on Ubuntu 24.04 on Azure User Guide
Overview
WonderCMS is a tiny, fast, flat file content management system. You edit pages by clicking directly on them in the browser, the frontend is themeable, and administration sits behind a single password login. There is no database: all content and configuration live in one JSON file on the local filesystem, so the whole site is easy to back up and move. The cloudimg image installs WonderCMS 3.6 on nginx and PHP 8.3, all from the Ubuntu 24.04 noble universe with no third party APT repositories. The administrator password is generated uniquely per instance at first boot and the admin login is moved to a random, unguessable address, so the well known default login never ships in the image.
What is included:
- WonderCMS 3.6.0 (MIT) deployed to
/var/www/wondercms, served by nginx with the defaultskytheme - PHP 8.3 FPM with the mbstring, curl, zip, and xml extensions
- A single JSON content store at
/var/www/wondercms/data/database.js, denied to web clients by nginx, no database server wondercms-firstboot.servicegenerating a per VM administrator password (stored only as a hash) and a randomised login URL slug- Host agnostic URLs: the site renders on the VM public IP, on 127.0.0.1, or on any domain you point at it
- nginx and PHP FPM enabled and auto starting on boot
- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key, and a VNet with a subnet. Standard_B2s (2 vCPU, 4 GB RAM) is a comfortable starting point; a flat file CMS is light, so this size serves a typical site well. Open inbound ports 80 and 443 (and 22 to your management network) on the network security group.
Step 1: Deploy and connect
Launch the image from the Azure Marketplace, then connect over SSH as azureuser:
ssh azureuser@<vm-ip>
The first boot service generates the per VM administrator credentials within a few seconds of the instance starting.
Step 2: Verify the services
Confirm nginx and PHP FPM are active and nginx is listening on port 80:
sudo systemctl is-active nginx php8.3-fpm wondercms-firstboot
sudo ss -tlnp | grep ':80 '

Step 3: Check the versions
WonderCMS stamps its version in index.php. Confirm the application, PHP, and nginx versions:
grep -oE "define\('VERSION', '[0-9.]+'\)" /var/www/wondercms/index.php
php -v | head -1
nginx -v

Step 4: Confirm the per VM credential rotation
The image ships with no content store and no working default login. The first boot service writes a fresh data/database.js with a per VM administrator password stored as a hash, and moves the login page to a random address, so the well known default admin password and default /loginURL address are both rejected. The bundled check confirms this end to end against the live store:
sudo systemctl is-active wondercms-firstboot.service
sudo bash /usr/local/sbin/wondercms-cred-roundtrip.sh

Step 5: Read your login address and password
The per VM credentials are written to a root only file. Read it to pick up your WONDERCMS_LOGIN_URL and WONDERCMS_ADMIN_PASSWORD:
sudo cat /stage/scripts/wondercms-credentials.log

Keep this file secure. WONDERCMS_LOGIN_URL is your private admin address and WONDERCMS_ADMIN_PASSWORD is your administrator password. Change the password from within the app once you have signed in for the first time.
Step 6: Browse to your site
The site responds on whatever address you reach it on. Confirm it is serving locally, then browse to http://<vm-ip>/ in your browser to see the public site on the default sky theme:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://127.0.0.1/

Step 7: Sign in to edit
Browse to your private login address (the WONDERCMS_LOGIN_URL from Step 5), enter your administrator password, and click Login. There is no username; WonderCMS uses a single password login. The content store is never web readable, so visiting http://<vm-ip>/data/database.js returns HTTP 403.

Step 8: Edit your pages
Once signed in you see the Settings and logout buttons and every editable region is outlined. Click any text to edit it in place and click outside to save; changes are live immediately. Use the menu to move between pages, and create new pages from Settings. The public site itself needs no external assets; the in browser editing interface loads a small set of static admin assets from the jsDelivr CDN.

Step 9: Settings and security
Open Settings to manage the site. The Security tab shows your admin login URL (change it here to rotate your private login address again), the site language, and the administrator password change form. Other tabs let you switch themes, install plugins, manage the menu, and upload files.

Step 10: Components
| Component | Path |
|---|---|
| WonderCMS application | /var/www/wondercms/ |
| Content store (JSON) | /var/www/wondercms/data/database.js (denied to web clients) |
| Uploaded files | /var/www/wondercms/data/files/ |
| Themes | /var/www/wondercms/themes/ |
| nginx vhost | /etc/nginx/sites-available/wondercms.conf |
| Firstboot script | /usr/local/sbin/wondercms-firstboot.sh |
| Credentials | /stage/scripts/wondercms-credentials.log (mode 0600 root:root) |
Step 11: Security and next steps
- Change the administrator password from Settings, Security after your first sign in, and store it in your own secrets manager.
- Enable HTTPS by installing certbot and requesting a certificate for your domain:
sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.example.com
- Restrict the network security group so that ports 80 and 443 are open only to your CDN or load balancer, and port 22 only to your management network.
- Keep the OS patched regularly with
sudo apt-get updateandsudo apt-get upgrade. - Point your domain at the instance; because the site is host agnostic, no URL rewrite is needed. WonderCMS can also enforce HTTPS from Settings once your certificate is in place.
- Back up by copying
/var/www/wondercms/data/; it holds your whole site in one place.
Licensing
WonderCMS is distributed under the MIT licence and is free to use commercially. cloudimg packages and supports the image; support is available 24/7 at support@cloudimg.co.uk. All product and company names are trademarks or registered trademarks of their respective holders and their use does not imply affiliation or endorsement.