Cockpit CMS on Ubuntu 24.04 LTS on Azure
Overview
Cockpit CMS is an open source, API first (headless) content platform. You model your content in a clean admin interface as collections and singletons made of typed fields, manage media in a built in asset manager, and then read everything back through a documented REST and GraphQL Content API. Because it is headless it never dictates how your site or app is built: the same content can feed a website, a mobile app, a static site generator or several frontends at once.
The cloudimg image serves Cockpit CMS 2.14.0 behind nginx with PHP 8.3 FPM and OPcache on a hardened, fully patched Ubuntu 24.04 LTS base. Cockpit stores its content in a self contained, file based datastore under storage/data, so there is no separate database server to run or maintain.
The image is deliberately shipped uninstalled, with no users and no application security key. On the first boot of every VM a one shot service generates a unique application security key, seeds a single administrator account with a strong per VM password, and writes those credentials to a root only file. Until that finishes, nginx serves Cockpit on the loopback interface only and nothing is published on port 80 — so no instance is ever reachable from the network in an unclaimed, unconfigured state, and no secret is ever shared between customers. Backed by 24/7 cloudimg support.
What is included:
- Cockpit CMS 2.14.0 served by nginx through the PHP 8.3 front controller, managed by systemd
- The Cockpit admin interface on
:80, requiring an administrator sign in - A per VM administrator account and application security key generated on first boot and recorded in a root only file
- A file based content datastore, shipped empty so no build data is carried into your instance
- The REST and GraphQL Content API for consuming your content from any frontend
nginx.serviceandphp8.3-fpm.serviceas enabled systemd units- 24/7 cloudimg support
Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a sensible starting point and is comfortable for a single editorial team; size up if you serve very high API traffic. NSG inbound: allow 22/tcp from your management network, and 80/tcp (plus 443/tcp once you terminate TLS on the VM) so browsers and your frontends can reach Cockpit and its API.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Cockpit CMS by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). Then Review + create and Create.
Step 2 - Deploy from the Azure CLI
Prefer the command line? The following creates the VM from the cloudimg offer, opens ports 22 and 80, and prints the public IP.
az vm create \
--resource-group my-rg \
--name cockpit-cms \
--image cloudimg:cockpit-cms-ubuntu-24-04:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group my-rg --name cockpit-cms --port 80 --priority 900
az vm show --resource-group my-rg --name cockpit-cms --show-details --query publicIps -o tsv
Step 3 - Confirm the services are running
Connect over SSH with the administrator user you chose at deploy time, then confirm the web tier is up and that first boot initialisation has completed.
systemctl is-active nginx php8.3-fpm
test -f /var/lib/cloudimg/cockpit-cms-firstboot.done && echo "first boot: complete"
php -r 'require "/var/www/cockpit/bootstrap.php"; echo "Cockpit ".APP_VERSION."\n";'
You should see active for both services, the first boot completion line, and the Cockpit version.

Step 4 - Retrieve this VM's administrator credentials
The administrator account was created on this VM's first boot, with a password unique to this machine. It is written to a root only file:
sudo cat /root/cockpit-cms-credentials.txt
The file lists the administrator username, the per VM password and the URL to sign in at. The application security key that Cockpit uses to sign tokens is generated per VM into config/config.php and is never the shared default baked into the source. You can confirm both without revealing the secrets:
sudo stat -c '%a %U:%G' /root/cockpit-cms-credentials.txt
sudo php -r '$c=require "/var/www/cockpit/config/config.php"; echo "sec-key length: ".strlen($c["sec-key"] ?? "")."\n"; echo "is default: ".(($c["sec-key"] ?? "")==="c3b40c4c-db44-s5h7-a814-b5931a15e5e1" ? "yes" : "no")."\n";'
The credentials file is 600 root:root, the security key is a long generated value, and it is not the default.

Step 5 - Sign in to Cockpit
Open http://<your-vm-public-ip>/ in a browser. Cockpit presents its sign in page. Enter the username <COCKPIT_ADMIN_USER> and the password <COCKPIT_ADMIN_PASSWORD> from the credentials file. The unauthenticated web installer at /install is deliberately disabled on this image, so the only way in is the administrator account seeded on first boot.

After signing in you land on the Cockpit dashboard, the home of the admin interface, with the Content, Assets and Settings areas in the navigation.

Step 6 - Model your content
Cockpit organises content into models. A collection holds many entries of the same shape (blog posts, products, team members); a singleton holds a single structured document (a homepage, global settings). Open Content and create a model, add typed fields to it (text, WYSIWYG, boolean, date, asset links and more), and save. Your models appear in the Content area ready for editors to fill.

Step 7 - Create and manage entries
Select a collection and choose Create entry to add content through the generated form. Entries can be published or drafted, and are immediately available over the API. Editors work entirely in this interface without touching code.

Step 8 - Consume content over the Content API
Cockpit exposes every model through a REST API. Create an API key in Settings > API (scope it read only for public frontends), then fetch entries as JSON. From the VM you can confirm the API is serving:
curl -s -o /dev/null -w 'login page: HTTP %{http_code}\n' http://127.0.0.1/auth/login
curl -s -o /dev/null -w 'API root: HTTP %{http_code}\n' http://127.0.0.1/api
A typical frontend request, once you have an API key, looks like this (replace the host and key):
curl -H "api-key: <API_KEY>" "http://<your-domain>/api/content/items/<MODEL_NAME>"
The API returns your entries as JSON, ready for any website, app or static site generator to render.
Step 9 - Verify the security posture
The image is secure by default. Confirm that the unauthenticated installer is denied, that the datastore is not web readable, and that the administrator account is enforced:
curl -s -o /dev/null -w '/install: HTTP %{http_code} (expect 404)\n' http://127.0.0.1/install/
curl -s -o /dev/null -w 'datastore file: HTTP %{http_code} (expect 404)\n' http://127.0.0.1/storage/data/system.sqlite
curl -s -o /dev/null -w 'root path: HTTP %{http_code}\n' http://127.0.0.1/
The installer and the raw datastore both return 404, so no stranger can seize the instance or download your content database.

Step 10 - Confirm first boot and ongoing patching
The one shot first boot service leaves a sentinel and enables unattended security upgrades so the OS keeps patching itself.
systemctl is-enabled cockpit-cms-firstboot.service
systemctl is-active unattended-upgrades.service
uname -r

Step 11 - Enable HTTPS with Let's Encrypt
Before putting Cockpit in front of real traffic, terminate TLS. Point a DNS record at the VM, allow 443/tcp in the NSG, then install a certificate with certbot for your domain:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d <your-domain>
Certbot obtains the certificate and rewrites the nginx vhost to serve Cockpit over HTTPS with automatic renewal.
Step 12 - Back up and maintain your VM
Cockpit's entire state is a directory tree. Back up the content datastore, uploaded assets and the per VM configuration together:
sudo tar czf <backup-dir>/cockpit-backup-$(date +%F).tgz \
-C /var/www/cockpit storage/data storage/uploads config/config.php
Restore by extracting the archive back into /var/www/cockpit on a fresh instance after first boot. Keep the /root/cockpit-cms-credentials.txt file somewhere safe, and change the administrator password from Account after your first sign in.
Security notes
- The image ships with no users and no application security key; both are generated per VM on first boot, so nothing secret is shared between customers.
- Cockpit is bound to loopback until first boot completes, so an unconfigured instance is never reachable from the network.
- The
/installweb installer is denied at the nginx layer, and the raw.sqlitedatastore, config and dotfiles are never web served. - Change the administrator password after first sign in, enable HTTPS before exposing the instance, and scope API keys to read only for public frontends.
- Keep the VM patched. Unattended security upgrades are enabled by default.
Architecture summary
| Component | Detail |
|---|---|
| Application | Cockpit CMS 2.14.0 (headless content platform, MIT) |
| Web server | nginx serving the PHP 8.3 front controller |
| Runtime | PHP 8.3 FPM with OPcache |
| Datastore | File based (SQLite), under /var/www/cockpit/storage/data |
| Document root | /var/www/cockpit |
| Admin interface | http://<vm>/ (port 80; add TLS on 443) |
| Content API | REST and GraphQL under /api |
| First boot service | cockpit-cms-firstboot.service (per VM key and administrator) |
| Credentials file | /root/cockpit-cms-credentials.txt (mode 600, root) |
| Base OS | Ubuntu 24.04 LTS, hardened and fully patched |
Support
Every cloudimg image is backed by 24/7 support. Email support@cloudimg.co.uk with the VM name and, where relevant, the output of the commands in this guide. Cockpit CMS is open source software licensed under the MIT License; the verbatim licence text ships in the image at /var/www/cockpit/LICENSE.