migration: add the before-state snapshot; S3 secret is NOT off-box
Snapshot records apps/images/env-names/backup config and data fingerprints for a post-restore diff. Also resolves an open unknown: the off-box JSON carries only accessKeyId, so the S3 secretAccessKey must be retrieved before the window. The restic passphrase is fine - it is on the agent host, which is not migrating.
This commit is contained in:
1 parent
144e7e77ca
commit
b313105148
2 files changed
+265
-4
No files matched your search
@@ -50,9 +50,16 @@ needed to restore are inside the thing being restored.
|
|||||||
|
|
||||||
- [ ] Export the Vault contents and store them off-server (personal password manager or
|
- [ ] Export the Vault contents and store them off-server (personal password manager or
|
||||||
offline media). Confirm the **Cloudron backup passphrase** is in your own hands.
|
offline media). Confirm the **Cloudron backup passphrase** is in your own hands.
|
||||||
- [ ] Confirm the backup target's S3 access key is available off-box. The agent host has
|
- [ ] **Retrieve the S3 secretAccessKey — the off-box copy does NOT have it.** Checked
|
||||||
`~/.hermes/security/backup_sites_backup.json` (0600) — check whether it carries the
|
2026-10-30: `~/.hermes/security/backup_sites_backup.json` carries `accessKeyId` and
|
||||||
key; if not, retrieve it from the Infomaniak console.
|
nothing else. A restore begins by pointing the new Cloudron at the backup target, so
|
||||||
|
the *secret* must be in hand before the window — get it from the Infomaniak console
|
||||||
|
and store it with the passphrase, off-box.
|
||||||
|
- [x] The **restic** passphrase is safe: `~/.hermes/scripts/backup.sh` documents that
|
||||||
|
`RESTIC_PASSWORD` lives in the agent host's `.env` **and** the co-op Vault. The agent
|
||||||
|
host is not being migrated, so the agent-side backup stays recoverable. (The Vault,
|
||||||
|
however, is an app on the box being migrated — so the Vault copy alone is not
|
||||||
|
off-box until it is exported.)
|
||||||
- [x] New host capacity: **4 CPU, 12 GB RAM, 250 GB disk** (given 2026-10-30) — ample for
|
- [x] New host capacity: **4 CPU, 12 GB RAM, 250 GB disk** (given 2026-10-30) — ample for
|
||||||
~6 GB of app data plus images. Old box used ~17 GB of 58 GB.
|
~6 GB of app data plus images. Old box used ~17 GB of 58 GB.
|
||||||
- [x] OS: **Ubuntu 26.04 LTS is supported** — Cloudron's install docs specify a fresh
|
- [x] OS: **Ubuntu 26.04 LTS is supported** — Cloudron's install docs specify a fresh
|
||||||
@@ -151,6 +158,16 @@ needed to restore are inside the thing being restored.
|
|||||||
advance, so a strict-host-key refusal doesn't stop you mid-migration.
|
advance, so a strict-host-key refusal doesn't stop you mid-migration.
|
||||||
- [ ] Announce the window in `#updates`.
|
- [ ] Announce the window in `#updates`.
|
||||||
|
|
||||||
|
## 3a. The "before" snapshot
|
||||||
|
|
||||||
|
`migration-before-state.json` in this repo is a machine-diffable record of the current
|
||||||
|
server: 16 apps with their manifest ids, image tags, state, health and **env var names**
|
||||||
|
(never values); the backup sites, schedule and retention; the newest run's id, state,
|
||||||
|
integrity signature and size; Cloudron's version; and data fingerprints (member count,
|
||||||
|
API-key count, ledger rows, `metrics_daily` rows, Gitea repo count). Capture nothing
|
||||||
|
further; after the restore, diff it. A silently-empty app is exactly what a diff catches
|
||||||
|
and a spot-check misses.
|
||||||
|
|
||||||
## 4. Cutover, in order
|
## 4. Cutover, in order
|
||||||
|
|
||||||
1. **Freeze writes.** Pause the portal's `membership_sweep` and `rag_refresh`, hold
|
1. **Freeze writes.** Pause the portal's `membership_sweep` and `rag_refresh`, hold
|
||||||
@@ -222,7 +239,6 @@ needed to restore are inside the thing being restored.
|
|||||||
open question in this runbook.
|
open question in this runbook.
|
||||||
- Whether the Vault export (§3 blocker) has actually been done.
|
- Whether the Vault export (§3 blocker) has actually been done.
|
||||||
- The Cloudron host's OS version, disk and RAM (not visible over the API).
|
- The Cloudron host's OS version, disk and RAM (not visible over the API).
|
||||||
- Whether the S3 access key is in the off-box JSON or only inside Cloudron.
|
|
||||||
- Whether any provider API key is bound to our current IP.
|
- Whether any provider API key is bound to our current IP.
|
||||||
- Whether the subscription permits a server move.
|
- Whether the subscription permits a server move.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
{
|
||||||
|
"app_count": 16,
|
||||||
|
"apps": {
|
||||||
|
"4023ccbf-d57a-4500-97df-14de9cf3516e": {
|
||||||
|
"env_names": [
|
||||||
|
"ALLOW_EMAIL_LOGIN",
|
||||||
|
"APP_TITLE",
|
||||||
|
"IMAGE_GEN_OAI_BASEURL",
|
||||||
|
"IMAGE_GEN_OAI_MODEL",
|
||||||
|
"SEARXNG_INSTANCE_URL",
|
||||||
|
"STT_API_KEY",
|
||||||
|
"SYSTEM_IMAGE_KEY",
|
||||||
|
"TTS_API_KEY"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "20261027-d099d31",
|
||||||
|
"location": "chat.inference.coop",
|
||||||
|
"manifest": "ai.librechat.cloudronapp@1.4.5",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"50ae6c97-e851-4d17-b013-51ca7a4e5be0": {
|
||||||
|
"env_names": [
|
||||||
|
"DEFAULT_PROMPT_SUGGESTIONS",
|
||||||
|
"ENABLE_ADMIN_CHAT_ACCESS",
|
||||||
|
"ENABLE_ADMIN_EXPORT",
|
||||||
|
"PYTHONPATH",
|
||||||
|
"RAG_EMBEDDING_ENGINE",
|
||||||
|
"RAG_EMBEDDING_MODEL",
|
||||||
|
"RAG_OPENAI_API_BASE_URL",
|
||||||
|
"RAG_OPENAI_API_KEY"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610270420400000",
|
||||||
|
"location": "chat-legacy.inference.coop",
|
||||||
|
"manifest": "com.openwebui.cloudronapp@3.7.8",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"55f5f904-3233-44de-ad7b-5dc7c8533b75": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610221509540000",
|
||||||
|
"location": "inference.coop",
|
||||||
|
"manifest": "io.cloudron.surfer@7.4.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"8b1a972c-08af-4e92-852c-d573c37b01ad": {
|
||||||
|
"env_names": [
|
||||||
|
"B3_API_KEY",
|
||||||
|
"LOOMIO_DISABLE_DEMO_GROUPS"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610270319320000",
|
||||||
|
"location": "forum.inference.coop",
|
||||||
|
"manifest": "org.loomio.cloudronapp@1.29.1",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"aa6f4597-6206-4509-b32e-c89750b2c1d8": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610290719420000",
|
||||||
|
"location": "matrix.inference.coop",
|
||||||
|
"manifest": "org.matrix.synapse@1.147.1",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"adababd4-2427-4bdd-9bf7-6bdad0302610": {
|
||||||
|
"env_names": [
|
||||||
|
"GREENPT_API_KEY",
|
||||||
|
"LITELLM_CORS_ORIGINS",
|
||||||
|
"LITELLM_MIGRATION_DIR",
|
||||||
|
"OLLAMA_API_KEY",
|
||||||
|
"TINFOIL_API_KEY",
|
||||||
|
"TINFOIL_USER_CACHE_SECRET"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "1.0.0-1793073788677",
|
||||||
|
"location": "gateway.inference.coop",
|
||||||
|
"manifest": "ai.coop.litellm@1.0.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"ae187071-7a43-4a6e-8a02-986609a66a1a": {
|
||||||
|
"env_names": [
|
||||||
|
"ADMIN_TOKEN",
|
||||||
|
"ADMIN_USERNAMES",
|
||||||
|
"PORTAL_BASE"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "20261029-4687efb",
|
||||||
|
"location": "panel.inference.coop",
|
||||||
|
"manifest": "coop.inference.admin-panel@0.1.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"c257ba3c-6737-4375-ad51-ea19586bf3f0": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610221511140000",
|
||||||
|
"location": "registry.inference.coop",
|
||||||
|
"manifest": "io.cloudron.container-registry@1.4.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"c91c13aa-30ed-4af9-9599-7a87ab4f221d": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610211624040000",
|
||||||
|
"location": "git.inference.coop",
|
||||||
|
"manifest": "io.gitea.cloudronapp@1.43.1",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"cb838bcf-f2e2-4670-b117-dca04b0ee957": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610211943370000",
|
||||||
|
"location": "vault.inference.coop",
|
||||||
|
"manifest": "com.github.bitwardenrs@1.26.5",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"d4f05e4b-75c6-492e-9faf-7afb0712fc94": {
|
||||||
|
"env_names": [
|
||||||
|
"ADMIN_TOKEN",
|
||||||
|
"ADMIN_TOKEN_LEGACY",
|
||||||
|
"BROKER_SECRET",
|
||||||
|
"CLOUDRON_TOKEN",
|
||||||
|
"DOCS_KNOWLEDGE_ID",
|
||||||
|
"INACTIVE_GROUP_ID",
|
||||||
|
"LIBRECHAT_SYNC_TOKEN",
|
||||||
|
"LISTMONK_API_TOKEN",
|
||||||
|
"LISTMONK_API_USER",
|
||||||
|
"LISTMONK_LIST_ID",
|
||||||
|
"LITELLM_BASE",
|
||||||
|
"LITELLM_DB_HOST",
|
||||||
|
"LITELLM_DB_NAME",
|
||||||
|
"LITELLM_DB_PASSWORD",
|
||||||
|
"LITELLM_DB_PORT",
|
||||||
|
"LITELLM_DB_USER",
|
||||||
|
"LITELLM_MASTER_KEY",
|
||||||
|
"LOOMIO_API_KEY",
|
||||||
|
"LOOMIO_B3_KEY",
|
||||||
|
"LOOMIO_GROUP_ID",
|
||||||
|
"MANUAL_MEMBERS",
|
||||||
|
"MATRIX_BOT_TOKEN",
|
||||||
|
"MATRIX_EXTRA_ROOMS",
|
||||||
|
"MATRIX_GENERAL_ROOM",
|
||||||
|
"MATRIX_HOMESERVER",
|
||||||
|
"MATRIX_SPACE_ID",
|
||||||
|
"MEMBERS_GROUP_ID",
|
||||||
|
"MEMBER_BUDGET",
|
||||||
|
"OC_OAUTH_CLIENT_ID",
|
||||||
|
"OC_OAUTH_CLIENT_SECRET",
|
||||||
|
"OC_PERSONAL_TOKEN",
|
||||||
|
"OWUI_API_KEY",
|
||||||
|
"OWUI_BASE",
|
||||||
|
"OWUI_JWT_SECRET",
|
||||||
|
"OWUI_MEMBERS_GROUP_ID",
|
||||||
|
"PORTAL_KEK",
|
||||||
|
"PORTAL_SECRET",
|
||||||
|
"WEBHOOK_TOKEN"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "20261030-6475a51",
|
||||||
|
"location": "portal.inference.coop",
|
||||||
|
"manifest": "coop.inference.member-portal@0.1.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"d7c73fff-ee42-4db0-98c0-4ce7a8ab35cc": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610252319260000",
|
||||||
|
"location": "search.inference.coop",
|
||||||
|
"manifest": "io.github.ascimoo.searx@2.119.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"daf8750e-2683-4104-83ea-f77d1b4601e8": {
|
||||||
|
"env_names": [
|
||||||
|
"BROKER_SECRET",
|
||||||
|
"PORTAL_BASE"
|
||||||
|
],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "20261029-700339a",
|
||||||
|
"location": "dashboard.inference.coop",
|
||||||
|
"manifest": "coop.inference.member-dashboard@0.1.0",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"eed2217c-b165-430e-bc29-7ccfef9b11e4": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610220221130000",
|
||||||
|
"location": "newsletter.inference.coop",
|
||||||
|
"manifest": "app.listmonk.cloudronapp@1.17.1",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"fbb256b9-ead3-41d8-bee0-d5ea87149436": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610261602550000",
|
||||||
|
"location": "email.inference.coop",
|
||||||
|
"manifest": "io.cloudron.mail@1.6.1",
|
||||||
|
"state": null
|
||||||
|
},
|
||||||
|
"fd261d67-b790-424f-9e82-f74883ee8585": {
|
||||||
|
"env_names": [],
|
||||||
|
"health": "healthy",
|
||||||
|
"image": "202610211606270000",
|
||||||
|
"location": "cloud.inference.coop",
|
||||||
|
"manifest": "com.nextcloud.cloudronapp@5.9.0",
|
||||||
|
"state": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"backup_runs_retained": 14,
|
||||||
|
"backup_sites": [
|
||||||
|
{
|
||||||
|
"bucket": "default",
|
||||||
|
"endpoint": "https://s3.swiss-backup02.infomaniak.com/",
|
||||||
|
"name": "Infomaniak Encrypted S3",
|
||||||
|
"provider": "s3-v4-compat",
|
||||||
|
"retention_days": 7,
|
||||||
|
"schedule": "00 00 23 * * *"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bucket": null,
|
||||||
|
"endpoint": "filesystem",
|
||||||
|
"name": "Default",
|
||||||
|
"provider": "filesystem",
|
||||||
|
"retention_days": 2,
|
||||||
|
"schedule": "never"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"captured_at": "2026-10-30T20:03:49Z",
|
||||||
|
"cloudron_version": "10.1.5",
|
||||||
|
"gitea_code_repos": 5,
|
||||||
|
"newest_backup": {
|
||||||
|
"bytes": 4983397240,
|
||||||
|
"created": "2026-10-30T14:57:05.000Z",
|
||||||
|
"has_integrity_signature": true,
|
||||||
|
"id": "box_v10.1.5_482bf510",
|
||||||
|
"state": "normal"
|
||||||
|
},
|
||||||
|
"portal_tables": {
|
||||||
|
"credit_ledger": 18,
|
||||||
|
"held_credits": 1,
|
||||||
|
"member_api_keys": 64,
|
||||||
|
"members": 82,
|
||||||
|
"metrics_daily": 57,
|
||||||
|
"pending_members": 3,
|
||||||
|
"sqlite_sequence": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user