Oqtane on Ubuntu 24.04 on Azure User Guide
Overview
Oqtane is an open source content management system and modular application framework built on ASP.NET Core and Blazor. It gives you a full admin experience for building sites, pages and content from reusable modules and themes, and gives developers a modern .NET platform for building web, desktop and mobile applications. The cloudimg image ships Oqtane 10.2.3 on the .NET 10 runtime, running as an ASP.NET Core application under Kestrel behind nginx on a hardened, fully patched Ubuntu 24.04 LTS base. The appliance is self contained: it uses an embedded SQLite database, so there is no separate database server to run. A unique host administrator account is created on the first boot of every VM using a per VM secret, and the install wizard is completed automatically so the very first page a visitor sees is a real, rendered Oqtane site. Backed by 24/7 cloudimg support.
What is included:
- Oqtane 10.2.3 (MIT licensed) on the .NET 10 runtime, run by Kestrel under systemd as
oqtane.service - An embedded SQLite database, so the appliance is complete on its own with no external database server
- nginx serving the site and admin on
:80, with the Blazor Server realtime connection proxied through - A per VM host administrator account created on first boot and recorded in a root only credentials file
- No shipped default login: the host account is created with a unique per VM secret, and no known or blank credential authenticates
- A per VM ASP.NET Core DataProtection keyring, so authentication is never shared across customer VMs
- Kestrel bound to
127.0.0.1:5000only, never exposed to the network; nginx is the only public listener - An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - 24/7 cloudimg support
This image ships only the open source, MIT licensed Oqtane framework. It is not affiliated with or endorsed by the Oqtane project.
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; size up for larger or busier sites. NSG inbound: allow 22/tcp from your management network and 80/tcp for the site and admin. The embedded SQLite database is never exposed on the network, and Kestrel listens on 127.0.0.1 only.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Oqtane 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 then Create.
Step 2 - Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name oqtane \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Then open port 80:
az vm open-port --resource-group <your-rg> --name oqtane --port 80 --priority 900
Step 3 - Confirm the services are running
SSH in as azureuser and confirm the Oqtane (Kestrel) service, nginx and the first boot unit are all active. Kestrel listens only on 127.0.0.1:5000; nginx is the only public listener, serving :80. The unauthenticated /healthz endpoint answers 200 for load balancer probes.
systemctl is-active oqtane nginx oqtane-firstboot
ss -ltnH | grep -E ':(80|5000)' | awk '{print $4}' | sort -u
curl -s -o /dev/null -w '/healthz -> %{http_code}\n' http://127.0.0.1/healthz

First boot completes the Oqtane install automatically. Immediately after a reboot the .NET app performs a short just in time warm up, so allow around 30 seconds for the first page request before it responds.
Step 4 - Retrieve the per VM host administrator login
Every VM creates its own Oqtane host administrator on first boot and writes the username, the generated password and the site URL to a root only credentials file. Read it with sudo:
sudo cat /root/oqtane-credentials.txt

You sign in with the OQTANE_ADMIN_USER (which is host) and the OQTANE_ADMIN_PASSWORD from this file.
Step 5 - Sign in
Browse to http://<vm-public-ip>/ and choose Login (top right), or go straight to http://<vm-public-ip>/login. Sign in with the username host and the password from Step 4.

Step 6 - The Admin Dashboard
Once signed in as the host user, open the Admin Dashboard (the gear icon in the top navigation, or http://<vm-public-ip>/admin). This is the control centre for the whole installation: Site Settings, Page Management, User and Role Management, Module and Theme Management, File Management, Scheduled Jobs, SQL Management and more.

Step 7 - The public website
Your public site is served on http://<vm-public-ip>/. On a fresh install the silent installer has already provisioned the default site and theme, so Oqtane serves a real rendered welcome page immediately - you never see an install wizard. As you build and publish pages in the admin, they replace this starter content.

Step 8 - Build pages with the control panel
When you are signed in, Oqtane shows a control panel in the top navigation (the pencil and gear icons) for adding and editing pages and modules directly on the site. Use it to add your first page, drop in modules, and publish content.

Step 9 - No known or default credentials
Oqtane ships no default login. The cloudimg image goes further: the captured image contains no database and no DataProtection keyring at all, and the host administrator is created with a unique per VM secret the first time the VM boots. You can prove that only the per VM secret works with the built in round trip check, which confirms the per VM host administrator authenticates through the sign in API while a blank password, common guesses and any build time value are all rejected:
sqlite3 /var/lib/oqtane/data/Oqtane.db 'SELECT Username FROM "User";'
sudo bash /usr/local/sbin/oqtane-cred-roundtrip.sh

Step 10 - Verify the stack and where your data lives
Confirm the ASP.NET Core runtime and the Oqtane framework. The SQLite database, the ASP.NET Core DataProtection keyring and your uploaded content all live on this VM's disk, so your site persists across reboots and rides with the VM.
dotnet --list-runtimes | grep AspNetCore
ls /opt/oqtane/app/Oqtane.Server.dll

Adding your own domain
The image serves the site on the VM's public IP out of the box. Oqtane routes requests using site aliases, and enforces a single canonical alias for the site. For production, add your own domain as an alias in Admin Dashboard -> Site Settings -> Aliases and make it the default, then point your DNS at the VM (or at an Azure Load Balancer or Application Gateway in front of it). For TLS, terminate HTTPS at a load balancer or Application Gateway, or place your own reverse proxy or certificate in front of nginx.
Security notes
- The host administrator account is unique per VM and no known or blank credential authenticates. Keep
/root/oqtane-credentials.txtprotected, and change the password from within Oqtane if you share access. - The ASP.NET Core DataProtection keyring is generated per VM on first boot, so authentication cookies are never shared between customer VMs.
- Kestrel listens on
127.0.0.1:5000only and is never reachable from the network. nginx is the only public listener. - The SQLite database lives at
/var/lib/oqtane/data/Oqtane.dbon the VM. - Restrict inbound
80/tcpin your NSG to the networks that need the site, and front the site with your own TLS for production.
Support
This image is maintained by cloudimg with 24/7 support. If you need help deploying or operating Oqtane on Azure, contact us at cloudimg.co.uk.