Application Development Azure

Payload CMS on Ubuntu 24.04 on Azure User Guide

| Product: Payload CMS on Ubuntu 24.04 LTS on Azure

Overview

Payload is a modern, open-source headless CMS and application framework built on Next.js and React. It is code-first - you define your collections, fields and access control in TypeScript - and it generates a fully customisable admin panel together with a REST and GraphQL API automatically. The cloudimg image installs Payload CMS 3.85.1 on Node.js 22 LTS, builds the Next.js production app, runs it as a systemd service behind an nginx reverse proxy on port 80, stores the SQLite database and uploaded media on a dedicated Azure data disk, and generates the application secret and a unique admin user on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • Payload CMS 3.85.1 on Node.js 22 LTS with the Next.js admin panel pre-built
  • The admin panel (/admin) and REST + GraphQL content API published on port 80 via nginx
  • A dedicated Azure data disk at /var/lib/payload for the SQLite database and uploaded media
  • A per-VM PAYLOAD_SECRET and a unique admin user generated on first boot
  • payload.service + nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B2ms (2 vCPU / 8 GiB RAM) is a good starting point. NSG inbound: allow 22/tcp from your management network and 80/tcp for the admin panel and API (front with TLS for public exposure - see Enabling HTTPS).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Payload 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). Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name payload \
  --image <marketplace-image-urn> \
  --size Standard_B2ms \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name payload --port 80 --priority 1010

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active payload.service nginx.service

Both report active. On first boot Payload generates its secret, creates the admin user and builds a clean database.

Step 5 - Retrieve your admin credentials

The admin password is generated uniquely on the first boot of your VM and written to a root-only file:

sudo cat /root/payload-credentials.txt

This file contains payload.admin.email (admin@cloudimg.local) and payload.admin.pass. Store the password somewhere safe.

Step 6 - Check the admin panel responds

The Payload admin panel is served on port 80 and returns 200 when healthy:

curl -s -o /dev/null -w '%{http_code}\n' http://localhost/admin

Step 7 - Open the admin panel

Browse to http://<vm-public-ip>/admin and sign in with admin@cloudimg.local and the password from Step 5.

Payload CMS login

The admin dashboard gives you an overview of your collections, globals and account:

Payload CMS dashboard

Payload generates the admin UI from the collections you define in code. The blank image ships the Users and Media collections - add your own in /opt/payload/src/collections:

Payload CMS collections

The systemd services and version are shown below:

Payload CMS service status

Step 8 - Authenticate against the API

Payload issues an auth token from /api/users/login. Confirm the generated credentials work:

curl -s -H 'Content-Type: application/json' --data '{"email":"admin@cloudimg.local","password":"<PAYLOAD_ADMIN_PASSWORD>"}' http://localhost/api/users/login | head -c 120; echo

A successful login returns a JSON object containing a "token" and the authenticated user.

Step 9 - Use the content API

Every collection you define is served over REST and GraphQL on the same port 80. For example, the built-in users and media collections:

# REST - list documents in a collection (auth required for protected collections)
curl http://<vm-public-ip>/api/media

# GraphQL endpoint
curl -X POST http://<vm-public-ip>/api/graphql \
  -H 'Content-Type: application/json' \
  --data '{"query":"{ Users { totalDocs } }"}'

Add collections and fields in your TypeScript config and Payload regenerates the admin UI and the API automatically.

Step 10 - Confirm content lives on the dedicated disk

The SQLite database and uploaded media are stored on the dedicated Azure data disk so they survive OS changes and can be resized independently:

findmnt /var/lib/payload

The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM. The database is /var/lib/payload/payload.db and uploads are written under /var/lib/payload/uploads.

Enabling HTTPS

The nginx reverse proxy terminates plain HTTP on port 80. For public exposure, put a certificate in front of it - add a DNS name for the VM and install certbot, or use the companion cloudimg nginx-ssl-certbot image as a TLS reverse proxy. Keep Payload bound to loopback (127.0.0.1:3000) so the only public surface is the TLS-terminated proxy. Set serverURL in /opt/payload/src/payload.config.ts to your HTTPS address and restart Payload.

Maintenance

  • Backups: snapshot the /var/lib/payload data disk to back up the database and media.
  • Database: the image uses SQLite, ideal for a single server; for production scale, switch to PostgreSQL by changing the adapter in /opt/payload/src/payload.config.ts and the DATABASE_URL in /opt/payload/.env.
  • Service: sudo systemctl restart payload after configuration changes; logs via journalctl -u payload. After editing collections, rebuild with sudo -u payload npm run build in /opt/payload then restart.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.