Help:User journeys/Converting a Canasta instance between orchestrators

From canasta

Journey info  ·  Platform: Any host (Docker Compose ⇄ Kubernetes)  ·  Time: ~1–2 hours + soak

This journey moves a running Canasta instance — a single wiki or a whole farm — from one orchestrator to the other with no data loss: Docker Compose → Kubernetes, or the reverse. There is no canasta migrate command; a conversion is three ordinary operations — canasta backup create on the source, canasta create --orchestrator <target> on the destination, and canasta backup restore — because a restore is an overlay onto a freshly-created target, not a directory clone. It leads with Compose → Kubernetes (the common direction: moving a live wiki onto a cluster) and notes where the reverse differs. Validated 2026-07-08 moving a two-wiki Compose farm onto a shared production k3s cluster with Canasta CLI 4.12.0. This is one concrete path, not the only way — for the concepts behind each orchestrator see Help:Orchestrators.

Prerequisites

  • A running source instance (Compose or Kubernetes) and a prepared target host. For a Kubernetes target that means a cluster with an ingress controller, cert-manager, and a ClusterIssuer already installed (a single-node canasta install k8s-cp provides all of these); for a Compose target, Docker. See Help:Installation and Help:Multi-node Kubernetes.
  • Canasta CLI 4.12.0 or later on the target, and the target's CLI at least as new as the source's. A restore run by an older CLI than the backup was taken with can silently drop data (uploaded media needs 4.6.0+ on a Kubernetes target). Check with canasta version on both hosts and canasta upgrade the older one first.
  • A shared or remote Restic repository reachable from both hosts — S3, B2, SFTP, a rest-server, or an NFS path. A local-path repo lives only on the host that wrote it, so a cross-host conversion cannot read it. The repo URL comes from RESTIC_REPOSITORY in the instance's config, never a flag. See Help:Backup and restore.
  • DNS control for every wiki hostname, and the ability to lower TTLs before the cutover.
  • Prior knowledge: basic Canasta operation on both orchestrators, and (for a Kubernetes target) kubectl for verification.

ℹ️ Note: Read Help:Backup and restore first — a conversion is built entirely on backup/restore, and the repo, snapshot-ID, and cross-host rules there are the foundation of everything below.

Phase 1: Prepare the source and take the definitive snapshot

Bring both ends to the same current CLI, then capture the state you will restore.

# On the SOURCE host — bring it current (also re-snapshot after any upgrade,
# so the archive format matches the target).
canasta upgrade
canasta version

# Confirm the instance backs up to a SHARED/REMOTE repo (not a local path),
# so the target host can read it. Set one if needed (never hand-edit .env):
canasta config set --id <id> --no-restart \
  RESTIC_REPOSITORY=s3:s3.<region>.amazonaws.com/<your-bucket> \
  RESTIC_PASSWORD=<repo-password> \
  AWS_ACCESS_KEY_ID=<key> AWS_SECRET_ACCESS_KEY=<secret> AWS_DEFAULT_REGION=<region>
canasta backup init --id <id>     # first time only

# Freeze writes so the snapshot is definitive. If you are the only editor,
# simply stop editing. For a multi-editor wiki, set the farm read-only first:
#   $wgReadOnly = 'Migrating — temporarily read-only';   (then: canasta restart --id <id>)
canasta backup create --id <id> --tag cutover
canasta backup list --id <id>     # note the snapshot ID you just created

Use the explicit snapshot ID from backup list for the restore below — never latest, which relies on host matching that differs across machines.

Phase 2: Create the target and restore

Create the destination instance, point it at the same repo, and overlay the snapshot.

# On the TARGET host. --staging-certs uses Let's Encrypt staging during a
# rehearsal so a repeated run can't hit the production rate limit; drop it for
# the real cutover. -w is the PRIMARY wiki's id (restore brings the rest).
canasta create \
  --orchestrator k8s \
  --id <id> \
  --wiki <primary-wiki-id> \
  --domain-name <primary.example.com> \
  --storage-class <class> \
  --tls-email <you@example.com> \
  --staging-certs

# Give the target the same repo credentials, then restore the snapshot.
canasta config set --id <id> --no-restart \
  RESTIC_REPOSITORY=... RESTIC_PASSWORD=... AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_DEFAULT_REGION=...
canasta backup list --id <id>     # the source's snapshot is visible here
canasta backup restore --id <id> --snapshot <snapshot-id> --skip-safety-backup

A full restore reproduces the snapshot exactly: the databases, uploaded media, and every config/ file — including deletions, so a settings file you removed on the source does not reappear on the target. All of a farm's wikis come back from one full restore; you do not re-run canasta add.

Instance ID. Reuse the same --id when the source and target hosts keep separate registries (the normal case — canasta run locally on each host). Use a distinct id only when one controller manages both hosts through --host, since a single registry can't hold two instances of the same id. The public domain is independent of the internal id either way.

Phase 3: Verify, then cut over

Verify before touching DNS — the cutover is reversible only until you flip it.

Data. Confirm every wiki's database and page content came across:

kubectl -n canasta-<id> exec statefulset/canasta-<id>-db -- \
  sh -c 'mariadb -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SHOW DATABASES"'

Routing and TLS. On Kubernetes there are two domain layers, and Canasta keeps them in sync for you: the ingress (which hostnames it accepts and gets certificates for) is auto-derived from the wiki URLs in wikis.yaml, so a restored farm's second, third, … wikis are routed automatically — no hand-editing. Confirm both the ingress hosts and live HTTPS:

kubectl -n canasta-<id> get ingress -o jsonpath='{.items[*].spec.rules[*].host}'; echo
curl -sSkIL https://<primary.example.com>/     # expect 200 / a redirect to Main_Page, no loop

If a wiki's canonical scheme changed in the move (e.g. an http-only Compose source onto TLS-terminating Kubernetes), set it so MediaWiki generates correct links:

canasta config set --id <id> MW_SITE_SERVER=https://<primary.example.com>

Flip DNS. Point every wiki hostname at the target's ingress address. cert-manager issues a real certificate once a hostname resolves to the target, so flip DNS before expecting valid TLS — a hostname that doesn't yet resolve leaves its certificate pending while the others serve normally. Keep the source running, untouched, as a fallback through the soak period.

ℹ️ Note: Converting to Docker Compose instead? The data steps are identical, but Compose has no ingress/cert-manager layer — Caddy terminates TLS itself. Verify with canasta status and browse each wiki; there is no separate domains list to reconcile.

Phase 4 (optional): Re-establish GitOps on the target

If the source was GitOps-managed, set it up fresh on the target after verification — the mechanism is per-orchestrator and is not carried across by the restore (Compose uses git-crypt; Kubernetes uses SOPS + age):

canasta gitops init --id <id> --name <env> \
  --repo git@github.com:<org>/<new-config-repo>.git \
  --key ~/<gitops>.key --encrypt-secrets
canasta gitops push --id <id>

Use a new repository for the target rather than the source's — the layouts and encryption differ, and force-pushing the target's tree over the source's repo would destroy your rollback. Store the exported key offsite. See Help:GitOps and Help:Secrets.

Cleanup / teardown

Only after the target has soaked and you are confident:

# On the SOURCE host — retire the old instance.
canasta delete --id <id> --yes

Give the migrated instance its own backup repository going forward (a fresh bucket), separate from the source's — two instances sharing one Restic repo interleave under the same host tag and break incremental chaining. Set it with canasta config set + canasta backup schedule set; see Help:Backup and restore.

Rollback (any time before you delete the source): point DNS back at the source, lift $wgReadOnly if you set it, and delete the half-migrated target with canasta delete.

Production considerations

  • Shared repo, not local-path. A cross-host conversion is impossible with a host-local repo. Provision S3/B2/SFTP/rest-server/NFS the instance can reach from both ends.
  • Version alignment. The target's CLI must be at least as new as the source's, and 4.6.0+ for Kubernetes media. Mismatches fail quietly — always canasta version both hosts first.
  • Certificate timing. Real Let's Encrypt has issuance rate limits; rehearse with --staging-certs and switch to production only for the final cutover.
  • Keep the source as a fallback. Don't delete it until the target has served real traffic through a soak window.
  • Farms. Every wiki's hostname must resolve to the target before its certificate can issue; a farm cut over all at once needs all its DNS records flipped.

Troubleshooting

Restore succeeds but a wiki returns nothing. On Kubernetes, check the ingress hosts (kubectl -n canasta-<id> get ingress) — every wiki hostname should appear, derived from wikis.yaml. A wiki reachable in the browser but 404 from the cluster is usually DNS not yet pointed at the target.

backup list on the target shows no snapshots. The target isn't pointed at the shared repo, or the repo is a local path that only exists on the source. Set RESTIC_REPOSITORY/RESTIC_PASSWORD (and cloud credentials) on the target with canasta config set.

HTTPS redirects endlessly / the certificate never goes Ready. Confirm the hostname resolves to the target (cert-manager validates over the public name) and that you are on CLI 4.12.0+; upgrade the target and re-run the restore if it was created on an older release.

Uploaded images are missing after the restore. The target's CLI predates Kubernetes media restore. Upgrade to 4.6.0+ (4.12.0 recommended) and restore again.

Links point at the wrong scheme or host. The restored MW_SITE_SERVER carries the source's value; set it on the target with canasta config set MW_SITE_SERVER=https://<host>.

See also Help:Backup and restore, Help:Orchestrators, Help:Networking and TLS, and Help:GitOps.