Calco

Self-hosting & deployment

Calco ships in two forms. This guide covers the enterprise, self-hosted distribution — a single binary (or Docker image) you run on your own infrastructure. If you are using the Cloud subscription on the Unikia platform, there is nothing to install; sign in and start rendering.

The Calco binary and Docker image are sold exclusively and delivered privately to enterprise customers under contract. This guide is public so you can evaluate the operational model, but the artifacts themselves are provided to you directly — they are not downloadable from a public registry.

What you run

Everything is one statically linked Go binary, calco, with subcommands. For a server deployment you run:

bash
calco serve            # HTTP API + web UI on :8080

The binary serves the API, the web dashboard, and the MCP endpoint from a single process. The rest of this page assumes calco serve; for the one-shot CLI commands (convert, sign, verify, storage migrate) see the CLI reference.

Runtime prerequisites

Rendering shells out to two system tools. They are already bundled in the Docker image — you only need to install them yourself when running the bare binary:

ToolUsed for
LibreOffice (libreoffice-calc, libreoffice-writer)XLSX/DOCX → PDF conversion
poppler-utils (pdftocairo, pdftoppm, pdfinfo)PDF → HTML/image rasterization

On Debian/Ubuntu:

bash
apt-get install -y libreoffice-calc libreoffice-writer poppler-utils fonts-dejavu-core ca-certificates

Option A — run the binary

Place the binary on the host, point it at a writable data directory, and start the server:

bash
# Minimal: SQLite + local storage, zero config
export CALCO_DB_PATH=/var/lib/calco/app.db
export STORAGE_DRIVER=local
export STORAGE_LOCAL_ROOT=/var/lib/calco/templates
export WEB_DIR=/opt/calco/web        # the bundled Next.js export

calco serve -addr :8080

-addr defaults to :8080. Put the process behind your own TLS-terminating reverse proxy (nginx, Traefik, a load balancer) and set PUBLIC_BASE_URL to the externally reachable URL so generated links and the MCP resource URL are correct.

WEB_DIR must point at the static web export shipped alongside the binary. If it is unset or wrong, the API still works but the dashboard route serves a placeholder page.

Option B — Docker image

The image bundles the binary, the web export, and the LibreOffice/poppler runtime, so a deployment needs only the image plus configuration. Run it directly:

bash
docker run -d --name calco \
  -p 8080:8080 \
  -v calco-data:/app/data \
  --env-file calco.env \
  <your-private-registry>/calco:1.0.0

The container's default command is calco serve. It listens on 8080, stores SQLite and local blobs under /app/data (mount a volume to persist them), and reads configuration from the environment.

Docker Compose

yaml
services:
  calco:
    image: <your-private-registry>/calco:1.0.0
    restart: unless-stopped
    ports:
      - "8080:8080"
    env_file:
      - calco.env
    volumes:
      - ./data:/app/data

If you were given source rather than a prebuilt image, build it with the included multi-stage Dockerfile (docker build -t calco:1.0.0 .) — it compiles the web UI and the Go binary and assembles the runtime image in one step.

Configuration

All configuration is via environment variables. The only ones most deployments need are a database, a storage driver, and the session/auth settings; everything else has a sensible default.

Core / server

VariableDefaultPurpose
PUBLIC_BASE_URL—Externally reachable base URL; used for generated links and the MCP resource id. Set this in production.
WEB_DIR—Path to the bundled Next.js static export (preset in the Docker image).
SESSION_SECRET—Secret used to sign session cookies. Set a strong value in production.
SESSION_TTL_HOURS24Session lifetime.
TEMPLATE_LOCALE—Default locale for currency/date formatters.

The listen address is the serve -addr flag (default :8080), not an env var.

Database

SQLite is the zero-config default and is fine for single-node deployments. Choose PostgreSQL (or AWS Aurora) for production HA.

VariableDefaultPurpose
CALCO_DB_DRIVERsqlitesqlite or postgres.
CALCO_DB_PATH/app/data/app.dbSQLite file path (sqlite driver).
DATABASE_URL—Postgres DSN (required when driver is postgres), e.g. postgres://user:pass@host:5432/calco?sslmode=require.

Schema migrations run automatically on boot. For Aurora, point DATABASE_URL at the cluster writer endpoint — migrations and the first-admin bootstrap must run against a writable endpoint.

Storage & cache

Template blobs and cached renders can live on the local filesystem or in S3 / MinIO. Local is the default.

VariableDefaultPurpose
STORAGE_DRIVERlocallocal or s3.
STORAGE_LOCAL_ROOT—Root directory for the local driver.
STORAGE_LOCAL_PRESIGN_BASE_URL—Enables HMAC-signed /_presigned/* download URLs for local storage.
STORAGE_S3_ENDPOINT / _REGION / _BUCKET / _KEY_PREFIX—S3 / MinIO target.
STORAGE_S3_ACCESS_KEY / _SECRET_KEY—S3 credentials.
STORAGE_S3_USE_PATH_STYLEfalseSet true for MinIO and other path-style endpoints.
STORAGE_S3_PRESIGN_TTL5mLifetime of SigV4 presigned download URLs.
CACHE_DRIVERnonenone, memory, local, or s3.
CACHE_TTL / CACHE_MEMORY_MAX_MB—Cache lifetime and in-memory size cap.

A presign-capable storage driver (S3, or local with STORAGE_LOCAL_PRESIGN_BASE_URL) is required for MCP render_document, which returns download links rather than inline bytes.

Authentication & OIDC

For a standalone deployment, bootstrap a local admin and you are done. To use your own identity provider, configure OIDC.

VariableDefaultPurpose
ADMIN_EMAIL / ADMIN_PASSWORD—Bootstrap the first admin on an empty database.
LOCAL_AUTH_DISABLEDfalseDisable local email/password login (OIDC-only).
OIDC_ISSUER_URL—OIDC issuer; enables SSO and the MCP OAuth resource server.
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET—OIDC client credentials.
OIDC_REDIRECT_URL—Callback URL (<PUBLIC_BASE_URL>/auth/oidc/callback).
OIDC_ADMIN_ROLEadminRole/claim value that grants admin.
OIDC_INTROSPECTION_URL—RFC 7662 endpoint; enables opaque-token validation for MCP OAuth.
OIDC_REQUIRED_ENTITLEMENT—Restrict access to tokens carrying this entitlement.

When OIDC is fully configured, the "create first admin" setup screen is suppressed and admins arrive via SSO.

MCP & batch limits

VariableDefaultPurpose
MCP_RESOURCE_URLPUBLIC_BASE_URL + /mcpCanonical MCP resource id / required token audience.
MCP_RENDER_URL_TTL15mLifetime of a rendered-document download link.
MCP_RENDER_RETENTION24hHow long stored render outputs are kept before sweeping.
BATCH_MAX_ITEMS500Max records per batch request.
BATCH_MAX_ARCHIVE_MB512Abort a batch once the archive exceeds this size.
BATCH_RENDER_TIMEOUT10mPer-request batch wall-clock timeout.

First boot & health

On first boot against an empty database, Calco runs migrations and — if ADMIN_EMAIL / ADMIN_PASSWORD are set — creates the initial admin and a default organization. Otherwise, the web UI presents a one-time "create first admin" screen.

Verify the server is healthy:

bash
curl http://localhost:8080/health
# {"status":"ok","storage":"local","cache":"none"}

The response echoes the active storage and cache drivers, which is a quick way to confirm your configuration was picked up.

Upgrading

Replace the binary or pull the new image tag and restart. Migrations for the new version run automatically on boot; on Postgres/Aurora they run against the writer endpoint. Always snapshot your database and storage before a major upgrade.