Install with Docker

Run Tidemark Billing from the published image with SQLite or MariaDB, and keep your data in a volume.

The Docker image runs the web server, the scheduler and a queue worker in one container. Everything that changes lives in the /data volume.

Start it with SQLite#

  1. Save the project's docker-compose.yml, or use this:

    services:
      billing:
        image: ghcr.io/tidemark-apps/billing:latest
        restart: unless-stopped
        ports:
          - "8080:8080"
        volumes:
          - billing-data:/data
        environment:
          APP_URL: http://localhost:8080
    
    volumes:
      billing-data:
    
  2. Run docker compose up -d.

  3. Open http://localhost:8080/install and create your admin account.

Set APP_URL to the address customers will use. It appears in emails, invoice links and webhook URLs. The project README lists the image tags latest, a minor version such as 0.1, and exact versions such as 0.1.0, for amd64 and arm64.

Skip the installer#

If you set BILLING_ADMIN_EMAIL and BILLING_ADMIN_PASSWORD, the container creates the admin account on its first start, as long as the installation has not run before. You can also set BILLING_COMPANY and BILLING_CURRENCY (default USD), and BILLING_ADMIN_NAME (default Administrator).

Remove the password from your compose file once the account exists.

Use MariaDB#

The project ships docker-compose.mysql.yml, which adds a mariadb:11 container.

  1. Edit the change-me passwords in the file.
  2. Run docker compose -f docker-compose.mysql.yml up -d.
  3. Open http://localhost:8080/install, choose MySQL / MariaDB, and enter host db, database billing and user billing, plus the password you set.

The database files live in the separate db-data volume.

What is in the data volume#

Path in /data Contents
.env Settings file, created on first start with a generated APP_KEY
database.sqlite The SQLite database (created empty even if you use MariaDB)
storage/ Uploads, attachments, logs, cache and sessions
plugins/ Plugins you install yourself

Plugins bundled with the image are in the image. Plugins you add or upload go in /data/plugins, which the app scans too.

What runs inside#

  • The web server listens on port 8080.
  • A loop runs php artisan schedule:run every 60 seconds, so you do not need a cron job.
  • A queue worker handles provisioning and webhook deliveries.
  • Logs go to the container's standard error, so docker compose logs billing shows them.
  • A health check requests /up every 30 seconds.

File ownership#

The container starts as root only to give /data to the user in PUID and PGID (both default to 1000), then drops to that user. On Unraid, use PUID=99 and PGID=100. If you start the container as a non-root user with docker --user, this step is skipped.

Was this article helpful?
Last updated 10 Nov 2026
Powered by Tidemark Billing