Kill Bill on Ubuntu 24.04 on Azure User Guide
Overview
Kill Bill is a mature open source platform for subscription billing and payments, released under the Apache License 2.0. It manages the whole recurring-revenue lifecycle: catalogs and price plans, subscriptions with trials, upgrades, downgrades and cancellations, usage metering, invoice generation and dunning, payments through pluggable gateways, refunds and chargebacks, credits and account balances, and a full audit trail over every change. It is multi-tenant from the ground up, and everything it exposes over its REST API is also available in the Kaui administration console that ships with this image.
A word about the version number, because it is easy to misread. 0.24 is a pre-1.0 version number, not a pre-1.0 project. The 0.24 line has been Kill Bill's production series for years, across twenty-one patch releases, with a documented security process, and Kill Bill has a production lineage that began at Groupon. This image ships Kill Bill 0.24.21 (released 12 August 2026) with Kaui 4.0.31 (released 15 September 2026).
What is included:
- Kill Bill 0.24.21 running in its own Apache Tomcat 9.0.122 instance as the unprivileged
killbilluser, bound to127.0.0.1:8080only - Kaui 4.0.31, the administration console, in a second Tomcat instance as the unprivileged
kauiuser, bound to127.0.0.1:9090only - Each application on the Java runtime its own upstream supports: Kill Bill on OpenJDK 17, Kaui on OpenJDK 21
- MySQL 8.0 bound to localhost, holding the
killbillandkauischemas - nginx as the only network front door, serving everything over HTTPS on port 443 with a certificate generated for your VM; port 80 issues a permanent redirect and answers load balancer probes at
/healthz - A default-deny host firewall, so the only ports reachable from outside your VM are 22, 80 and 443
- No default login and no data. The administrator password, the tenant API key and secret, both database passwords, the console's session and encryption keys and the TLS certificate are all generated on the first boot of your VM
Kill Bill and Kaui are trademarks of their respective owners; KILL BILL is separately a registered trademark of Miramax LLC for an unrelated film franchise. cloudimg is not affiliated with, endorsed by or sponsored by any of them; this image packages the unmodified open source software.

Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2ms (2 vCPU, 8 GiB RAM) is the recommended size and the size this image is tested on: Kill Bill and Kaui are two JVMs whose configured heaps total 3.5 GiB, and with MySQL alongside them a 4 GiB VM cannot hold the stack without swap. Network security group inbound rules: 22/tcp from your management network, 443/tcp for the console and API, and optionally 80/tcp, which only redirects to HTTPS.
Step 1: Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for Kill Bill 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 HTTPS (443). Then select Review + create and Create.
Step 2: Deploy from the Azure CLI
az vm create \
--resource-group my-resource-group \
--name killbill \
--image <marketplace-image-urn> \
--size Standard_B2ms \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Open HTTPS (and, if you want the redirect, HTTP) to your users:
az vm open-port --resource-group my-resource-group --name killbill --port 443 --priority 900
az vm open-port --resource-group my-resource-group --name killbill --port 80 --priority 910
Step 3: Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4: Confirm the Kill Bill stack is running
First boot creates your databases, generates this VM's secrets and starts both applications before anything is served. Allow about three minutes after the VM is created; Kaui is a JRuby application and takes the longest to warm up. When the four services report active, the stack is ready:
systemctl is-active mysql killbill kaui nginx
active
active
active
active
Each application runs on the Java runtime its own upstream supports, and Kill Bill answers its own health check:
curl -s -o /dev/null -w 'Kill Bill health: HTTP %{http_code}\n' http://127.0.0.1:8080/1.0/healthcheck
Kill Bill health: HTTP 200

Step 5: Check what the network can reach
Only SSH and the two web ports are reachable from outside your VM. Kill Bill, Kaui and MySQL are all bound to the loopback address:
ss -H -lnt | awk '{print $4}' | sort -u
*:1099
*:36003
0.0.0.0:22
0.0.0.0:443
0.0.0.0:80
127.0.0.1:3306
127.0.0.53%lo:53
127.0.0.54:53
[::]:22
[::]:443
[::]:80
[::ffff:127.0.0.1]:8080
[::ffff:127.0.0.1]:9090
Three entries deserve an explanation. [::ffff:127.0.0.1]:8080 and :9090 are the IPv4-mapped form of 127.0.0.1 — that is Kill Bill and Kaui listening on loopback only. *:1099, and the second high-numbered port beside it (36003 here — the kernel picks a different one on every boot, so expect another number on your VM), belong to an RMI registry that Kill Bill's plugin framework starts for its own internal use; Kill Bill only ever contacts it on 127.0.0.1, but the Java call that creates it accepts no bind address, so it binds every interface. The image therefore ships a default-deny firewall, which is what actually decides the reachable surface:
nft list chain inet cloudimg_killbill input | grep -E 'policy|tcp dport'
type filter hook input priority filter; policy drop;
tcp dport { 22, 80, 443 } accept

Port 80 serves nothing but a health probe and a permanent redirect to HTTPS:
curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\n' http://127.0.0.1/
301 -> https://127.0.0.1/
Step 6: Retrieve this VM's credentials
Every secret this image uses is generated on the first boot of your own VM and written to a file only root can read. Nothing is shared with any other VM, and none of the credentials published in Kill Bill's own documentation works here.
ls -l /root/killbill-credentials.txt
-rw------- 1 root root 977 /root/killbill-credentials.txt
sudo sed -E 's/=(.+)/=<generated-on-your-vm>/' /root/killbill-credentials.txt
# Kill Bill on Ubuntu 24.04 by cloudimg - generated on first boot, unique to THIS VM.
# Keep this file safe. Change the administrator password after your first sign in.
KILLBILL_URL=<generated-on-your-vm>
KILLBILL_API_URL=<generated-on-your-vm>
KILLBILL_ADMIN_USER=<generated-on-your-vm>
KILLBILL_ADMIN_PASSWORD=<generated-on-your-vm>
KILLBILL_TENANT_API_KEY=<generated-on-your-vm>
KILLBILL_TENANT_API_SECRET=<generated-on-your-vm>
KILLBILL_DB_USER=<generated-on-your-vm>
KILLBILL_DB_PASSWORD=<generated-on-your-vm>
KAUI_DB_USER=<generated-on-your-vm>
KAUI_DB_PASSWORD=<generated-on-your-vm>

To read the real values on your own VM, print the file:
sudo cat /root/killbill-credentials.txt
Step 7: Run the built-in self-test
The image ships a self-test that proves the appliance is working and that every credential published in Kill Bill's documentation is refused on your VM — the built-in admin/password administrator, the bob/lazar tenant from the tutorials, blank and weak passwords, and the root/root database login:
sudo /usr/local/sbin/killbill-selftest.sh /root/killbill-credentials.txt | tail -26
The last line is KILLBILL_SELFTEST_OK when every check passed.

Step 8: Sign in to the Kaui console
Open KILLBILL_URL from the credentials file in a browser — that is https://<vm-public-ip>/. Sign in as admin with KILLBILL_ADMIN_PASSWORD.
Your browser will warn about the certificate: the image generates a self-signed certificate for your VM's address at first boot. Step 12 covers installing your own.
Step 9: Register your tenant
Kill Bill is multi-tenant, and first boot has already created a tenant for you with the API key and secret in your credentials file. Kaui stores tenant API secrets itself, encrypted at rest, so the first time you sign in it asks you to register that tenant. This is Kill Bill's normal onboarding, not an error.
On the Add tenant page enter any name you like (for example production), then paste KILLBILL_TENANT_API_KEY into API key and KILLBILL_TENANT_API_SECRET into API secret, and save.

Step 10: Load a catalog and create your first subscription
Kill Bill bills against a catalog: the products, plans and prices you sell. Until you upload one there is nothing to subscribe an account to. The commands below use the REST API with the credentials from Step 6; export them first so they never appear in your shell history:
read -rs KBPW && export KBPW
read -rs KBKEY && export KBKEY
read -rs KBSEC && export KBSEC
Upload a minimal catalog with one £29/month plan. Note the text/xml content type — Kill Bill's catalog endpoint requires it:
curl -sS -X POST \
-u "admin:$KBPW" \
-H "X-Killbill-ApiKey: $KBKEY" -H "X-Killbill-ApiSecret: $KBSEC" \
-H 'X-Killbill-CreatedBy: setup' -H 'Content-Type: text/xml' \
--data-binary @catalog.xml \
https://<vm-public-ip>/1.0/kb/catalog/xml
Create an account:
curl -sS -X POST \
-u "admin:$KBPW" \
-H "X-Killbill-ApiKey: $KBKEY" -H "X-Killbill-ApiSecret: $KBSEC" \
-H 'X-Killbill-CreatedBy: setup' -H 'Content-Type: application/json' \
-d '{"name":"Northwind Trading Ltd","email":"billing@northwind.example","currency":"GBP","externalKey":"northwind"}' \
https://<vm-public-ip>/1.0/kb/accounts
Then subscribe it to a plan, using the accountId the previous call returned in its Location header:
curl -sS -X POST \
-u "admin:$KBPW" \
-H "X-Killbill-ApiKey: $KBKEY" -H "X-Killbill-ApiSecret: $KBSEC" \
-H 'X-Killbill-CreatedBy: setup' -H 'Content-Type: application/json' \
-d '{"accountId":"<account-id>","planName":"standard-monthly"}' \
'https://<vm-public-ip>/1.0/kb/subscriptions?callCompletion=true&callTimeoutSec=40'
Accounts you create appear immediately in Kaui:

Opening an account shows what billing has produced — the balance, the bill cycle day and the date of the next invoice:

And the Subscriptions tab shows the recurring plan itself, with the date it is charged up to:

Step 11: Using the REST API
Everything Kaui does is the REST API underneath, at https://<vm-public-ip>/1.0/kb/. Requests take HTTP basic authentication with the administrator credentials plus the two tenant headers:
curl -sS -u "admin:$KBPW" \
-H "X-Killbill-ApiKey: $KBKEY" -H "X-Killbill-ApiSecret: $KBSEC" \
'https://<vm-public-ip>/1.0/kb/accounts/pagination'
Any call that changes data also requires X-Killbill-CreatedBy, which Kill Bill records in its audit log.
Two groups of endpoints are deliberately refused at the front door on this image. /1.0/kb/test is Kill Bill's integration-test clock, which can move time forward and cause invoices to be generated; it is disabled in the application and blocked by nginx. /1.0/kb/admin contains cache-flush and queue endpoints which, in this release, check only that you are authenticated and not what permissions you hold. Both are reachable from a shell on the VM via http://127.0.0.1:8080 if you genuinely need them.
curl -sk -o /dev/null -w '/1.0/kb/test/clock -> %{http_code}\n' https://127.0.0.1/1.0/kb/test/clock
/1.0/kb/test/clock -> 404
Step 12: Use your own domain and certificate
Point a DNS record at your VM's public IP, then replace the self-signed certificate. With certbot:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d billing.example.com
Certbot rewrites the nginx server block and reloads it. If you prefer to install a certificate you already hold, replace /etc/ssl/killbill/killbill.crt and /etc/ssl/killbill/killbill.key (keep the key 0600 root:root) and reload nginx.
Step 13: Back up and restore
Everything transactional lives in the two MySQL schemas. Back both up together — Kaui's schema holds your tenant registrations, and a killbill backup without it means re-registering tenants by hand:
sudo mysqldump --single-transaction --routines --databases killbill kaui \
| gzip > killbill-backup-$(date +%F).sql.gz
Also copy /root/killbill-credentials.txt somewhere safe: it holds the tenant API secret, which Kill Bill stores only as a hash and cannot show you again.
To restore onto a fresh VM, stop the applications, load the dump, and start them again:
sudo systemctl stop kaui killbill
gunzip < killbill-backup-2026-09-20.sql.gz | sudo mysql
sudo systemctl start killbill kaui
Step 14: Keep the VM patched
The image is built entirely from Ubuntu's main archive and unattended-upgrades is enabled, so operating system security updates install themselves. To apply everything pending immediately:
sudo apt-get update && sudo apt-get -y upgrade
Kill Bill, Kaui and Tomcat are installed from upstream release artifacts rather than Ubuntu packages, so they are upgraded by replacing the deployed application. Check the running versions before and after any upgrade, and always take a database backup first — Kill Bill applies schema migrations on start-up.
Troubleshooting
Kaui shows a 500 error just after boot. Kaui is a JRuby application and its first start takes a minute or two on a 2 vCPU VM. Check progress with journalctl -u kaui -f. If it persists, confirm /etc/killbill/kaui.env exists and that first boot completed — systemctl status killbill-firstboot.
The sign-in page rejects the password from the credentials file. Confirm you are using KILLBILL_ADMIN_PASSWORD and the username admin. Kill Bill records failed sign-ins and rate-limits by source address, so wait a moment between attempts.
Kaui signs in but shows no data. The tenant is not registered in Kaui yet — see Step 9.
Check everything at once. The self-test in Step 7 exercises the services, the reachable port set, the credential round trip and the refusal of every published default, and prints a line per check.