E-commerce Azure

Drupal Commerce on Ubuntu 24.04 on Azure User Guide

| Product: Drupal Commerce on Ubuntu 24.04 LTS on Azure

Overview

Drupal Commerce is the open source e-commerce framework built on Drupal. Rather than bolting a shop onto a content system, it models commerce natively: products and variations, carts and orders, a configurable checkout flow, flexible pricing and promotions, tax and currency handling, and pluggable payment gateways are all first class Drupal entities. Every commerce object is fieldable, referenceable and viewable with the same tools you use for the rest of the site, so catalog data and editorial content are modelled together instead of synchronised between systems.

The cloudimg image delivers Drupal Commerce fully installed on Ubuntu 24.04 — Drupal core 11.4.4 with Drupal Commerce 3.3.8, served by Apache 2.4 with PHP 8.3 and backed by MySQL 8.0, all from the Ubuntu 24.04 main and universe repositories with no third-party APT repositories. The site is installed onto your own VM at first boot, with the Commerce modules already enabled and a default store already created, so you land on a working storefront and Commerce admin rather than an installer. Backed by 24/7 cloudimg support.

What is included:

  • Drupal core 11.4.4 (GPL-2.0-or-later) at /var/www/html/drupal, installed from the official ftp.drupal.org tarball and verified against the publisher's own checksum at build time
  • Drupal Commerce 3.3.8 (Commerce Core, GPL-2.0-or-later) installed via Composer, with nine Commerce modules enabled: commerce, commerce_price, commerce_store, commerce_product, commerce_order, commerce_cart, commerce_checkout, commerce_payment and commerce_tax
  • Apache 2.4 with mod_rewrite, MySQL 8.0, and PHP 8.3 with the mysql, gd, mbstring, xml, curl, zip, intl and bcmath extensions
  • Drush 13 at /usr/local/bin/drush for command line administration
  • A default store created at first boot, so products are immediately sellable
  • Per-VM administrator, application database and MySQL root passwords, all generated on first boot and written to a root-only file — no shared or default credential ships in the image
  • 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 the recommended size and is sufficient for a low to medium traffic store; move to a D2s or D4s size for larger catalogs, heavy concurrent checkout traffic, or many contributed modules.

Allow inbound TCP 80 from the addresses that should reach the storefront, and TCP 22 for administration.

Step 1 — Deploy from the Azure Marketplace

In the Azure portal choose Create a resource, search for Drupal Commerce on Ubuntu 24.04 LTS by cloudimg, and select Create. Pick your subscription, resource group and region, choose the Standard_B2s size, supply your SSH public key for the azureuser account, and allow inbound ports 22 and 80.

Step 2 — Deploy from the Azure CLI

az vm create \
  --resource-group my-resource-group \
  --name my-drupal-commerce \
  --image cloudimg1702aborea:drupal-commerce-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --generate-ssh-keys \
  --public-ip-sku Standard

Step 3 — Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 — Confirm the services are running

Both services that back Drupal Commerce should report active, the first-boot service should report inactive (it is a one-shot that has already completed), and the storefront answers HTTP 200:

systemctl is-active apache2 mysql drupal-commerce-firstboot
ss -tlnH | awk '{print $1, $4}' | grep -E ':80$|:3306$'
curl -s -o /dev/null -w 'storefront -> %{http_code}\n' http://127.0.0.1/

Expected: active, active, then inactive for the completed one-shot, the two listening sockets, and storefront -> 200. Note that MySQL listens on 127.0.0.1:3306 only — the database is not exposed to the network.

Service status and listening ports

Step 5 — Retrieve your administrator credentials

On the first boot of every VM, a one-shot service (drupal-commerce-firstboot.service) generates credentials that are unique to that VM: a fresh MySQL root password, a fresh application database password, and a fresh Drupal administrator password. It then installs the site, enables the Commerce modules and creates the default store. No shared or default credential ships in the image.

sudo cat /stage/scripts/drupal-commerce-credentials.log
sudo stat -c '%a %U:%G %n' /stage/scripts/drupal-commerce-credentials.log

The file is mode 0600 and owned by root, so only root can read it. It contains the storefront and admin URLs, the administrator username (cloudimg) and password, and the database credentials.

Per-VM credentials, masked, and the root-only file mode

You can prove the database credentials really authenticate — and that a wrong password is genuinely rejected — from the VM's own shell:

DB_USER=$(sudo awk -F= '$1=="DRUPAL_DB_USER"{print $2}' /stage/scripts/drupal-commerce-credentials.log)
DB_PASS=$(sudo awk -F= '$1=="DRUPAL_DB_PASSWORD"{print $2}' /stage/scripts/drupal-commerce-credentials.log)
OK=$(mysql -u "$DB_USER" -p"$DB_PASS" -D drupalcommerce -N -B -e 'SELECT 1' 2>/dev/null || true)
BAD=$(mysql -u "$DB_USER" -p'wrong-password' -D drupalcommerce -N -B -e 'SELECT 1' 2>/dev/null || true)
echo "correct password -> ${OK:-rejected}"
echo "wrong password   -> ${BAD:-rejected}"

Expected: correct password -> 1 and wrong password -> rejected.

Step 6 — Visit the storefront

Browse to http://<vm-public-ip>/. The storefront is served by the Olivero front-end theme and is ready for your own content and products.

The Drupal Commerce storefront

The image does not bake an address into the site configuration. Drupal derives the base URL from the incoming request, so the storefront answers correctly on the VM's public address, its private address, or a custom domain you point at it later — with no reconfiguration. You can see that for yourself:

PRIVATE_IP=$(hostname -I | awk '{print $1}')
curl -s -o /dev/null -w 'public request  -> %{http_code}\n' -H "Host: shop.example.com" http://127.0.0.1/user/login
curl -s -o /dev/null -w 'private address -> %{http_code}\n' "http://${PRIVATE_IP}/user/login"

Expected: 200 for both.

Step 7 — Sign in as the administrator

Browse to http://<vm-public-ip>/user/login and sign in with the username cloudimg and the password from the credentials file.

The Drupal sign-in page

Step 8 — The Commerce dashboard

After signing in, choose Commerce in the administration menu. The dashboard gives you Orders, Products and Configuration, alongside store performance panels for carts, placed orders, gross sales and best selling products.

The Drupal Commerce administration dashboard

Step 9 — Review your store

A default store, cloudimg Demo Store, is created on first boot so that products are immediately sellable — Commerce requires a store before anything can be sold. Find it under Commerce → Configuration → Stores. Select Edit to set your own store name, email address, postal address, default currency and billing countries.

The default store created at first boot

Step 10 — Create your first product

Choose Commerce → Products → Add product. Give the product a title and description, then use Save and add variations to create the purchasable variations, each with its own SKU and price. Variations are what customers actually add to the cart, so a single product can carry several sizes, colours or editions.

Adding a product

Step 11 — Confirm the versions

cd /var/www/html/drupal && sudo -u www-data /usr/local/bin/drush status --field=drupal-version
php -r '$l=json_decode(file_get_contents("/var/www/html/drupal/composer.lock"),true); foreach($l["packages"] as $p){ if($p["name"]==="drupal/commerce") printf("drupal/commerce %s\n",$p["version"]); }'
php -v | head -1

Expected: 11.4.4, drupal/commerce 3.3.8, and PHP 8.3.

Drupal core, Drupal Commerce and PHP versions

Step 12 — Confirm Commerce is installed

cd /var/www/html/drupal && sudo -u www-data /usr/local/bin/drush pm:list --status=enabled --filter=commerce --field=name
cd /var/www/html/drupal && sudo -u www-data /usr/local/bin/drush php:eval 'printf("stores configured: %d\n", count(\Drupal::entityTypeManager()->getStorage("commerce_store")->loadMultiple()));'

Expected: the enabled Commerce modules, then stores configured: 1.

Enabled Commerce modules, the first-boot store and the Commerce schema

First-boot service and security model

drupal-commerce-firstboot.service is a one-shot unit ordered After=mysql.service apache2.service. On the first boot of each VM it generates the per-VM secrets, provisions the application database, installs the site, enables the Commerce modules, creates the default store, writes the credentials file at mode 0600, and drops a sentinel at /var/lib/cloudimg/drupal-commerce-firstboot.done so it runs exactly once.

systemctl status drupal-commerce-firstboot.service --no-pager | head -5
sudo test -f /var/lib/cloudimg/drupal-commerce-firstboot.done && echo "sentinel present — first boot completed"

Because every secret is generated on your own VM, no two cloudimg deployments of this image share a credential, and nothing sensitive exists in the published image.

Administration from the command line

Drush is installed for routine administration:

cd /var/www/html/drupal && sudo -u www-data /usr/local/bin/drush status | head -12

To reset the administrator password, or to add another administrator:

cd /var/www/html/drupal
sudo -u www-data /usr/local/bin/drush user:password cloudimg 'your-new-password'
sudo -u www-data /usr/local/bin/drush user:create alice --mail=alice@example.com --password='her-password'
sudo -u www-data /usr/local/bin/drush user:role:add administrator alice

Using your own domain and HTTPS

The image serves plain HTTP on port 80 so that it works immediately on any address. For a production storefront, point your domain at the VM and terminate TLS. The quickest route is Certbot with the Apache plugin:

sudo apt-get update && sudo apt-get install -y certbot python3-certbot-apache
sudo certbot --apache -d shop.example.com

Because no address is baked into the site configuration, the storefront starts answering on your domain as soon as DNS resolves — there is nothing to reconfigure in Drupal.

For a production site you should also tighten the trusted host pattern. The image ships a permissive pattern so the storefront works on any address out of the box; once you have settled on your domain, edit /var/www/html/drupal/sites/default/settings.php and replace it:

$settings['trusted_host_patterns'] = ['^shop\.example\.com$'];

Keeping Drupal and Commerce up to date

Both Drupal core and Drupal Commerce are pinned to the versions verified at build time, so the image you certified is the image that runs. Apply upstream updates with Composer when you are ready:

cd /var/www/html/drupal
sudo -u www-data composer update drupal/core-recommended --with-all-dependencies
sudo -u www-data composer update drupal/commerce --with-all-dependencies
sudo -u www-data /usr/local/bin/drush updatedb -y
sudo -u www-data /usr/local/bin/drush cache:rebuild

Always take a backup first (see below), and test updates outside production.

Two advisory notices appear on Drupal's status report on this platform, neither of which is a fault:

  • HTML5 validation — the image explicitly sets enable_html5_validation to TRUE to preserve current form behaviour. Drupal notes that this setting is removed in Drupal 13; the notice is a forward-compatibility advisory, not an error.
  • GD library / AVIF — the PHP GD build shipped by Ubuntu 24.04 supports GIF, JPEG, PNG and WebP but not AVIF, because the distribution package is built without that codec. All common web image formats are supported.

Backup and maintenance

Back up the database and the site files:

cd /var/www/html/drupal
sudo -u www-data /usr/local/bin/drush sql:dump --result-file=/var/backups/drupalcommerce-$(date +%F).sql
sudo tar czf /var/backups/drupal-files-$(date +%F).tar.gz /var/www/html/drupal/sites/default/files

The operating system receives unattended security upgrades. Check for pending updates with:

apt-get -s -o APT::Get::Always-Include-Phased-Updates=true dist-upgrade | grep -c '^Inst ' || true

Licensing

Drupal core and Drupal Commerce are both distributed under the GNU General Public License, version 2 or later (GPL-2.0-or-later). The licence text ships in the image at /var/www/html/drupal/LICENSE.txt and /var/www/html/drupal/modules/contrib/commerce/LICENSE.txt. cloudimg charges only for the packaging, maintenance and support of the image; the software itself remains under its open source licence.

Support

Every cloudimg image includes 24/7 support. Contact support@cloudimg.co.uk with your Azure subscription ID and the VM name.