A practical guide to self-hosted messaging backups with Matrix, Synapse, mautrix, MsgVault, Tailscale, and official account exports.
A practical guide to self-hosted messaging backups with Matrix, Synapse, mautrix, MsgVault, Tailscale, and official account exports
Important: A connected bridge is not proof of a complete backup. The durable model is official exports + live bridges + explicit coverage records + encrypted backups + restore drills.
This guide explains a real-world personal message-backup architecture, how its pieces fit together, how to reproduce it on a home server, and how to build simpler versions on a Mac or Windows PC.
It intentionally contains no private domains, account names, addresses, access tokens, host fingerprints, personal message counts, or network details. Replace placeholders such as <matrix-domain> and <tailnet-hostname> with values from your own environment.
Who this guide is for
Home-lab owners who want a recoverable private messaging archive.
People who want one place to read current conversations without surrendering all historical custody.
Mac or Windows users who want a simpler, local-first setup.
Anyone evaluating a custom Synapse server, mautrix bridges, Beeper, or an export-only backup routine.
The core idea
This system does two separate jobs:
Capture new messages continuously through live bridges.
Preserve older history from official account exports.
Both streams land in Matrix, but they remain operationally separate. A searchable archive indexes eligible Matrix rooms. Encrypted, off-site backups protect the databases, media, credentials, and import state.
The separation matters. Importing an old export directly into a live bridge room can confuse the bridge, create duplicates, or, in the worst case, send imported events back toward the original network.
What each component does
Component
Job
It is not
Matrix
Open protocol for users, rooms, spaces, events, and media
A specific app or social network
Synapse
The personal Matrix homeserver and authoritative room history
A complete disaster-recovery copy by itself
Element
Desktop/mobile Matrix client
The server or archive database
mautrix bridge
Translates live service events into Matrix rooms and optionally sends replies back
Guaranteed historical backfill
Official account export
Point-in-time copy obtained from the original platform
Continuous synchronization
Archive importer
Converts export data into dedicated Matrix archive rooms
A tool that should modify live bridge rooms
MsgVault
Indexes joined rooms and presents searchable conversation history
A replacement for Synapse or the original service
Tailscale
Private networking and identity-aware remote access
An application-data backup
Encrypted off-site backup
Recovers databases, media, state, and secrets
Something that should live only on the main server
Why exports and bridges are both necessary
A bridge can be healthy while containing only messages received after login. Some platforms expose a small reconnect window. Others provide no reliable historical API at all.
Official exports are often the best source for older history, but they are snapshots. They can also omit content, arrive in many parts, or take days to prepare.
The pattern is:
Archive rooms contain historical export events and archive-only Matrix identities.
Live rooms are owned by the bridge and contain current traffic.
Both can appear inside one Matrix Space and under one provider label in the archive UI.
A coverage ledger records the last event present in the export, the first verified live event, known gaps, media tests, authentication status, and restart/session-loss tests.
Never mark a provider complete merely because its container is running or its icon appears in a client.
A resilient home-lab architecture
A strong personal deployment separates the major trust and recovery boundaries into three guests:
Why split the guests?
Synapse can be restored without rebuilding bridge containers.
Bridge sessions and databases have a smaller, separate trust boundary.
Archive indexing cannot accidentally become the homeserver database.
Each service can be snapshotted, upgraded, and rolled back independently.
A failed importer or large index operation has clearer resource limits.
A mini PC, NAS, or VPS can run the same logical components as containers on one machine. Keep volumes, databases, users, and credentials separate even when the hardware is shared.
Network and access model
For a single-person system that does not need public Matrix federation, keep the application private:
Give the hypervisor and every guest its own Tailscale identity.
Serve Synapse and the archive UI over Tailnet-only HTTPS.
Bind databases and application APIs to loopback or a private interface.
Keep bridge provisioning endpoints private to the Tailnet.
Disable public registration.
Do not expose bridge login or administration endpoints to the open internet.
Tailscale reduces ingress risk, but it does not protect you from compromised credentials, malicious bridges, application vulnerabilities, or bad backups. Keep normal service authentication and least-privilege appservice registrations.
Messaging networks and realistic coverage
Service
Historical source
Typical live path
Key limitation
Facebook Messenger
Meta Accounts Center export
mautrix-facebook
Treat as live-only unless you independently verify backfill
Instagram
Meta Accounts Center export
mautrix-instagram
Initial history may be unavailable; reconnect catch-up can be small
LinkedIn
LinkedIn data export
mautrix-linkedin
A connected session does not prove historical coverage
X
X account archive
mautrix-twitter
Historical or missed-message backfill may be unsupported
Telegram
Telegram Desktop export when needed
mautrix-telegram
Portal discovery and full message history are separate checks
WhatsApp
Device/chat exports and device backup
mautrix-whatsapp
Linked-device history and exports may be partial
Signal
Device-local backup where supported
mautrix-signal
Historical portability varies by platform
iMessage
Mac Messages data plus device backup/export tooling
mautrix-imessage on an always-on Mac
Requires macOS permissions and careful sent-message validation
Slack
Workspace export subject to plan and policy
mautrix-slack
Export and app scope depend on authorization and workplace rules
Messenger and Instagram
Request JSON exports with messages and media from Meta Accounts Center. Preserve every downloaded archive part unchanged.
A well-designed Meta importer should:
read inbox, archived, filtered, and migration/cutover thread sets exposed by the export;
merge shards chronologically;
repair obvious text-encoding corruption without changing valid Unicode;
preserve timestamps, reactions, calls, shares, attachments, and local media where supported;
generate deterministic Matrix room, identity, and transaction IDs;
use a checkpoint and final report;
import into non-federated archive rooms through a no-URL, least-privilege appservice;
never send historical events into live Facebook or Instagram bridge portals.
Use different Matrix identity namespaces for live and archive events, while displaying both under a friendly Messenger or Instagram label.
LinkedIn
Request messages and related account data from LinkedIn's privacy settings. Keep the official download encrypted and unchanged.
If you have not written and reviewed a LinkedIn archive importer, the export itself is your historical recovery source. A live bridge heartbeat proves only that the current session works.
X
Request the X account archive and preserve all supplied parts. Direct-message data is commonly packaged in JavaScript-wrapped data files with separate media directories.
A safe X importer should:
parse data without evaluating arbitrary JavaScript;
use stable numeric account IDs as identity keys rather than display names;
import direct and group conversations, supported edits/notices, reactions, and local media;
require an explicit inclusive end timestamp for the export;
use archive-only identities and non-federated rooms;
support dry runs, resumable checkpoints, identity maps, and final reports.
Keep the stable internal origin name even if the user-facing brand changes. Record any gap between the final exported event and the first live bridge event.
The universal export workflow
Follow this for every platform:
Request messages plus media for the full available date range.
Prefer JSON for machine processing; keep HTML too if it is useful for human reading.
Download every part before the link expires.
Record the request date, download date, account identifier, time zone, format, categories, and file list in a private manifest.
Calculate checksums and preserve the original files read-only.
Extract only a working copy into a restricted local directory.
Inspect conversation, event, attachment, and date-range counts.
Run the importer in dry-run mode and retain its report.
Back up Synapse, bridge databases, and the archive database before the real import.
Import into dedicated archive rooms, never live bridge portals.
Reconcile event and attachment counts in Synapse and the archive.
Record the export/live boundary and any known gap or overlap.
Encrypt and back up the original export, checksum manifest, importer checkpoint/report, databases, media, and required registrations.
Provisioning a home-server deployment from scratch
The details vary by hardware and distribution, but the dependency order should remain stable.
1. Prepare recovery material first
Before changing a working system, collect:
the desired infrastructure configuration revision;
checksummed guest or VM backups;
logical PostgreSQL dumps for Synapse and bridge databases;
Synapse media and signing state;
bridge session/state directories and matching appservice registrations;
the archive database, attachments, workflow state, and snapshots;
original provider exports, checksums, checkpoints, reports, portal maps, and deduplication inputs;
an offline secret bundle and a separate path to its decryption key;
a Tailscale re-enrollment method.
Work on copies. Do not overwrite the last known-good backup during a recovery attempt.
2. Install the hypervisor
Install Proxmox, another hypervisor, or a stable Linux host. For a hypervisor deployment:
use redundant or well-monitored storage where possible;
separate host configuration from guest application data;
enroll the host in Tailscale and prove remote recovery access;
record storage, network, boot, and guest definitions without committing secrets or private keys.
Hardware identifiers, disk IDs, MAC addresses, and network interface names must be reviewed when cloning to a different machine.
3. Create the guests
Create:
a Synapse guest with PostgreSQL and enough storage for Matrix media;
a bridge guest with Docker/Podman, PostgreSQL, and independent state volumes per provider;
an archive guest with storage for the index and attachments.
Give every guest a distinct machine identity and Tailscale hostname. Start Synapse first, bridges second, and the archive last.
4. Provision Synapse
Install Synapse and PostgreSQL.
Configure a permanent Matrix server name such as <matrix-domain>.
Disable public registration and federation unless you explicitly need them.
Create root-owned signing and registration secrets outside source control.
Restore PostgreSQL through a logical dump; do not transplant raw PostgreSQL directories across major versions.
Restore Matrix media and signing state with correct ownership.
Install live bridge registrations and archive-only registrations as one consistent token set.
Install a narrowly scoped double-puppet registration if desired.
Serve the Matrix client API through Tailnet-only HTTPS.
Verify the Matrix versions endpoint and create users through an administrative command rather than public registration.
5. Provision the bridge host
Install Docker or Podman and PostgreSQL.
Give each bridge its own database owner, password, state directory, registration, and port.
Pin container images by immutable digest.
Generate configurations before installing their appservice registrations in Synapse.
Copy registration files to Synapse through a secure channel.
Start one bridge at a time and perform interactive provider login.
Mark intentionally disabled bridges so monitoring can distinguish a login gate from a crash.
Expose provisioning APIs only through the private network.
Browser-session bridges are unofficial. A platform may invalidate sessions or change behavior without notice. Prefer direct provisioning APIs or a trusted local bridge manager rather than pasting cookies into Matrix history.
6. Provision MsgVault or another archive
Create a dedicated, non-admin Matrix archive user.
Give it access only to eligible unencrypted rooms.
Use a separate, revocable administrative identity for temporary private-room enrollment.
Exclude bridge management and login rooms before broad enrollment.
Store the archive API key and Matrix token in root-owned runtime files.
Put the archive database in WAL mode or use the archive's supported storage model.
Enable native snapshots and encrypted off-site replication.
Reconcile message counts by provider and room after initial sync.
For messenger sources, a good archive UI should show a scrollable contact/conversation list and the complete chronological history for the selected person or group. It should not force chat history into an email-inbox metaphor.
Identity matching must prefer stable external IDs, provider-scoped handles, or unique phone numbers. Never silently merge two people just because their display names match.
7. Import historical exports
For one provider at a time:
Stage the export outside source control with restrictive permissions.
Stop or pause the affected live bridge and archive scheduler when required.
Confirm there is no competing import, index rebuild, database backup, or room-enrollment writer.
Take fresh database and media backups.
Load the provider's archive-only appservice registration.
Generate portal maps and existing-event deduplication inputs without copying credentials into the staging directory.
Run a dry run with persistent checkpoint and report paths.
Require zero unexplained failures.
Perform the real import with the same configuration.
Invite the archive identity, synchronize, and compare per-room counts.
Update the coverage ledger.
Back up the resulting databases, media, checkpoint, report, and original export before enabling normal live capture.
8. Re-enable normal operation
Start in order:
Synapse and PostgreSQL.
Individual bridges.
Room enrollment timers.
MsgVault or the archive indexer.
Element and other clients.
Remove temporary bulk-import rate-limit changes and restore normal history limits. Validate fresh inbound events, media, restart behavior, archive cursor movement, and representative conversations, not just process health.
Backup design
Synapse
Preserve:
logical PostgreSQL dumps;
Matrix media and signing state;
homeserver secrets;
all appservice registrations.
Bridges
Preserve:
logical PostgreSQL dumps;
per-provider session, media, and state directories;
root-owned bridge configuration;
generated appservice registrations;
deployed configuration revision;
coverage ledger.
The registration tokens on the bridge host and Synapse must be restored as a matching set.
Archive
Preserve:
database, WAL-consistent state, and attachments;
native snapshots;
local workflow state;
archive API key and Matrix credential;
encrypted off-site repository and separately escrowed password.
Social exports
Preserve:
original archives and checksum manifest;
private metadata about request/download scope;
portal and deduplication maps used by the exact run;
importer checkpoints and reports;
coverage ledger;
matching archive appservice registrations.
Raw export directories contain complete private conversations and media. Protect them like the message databases. A successful importer report does not replace the original export.
Restore order
Recreate the host, guests, storage, and private networking.
Restore Synapse signing state, secrets, media, and appservice registrations.
Restore Synapse PostgreSQL from a logical dump.
Restore bridge databases and session directories, but keep bridges stopped.
Restore archive databases, attachments, workflow state, and credentials.
Start Synapse and verify room/media integrity.
Start bridges one at a time and verify matching registration tokens.
Start the archive and validate cursors, message counts, and attachments.
Restore/import social exports only when the database state requires it.
Run inbound and media tests before enabling outbound sending.
Restore into an isolated network first. Rotate cloned machine identities and credentials when chain of custody is uncertain.
Minimum evidence for a successful recovery drill
Decrypt and list the off-site repository without credentials stored on the main server.
Restore one guest or container set with networking disabled.
Validate database integrity and expected record/media counts.
Boot the restored services with rotated machine identities.
Open representative conversations and attachments.
Record backup age, restore duration, missing manual steps, and known data gaps.
Recovery point and recovery time targets are objectives until a real isolated drill proves them.
Simpler self-hosting options
Option
Best for
Main advantage
Main limitation
Dedicated home server with separate guests
Maximum control and recoverability
Strong isolation and independent restores
Highest maintenance effort
Mini PC or NAS with containers
Most self-hosters
Quiet, always-on, simpler than a hypervisor
Less isolation
Encrypted VPS
People without reliable home internet
Always on and reachable
Provider trust and storage cost
Mac or Windows PC
Trying the idea with existing hardware
No new machine
Sync stops during sleep and updates
Official exports only
Nontechnical or privacy-first users
Lowest risk and maintenance
No continuous capture or unified client
Beeper plus independent exports
People prioritizing a convenient multi-network client
Fastest daily experience
Not automatically a complete self-controlled backup
A practical Mac or Windows path
Level 1: official exports only
Request exports from every service you care about.
Keep each download unchanged.
Put a second copy on an encrypted external drive.
Put a third encrypted copy in cloud storage if acceptable.
Repeat monthly or quarterly.
Test opening a copy at least annually.
This is already meaningful self-custody.
Level 2: one client plus exports
Use Element with a Matrix provider or a multi-network client such as Beeper for daily reading. Continue creating official exports. A connected account is not the same as a historical backup, and a client cache is not a server backup.
Level 3: private stack on your computer
Run Synapse, PostgreSQL, selected bridges, and optionally an archive UI in separate containers with separate volumes. Add Tailscale if you want remote access.
The computer must remain awake for continuous capture. Schedule supported database dumps or stop the stack before filesystem snapshots.
Mac notes
An always-on Mac mini works well; a sleeping laptop does not.
Docker Desktop or OrbStack can host Linux services.
Store data on encrypted APFS and include logical dumps in Time Machine or another versioned backup.
iMessage bridging requires an appropriate Mac and privacy permissions for the Messages database.
macOS can deny command-line access to protected folders. Select only the intended export through Finder, copy it to a private staging directory, and leave the original unchanged.
Windows notes
Use Docker Desktop with the WSL 2 backend.
Prefer named Docker volumes or the WSL filesystem over a casually synchronized desktop directory.
Plan for sleep and Windows Update reboots.
Use BitLocker and store the recovery key outside the PC.
There is no normal Windows-native iMessage bridge; use an always-on Mac or preserve Apple-provided/local exports separately.
Where Beeper fits
Beeper can be a convenient multi-network client or connection operator for someone who does not want to maintain every bridge. Its product and self-hosting capabilities can change, so verify current behavior before designing around it.
Do not assume Beeper bridge-management tooling is a drop-in controller for an arbitrary self-hosted Synapse. A custom Synapse deployment normally uses its own appservice registrations and direct mautrix administration.
Whichever route you choose:
keep requesting official exports;
confirm whether older history is actually present;
maintain independent encrypted copies of exports and important media;
understand where login sessions and decrypted data are processed;
do not treat a client cache as a server backup.
A sensible hybrid is Beeper for day-to-day messaging plus an independent export/archive routine for recovery.
Privacy and security boundaries
Bridging changes the trust model:
messages are copied out of their original platform;
server-side archives usually need unencrypted Matrix rooms;
Synapse, bridge databases, archive indexes, and backups may contain sensitive text and attachments;
unofficial browser-session bridges can break or create platform-policy risk;
work and third-party conversations should be archived only when policy and participant expectations permit it.
Security rules:
Exclude management and login rooms from the durable archive.
Never paste browser cookies into an archived or shared Matrix room.
Keep appservice namespaces narrow and provider-specific.
Keep secrets out of Git, logs, export staging directories, and client-side JavaScript.
Pin bridge images and dependencies by immutable revision.
Keep public registration and federation disabled unless deliberately required.
Rotate tokens after uncertain custody or a cloned restore.
Do not expose raw databases or bridge provisioning APIs to browser clients.
Use HTTPS and private networking, but retain application-level authentication.
Keep backup encryption keys separate from backup data.
Operational caveats
Platforms can invalidate sessions or change unofficial APIs.
A sleeping desktop can miss live events.
Some services provide incomplete exports or omit attachments.
End-to-end encrypted rooms may be unreadable to a server-side archive.
Synapse stores only events it received; the archive cannot reconstruct remote-deleted or never-exposed data.
Restricted room history can hide pre-join events from the archive identity.
Bulk enrollment may need carefully bounded invite, join, and per-room rate-limit changes.
Large imports and full-text index builds can hold database locks for a long time.
WAL growth and progress counters can be useful safe progress indicators; do not terminate an unknown writer merely because an operation is slow.
Final acceptance checklist
The desired configuration revision and backup generation are recorded.
Synapse health, room history, media, and appservice transactions work.
Every enabled bridge is logged in and receives a fresh test event.
Historical export boundaries are explicit for Messenger, Instagram, LinkedIn, X, and other providers.
Management/login rooms are absent from the archive.
Messenger sources show a contact list and complete chronological history.
Identity matching does not silently merge people by display name.
Synapse and archive counts are reconciled by provider and room.
Original exports, checkpoints, reports, databases, media, and registrations are encrypted off-site.
Backups decrypt, checksums pass, and at least one isolated restore boots.
No raw export, token, session, database, or backup is present in source control.
Recommended progression
Start with official exports and two encrypted copies.
Add one private Matrix server and one bridge.
Add an archive only after Matrix history is stable.
Add providers one at a time and record coverage boundaries.
Automate database/media backups.
Perform a disconnected restore drill.
Split services into more guests only when isolation and recovery needs justify it.
The most important lesson is simple: connection status is not backup status. Self-hosting succeeds when you can explain the coverage boundary, restore the data, and prove the restored system works.