Skip to content
zublms
Documentation
Documentation/Administration
Setup requiredSelf-hosted customers, system administrators and implementation partners

Install, start & upgrade ZubLMS

Prepare a customer host, install a release safely, inspect its status and plan a recoverable upgrade.

Choose the right installation path

This guide is for operators installing the supplied customer release on a provisioned Linux host. Learners and company administrators using a hosted workspace do not need to run these commands.

The installer manages API, worker, web and temporary setup jobs using deploy/release/compose.yml. It is an external-services profile: PostgreSQL, Keycloak, OpenBao, the independent recovery journal and DNS/TLS must be provisioned separately. It is not an all-in-one infrastructure installer or an SSH deployment tool.

Do not run Install against an existing development or VPS deployment. Existing zublms-dev and zublms-production projects are protected. First Install requires an empty application database; existing installations need a separately reviewed migration/adoption procedure.

Prepare the host and dependencies

  • Use Python 3.10 or newer and Docker Compose v2 with --wait support on the intended Linux host. Use a local Unix-socket Docker context; remote SSH/TCP contexts are refused.
  • Provision PostgreSQL with separate application and migration credentials. Use a direct connection or session pooling for migrations; transaction pooling cannot preserve the migration advisory lock.
  • Provision HTTPS identity, OpenBao and recovery-journal services with usable workload credentials. Configure the first organisation/owner and journal according to the supplied release runbook; no demo accounts or default password are created.
  • Prepare a persistent object directory accessible to UID/GID 10001. This release profile uses filesystem storage; the installer does not move data, recursively change ownership or adopt another storage backend.
  • Retain the required worker sandbox. The Docker Desktop private /proc limitation is not bypassed; qualify the actual Linux host.
  • Obtain API, worker, admin and web images pinned by SHA-256 digest. Verify release signatures and matching full source-revision labels. Label comparison alone is not signature verification.

Prepare private configuration

Detailed infrastructure provisioning remains in docs/production-deployment.md and docs/customer-installer.md in the supplied project. These files should be read before operating the installer. Installation state binds the Docker engine, project, database credential contents and object mount; moving them requires recovery/requalification.

  1. Use deploy/release/release.env.example in your supplied release as the template. Create a private absolute-path file such as /etc/zublms/release.env without overwriting an existing file. Restrict it to mode 0600.
  2. Set the four pinned image references, SECRETS_DIR, OBJECTS_DIR, ACME_EMAIL, identity client/issuer and HTTPS OpenBao/journal endpoints. Store the five required secrets in separate protected files: runtime database URL, migration database URL, OIDC client secret, OpenBao token and journal token. Never put credentials in images or public documentation.
  3. Set PUBLIC_BASE_URL and SITE_ADDRESS to the same customer hostname. The web image must be built for that public origin; qualify matching images, canonical links, sitemap, identity redirects, TLS and customer branding together.
  4. Keep a stable private state directory across release checkouts. The default is .zublms-installer/<project> beside the environment file. Use mode 0700 and retain its receipt and logs. If choosing --state-dir, supply the same location on every command.

Preview the plan

Run from the supplied release directory. Replace the example project and paths with your provisioned customer installation. --plan prints the intended steps without Docker calls, network access or filesystem writes; it does not prove that prerequisites are ready.

Example JSON payload
./zublms install --env-file /etc/zublms/release.env --project zublms-example --plan

Install a new release

Install validates the target, pulls the pinned images, checks revision/origin labels, runs worker preflight and read-only database inspection, applies forward migrations in a temporary job, starts the services and checks HTTPS readiness. A successful run saves a private installation receipt.

Unmanaged existing containers and non-empty application databases are refused. Repeating a successful Install directs you to Start or Upgrade; it does not reset data. Temporary preflight/migration containers normally disappear on exit, leaving only the long-running services.

Example JSON payload
./zublms install --env-file /etc/zublms/release.env --project zublms-example

Start and inspect an installed release

Start requires the previous successful receipt, unchanged configuration and all three existing containers with matching images. It starts and checks them without pulling images, migrating, rebuilding or recreating containers. Changed configuration belongs in Upgrade.

Status starts nothing, applies no migrations and writes no state or diagnostic logs. It reports container state, API health and the last recorded verified revision. It is not a fresh end-to-end test of identity, public HTTPS, queues or learning workflows.

Exit codes: 0 checks passed; 1 operational failure; 2 invalid arguments; 3 Status reports missing, degraded or unmanaged state; 130 interrupted. --wait 180 is the default readiness deadline per phase; supported values are 10–900 seconds.

Example JSON payload
./zublms start --env-file /etc/zublms/release.env --project zublms-example
./zublms status --env-file /etc/zublms/release.env --project zublms-example

Prepare a recoverable upgrade

Before upgrading, verify coordinated recovery inputs for the database, objects, keys and independent journal. Keep the last successful receipt and current revision from Status. Schedule downtime and qualify the candidate release.

Upgrade requires a private mode-0600 JSON checkpoint record. Its project and release_revision must match the installed receipt; verified_at must be a timezone-aware UTC timestamp within 24 hours and not in the future. Record durable recovery references, never credentials.

The installer checks the record but cannot verify that the recovery claim is true. Complete the recovery verification before setting restore_verified to true. The template below is deliberately incomplete and cannot be used as evidence. Automatic/off-server backup creation and automatic OpenBao unsealing remain separate pending work.

Example JSON payload
{
  "project": "zublms-example",
  "release_revision": "REPLACE_WITH_CURRENT_40_CHARACTER_REVISION",
  "verified_at": "REPLACE_WITH_ACTUAL_VERIFICATION_TIME",
  "restore_verified": false,
  "references": {
    "database": "REPLACE_WITH_VERIFIED_DATABASE_REFERENCE",
    "objects": "REPLACE_WITH_COORDINATED_OBJECT_REFERENCE",
    "keys": "REPLACE_WITH_KEY_RECOVERY_REFERENCE",
    "journal": "REPLACE_WITH_INDEPENDENT_JOURNAL_REFERENCE"
  }
}

Run Upgrade

Upgrade requires a prior successful receipt. It validates the candidate and recovery record before downtime, stops web ingress, worker and API, verifies stopped state, migrates forward, starts the matching release and checks readiness.

A failure after migration begins stops runtime services and blocks ordinary Start. Schema changes may have partially completed. No automatic binary/schema rollback is performed. Database credential rotation, moved mounts, another engine or lost state require an explicit recovery/requalification procedure; do not delete the receipt to bypass a guard.

Example JSON payload
./zublms upgrade --env-file /etc/zublms/release.env --project zublms-example \
  --backup-record /etc/zublms/recovery-checkpoint.json

Troubleshoot without losing data

Modifying commands retain private logs, a resolved Compose snapshot and an atomic receipt. Treat all diagnostics as confidential even though known secret values are masked. Status does not dump environment variables. The installer never runs volume deletion, prune, down, fixture reset or automatic adoption.

  1. Run Status and inspect the command’s private diagnostic log. Do not start an older binary against a potentially advanced schema.
  2. After an interrupted Docker client or host, inspect the exact <project>-installer-job container and its logs. An interrupted job can remain and blocks another attempt; it is not silently deleted.
  3. Resolve the cause, then retry the same Install or Upgrade with the same configuration and state. Completed migrations are not undone or reseeded.
  4. For a different recovery release or restored data, follow the supplied restore-admission procedure. Do not prune volumes, reset fixtures, downgrade schemas, disable TLS/RLS or relax worker isolation.

Verify before inviting users

Local installer and disposable-database tests cover specific safeguards; they do not qualify every Linux host, public identity/TLS/journal setup or restore procedure. A successful readiness response alone is not customer-release approval. No automatic post-reboot unseal is provided by this installer.

  • Verify sign-in/sign-out and any required company SSO, including denied/revoked access.
  • Check learner delivery on phone and desktop, author publication, manager assignments and authorised reports.
  • Confirm worker jobs, certificates, email and recovery procedures on the actual customer host.
  • Review customer branding, public URLs, legal/contact information and responsibilities for retention and support.

Documentation reviewed 3 November 2026 · Current implementation snapshot

Need account help? Contact your company administrator. Planning a rollout? Talk to us.