All systems operational 21 cryptocurrencies accepted · Monero welcome No-KYC policy
ChainVPS

Chat · no KYC

Host Matrix (Synapse) on an Offshore VPS

Run your own Matrix homeserver on an offshore, no-KYC VPS and hold the keys to your own end-to-end-encrypted, federated chat network.

What it is

Synapse is the reference server implementation of Matrix, an open protocol for decentralized, end-to-end-encrypted real-time chat, voice, and video. Self-hosting Synapse gives you your own homeserver that can federate with the wider Matrix network or stay fully private, with every message, media file, and account living on hardware you control.

Why host it offshore

Chat metadata (who talks to whom, when, and from where) is exactly the kind of data centralized platforms and their host jurisdictions log and hand over. On a no-KYC, offshore VPS paid in crypto, the homeserver holding your community's messages and encryption keys is registered to no real-world identity and sits in a privacy-friendly jurisdiction outside your home country's reach.

The deploy

A working reference setup

Copy this onto a fresh ChainVPS instance. Replace the placeholders, then bring it up.

docker-compose.yml
# ── One-time setup, run in order on Ubuntu 24.04 (Docker + compose-plugin installed) ──
#
# 1. Generate Synapse's config (replace matrix.example.com with your real domain):
#    mkdir -p synapse-data pgdata
#    docker run --rm -v "$(pwd)/synapse-data:/data" \
#      -e SYNAPSE_SERVER_NAME=matrix.example.com \
#      -e SYNAPSE_REPORT_STATS=no \
#      ghcr.io/element-hq/synapse:latest generate
#
# 2. In synapse-data/homeserver.yaml, REPLACE the generated sqlite `database:`
#    block with the postgres block shown at the bottom of this file, and add
#    `x_forwarded: true` under the port-8008 listener (you are behind a proxy).
#
# 3. Bring the stack up:  docker compose up -d
#
# 4. Create your admin user:
#    docker compose exec synapse register_new_matrix_user \
#      -u admin -a -c /data/homeserver.yaml http://localhost:8008
#
# 5. Put a TLS reverse proxy (Caddy/nginx) on 443 -> 127.0.0.1:8008 and serve
#    /.well-known/matrix/server + /.well-known/matrix/client for federation.

services:
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: synapse
      POSTGRES_PASSWORD: CHANGE_ME_STRONG_DB_PASSWORD
      POSTGRES_DB: synapse
      # Synapse REQUIRES the DB to use C locale — this is a hard requirement:
      POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"
    volumes:
      - ./pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U synapse"]
      interval: 10s
      timeout: 5s
      retries: 5

  synapse:
    image: ghcr.io/element-hq/synapse:latest
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      SYNAPSE_SERVER_NAME: matrix.example.com
      SYNAPSE_REPORT_STATS: "no"
    volumes:
      - ./synapse-data:/data
    ports:
      # Client + federation HTTP. Bound to localhost — TLS is terminated by
      # your reverse proxy. Never expose 8008 to the internet in the clear.
      - "127.0.0.1:8008:8008"

# ── Paste this into synapse-data/homeserver.yaml, replacing the sqlite block ──
# database:
#   name: psycopg2
#   args:
#     user: synapse
#     password: CHANGE_ME_STRONG_DB_PASSWORD
#     dbname: synapse
#     host: db
#     port: 5432
#     cp_min: 5
#     cp_max: 10

Firewall

Ports to open

PortProtocolPurpose
443TCPHTTPS reverse proxy: Element/client API + /.well-known federation delegation (the only port that must face the internet)
8008TCPSynapse client+federation HTTP listener — bind to 127.0.0.1 only, TLS handled by the proxy
8448TCPOptional direct federation port; only needed if you do NOT use .well-known delegation (requires its own TLS)
5432TCPPostgreSQL — internal Docker network only, never publish to the host or internet

Right-sizing

Which plan you need

Light

VPS Nano / Small (2 vCPU, 2-4 GB RAM)

Personal or family server, under ~10 users, little or no federation. Synapse is memory-hungry — 2 GB is the realistic floor, 4 GB if you join any large public rooms.

Medium

VPS Pro (4 vCPU, 8 GB RAM)

Small community of tens to low hundreds of users with active federation. Tune Synapse caches and Postgres shared_buffers; SSD storage matters for media and DB.

Heavy

Dedicated (8+ cores, 16-32 GB RAM)

Hundreds to thousands of users or membership in very large federated rooms. Split Synapse into workers (federation sender, sync, media) and give Postgres its own tuning; unmetered bandwidth keeps media/federation traffic uncapped.

Best locations: Pick a privacy-tier location for a comms server: Switzerland and Iceland offer strong data-protection jurisdictions and are natural homes for a homeserver holding message metadata and keys, while Netherlands and Luxembourg give low-latency, well-peered routes into Europe for smoother real-time chat and voice. Since Matrix is real-time, favor the privacy-tier region closest to your core users; unmetered bandwidth and included DDoS protection matter because a federated, internet-facing homeserver is a standing target.

Lock it down

Hardening checklist

  • Disable open registration: set enable_registration: false, or gate signups behind registration_requires_token with per-invite tokens — an open Matrix server is found and flooded by spam bots within days.
  • Federation control: use /.well-known/matrix/server delegation so your server_name stays clean (@user:example.com), and if the server is private set federation_domain_whitelist (or disable federation entirely) to stop unknown servers from reaching you.
  • Lock down URL previews and media: url_preview_enabled pulls arbitrary URLs server-side (SSRF risk) — keep the default url_preview_ip_range_blacklist for private ranges, cap max_upload_size, and run periodic media retention/purge because media storage grows without bound.
  • Tighten rate limits behind the proxy: set x_forwarded: true on the 8008 listener so Synapse sees real client IPs, then tune rc_login, rc_registration, and rc_message to blunt brute-force and abuse; ChainVPS DDoS protection covers the L3/4 layer beneath this.
  • Back up Postgres and the signing key: dump the DB regularly and copy synapse-data/*.signing.key offsite — losing the signing key means your server identity and all federation trust are permanently gone.
  • Keep it patched: pin and regularly bump the ghcr.io/element-hq/synapse tag, keep report_stats: no, and never publish port 8008 or 5432 to the internet — only 443 (and optionally 8448) should be reachable.

Questions

Hosting Matrix (Synapse) — FAQ

Do I need my own domain?

Yes. Matrix user IDs and federation are tied to a domain (e.g. @you:example.com). You need a domain with DNS you control to point at the VPS and to serve the /.well-known federation records. The domain can be registered through a privacy-respecting registrar; the server itself stays no-KYC.

Can I run Synapse fully private, with no federation?

Yes. Set a federation_domain_whitelist that is empty or omit the federation listener so your homeserver never talks to the public Matrix network. Your users still get full end-to-end-encrypted chat, voice, and video among themselves, entirely on your offshore server.

Why PostgreSQL instead of the default SQLite?

Synapse ships with SQLite for quick testing only. It does not handle concurrency or federation load and cannot be scaled with workers. Any real deployment must use PostgreSQL created with C locale (the compose file above does this for you); migrating later is painful, so start on Postgres.

How much RAM does Synapse really need?

More than people expect. A quiet single-user server fits in ~1.5-2 GB, but the moment you join large federated rooms, per-room caches balloon memory. Budget 4 GB for a small community and scale caches (caches: global_factor) to your RAM rather than letting them grow unmanaged.

Which client do my users install?

Element (web, desktop, iOS, Android) is the standard Matrix client and connects to your homeserver by entering its URL. The /.well-known/matrix/client record you serve on 443 lets Element auto-discover your server from just a user's Matrix ID.

Will hosting offshore hurt federation or call quality?

No. Federation works over standard HTTPS regardless of location, and included DDoS protection keeps the public-facing server stable. For real-time voice/video, choose the privacy-tier location closest to your users to minimize latency; Netherlands and Luxembourg are well-peered for European traffic.

Spin up Matrix (Synapse)
in the next 60 seconds.

Unmetered bandwidth · DDoS included · 21 cryptocurrencies · no KYC.