Element + Matrix Homeserver
Decentralized communication with Matrix Synapse and Element web client.
Overview
Matrix Synapse is the reference implementation of the Matrix protocol, an open standard for secure, decentralized real-time communication. Developed by the Matrix.org Foundation, Synapse serves as a homeserver that enables federation with other Matrix servers worldwide, creating a distributed network where users maintain control over their data while communicating across server boundaries. This architecture eliminates single points of failure and vendor lock-in common in centralized messaging platforms.
This stack combines Synapse with Element Web (formerly Riot), the flagship Matrix client that provides a modern web interface for messaging, voice, and video calls. PostgreSQL serves as the primary database for storing room state, user data, and message history with ACID compliance ensuring data integrity during concurrent operations. Redis handles session caching and worker coordination for horizontal scaling, while Coturn provides TURN/STUN services essential for voice and video calls behind NAT firewalls. Nginx acts as a reverse proxy, handling SSL termination and routing federation traffic.
Organizations seeking to deploy private, self-hosted communication infrastructure will find this stack particularly valuable. Unlike centralized services, Matrix federation allows internal users to communicate with external Matrix servers while maintaining control over sensitive data. The combination of Synapse's robust server implementation with Element's polished interface creates a production-ready alternative to platforms like Slack or Microsoft Teams, with the added benefit of end-to-end encryption by default and compliance with data sovereignty requirements.
Key Features
- Matrix protocol federation enabling communication across different homeservers
- End-to-end encryption for messages, voice calls, and video calls using Olm/Megolm cryptographic ratchets
- PostgreSQL backend with optimized schema for Matrix's directed acyclic graph room structure
- Redis-powered worker mode supporting horizontal scaling across multiple Synapse processes
- Coturn TURN/STUN server for WebRTC voice and video calls through NAT firewalls
- Element Web client with real-time synchronization, message threading, and rich media support
- Server-side room directory and user discovery with configurable federation policies
- Application service integration allowing bridges to IRC, Discord, Telegram, and other platforms
Common Use Cases
- 1Enterprise internal communication with end-to-end encryption compliance requirements
- 2Educational institutions requiring FERPA-compliant messaging with external collaboration
- 3Healthcare organizations needing HIPAA-compliant communication infrastructure
- 4Government agencies requiring sovereign control over communication data
- 5Open source projects wanting community chat with IRC/Discord bridge integration
- 6Privacy-focused organizations migrating from centralized platforms like Slack or Teams
- 7International companies needing federated communication across regional data boundaries
Prerequisites
- Minimum 2GB RAM (PostgreSQL requires 1GB+, Synapse 512MB+ for small deployments)
- Valid domain name with DNS control for Matrix federation on port 8448
- SSL certificate authority access or Let's Encrypt compatibility for HTTPS
- Understanding of Matrix protocol concepts including homeservers, rooms, and federation
- Network firewall configuration allowing ports 80, 443, 8448, and 3478-5349 range
- Basic knowledge of reverse proxy configuration for Element Web and Synapse integration
For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms
docker-compose.yml
docker-compose.yml
1services: 2 postgres: 3 image: postgres:15-alpine4 environment: 5 - POSTGRES_USER=synapse6 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}7 - POSTGRES_DB=synapse8 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C9 volumes: 10 - postgres_data:/var/lib/postgresql/data11 networks: 12 - matrix_net1314 redis: 15 image: redis:7-alpine16 volumes: 17 - redis_data:/data18 networks: 19 - matrix_net2021 synapse: 22 image: matrixdotorg/synapse:latest23 environment: 24 - SYNAPSE_SERVER_NAME=localhost25 - SYNAPSE_REPORT_STATS=no26 volumes: 27 - synapse_data:/data28 depends_on: 29 - postgres30 - redis31 ports: 32 - "8008:8008"33 - "8448:8448"34 networks: 35 - matrix_net3637 element-web: 38 image: vectorim/element-web:latest39 ports: 40 - "8080:80"41 volumes: 42 - ./element-config.json:/app/config.json:ro43 depends_on: 44 - synapse45 networks: 46 - matrix_net4748 coturn: 49 image: coturn/coturn:latest50 ports: 51 - "3478:3478"52 - "3478:3478/udp"53 - "5349:5349"54 - "5349:5349/udp"55 environment: 56 - TURN_REALM=localhost57 - TURN_SECRET=${TURN_SECRET}58 networks: 59 - matrix_net6061 nginx: 62 image: nginx:alpine63 ports: 64 - "80:80"65 - "443:443"66 volumes: 67 - ./nginx.conf:/etc/nginx/nginx.conf:ro68 depends_on: 69 - synapse70 - element-web71 networks: 72 - matrix_net7374volumes: 75 postgres_data: 76 redis_data: 77 synapse_data: 7879networks: 80 matrix_net: .env Template
.env
1# Matrix/Element2POSTGRES_PASSWORD=secure_postgres_password3TURN_SECRET=secure_turn_secret45# Element at http://localhost:80806# Synapse API at http://localhost:8008Usage Notes
- 1Element at http://localhost:8080
- 2Synapse at http://localhost:8008
- 3Federation via port 8448
- 4TURN for voice/video
- 5Decentralized and private
Individual Services(6 services)
Copy individual services to mix and match with your existing compose files.
postgres
postgres:
image: postgres:15-alpine
environment:
- POSTGRES_USER=synapse
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=synapse
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- matrix_net
redis
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- matrix_net
synapse
synapse:
image: matrixdotorg/synapse:latest
environment:
- SYNAPSE_SERVER_NAME=localhost
- SYNAPSE_REPORT_STATS=no
volumes:
- synapse_data:/data
depends_on:
- postgres
- redis
ports:
- "8008:8008"
- "8448:8448"
networks:
- matrix_net
element-web
element-web:
image: vectorim/element-web:latest
ports:
- "8080:80"
volumes:
- ./element-config.json:/app/config.json:ro
depends_on:
- synapse
networks:
- matrix_net
coturn
coturn:
image: coturn/coturn:latest
ports:
- "3478:3478"
- 3478:3478/udp
- "5349:5349"
- 5349:5349/udp
environment:
- TURN_REALM=localhost
- TURN_SECRET=${TURN_SECRET}
networks:
- matrix_net
nginx
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- synapse
- element-web
networks:
- matrix_net
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 postgres:5 image: postgres:15-alpine6 environment:7 - POSTGRES_USER=synapse8 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}9 - POSTGRES_DB=synapse10 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C11 volumes:12 - postgres_data:/var/lib/postgresql/data13 networks:14 - matrix_net1516 redis:17 image: redis:7-alpine18 volumes:19 - redis_data:/data20 networks:21 - matrix_net2223 synapse:24 image: matrixdotorg/synapse:latest25 environment:26 - SYNAPSE_SERVER_NAME=localhost27 - SYNAPSE_REPORT_STATS=no28 volumes:29 - synapse_data:/data30 depends_on:31 - postgres32 - redis33 ports:34 - "8008:8008"35 - "8448:8448"36 networks:37 - matrix_net3839 element-web:40 image: vectorim/element-web:latest41 ports:42 - "8080:80"43 volumes:44 - ./element-config.json:/app/config.json:ro45 depends_on:46 - synapse47 networks:48 - matrix_net4950 coturn:51 image: coturn/coturn:latest52 ports:53 - "3478:3478"54 - "3478:3478/udp"55 - "5349:5349"56 - "5349:5349/udp"57 environment:58 - TURN_REALM=localhost59 - TURN_SECRET=${TURN_SECRET}60 networks:61 - matrix_net6263 nginx:64 image: nginx:alpine65 ports:66 - "80:80"67 - "443:443"68 volumes:69 - ./nginx.conf:/etc/nginx/nginx.conf:ro70 depends_on:71 - synapse72 - element-web73 networks:74 - matrix_net7576volumes:77 postgres_data:78 redis_data:79 synapse_data:8081networks:82 matrix_net:83EOF8485# 2. Create the .env file86cat > .env << 'EOF'87# Matrix/Element88POSTGRES_PASSWORD=secure_postgres_password89TURN_SECRET=secure_turn_secret9091# Element at http://localhost:808092# Synapse API at http://localhost:800893EOF9495# 3. Start the services96docker compose up -d9798# 4. View logs99docker compose logs -fOne-Liner
Run this command to download and set up the recipe in one step:
terminal
1curl -fsSL https://docker.recipes/api/recipes/element-matrix-complete/run | bashTroubleshooting
- Federation not working: Verify port 8448 is accessible externally and SSL certificate covers your domain's Matrix subdomain
- Voice/video calls failing: Check that Coturn ports 3478, 5349, and configured port range are open in firewall for UDP traffic
- Database connection errors: Ensure PostgreSQL locale settings match Synapse requirements (UTF-8, C collation) and user has proper permissions
- Element showing 'Failed to start' error: Verify config.json contains correct homeserver URL and base_url matches your domain
- High memory usage in PostgreSQL: Tune shared_buffers and effective_cache_size based on available RAM, consider vacuuming large rooms
- Synapse workers not distributing load: Check Redis connectivity and ensure worker configuration file properly defines worker types and ports
Community Notes
Loading...
Loading notes...
Download Recipe Kit
Get all files in a ready-to-deploy package
Includes docker-compose.yml, .env template, README, and license
Components
synapseelement-webpostgresqlrediscoturn
Tags
#matrix#element#chat#decentralized#federation
Category
Message Queues & BrokersAd Space
Shortcuts: C CopyF FavoriteD Download