docker.recipes

Matrix Synapse + PostgreSQL + Element

advanced

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:latest
4 environment:
5 - SYNAPSE_CONFIG_DIR=/data
6 - SYNAPSE_DATA_DIR=/data
7 - SYNAPSE_SERVER_NAME=${SERVER_NAME}
8 - SYNAPSE_REPORT_STATS=no
9 volumes:
10 - synapse-data:/data
11 ports:
12 - "8008:8008"
13 depends_on:
14 - postgres
15 networks:
16 - matrix-network
17 restart: unless-stopped
18
19 postgres:
20 image: postgres:15
21 environment:
22 - POSTGRES_USER=synapse
23 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
24 - POSTGRES_DB=synapse
25 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
26 volumes:
27 - postgres-data:/var/lib/postgresql/data
28 networks:
29 - matrix-network
30 restart: unless-stopped
31
32 element:
33 image: vectorim/element-web:latest
34 volumes:
35 - ./element-config.json:/app/config.json:ro
36 ports:
37 - "80:80"
38 depends_on:
39 - synapse
40 networks:
41 - matrix-network
42 restart: unless-stopped
43
44 coturn:
45 image: coturn/coturn:latest
46 environment:
47 - DETECT_EXTERNAL_IP=yes
48 - DETECT_RELAY_IP=yes
49 volumes:
50 - ./turnserver.conf:/etc/coturn/turnserver.conf:ro
51 ports:
52 - "3478:3478/tcp"
53 - "3478:3478/udp"
54 - "5349:5349/tcp"
55 - "5349:5349/udp"
56 networks:
57 - matrix-network
58 restart: unless-stopped
59
60 nginx:
61 image: nginx:alpine
62 volumes:
63 - ./nginx.conf:/etc/nginx/nginx.conf:ro
64 ports:
65 - "443:443"
66 - "8448:8448"
67 depends_on:
68 - synapse
69 - element
70 networks:
71 - matrix-network
72 restart: unless-stopped
73
74volumes:
75 synapse-data:
76 postgres-data:
77
78networks:
79 matrix-network:
80 driver: bridge

.env Template

.env
1# Matrix Synapse
2SERVER_NAME=localhost
3POSTGRES_PASSWORD=secure_postgres_password
4
5# Generate config first:
6# docker run --rm -v synapse-data:/data -e SYNAPSE_SERVER_NAME=localhost matrixdotorg/synapse:latest generate

Usage Notes

  1. 1Element at http://localhost
  2. 2Synapse at http://localhost:8008
  3. 3Federation on port 8448
  4. 4Generate config before first run
  5. 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 file
2cat > docker-compose.yml << 'EOF'
3services:
4 synapse:
5 image: matrixdotorg/synapse:latest
6 environment:
7 - SYNAPSE_CONFIG_DIR=/data
8 - SYNAPSE_DATA_DIR=/data
9 - SYNAPSE_SERVER_NAME=${SERVER_NAME}
10 - SYNAPSE_REPORT_STATS=no
11 volumes:
12 - synapse-data:/data
13 ports:
14 - "8008:8008"
15 depends_on:
16 - postgres
17 networks:
18 - matrix-network
19 restart: unless-stopped
20
21 postgres:
22 image: postgres:15
23 environment:
24 - POSTGRES_USER=synapse
25 - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
26 - POSTGRES_DB=synapse
27 - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
28 volumes:
29 - postgres-data:/var/lib/postgresql/data
30 networks:
31 - matrix-network
32 restart: unless-stopped
33
34 element:
35 image: vectorim/element-web:latest
36 volumes:
37 - ./element-config.json:/app/config.json:ro
38 ports:
39 - "80:80"
40 depends_on:
41 - synapse
42 networks:
43 - matrix-network
44 restart: unless-stopped
45
46 coturn:
47 image: coturn/coturn:latest
48 environment:
49 - DETECT_EXTERNAL_IP=yes
50 - DETECT_RELAY_IP=yes
51 volumes:
52 - ./turnserver.conf:/etc/coturn/turnserver.conf:ro
53 ports:
54 - "3478:3478/tcp"
55 - "3478:3478/udp"
56 - "5349:5349/tcp"
57 - "5349:5349/udp"
58 networks:
59 - matrix-network
60 restart: unless-stopped
61
62 nginx:
63 image: nginx:alpine
64 volumes:
65 - ./nginx.conf:/etc/nginx/nginx.conf:ro
66 ports:
67 - "443:443"
68 - "8448:8448"
69 depends_on:
70 - synapse
71 - element
72 networks:
73 - matrix-network
74 restart: unless-stopped
75
76volumes:
77 synapse-data:
78 postgres-data:
79
80networks:
81 matrix-network:
82 driver: bridge
83EOF
84
85# 2. Create the .env file
86cat > .env << 'EOF'
87# Matrix Synapse
88SERVER_NAME=localhost
89POSTGRES_PASSWORD=secure_postgres_password
90
91# Generate config first:
92# docker run --rm -v synapse-data:/data -e SYNAPSE_SERVER_NAME=localhost matrixdotorg/synapse:latest generate
93EOF
94
95# 3. Start the services
96docker compose up -d
97
98# 4. View logs
99docker compose logs -f

One-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 | bash

Troubleshooting

  • 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

Ad Space