Skip to content
Get started

Self-hosting overview

Self-hosting Mildport keeps every customer file inside your own network. The engine verifies its license offline and has no telemetry, so it runs perfectly well in a VPC with tight egress rules — or none at all.

You bring the database and object storage. We bring the import engine and the decode sidecars.

  1. A paid plan. Self-hosting comes with paid plans; the free tier is the cloud trial.

  2. Image access. Our images are private. Request access once from the Self-hosting page in your account — see Image access.

  3. A license key and the public key. Both come from your account: the key from Licenses, the IMPORT_LICENSE_PUBLIC_KEY value from Self-hosting.

All-in-one container

Engine and all three decode sidecars in one image. The smallest footprint and the fastest start — bring your own MongoDB.

Docker Compose

The full stack as separate services: engine, database, decode sidecars, optional object storage. Good for a single host.

Kubernetes (Helm)

The engine and sidecars as a chart, each sidecar independently toggleable, with the preflight wired into helm test.

Air-gapped

No outbound internet at all. Mirror the images, serve one frontend asset yourself, and nothing phones home. Read the runbook →

Service Role
mildport The import engine and license-keyed REST API (listens on :8090)
mongo Metadata, mappings, delivery log
pdf-probe Decode sidecar — PDF table extraction
xlsx-decode Decode sidecar — spreadsheets
ocr Decode sidecar — scans and photos
minio (optional) S3-compatible blob storage for large files

Only the engine and MongoDB are required. Each decode sidecar is optional: without pdf-probe the engine simply won’t accept PDFs, and so on. If your estate is already Postgres, FerretDB is a verified experimental option — same connection string, not a production database we staff yet.

The smallest possible start — one container, two environment variables:

Terminal window
docker login ghcr.io -u <your-github-username> # after access is granted
docker run --rm -p 8090:8090 \
-e MONGO_CONNECTION_STRING="mongodb://host:27017/cap_import" \
-e IMPORT_LICENSE_PUBLIC_KEY="<from the Self-hosting page>" \
ghcr.io/capitality-io/mildport-aio

Check it answers:

Terminal window
curl localhost:8090/health
# {"status":"ok","service":"mildport"}

That is a working engine for server-to-server calls. If a browser embeds the widget, also set ALLOWED_ORIGINS to that page’s origin — the production image refuses every cross-origin browser request when it is empty (including localhost). Then point the widget at the engine with api-base-url, hand it your license key, and run a real import — Your first import.

The chart installs straight from the OCI registry once your account has image access:

Terminal window
helm install mildport oci://ghcr.io/capitality-io/charts/mildport \
-n mildport --create-namespace -f values.prod.yaml
helm test mildport -n mildport # runs the preflight in-cluster

Bring your own MongoDB and S3-compatible storage. An all-in-one mode folds the engine and the three decode sidecars into a single pod; semantic matching stays a separate pod you can turn off. Each sidecar can also be disabled individually on the granular chart.

The engine ships a check that refuses to let you misdeploy — it validates the license setup, Mongo URI, CORS allowlist, storage, sidecar reachability and entitlements, and exits non-zero on anything blocking:

Terminal window
pnpm import:self-host-check # from a source checkout
Terminal window
docker run --rm --env-file .env ghcr.io/capitality-io/mildport-aio \
bun dist/cli/self-host-check.js # from the image

On Kubernetes, helm test mildport runs the same check inside the cluster, against the config the deployment actually has.

Next: Your first import · Deployment troubleshooting · Configuration reference · Licensing