matcha

package module
v0.11.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 20, 2026 License: MIT Imports: 19 Imported by: 0

README

Matcha

Go library for deploying containerized applications with automatic SSL, zero-downtime updates, and SQLite backup management.

This is not a generic Docker orchestration tool. Matcha is purpose-built for deploying a single Docker app per server with kamal-proxy handling reverse proxy, TLS, and zero-downtime deploys. It powers Fusionaly, Formlander, and Lognorth.

How it works

Matcha runs two Docker containers on your server:

Internet → kamal-proxy (ports 80/443, TLS) → your-app (internal port)

kamal-proxy handles:

  • Automatic Let's Encrypt SSL certificates
  • Zero-downtime deploys (health checks new container, buffers requests during switch, drains old connections)
  • Host-based routing

Matcha handles:

  • Installing Docker and kamal-proxy on a fresh server
  • Pulling and running your app container
  • Registering your app with kamal-proxy
  • SQLite backups with retention policies (daily/weekly/monthly)
  • Self-updating manager binaries via GitHub releases
  • Automatic daily updates via cron
Deploy flow
Install:  check system → install Docker → start kamal-proxy → start app → register with proxy
Update:   pull new image → start new container → kamal-proxy health checks → switch traffic → done

On update, kamal-proxy health-checks the new container before switching. If the new container is unhealthy, traffic stays on the old one and the deploy fails safely.

Usage

Embed matcha in your project's CLI:

package main

import (
    "fmt"
    "os"

    "github.com/karloscodes/matcha"
)

var version = "dev" // set via ldflags at build time

func main() {
    m := matcha.New(matcha.Config{
        Name:     "myapp",
        AppImage: "ghcr.io/user/myapp:latest",

        // Optional
        AppPort:    8080,                // port your app listens on (default: 8080)
        HealthPath: "/up",               // health check endpoint (default: /up)
        Backups:    true,                // SQLite backup with retention
        CronUpdates: true,               // daily 3 AM auto-update
        ManagerRepo:    "user/myapp",    // GitHub repo for self-updates
        ManagerVersion: version,         // current version
    })

    if len(os.Args) < 2 {
        fmt.Println("Usage: myapp <install|update|reload|status|restore-db>")
        os.Exit(1)
    }

    var err error
    switch os.Args[1] {
    case "install":
        err = m.Install()
    case "update":
        err = m.Update()
    case "reload":
        err = m.Reload()
    case "status":
        err = m.Status()
    case "restore-db":
        err = m.RestoreDB()
    case "exec":
        err = m.Exec(os.Args[2:]...)
    }

    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}

Build and distribute this binary. On your server:

# First time: installs Docker, kamal-proxy, deploys your app
myapp install

# Pulls latest image, zero-downtime redeploy
myapp update

# Check what's running
myapp status

# Run a command inside the app container
myapp exec sh

Config

Field Default Description
Name required App name. Used for container names, env prefix, install directory.
AppImage required Docker image to deploy (e.g., ghcr.io/user/myapp:latest).
AppPort 8080 Port your app listens on inside the container.
HealthPath /up Endpoint kamal-proxy checks before switching traffic. Must return 200.
ProxyImage basecamp/kamal-proxy:latest kamal-proxy Docker image.
InstallDir /opt/{Name} Where config and data are stored on the server.
Backups false Enable SQLite backup with retention (7 daily, 14 weekly, 90 monthly).
CronUpdates false Set up a daily 3 AM cron job that runs update.
ManagerRepo "" GitHub repo (e.g., user/myapp) for self-updating the manager binary.
ManagerVersion "" Current version string (set via -ldflags "-X main.version=v1.0.0").

What your app needs

  1. A Docker image pushed to a registry (Docker Hub, GHCR, etc.)
  2. A health endpoint (default /up) that returns HTTP 200 when ready
  3. That's it

Environment variables

Matcha passes these to your container:

Variable Example Description
{NAME}_DOMAIN MYAPP_DOMAIN=app.example.com Configured domain
{NAME}_PRIVATE_KEY MYAPP_PRIVATE_KEY=abc123... Generated secret key
{NAME}_APP_PORT MYAPP_APP_PORT=8080 Port config
{NAME}_ENV MYAPP_ENV=production Always "production"

Volumes

Matcha mounts two volumes into your container:

  • /app/storage — persistent data (SQLite databases, uploads, etc.)
  • /app/logs — application logs

These are stored on the host at {InstallDir}/storage/ and {InstallDir}/logs/.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BackupFile

type BackupFile struct {
	Name      string
	Path      string
	CreatedAt time.Time
	Size      int64
}

BackupFile represents a database backup file.

type Config

type Config struct {
	// Required
	Name     string // "fusionaly" → env prefix FUSIONALY_, container names, etc.
	AppImage string // "karloscodes/fusionaly:latest"

	// Optional with defaults
	InstallDir string // default: /opt/{Name}
	BinaryPath string // default: /usr/local/bin/{Name}
	ProxyImage string // default: basecamp/kamal-proxy:latest
	HealthPath string // default: /up
	AppPort    int    // default: 8080

	// Feature flags
	CronUpdates bool // daily 3 AM auto-update cron job
	Backups     bool // SQLite backup with retention policy

	// Self-update configuration (see selfupdate.go for conventions)
	// When configured, Update() checks GitHub releases for newer versions
	// and downloads the new binary automatically.
	ManagerRepo    string // GitHub repo for releases, e.g., "karloscodes/fusionaly"
	ManagerVersion string // current version, e.g., "v1.4.37" (set via ldflags at build time)
}

Config defines how Matcha deploys your application.

type Matcha

type Matcha struct {
	// contains filtered or unexported fields
}

Matcha is the main orchestrator for deployments.

func New

func New(cfg Config) *Matcha

New creates a new Matcha instance with the given configuration.

func (*Matcha) AppContainerName

func (m *Matcha) AppContainerName() string

AppContainerName returns the app container name.

func (*Matcha) BackupDB

func (m *Matcha) BackupDB() (string, error)

BackupDB creates a backup of the database and returns the backup path.

func (*Matcha) Deploy

func (m *Matcha) Deploy() error

Deploy triggers a deployment with current configuration.

func (*Matcha) EnvPrefix

func (m *Matcha) EnvPrefix() string

EnvPrefix returns the uppercase name used for environment variables.

func (*Matcha) Exec

func (m *Matcha) Exec(args ...string) error

Exec runs a command inside the app container.

func (*Matcha) GetConfig

func (m *Matcha) GetConfig() Config

GetConfig returns the current configuration.

func (*Matcha) GetDomain

func (m *Matcha) GetDomain() (string, error)

GetDomain reads the domain from the .env file.

func (*Matcha) Install

func (m *Matcha) Install() error

Install runs the full installation process.

func (*Matcha) NetworkName

func (m *Matcha) NetworkName() string

NetworkName returns the Docker network name.

func (*Matcha) ProxyContainerName added in v0.11.0

func (m *Matcha) ProxyContainerName() string

ProxyContainerName returns the proxy container name.

func (*Matcha) Reload

func (m *Matcha) Reload() error

Reload restarts containers with current config (no image pull).

func (*Matcha) RestoreDB

func (m *Matcha) RestoreDB() error

RestoreDB lists backups and restores the selected one.

func (*Matcha) SaveImage

func (m *Matcha) SaveImage() error

SaveImage persists the current app image to the .env file.

func (*Matcha) SelfUpdate

func (m *Matcha) SelfUpdate() (bool, error)

SelfUpdate checks for a newer manager version and updates if available. Returns true if an update was performed.

func (*Matcha) SetImage

func (m *Matcha) SetImage(image string)

SetImage changes the app image for subsequent deployments.

func (*Matcha) StartSpinner

func (m *Matcha) StartSpinner(name string) *Spinner

StartSpinner creates and starts an animated spinner for a step.

func (*Matcha) Status

func (m *Matcha) Status() error

Status shows the current state of the deployment.

func (*Matcha) Update

func (m *Matcha) Update() error

Update pulls the latest image and performs a deployment. Also checks for manager self-updates if configured.

type Spinner

type Spinner struct {
	// contains filtered or unexported fields
}

Spinner handles animated progress display.

func (*Spinner) Stop

func (s *Spinner) Stop(success bool)

Stop stops the spinner and shows success or failure.

Directories

Path Synopsis
Package testrunner provides utilities for running integration tests in isolated environments using OrbStack VMs.
Package testrunner provides utilities for running integration tests in isolated environments using OrbStack VMs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL