Mercur on Ubuntu 24.04 on Azure User Guide
Overview
Mercur is an open source multi vendor marketplace platform built on the Medusa v2 commerce engine. Where a conventional store has one catalogue and one owner, Mercur adds the seller as a first class concept: vendors register themselves, the marketplace operator approves them, and each vendor then manages their own products, offers, promotions, stock and orders from a dedicated panel. The operator keeps central oversight of every store, order and payout. Because it is built on Medusa, the whole marketplace is also a headless REST API that any storefront, mobile app or point of sale client can consume.
The cloudimg image builds Mercur 2.2.1 and both of its web panels ahead of time and bakes them into the image, so the marketplace answers as soon as the VM finishes its first boot, with nothing to compile, download or configure. Backed by 24/7 cloudimg support.
What is included:
- Mercur 2.2.1 (MIT licensed) with the marketplace REST API, the admin panel and the vendor panel, all served by one Node process
- The admin panel at
/dashboardfor the marketplace operator, and the vendor panel at/sellerfor individual sellers, with seller self registration enabled - PostgreSQL 16 and Redis 7 on the same VM, both bound to the loopback interface
- nginx as a reverse proxy on port 80, so the marketplace, both panels and the API share one origin
- A unique administrator account, database password, token signing secret and cookie secret generated on the first boot of every VM
mercur-set-origin, a helper that points the appliance at your own domain or TLS terminator without a rebuild- Node.js 22 and a fully patched Ubuntu 24.04 LTS base with unattended security upgrades enabled
Key facts:
| Item | Value |
|---|---|
| Platform | Ubuntu 24.04 LTS |
| Default SSH user | azureuser |
| Marketplace API | http://<vm-ip>/ |
| Admin panel | http://<vm-ip>/dashboard |
| Vendor panel | http://<vm-ip>/seller |
| Application directory | /opt/mercur |
| Credentials file | /root/mercur-credentials.txt |
| Recommended VM size | Standard_B2s (2 vCPU, 4 GiB) |
Prerequisites
- An Azure subscription with permission to create virtual machines.
- An SSH key pair for the
azureuseraccount. - A network security group that allows inbound TCP 22 for SSH and TCP 80 for the marketplace.
- Recommended VM size: Standard_B2s (2 vCPU, 4 GiB). The whole stack runs comfortably inside that envelope.
Step 1 - Deploy from the Azure Marketplace
- In the Azure portal, choose Create a resource and search for Mercur on Ubuntu 24.04 LTS by cloudimg.
- Choose Create, then select your subscription, resource group and region.
- Set the VM size to Standard_B2s, choose SSH public key as the authentication type and set the username to
azureuser. - On the Networking tab, allow inbound SSH (22) and HTTP (80).
- Choose Review + create, then Create.
Step 2 - Deploy from the Azure CLI
Run these on your own workstation, where the Azure CLI is installed and signed in. They create the VM, open the marketplace port and print the public IP address:
az vm create \
--resource-group my-resource-group \
--name mercur-01 \
--image cloudimg:mercur:default:latest \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group my-resource-group --name mercur-01 --port 80
az vm show --resource-group my-resource-group --name mercur-01 \
--show-details --query publicIps --output tsv
Step 3 - Connect to your VM
ssh azureuser@<vm-ip>
Step 4 - Confirm the marketplace is running
First boot generates every per VM secret and starts the marketplace. Confirm it has completed:
test -f /var/lib/cloudimg/mercur-firstboot.done && echo "first boot: complete"
Expected output:
first boot: complete
Check the services:
systemctl is-active mercur.service postgresql redis-server nginx
Expected output:
active
active
active
active

Check the health endpoint:
curl -s -o /dev/null -w 'health endpoint: HTTP %{http_code}\n' http://127.0.0.1/healthz
Expected output:
health endpoint: HTTP 200
Confirm both panels are being served:
curl -s -o /dev/null -w '/dashboard: HTTP %{http_code}\n' -L http://127.0.0.1/dashboard
curl -s -o /dev/null -w '/seller: HTTP %{http_code}\n' -L http://127.0.0.1/seller
Expected output:
/dashboard: HTTP 200
/seller: HTTP 200
Step 5 - Retrieve the administrator password
The image ships with no usable account. First boot creates a single administrator with a password unique to your VM and writes it to a root only file:
sudo stat -c '%a %U:%G' /root/mercur-credentials.txt
Expected output:
600 root:root
Read the credentials:
sudo cat /root/mercur-credentials.txt
The file contains your marketplace URLs, the administrator email address and the generated password.

Step 6 - Sign in to the admin panel
Open http://<vm-ip>/dashboard in a browser and sign in with the administrator email address and password from Step 5.

After signing in you land on the marketplace console. The left hand navigation carries the ordinary commerce sections plus the two that make this a marketplace rather than a single store: Stores, the registry of every vendor, and Payouts, what each vendor is owed.

Step 7 - Onboard your first vendor
Vendors register themselves through the vendor panel. Open http://<vm-ip>/seller in a browser and choose Create an account.

You can also register a vendor from the command line. This creates a member account and then the store it owns:
TOKEN=$(curl -s -X POST -H 'Content-Type: application/json' \
-d '{"email":"vendor@example.com","password":"Choose-A-Strong-Password"}' \
http://127.0.0.1/auth/member/emailpass/register | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')
echo "member registered: ${TOKEN:+yes}"
Expected output:
member registered: yes
Create the store that member owns:
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"Harbourside Supply Co.","email":"vendor@example.com","handle":"harbourside-supply","currency_code":"gbp"}' \
http://127.0.0.1/vendor/sellers | sed -n 's/.*"status":"\([^"]*\)".*/store status: \1/p'
Expected output:
store status: pending_approval
A newly registered store arrives as Pending and cannot trade until you approve it. That approval step is the marketplace operator's control over who sells on the platform.
Step 8 - Approve the store
In the admin panel choose Stores. The vendor you just registered appears in the registry with a Pending status.

Use the row actions to review and approve the store. Once approved, the vendor can sign in at /seller and start listing products. Each vendor sees only their own catalogue and orders, while you keep the full view across every store.
Products added by your vendors appear under Products, where Offers records which vendor sells which product and at what price. That is the mechanism that lets several independent sellers list against the same catalogue entry.

Step 9 - Point the marketplace at your own domain
The appliance serves both panels from the same origin as the API, so it works on the VM address with no configuration. When you put it behind a domain name, a load balancer or a TLS terminator, tell it the public origin so that CORS and uploaded file URLs match:
sudo mercur-set-origin https://shop.example.com
The helper updates the marketplace configuration and restarts the service. Run it again at any time if the address changes. To return to the default behaviour where the panels follow whatever address the browser used:
sudo mercur-set-origin --same-origin http://127.0.0.1
Expected output ends with:
MERCUR_SET_ORIGIN_OK same-origin http://127.0.0.1
Security
The image contains no usable credential. Every secret is generated on the first boot of your VM:
sudo /usr/local/lib/mercur/mercur-start-guard.sh
Expected output:
mercur-start-guard: OK - per-VM secrets in effect
That guard runs before the marketplace starts, on every start. It refuses to run if the token signing secret or cookie secret is empty, is the value published in the upstream project, or still holds a build time value. Upstream's demo catalogue, which ships a published seller login, is never installed.

Recommended hardening:
- Restrict the network security group to the addresses that need it. Allow TCP 80 only from your users, and TCP 22 only from your administrators. The marketplace process also listens on port 9000 directly; leave that port closed in the network security group so all traffic arrives through nginx.
- Put a TLS certificate in front of the appliance and run
mercur-set-origin https://your-domain. The session cookie automatically becomes a Secure cookie as soon as the proxy in front setsX-Forwarded-Proto: https, so no further change is needed. - Change the administrator password after your first sign in, from the account menu in the admin panel.
- Take regular backups of the PostgreSQL database, which holds every store, product, order and payout record.
Maintenance
Restart the marketplace:
sudo systemctl restart mercur.service
Check the service state:
sudo systemctl status mercur.service --no-pager | head -4
To read the application log, use sudo journalctl -u mercur.service -n 50 --no-pager, or follow it live with sudo journalctl -u mercur.service -f.
Back up the marketplace database:
sudo -u postgres pg_dump mercur | gzip > ~/mercur-backup.sql.gz
ls -lh ~/mercur-backup.sql.gz
The base image applies security updates automatically through unattended upgrades.

Server components
| Component | Version | Purpose |
|---|---|---|
| Mercur | 2.2.1 | Multi vendor marketplace platform |
| Node.js | 22.x | Runtime for the marketplace API and panels |
| PostgreSQL | 16 | Stores, products, orders, payouts |
| Redis | 7 | Cache, event bus, workflow engine and locking |
| nginx | 1.24 | Reverse proxy on port 80 |
Scripts and log files
| Path | Purpose |
|---|---|
/opt/mercur |
Application directory |
/opt/mercur/packages/api/.medusa/server |
Built marketplace server and both panels |
/opt/mercur/panels-pristine |
Pristine panel bundles used by mercur-set-origin |
/root/mercur-credentials.txt |
Per VM administrator credentials |
/usr/local/bin/mercur-set-origin |
Points the appliance at a public origin |
/stage/scripts/mercur-firstboot.sh |
First boot provisioning script |
/var/log/cloudimg-firstboot.log |
First boot log |
On startup
mercur-firstboot.service runs once, on the very first boot of your VM. It generates the database password, the token signing secret, the cookie secret and the administrator password, points the panels at this VM, applies any outstanding database migrations, and only then writes the marker that permits mercur.service to start. It disables itself afterwards, so later reboots go straight to the marketplace.
Confirm it ran and then stood down:
test -f /var/lib/cloudimg/mercur-firstboot.done && echo "first boot: complete"
systemctl is-enabled mercur-firstboot.service || true
Expected output:
first boot: complete
disabled
disabled is the expected state here: the unit removes itself from the boot sequence once it has provisioned the VM. systemctl reports a non zero exit status for a disabled unit, which is why the command above ends with || true.
Read the first boot log with sudo cat /var/log/cloudimg-firstboot.log if you need to see what it did.
Troubleshooting
The panels bounce back to the sign in page. The marketplace signs users in with a session cookie. If you have placed a TLS terminator in front of the appliance, make sure it forwards X-Forwarded-Proto so the cookie is issued correctly, then run sudo mercur-set-origin https://your-domain.
The marketplace does not answer on port 80. Check that first boot finished and the service started:
systemctl is-active mercur.service
sudo journalctl -u mercur-firstboot.service -n 20 --no-pager
The service refuses to start. The start guard blocks startup if the per VM secrets are missing. Run it directly to see which check failed:
sudo /usr/local/lib/mercur/mercur-start-guard.sh
Uploaded product images do not display. The address baked into uploaded file URLs is set on first boot. If you have since moved the appliance to a domain name, run sudo mercur-set-origin https://your-domain.
Support
cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with your Azure subscription ID and the VM name.
Mercur is open source software licensed under the MIT licence. cloudimg is not affiliated with or endorsed by Mercur or Medusa.