Matrix Synapse + PostgreSQL + Element
Federated messaging with Element web client.
Overview
Matrix Synapse is an open-source reference implementation of the Matrix protocol, a decentralized communication standard that enables federated messaging, voice, and video calls across different servers and clients. Developed by the Matrix.org Foundation, Synapse serves as a homeserver that stores user accounts, room data, and message history while facilitating federation with other Matrix servers worldwide. This creates a truly distributed communication network where users can communicate across organizational boundaries without relying on centralized platforms. This comprehensive stack combines Synapse with PostgreSQL for robust data persistence, Element Web as a modern React-based client interface, NGINX for SSL termination and federation proxy, and Coturn for NAT traversal in voice/video calls. PostgreSQL provides ACID-compliant storage for Matrix's complex relational data including user accounts, room memberships, message threading, and encryption keys, while Element Web offers end-to-end encryption, file sharing, voice/video calling, and rich media support through a familiar chat interface. Organizations seeking communication sovereignty will find this stack invaluable for maintaining control over their messaging infrastructure while participating in the broader Matrix federation. The combination supports everything from small team chat to large-scale enterprise communication, with built-in encryption ensuring privacy and the federation capability enabling secure communication with external Matrix servers, making it ideal for privacy-conscious organizations, educational institutions, and government agencies requiring auditable, self-hosted communication solutions.
Key Features
- End-to-end encryption for all messages, files, and voice/video calls using Matrix's Olm and Megolm cryptographic protocols
- Federation support allowing communication with users on other Matrix homeservers across the internet
- PostgreSQL backend with optimized schemas for Matrix's event-sourced architecture and efficient message retrieval
- Element Web client with support for threads, spaces, reactions, file sharing, and screen sharing
- TURN/STUN server via Coturn for reliable voice and video calls behind NAT and firewalls
- Admin API for user management, room administration, and server statistics through Synapse's REST endpoints
- Presence and typing indicators with configurable federation policies for privacy control
- Room aliases and directory services for easy room discovery and memorable addresses
Common Use Cases
- 1Enterprise internal communication requiring data sovereignty and compliance with regulations like GDPR or HIPAA
- 2Educational institutions needing secure student-faculty communication with administrative oversight capabilities
- 3Open source projects requiring persistent chat history and integration with development workflows
- 4Healthcare organizations needing encrypted messaging that maintains audit trails for patient communication
- 5Government agencies requiring secure inter-departmental communication with controlled external federation
- 6Remote teams needing voice/video calling with message persistence across different time zones
- 7Community servers for gaming guilds, hobby groups, or local organizations with custom moderation policies
Prerequisites
- Minimum 2GB RAM for the full stack, with 4GB+ recommended for active usage and message history retention
- Domain name with DNS control for federation setup and SSL certificate management
- Ports 80, 443, 8448, 3478, and 5349 available and properly forwarded for web access, federation, and TURN services
- Basic understanding of Matrix concepts including homeservers, federation, and room structures
- SSL certificates configured in NGINX for HTTPS termination and Matrix federation over port 8448
- Understanding of PostgreSQL backup procedures for message history and user data preservation
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 synapse: 3 image: matrixdotorg/synapse:latest4 environment: 5 - SYNAPSE_CONFIG_DIR=/data6 - SYNAPSE_DATA_DIR=/data7 - SYNAPSE_SERVER_NAME=${SERVER_NAME}8 - SYNAPSE_REPORT_STATS=no9 volumes: 10 - synapse-data:/data11 ports: 12 - "8008:8008"13 depends_on: 14 - postgres15 networks: 16 - matrix-network17 restart: unless-stopped1819 postgres: 20 image: postgres:1521 environment: 22 - POSTGRES_USER=synapse23 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}24 - POSTGRES_DB=synapse25 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C26 volumes: 27 - postgres-data:/var/lib/postgresql/data28 networks: 29 - matrix-network30 restart: unless-stopped3132 element: 33 image: vectorim/element-web:latest34 volumes: 35 - ./element-config.json:/app/config.json:ro36 ports: 37 - "80:80"38 depends_on: 39 - synapse40 networks: 41 - matrix-network42 restart: unless-stopped4344 coturn: 45 image: coturn/coturn:latest46 environment: 47 - DETECT_EXTERNAL_IP=yes48 - DETECT_RELAY_IP=yes49 volumes: 50 - ./turnserver.conf:/etc/coturn/turnserver.conf:ro51 ports: 52 - "3478:3478/tcp"53 - "3478:3478/udp"54 - "5349:5349/tcp"55 - "5349:5349/udp"56 networks: 57 - matrix-network58 restart: unless-stopped5960 nginx: 61 image: nginx:alpine62 volumes: 63 - ./nginx.conf:/etc/nginx/nginx.conf:ro64 ports: 65 - "443:443"66 - "8448:8448"67 depends_on: 68 - synapse69 - element70 networks: 71 - matrix-network72 restart: unless-stopped7374volumes: 75 synapse-data: 76 postgres-data: 7778networks: 79 matrix-network: 80 driver: bridge.env Template
.env
1# Matrix Synapse2SERVER_NAME=localhost3POSTGRES_PASSWORD=secure_postgres_password45# Generate config first:6# docker run --rm -v synapse-data:/data -e SYNAPSE_SERVER_NAME=localhost matrixdotorg/synapse:latest generateUsage Notes
- 1Element at http://localhost
- 2Synapse at http://localhost:8008
- 3Federation on port 8448
- 4Generate config before first run
- 5COTURN for voice/video calls
Individual Services(5 services)
Copy individual services to mix and match with your existing compose files.
synapse
synapse:
image: matrixdotorg/synapse:latest
environment:
- SYNAPSE_CONFIG_DIR=/data
- SYNAPSE_DATA_DIR=/data
- SYNAPSE_SERVER_NAME=${SERVER_NAME}
- SYNAPSE_REPORT_STATS=no
volumes:
- synapse-data:/data
ports:
- "8008:8008"
depends_on:
- postgres
networks:
- matrix-network
restart: unless-stopped
postgres
postgres:
image: postgres:15
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-network
restart: unless-stopped
element
element:
image: vectorim/element-web:latest
volumes:
- ./element-config.json:/app/config.json:ro
ports:
- "80:80"
depends_on:
- synapse
networks:
- matrix-network
restart: unless-stopped
coturn
coturn:
image: coturn/coturn:latest
environment:
- DETECT_EXTERNAL_IP=yes
- DETECT_RELAY_IP=yes
volumes:
- ./turnserver.conf:/etc/coturn/turnserver.conf:ro
ports:
- 3478:3478/tcp
- 3478:3478/udp
- 5349:5349/tcp
- 5349:5349/udp
networks:
- matrix-network
restart: unless-stopped
nginx
nginx:
image: nginx:alpine
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "443:443"
- "8448:8448"
depends_on:
- synapse
- element
networks:
- matrix-network
restart: unless-stopped
Quick Start
terminal
1# 1. Create the compose file2cat > docker-compose.yml << 'EOF'3services:4 synapse:5 image: matrixdotorg/synapse:latest6 environment:7 - SYNAPSE_CONFIG_DIR=/data8 - SYNAPSE_DATA_DIR=/data9 - SYNAPSE_SERVER_NAME=${SERVER_NAME}10 - SYNAPSE_REPORT_STATS=no11 volumes:12 - synapse-data:/data13 ports:14 - "8008:8008"15 depends_on:16 - postgres17 networks:18 - matrix-network19 restart: unless-stopped2021 postgres:22 image: postgres:1523 environment:24 - POSTGRES_USER=synapse25 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}26 - POSTGRES_DB=synapse27 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C28 volumes:29 - postgres-data:/var/lib/postgresql/data30 networks:31 - matrix-network32 restart: unless-stopped3334 element:35 image: vectorim/element-web:latest36 volumes:37 - ./element-config.json:/app/config.json:ro38 ports:39 - "80:80"40 depends_on:41 - synapse42 networks:43 - matrix-network44 restart: unless-stopped4546 coturn:47 image: coturn/coturn:latest48 environment:49 - DETECT_EXTERNAL_IP=yes50 - DETECT_RELAY_IP=yes51 volumes:52 - ./turnserver.conf:/etc/coturn/turnserver.conf:ro53 ports:54 - "3478:3478/tcp"55 - "3478:3478/udp"56 - "5349:5349/tcp"57 - "5349:5349/udp"58 networks:59 - matrix-network60 restart: unless-stopped6162 nginx:63 image: nginx:alpine64 volumes:65 - ./nginx.conf:/etc/nginx/nginx.conf:ro66 ports:67 - "443:443"68 - "8448:8448"69 depends_on:70 - synapse71 - element72 networks:73 - matrix-network74 restart: unless-stopped7576volumes:77 synapse-data:78 postgres-data:7980networks:81 matrix-network:82 driver: bridge83EOF8485# 2. Create the .env file86cat > .env << 'EOF'87# Matrix Synapse88SERVER_NAME=localhost89POSTGRES_PASSWORD=secure_postgres_password9091# Generate config first:92# docker run --rm -v synapse-data:/data -e SYNAPSE_SERVER_NAME=localhost matrixdotorg/synapse:latest generate93EOF9495# 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/matrix-synapse-complete/run | bashTroubleshooting
- Federation not working with other servers: Verify port 8448 is accessible externally and SSL certificates are valid for the server name
- Element shows 'Unable to connect to homeserver': Check that NGINX is properly proxying to Synapse on port 8008 and CORS headers are configured
- Voice/video calls failing to connect: Ensure Coturn is accessible on ports 3478/5349 and external IP detection is working correctly
- Database connection errors on startup: Verify PostgreSQL is fully initialized before Synapse starts, may need to add health checks or startup delays
- High memory usage in Synapse: Configure message retention policies and enable message history purging in homeserver.yaml
- Users unable to join federated rooms: Check that your server's signing keys are published correctly and DNS SRV records are configured for federation
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
synapsepostgresqlelement-webnginxcoturn
Tags
#matrix#synapse#element#federation#e2ee
Category
Message Queues & BrokersAd Space
Shortcuts: C CopyF FavoriteD Download