π§ͺ Testers wanted: Element Server Suite (ESS Community) for Cloudron
-
Migration update: v0.3.13 tested with real Synapse data
A real end-to-end migration rehearsal has now been completed using a
disposable ESS target and a copy of an existing PostgreSQL-backed Synapse
homeserver. The live source server was not modified.The rehearsal covered:
- restoring a real Synapse PostgreSQL database;
- preserving the original Matrix server name and signing key;
- copying the media store;
- running the official
mas-cli syn2masdry run and real import; - importing human users, password hashes, OIDC links, devices, sessions, and
access tokens; - verifying an imported access token against
/_matrix/client/v3/account/whoami; - preserving existing appservice registrations;
- retaining rooms, history, E2EE/device data, and media;
- restoring the clean ESS target through the rollback command.
The test uncovered several problems in the original v0.3.11 workflow. These
included ineffective process shutdown, the wrong Synapse configuration being
passed tosyn2mas, MAS migration metadata being removed during database
restore, warning exit codes being treated as failures, and appservice
registrations not being copied.These issues are fixed in v0.3.13.
Do not use v0.3.11 or v0.3.12 for migration. Use v0.3.13 or later.
The corrected process requires putting only the new ESS target into Cloudron
debug/recovery mode so Synapse and MAS are completely offline before the
database is restored. The source Synapse installation remains untouched and
continues to be the fallback until the final domain cutover.Current instructions:
https://git.due.ren/andreas/cloudron-ess/-/blob/main/docs/MIGRATION.md
Although the workflow has now passed a real-data rehearsal, migration should
still be treated as a maintenance operation: take backups, rehearse with a
copy, inspect thesyn2maswarnings, and plan the domain cutover carefully. -
I set up a new server. The installation went smoothly. I logged in via Cloudron using two different CR users.
User 1: logged in to element x on iOS
User 2: logged in to element x on GrapheneOS/Android (installed thru google play store)iOS to Android:
- Text messages

- Audio calls

- Video calls

I'll test iOS to iOS when I get my hands on fam devices tonight.
Edit: BTW, I tried the option "blur background" in the video settings and things became REALLY laggy on my Pixel 10. I enabled it during the call. Maybe that's why.
- Text messages
-
Migration update: guided one-command Synapse β ESS wizard in v0.3.17
The migration workflow has now been wrapped in an interactive wizard. After installing a fresh ESS target on temporary domains, run this on a Mac or Linux computer where the Cloudron CLI is installed and logged in:
bash <(curl -fsSL https://git.due.ren/andreas/cloudron-ess/-/raw/v0.3.17/scripts/cloudron-synapse-to-ess.sh)No migration arguments are required. The wizard asks for:
- the domain of the old Cloudron Synapse app;
- the primary domain of the fresh ESS target;
- rehearsal or final migration;
- explicit confirmation before starting;
- a second confirmation after the complete
syn2masdry-run.
In final mode it freezes the old homeserver before the database dump, leaves both apps safely offline for the domain switch, and starts ESS only after the operator confirms
CUTOVER-DONE.The wizard handles Cloudron backups, PostgreSQL export/restore, the original signing key and server name, appservice registrations, local media, S3 configuration, target recovery mode, preflight checks, the official
syn2masdry-run/import, and rollback.One important media detail: local media is copied even when S3 is enabled. S3 may have been enabled after older media was created, or an asynchronous upload may be incomplete. The migrated target therefore preserves the union of all local files and existing S3 objects instead of assuming the bucket is complete.
I completed a real end-to-end rehearsal through the new no-argument terminal UI using a fresh disposable ESS target and an existing Cloudron Synapse database. It completed with exit code 0 and verified:
- 3,061 Synapse user rows and all 45 human users;
- matching imported human compatibility sessions;
- 29,533 local media files / 2,389,933,963 bytes;
- identical signing-key and S3-provider fingerprints;
- identical contents for both appservice registrations;
- successful read access to the existing S3 bucket;
- removal of credential-bearing staging data after success.
The old homeserver stayed online throughout the rehearsal. The disposable target was kept in recovery mode, verified, then uninstalled. Only backups created by the test were marked for immediate expiry, and they have already been cleaned up.
Documentation:
- Guided wizard: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.17/scripts/cloudron-synapse-to-ess.md
- Full migration reference/manual fallback: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.17/docs/MIGRATION.md
The final production domain reassignment remains an explicit Cloudron dashboard step because legacy Synapse/Element domains and bare-domain well-known setups differ between installations. The wizard does not guess or silently take over domains.
-
Migration update: full production-style cutover tested end-to-end β v0.3.18
Since the last update I ran the complete final-migration path (not just a rehearsal) on a dedicated test Cloudron, exactly the way a real production switch would go.
Test setup
- Fresh legacy Cloudron Synapse (
org.matrix.synapse1.138.1) as the source - Two users, both linked to Cloudron SSO
- Five live device sessions before migration: Element X on iOS, Element X on Android, and Element Web/Safari sessions
- Fresh ESS target installed on temporary domains via the community catalog
What the wizard did
Rehearsal first (validated, target discarded), then final mode: backups of both apps, source frozen before the export, PostgreSQL/signing-key/config transfer,
syn2masdry-run, real import, then the interactiveCUTOVER-DONEgate while I moved the production domains over in the dashboard.The result
All five pre-migration device sessions survived the migration without re-authentication. Both phones and the browser sessions just kept syncing against the migrated MAS+Synapse β token sets verified hash-identical, device IDs preserved in MAS compatibility sessions, signing key identical, SSO links and password hashes intact. Calls work too (after the fix below).
Two things the test uncovered, both addressed in v0.3.18
-
Wizard bug (fixed): the post-cutover health check probed the Matrix client API on the MAS port instead of Synapse's port, so a perfectly healthy cutover was reported as failed and the wizard (correctly, but unnecessarily) froze everything again. Failing closed instead of open was the designed behavior, but the probe itself was wrong.
-
Cutover pitfall (now documented in the wizard and docs): if your legacy setup used Cloudron's Domains β Well-Known feature for Matrix, those entries survive the migration and keep intercepting
https://<server-name>/.well-known/matrix/clientat the platform nginx β before ESS's apex alias ever gets asked. Since that fixed template can't carryrtc_foci, Element Call fails withMISSING_MATRIX_RTC_TRANSPORTeven though ESS itself is completely healthy. Delete those dashboard well-known entries during cutover and let the ESS apex alias serve its own complete payload. Mobile Element X caches well-known at login, so force-close and reopen the app afterward.
Migration command (updated pin):
bash <(curl -fsSL https://git.due.ren/andreas/cloudron-ess/-/raw/v0.3.18/scripts/cloudron-synapse-to-ess.sh)Docs:
- Guided wizard: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.18/scripts/cloudron-synapse-to-ess.md
- Migration reference / manual fallback: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.18/docs/MIGRATION.md
Where this stands
With rehearsal, final migration, real domain cutover, session survival, SSO, and calls all verified end-to-end, I consider this essentially production-ready. I'm mainly waiting for feedback from more testers with different setups (bridges/appservices, large media stores, S3, federation-heavy servers) before calling it stable β and my own plan is to migrate my production Matrix servers over soon.
If you test it, please report back either way β successful boring migrations are just as useful as bug reports.
- Fresh legacy Cloudron Synapse (
-
Migration update: full production-style cutover tested end-to-end β v0.3.18
Since the last update I ran the complete final-migration path (not just a rehearsal) on a dedicated test Cloudron, exactly the way a real production switch would go.
Test setup
- Fresh legacy Cloudron Synapse (
org.matrix.synapse1.138.1) as the source - Two users, both linked to Cloudron SSO
- Five live device sessions before migration: Element X on iOS, Element X on Android, and Element Web/Safari sessions
- Fresh ESS target installed on temporary domains via the community catalog
What the wizard did
Rehearsal first (validated, target discarded), then final mode: backups of both apps, source frozen before the export, PostgreSQL/signing-key/config transfer,
syn2masdry-run, real import, then the interactiveCUTOVER-DONEgate while I moved the production domains over in the dashboard.The result
All five pre-migration device sessions survived the migration without re-authentication. Both phones and the browser sessions just kept syncing against the migrated MAS+Synapse β token sets verified hash-identical, device IDs preserved in MAS compatibility sessions, signing key identical, SSO links and password hashes intact. Calls work too (after the fix below).
Two things the test uncovered, both addressed in v0.3.18
-
Wizard bug (fixed): the post-cutover health check probed the Matrix client API on the MAS port instead of Synapse's port, so a perfectly healthy cutover was reported as failed and the wizard (correctly, but unnecessarily) froze everything again. Failing closed instead of open was the designed behavior, but the probe itself was wrong.
-
Cutover pitfall (now documented in the wizard and docs): if your legacy setup used Cloudron's Domains β Well-Known feature for Matrix, those entries survive the migration and keep intercepting
https://<server-name>/.well-known/matrix/clientat the platform nginx β before ESS's apex alias ever gets asked. Since that fixed template can't carryrtc_foci, Element Call fails withMISSING_MATRIX_RTC_TRANSPORTeven though ESS itself is completely healthy. Delete those dashboard well-known entries during cutover and let the ESS apex alias serve its own complete payload. Mobile Element X caches well-known at login, so force-close and reopen the app afterward.
Migration command (updated pin):
bash <(curl -fsSL https://git.due.ren/andreas/cloudron-ess/-/raw/v0.3.18/scripts/cloudron-synapse-to-ess.sh)Docs:
- Guided wizard: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.18/scripts/cloudron-synapse-to-ess.md
- Migration reference / manual fallback: https://git.due.ren/andreas/cloudron-ess/-/blob/v0.3.18/docs/MIGRATION.md
Where this stands
With rehearsal, final migration, real domain cutover, session survival, SSO, and calls all verified end-to-end, I consider this essentially production-ready. I'm mainly waiting for feedback from more testers with different setups (bridges/appservices, large media stores, S3, federation-heavy servers) before calling it stable β and my own plan is to migrate my production Matrix servers over soon.
If you test it, please report back either way β successful boring migrations are just as useful as bug reports.
@andreasdueren Does the migration process work on existing installs to keep using the same domain?
- Fresh legacy Cloudron Synapse (
-
@andreasdueren Does the migration process work on existing installs to keep using the same domain?
-
Hi all,
The existing Synapse/Element packages on Cloudron work, but they predate Matrix 2.0: no Matrix Authentication Service, which means next-gen auth (Element X), and especially Element Call don't work properly. Instead of patching the old package I've built a new one that packages the full Element Server Suite (ESS Community) stack β the same components as Element's official Helm chart (element-hq/ess-helm), repackaged as a single Cloudron app.
What's included
One app, one container, the whole stack:
Component Version What it does Synapse 1.157.1 Matrix homeserver (MSC4143 RTC transports enabled) Matrix Authentication Service 1.21.0 Next-gen auth (OIDC-native, Element X compatible) Element Web 1.12.24 Web client with embedded Element Call Element Call (standalone SPA) 0.22.0 Guest-accessible call links LiveKit SFU + lk-jwt 1.13.4 / 0.5.0 WebRTC media backend for calls Element Admin 0.1.12 Admin UI (users, rooms) Hookshot 7.4.3 Webhooks/bridges (optional) Cloudron integration: SSO via the Cloudron OIDC addon β MAS β Synapse. Your Cloudron users log in with their normal accounts, including on Element X mobile. PostgreSQL via the Cloudron addon, well-known files served automatically, all configs regenerated from Cloudron env on every start.
What works today (v0.3.8)
Login via Cloudron SSO on Element Web and Element X (iOS tested)
Messaging, media, federation with other Matrix servers
Element Call between users on your server (desktop confirmed, mobile in testing)
Element Admin against MAS + Synapse admin APIs
Install
Install as a custom app via the version catalog:
App Store β Settings (gear icon) β Custom App Repository and enter
https://git.due.ren/andreas/cloudron-ess/-/raw/main/CloudronVersions.json.Repo:
https://git.due.ren/andreas/cloudron-essThe app asks for several locations at install time (all prefilled except the primary):
- Primary location = the account/auth domain β set this to e.g.
account.example.com(this is where MAS lives; it must be primary because Cloudron's OIDC addon only registers callbacks on the primary domain) chat.β Element Web,matrix.β Synapse,mrtc.β RTC backend,admin.matrix.β Admin,call.β standalone Element Call
Current limitations / gotchas (please read before testing)
- The apex domain alias. Matrix identity lives on your bare domain (
@user:example.com), sohttps://example.com/.well-known/matrix/*must be served correctly. Right now the only way to do this is to add your bare domain as an alias on the ESS app β the app then serves the well-known files itself and redirects everything else to Element Web. That means the apex domain has to be parked on this app, which is far from ideal if you want to run something else there. Cloudron's built-in per-domain well-known support doesn't allow the custom JSON entries Matrix RTC needs (org.matrix.msc4143.rtc_foci), hence the request to the Cloudron team below. - Server name is permanent. The Matrix server name is baked in at first start. Changing domains later will brick your identity β the app refuses to start on a mismatch by design.
- Federated calls require the other homeserver to also advertise an RTC transport (
rtc_fociin its well-known). Calls with users on servers that haven't deployed Matrix RTC yet will show "Call is not supported" on their side. - Fresh installs only. No migration path yet from the existing Cloudron Synapse package (syn2mas migration is on the roadmap, untested).
- Element X mobile calls β still shaking out well-known caching issues (log out/in after server updates if calls error out). Actively being worked on.
- Resource usage: this is ~7 services in one container. Give it 2β4 GB memory.
- Hookshot ships but is off by default; workers/redis scaling not implemented yet.
Request for the Cloudron team
@girish @nebulon The apex-domain situation (limitation #1) could be solved cleanly with a small platform feature: let an app declare custom well-known entries for its parent/apex domain β either in
CloudronManifest.jsonor via an API the app can call β so Cloudron's nginx serves e.g.https://example.com/.well-known/matrix/{server,client}and/.well-known/element/element.jsonon the app's behalf, without the app claiming the whole apex as an alias.Cloudron already serves some well-known content per domain, but there's no way to set the arbitrary JSON that Matrix needs today (e.g. the
org.matrix.msc4143.rtc_focitransport entry that Element Call requires), and no way for a package to register it automatically. AwellKnownsection in the manifest (updated on configure/restart) would benefit any protocol using apex-domain discovery β Matrix, WebFinger/Mastodon delegation, etc. Happy to write up a concrete proposal or beta-test an implementation with this package.How you can help
- Install it on a test domain and report: SSO login, Element X login, 1:1 and group calls, federation with matrix.org
- Especially interested in: calls between two different ESS-package servers, iOS vs Android behavior, and apex/alias setups
- Issues β please reply here
Everything is rebuilt from upstream Element artifacts, config generation mirrors the official Helm chart, so upstream version bumps should be routine once this stabilizes. My plan is to eventually either implement the upstream ESS Community migration tool or build a custom script for future migrations from the legacy Cloudron matrix apps.
Thanks for testing!
Pinging the Cloudron team @girish @nebulon one more time more cleanly for this, or a comparative feature request (if you give me permissions on git.cloudron.io Iβm happy to commit something directly):
andreasdueren said:
Request for the Cloudron team
@girish @nebulon The apex-domain situation (limitation #1) could be solved cleanly with a small platform feature: let an app declare custom well-known entries for its parent/apex domain β either in
CloudronManifest.jsonor via an API the app can call β so Cloudron's nginx serves e.g.https://example.com/.well-known/matrix/{server,client}and/.well-known/element/element.jsonon the app's behalf, without the app claiming the whole apex as an alias.Cloudron already serves some well-known content per domain, but there's no way to set the arbitrary JSON that Matrix needs today (e.g. the
org.matrix.msc4143.rtc_focitransport entry that Element Call requires), and no way for a package to register it automatically. AwellKnownsection in the manifest (updated on configure/restart) would benefit any protocol using apex-domain discovery β Matrix, WebFinger/Mastodon delegation, etc. Happy to write up a concrete proposal or beta-test an implementation with this package. -
@andreasdueren is this same or different from https://docs.cloudron.io/domains#matrix-server-location ? I guess we can also add element.json there.
-
@andreasdueren is this same or different from https://docs.cloudron.io/domains#matrix-server-location ? I guess we can also add element.json there.
@girish Almost the same, with two differences:
-
That feature only serves a fixed set of locations (
matrix/server,matrix/client,host-meta,caldav/carddav).element/element.jsonisn't in the whitelist, so adding it to the domain config today would still 404. If you're open to adding it there, or better, serving any configured location, that solves it. I actually have a small patch for the generic version ready (branchwellknown-generic-locationson https://git.due.ren/andreas/cloudron-box, incl. regression test) if you want an MR. -
The entries are static text the admin maintains by hand, while the correct values (e.g.
rtc_focifor Element Call, the MAS auth block) come from the app and change with its config. That's the angle of my feature request: letting an app declare/update these entries for its apex domain itself, so they can't go stale. The dashboard feature would stay as the manual override.
So: same mechanism, just asking for it to be un-whitelisted and optionally app-populated.
-
-
@girish Almost the same, with two differences:
-
That feature only serves a fixed set of locations (
matrix/server,matrix/client,host-meta,caldav/carddav).element/element.jsonisn't in the whitelist, so adding it to the domain config today would still 404. If you're open to adding it there, or better, serving any configured location, that solves it. I actually have a small patch for the generic version ready (branchwellknown-generic-locationson https://git.due.ren/andreas/cloudron-box, incl. regression test) if you want an MR. -
The entries are static text the admin maintains by hand, while the correct values (e.g.
rtc_focifor Element Call, the MAS auth block) come from the app and change with its config. That's the angle of my feature request: letting an app declare/update these entries for its apex domain itself, so they can't go stale. The dashboard feature would stay as the manual override.
So: same mechanism, just asking for it to be un-whitelisted and optionally app-populated.
fyi: @andreasdueren
https://git.due.ren/andreas/cloudron-box can't be accessed without an account. -
-
fyi: @andreasdueren
https://git.due.ren/andreas/cloudron-box can't be accessed without an account.@James Oops, sorry about that. It's public now. https://git.due.ren/andreas/cloudron-box/-/commit/314e5f7a39aec36e61bc21dfced5f26dec797b96
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better π
Register Login