Drupal Commerce on AWS User Guide
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 on a LAMP stack: 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 main and universe repositories with no third-party APT repositories. The site is installed onto your own instance 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_paymentandcommerce_tax - Apache 2.4 with
mod_rewrite, MySQL 8.0, and PHP 8.3 with themysql,gd,mbstring,xml,curl,zip,intlandbcmathextensions - Drush 13 at
/usr/local/bin/drushfor command line administration - A default store created at first boot, so products are immediately sellable
- Two dedicated EBS data volumes: the MySQL datadir at
/var/lib/mysqland the Drupal application tier at/var/www, each independently resizable - Per-instance administrator, application database and MySQL root passwords, all generated on first boot and written to a root-only file, plus a Drupal site installed fresh per instance (unique admin, unique security hash salt) — no shared or default credential ships in the image
- 24/7 cloudimg support
Connecting to your instance
Connect over SSH on port 22 using the private key for the key pair you selected at launch. The login user depends on the operating system variant you launched:
| OS variant | SSH login user |
|---|---|
| Ubuntu 24.04 | ubuntu |
ssh -i /path/to/your-key.pem ubuntu@<instance-public-ip>
Prerequisites
An AWS account, an EC2 key pair, and a VPC subnet. m5.large (2 vCPU, 8 GB RAM) is the recommended instance type and is sufficient for a low to medium traffic store; move to an m5.xlarge or larger for large catalogs, heavy concurrent checkout traffic, or many contributed modules.
In the instance's security group, allow inbound TCP 80 from the addresses that should reach the storefront, and TCP 22 for administration. To serve HTTPS later, also allow TCP 443.
Step 1 - Launch from AWS Marketplace
In the AWS Marketplace console find Drupal Commerce by cloudimg and choose Continue to Subscribe, then Continue to Configuration and Continue to Launch. Pick your region, the m5.large instance type, your VPC subnet, your key pair, and a security group that allows inbound 22 and 80.
Step 2 - Launch from the EC2 CLI
aws ec2 run-instances \
--image-id <ami-id-from-the-listing> \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--subnet-id subnet-xxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=drupal-commerce}]'
Step 3 - Confirm the services are running
Both services that back Drupal Commerce should report active, and the storefront answers HTTP 200. MySQL listens on 127.0.0.1:3306 only, so the database is never exposed to the network:
for s in apache2 mysql; do echo "$s -> $(systemctl is-active "$s")"; done
ss -tlnH | awk '{print $4}' | grep -E ':80$|:3306$'
curl -s -o /dev/null -w 'storefront -> HTTP %{http_code}\n' http://127.0.0.1/
Expected: apache2 -> active, mysql -> active, the two listening sockets, and storefront -> HTTP 200.
Step 4 - Retrieve your administrator credentials
On the first boot of every instance, a one-shot service (drupal-commerce-firstboot.service) generates credentials that are unique to that instance: a fresh MySQL root password, a fresh application database password, and a fresh Drupal administrator password. It then installs the site (so the security hash salt and the administrator account are unique too), enables the Commerce modules and creates the default store. No shared or default credential ships in the image.
sudo stat -c '%a %U:%G %n' /stage/scripts/drupal-commerce-credentials.log
sudo awk -F= '/^DRUPAL_ADMIN_USER=/{print} /^DRUPAL_COMMERCE_URL=/{print} /^DRUPAL_COMMERCE_ADMIN_URL=/{print}' /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. Read the administrator password itself with sudo cat /stage/scripts/drupal-commerce-credentials.log.
You can prove the database credentials really authenticate - and that a wrong password is genuinely rejected - from the instance's own shell, without printing any secret:
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 5 - Visit the storefront
Browse to http://<instance-public-ip>/product/1 (or any product) to see the storefront, served by the Olivero front-end theme with a price and an add-to-cart action. The store is ready for your own products and content.

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 instance's public address, its private address, or a custom domain you point at it later - with no reconfiguration and no "host not trusted" error. You can see that for yourself:
PRIVATE_IP=$(hostname -I | awk '{print $1}')
curl -s -o /dev/null -w 'custom host -> HTTP %{http_code}\n' -H "Host: shop.example.com" http://127.0.0.1/user/login
curl -s -o /dev/null -w 'private addr -> HTTP %{http_code}\n' "http://${PRIVATE_IP}/user/login"
Expected: 200 for both.
Step 6 - The shopping cart
Adding a product places it in the cart, where the customer can adjust quantities before checking out.

Step 7 - Checkout
The default checkout flow offers a returning-customer login and a guest checkout, then collects order information and payment. Add a payment gateway under Commerce -> Configuration -> Payment gateways to take live payments.

Step 8 - Sign in as the administrator
Browse to http://<instance-public-ip>/user/login and sign in with the username cloudimg and the password from the credentials file. Then 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.

You can confirm the administrator account from the command line:
cd /var/www/html/drupal && sudo -u www-data /usr/local/bin/drush user:information cloudimg --field=name
Step 9 - Add 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.

Step 10 - 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.
Step 11 - 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.
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 instance it generates the per-instance 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. It resolves the instance's public address via EC2 IMDSv2 for the credentials-file URL, falling back to the private address.
sudo test -f /var/lib/cloudimg/drupal-commerce-firstboot.done && echo "sentinel present - first boot completed"
Because every secret and the whole site are generated on your own instance, no two cloudimg deployments of this image share a credential or a hash salt, and nothing sensitive exists in the published image.
Administration from the command line
Drush is installed for routine administration. 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 instance 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. Alternatively, place an Application Load Balancer with an AWS Certificate Manager certificate in front of the instance.
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 launched 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.
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 2>/dev/null | 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 AWS account ID and the instance ID.