How to Self-Host Kill Bill with Docker Compose
What Is Kill Bill?
Kill Bill is an open-source subscription billing and payment platform. It handles recurring billing, invoicing, payment processing, and revenue recognition — the kind of billing infrastructure that companies like Stripe Billing, Chargebee, and Zuora charge thousands per month for. Kill Bill powers billing for organizations processing millions in transactions. Self-hosting it gives you full control over your billing data and zero per-transaction fees.
Updated February 2026: Verified with latest Docker images and configurations.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 4 GB of free RAM (minimum)
- 10 GB of free disk space
- A domain name (recommended for production use)
Docker Compose Configuration
Create a docker-compose.yml file:
services:
killbill:
image: killbill/killbill:0.24.16
container_name: killbill
restart: unless-stopped
ports:
- "8080:8080"
environment:
# Database connection
- KILLBILL_DAO_URL=jdbc:postgresql://db:5432/killbill
- KILLBILL_DAO_USER=killbill
- KILLBILL_DAO_PASSWORD=changeme_kb_password
# Catalog and overdue config (optional)
- KILLBILL_CATALOG_URI=SpyCarAdvanced.xml
# JVM tuning — adjust based on available RAM
- JAVA_OPTS=-Xms512m -Xmx1g
volumes:
- killbill-logs:/var/lib/killbill/logs
depends_on:
db:
condition: service_healthy
networks:
- killbill-net
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/1.0/healthcheck"]
interval: 30s
timeout: 10s
retries: 10
start_period: 120s
kaui:
image: killbill/kaui:3.0.23
container_name: kaui
restart: unless-stopped
ports:
- "9090:8080"
environment:
# Kaui database connection
- KAUI_DB_ADAPTER=postgresql
- KAUI_DB_URL=jdbc:postgresql://db:5432/kaui
- KAUI_DB_USERNAME=killbill
- KAUI_DB_PASSWORD=changeme_kb_password
# Kill Bill API connection
- KAUI_KILLBILL_URL=http://killbill:8080
- KAUI_KILLBILL_API_KEY=bob
- KAUI_KILLBILL_API_SECRET=lazar
depends_on:
killbill:
condition: service_healthy
networks:
- killbill-net
db:
image: postgres:16-alpine
container_name: killbill-db
restart: unless-stopped
environment:
- POSTGRES_USER=killbill
- POSTGRES_PASSWORD=changeme_kb_password
volumes:
- db-data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
networks:
- killbill-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U killbill"]
interval: 10s
timeout: 5s
retries: 5
volumes:
killbill-logs:
db-data:
networks:
killbill-net:
Create an init-db.sql file to initialize both databases:
-- Kill Bill requires separate databases for the app and Kaui
CREATE DATABASE killbill;
CREATE DATABASE kaui;
-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE killbill TO killbill;
GRANT ALL PRIVILEGES ON DATABASE kaui TO killbill;
Important: Change changeme_kb_password to a strong password in all three services. The KAUI_KILLBILL_API_KEY and KAUI_KILLBILL_API_SECRET are the default tenant credentials — you’ll create your own tenant in the initial setup.
Start the stack:
docker compose up -d
Kill Bill takes 60–120 seconds to initialize on first startup (database migrations run automatically). Watch logs:
docker compose logs -f killbill
Wait until you see Kill Bill server started.
Initial Setup
- Access Kaui at
http://your-server:9090 - Log in with the default credentials: admin / password
- Create a tenant — Kill Bill is multi-tenant. Click “Create New Tenant”:
- API Key: choose something meaningful (e.g.,
production) - API Secret: generate a strong secret
- Name: your company name
- API Key: choose something meaningful (e.g.,
- Upload a catalog — the catalog defines your products, plans, and pricing. Kill Bill ships with a sample
SpyCarAdvanced.xmlcatalog. For production, you’ll create your own. - Change the default admin password immediately under Account Settings.
Configuration
Catalog (Product/Plan Definitions)
Kill Bill’s catalog is an XML file that defines your billing model:
<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="CatalogSchema.xsd">
<effectiveDate>2026-03-01T00:00:00+00:00</effectiveDate>
<catalogName>MyBilling</catalogName>
<currencies>
<currency>USD</currency>
</currencies>
<products>
<product name="Standard">
<category>BASE</category>
</product>
</products>
<rules>
<changePolicy>
<changePolicyCase>
<policy>IMMEDIATE</policy>
</changePolicyCase>
</changePolicy>
</rules>
<plans>
<plan name="standard-monthly">
<product>Standard</product>
<finalPhase type="EVERGREEN">
<duration><unit>UNLIMITED</unit></duration>
<recurring>
<billingPeriod>MONTHLY</billingPeriod>
<recurringPrice>
<price><currency>USD</currency><value>29.99</value></price>
</recurringPrice>
</recurring>
</finalPhase>
</plan>
</plans>
<priceLists>
<defaultPriceList name="DEFAULT">
<plans>
<plan>standard-monthly</plan>
</plans>
</defaultPriceList>
</priceLists>
</catalog>
Upload via API:
curl -X POST \
http://localhost:8080/1.0/kb/catalog \
-u admin:password \
-H "X-Killbill-ApiKey: production" \
-H "X-Killbill-ApiSecret: your-secret" \
-H "Content-Type: application/xml" \
-H "X-Killbill-CreatedBy: admin" \
-d @catalog.xml
Payment Plugins
Kill Bill supports payment gateways via plugins. Popular options:
- Stripe:
killbill-stripe-plugin - PayPal:
killbill-paypal-express-plugin - Braintree:
killbill-braintree-plugin - Adyen:
killbill-adyen-plugin
Install plugins by adding them to the Kill Bill container or via the plugin API.
Email Notifications
Configure SMTP for invoice and payment notifications:
KB_org_killbill_billing_util_email_smtp_host=smtp.example.com
KB_org_killbill_billing_util_email_smtp_port=587
KB_org_killbill_billing_util_email_smtp_useSSL=true
KB_org_killbill_billing_util_email_smtp_userName=user@example.com
KB_org_killbill_billing_util_email_smtp_password=smtp-password
Reverse Proxy
For production, put Kill Bill behind a reverse proxy. Example Nginx configuration:
# Kaui admin UI
server {
listen 443 ssl;
server_name billing.example.com;
location / {
proxy_pass http://localhost:9090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# Kill Bill API (restrict access)
server {
listen 443 ssl;
server_name billing-api.example.com;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# Restrict to trusted IPs
allow 10.0.0.0/8;
deny all;
}
}
Backup
Back up the PostgreSQL database regularly:
# Dump both databases
docker exec killbill-db pg_dump -U killbill killbill > killbill-backup.sql
docker exec killbill-db pg_dump -U killbill kaui > kaui-backup.sql
# Compress
gzip killbill-backup.sql kaui-backup.sql
Key volumes to back up:
db-data— all billing data, invoices, payments, subscriptionskillbill-logs— audit trail
Troubleshooting
Kill Bill won’t start (database connection refused)
Symptom: Connection refused errors in Kill Bill logs.
Fix: Ensure the PostgreSQL container is healthy before Kill Bill starts. The depends_on with condition: service_healthy in the Compose file handles this. If using an external database, verify the connection URL, username, and password.
Kaui shows “Kill Bill server is not available”
Symptom: Kaui loads but can’t connect to Kill Bill.
Fix: Kill Bill takes 60–120 seconds to fully start. Wait for the healthcheck to pass. Verify KAUI_KILLBILL_URL points to the correct internal address (http://killbill:8080).
Invoice generation fails
Symptom: Subscriptions exist but no invoices generated. Fix: Check that a valid catalog is uploaded for the tenant. Invoices are generated on the billing date — if you just created the subscription, the first invoice may not appear until the next billing cycle. Force an invoice dry-run via API to verify.
Out of memory errors
Symptom: Kill Bill crashes with Java heap errors.
Fix: Increase JVM heap in JAVA_OPTS. Default is -Xmx1g. For production with 1,000+ active subscriptions, use -Xmx2g or higher.
Plugin installation fails
Symptom: Payment plugin won’t load after installation. Fix: Plugins must match the Kill Bill version. Check plugin compatibility at the Kill Bill plugin registry. Restart Kill Bill after plugin installation.
Resource Requirements
- RAM: 2 GB minimum (Kill Bill + Kaui + PostgreSQL). 4 GB recommended for production.
- CPU: 2 cores minimum. Payment processing and invoice generation are CPU-intensive during batch runs.
- Disk: 2 GB for application. Database grows with transaction volume — plan 1 GB per 100,000 invoices.
Verdict
Kill Bill is the real deal for subscription billing. It handles complex scenarios — proration, plan changes, add-ons, usage-based billing, multi-currency, multi-tenancy — that simpler tools like Invoice Ninja and SolidInvoice can’t touch. The trade-off is complexity: the catalog XML, plugin system, and API-first design mean Kill Bill has a steep learning curve.
Use Kill Bill if you’re running a SaaS product or subscription business and need production-grade billing infrastructure. It replaces Stripe Billing, Chargebee, or Zuora at a fraction of the cost.
Use Invoice Ninja instead if you need straightforward invoicing for freelance or small business work. Kill Bill is overkill for sending invoices to clients.
FAQ
Is Kill Bill overkill for freelancers sending invoices?
Yes. Kill Bill is designed for subscription billing platforms processing thousands of transactions — SaaS companies, subscription boxes, recurring service providers. If you need to send invoices to clients and track payments, Invoice Ninja is the right tool. Kill Bill’s XML catalog system and API-first design add complexity that freelancers don’t need.
How does Kill Bill compare to Stripe Billing?
Kill Bill handles the same use cases — subscriptions, plan changes, proration, invoicing, payment processing — but runs on your infrastructure with zero per-transaction fees. Stripe Billing charges 0.5-0.8% per transaction on top of payment processing fees. For high-volume businesses, Kill Bill saves significant money. The trade-off: self-hosting means you handle maintenance, updates, and scaling.
Can Kill Bill handle complex pricing models?
Yes. Kill Bill’s XML catalog supports tiered pricing, usage-based billing, add-ons, trial periods, plan migrations with proration, multi-currency, and custom billing cycles. It handles scenarios that simpler tools cannot — like mid-cycle plan changes with prorated credits and charges calculated to the day.
What payment gateways does Kill Bill support?
Stripe, PayPal, Braintree, Adyen, and Authorize.net through official plugins. Additional gateways can be added by writing custom payment plugins in Java. The plugin architecture separates billing logic from payment processing, so you can switch gateways without changing your billing setup.
Why does Kill Bill need so much RAM?
Kill Bill is a Java application running on the JVM. The default heap allocation is 1 GB (-Xmx1g), plus Kaui (Ruby on Rails) and PostgreSQL. The JVM needs memory headroom for garbage collection and concurrent processing. For production with 1,000+ active subscriptions, increase to -Xmx2g or higher to avoid out-of-memory errors during batch invoice generation.
Is Kill Bill multi-tenant?
Yes. Kill Bill supports full multi-tenancy — each tenant has isolated data, catalogs, and payment configurations. This makes it suitable for platforms that bill on behalf of multiple businesses. Create tenants through the API or Kaui admin interface, each with its own API key and secret.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments