A complete self-hosted Matrix server with WhatsApp, Telegram, Discord, and Signal bridges.
- Docker & Docker Compose
- Domain name with DNS configured
- Ports 80, 443, 8448 open
- Minimum 2GB RAM
mkdir -p /opt/synapse
cd /opt/synapse
docker network create mautrixCreate docker-compose.yml:
services:
synapse:
image: docker.io/matrixdotorg/synapse:latest
restart: unless-stopped
volumes:
- ./synapse-data:/data
depends_on:
- db
ports:
- '127.0.0.1:8008:8008/tcp'
db:
image: docker.io/postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_USER: synapse_user
POSTGRES_PASSWORD: your_secure_password
POSTGRES_DB: postgres
POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
volumes:
- ./postgres-data:/var/lib/postgresql/data
mautrix-whatsapp:
image: dock.mau.dev/mautrix/whatsapp:latest
container_name: mautrix-whatsapp
restart: unless-stopped
depends_on:
- db
- synapse
volumes:
- ./mautrix-whatsapp:/data
mautrix-telegram:
image: dock.mau.dev/mautrix/telegram:latest
container_name: mautrix-telegram
restart: unless-stopped
depends_on:
- db
- synapse
volumes:
- ./mautrix-telegram:/data
ports:
- 29317:29317
mautrix-discord:
image: dock.mau.dev/mautrix/discord:latest
container_name: mautrix-discord
restart: unless-stopped
depends_on:
- db
- synapse
volumes:
- ./mautrix-discord:/data
ports:
- 29334:29334
mautrix-signal:
image: dock.mau.dev/mautrix/signal:latest
container_name: mautrix-signal
restart: unless-stopped
depends_on:
- db
- synapse
- signald
volumes:
- ./mautrix-signal:/data
ports:
- 29328:29328
signald:
image: docker.io/signald/signald:latest
container_name: signald
restart: unless-stopped
volumes:
- ./signald:/signald
networks:
default:
name: mautrix
external: truedocker run -it --rm \
-v ./synapse-data:/data \
-e SYNAPSE_SERVER_NAME=yourdomain.com \
-e SYNAPSE_REPORT_STATS=no \
matrixdotorg/synapse:latest generateEdit synapse-data/homeserver.yaml:
database:
name: psycopg2
args:
user: synapse_user
password: your_secure_password
database: synapse
host: db
cp_min: 5
cp_max: 10Start PostgreSQL first:
docker compose up -d db
sleep 10
docker exec -it synapse-db-1 psql -U synapse_user -d postgres <<EOF
CREATE DATABASE synapse ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse_user;
CREATE DATABASE whatsapp ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse_user;
CREATE DATABASE telegram ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse_user;
CREATE DATABASE discord ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse_user;
CREATE DATABASE signal ENCODING 'UTF8' LC_COLLATE='C' LC_CTYPE='C' template=template0 OWNER synapse_user;
\q
EOFdocker compose up -d synapsedocker exec -it synapse-synapse-1 register_new_matrix_user \
http://localhost:8008 -c /data/homeserver.yamlInstall Nginx and Certbot:
apt update
apt install nginx certbot python3-certbot-nginx -yCreate /etc/nginx/sites-available/matrix:
server {
listen 80;
server_name yourdomain.com;
location / {
return 200 "OK";
}
}Enable and get SSL certificate:
ln -s /etc/nginx/sites-available/matrix /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx
# Get SSL certificate
certbot --nginx -d yourdomain.comCreate final Nginx configuration at /etc/nginx/sites-available/matrix:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location /.well-known/matrix/server {
return 200 '{"m.server": "yourdomain.com:8448"}';
default_type application/json;
add_header Access-Control-Allow-Origin *;
}
location /.well-known/matrix/client {
return 200 '{"m.homeserver": {"base_url": "https://yourdomain.com"}}';
default_type application/json;
add_header Access-Control-Allow-Origin *;
}
location /_matrix {
proxy_pass http://127.0.0.1:8008;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
client_max_body_size 50M;
}
}
server {
listen 8448 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location /_matrix {
proxy_pass http://127.0.0.1:8008;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 50M;
}
}Test and reload:
nginx -t
systemctl reload nginxTest your Matrix server:
curl https://yourdomain.com/_matrix/client/versionsYou should see a JSON response with Matrix versions.
# Generate config
docker run --rm --network=mautrix -v $PWD/mautrix-whatsapp:/data:z \
dock.mau.dev/mautrix/whatsapp:latest
# Edit config
nano mautrix-whatsapp/config.yamlRequired changes:
homeserver:
address: https://yourdomain.com
domain: yourdomain.com
appservice:
address: http://mautrix-whatsapp:29318
hostname: 0.0.0.0
port: 29318
database:
type: postgres
uri: postgres://synapse_user:your_secure_password@db/whatsapp?sslmode=disable
bridge:
permissions:
"*": relay
"yourdomain.com": user
"@admin:yourdomain.com": adminGenerate registration and add to Synapse:
docker run --rm --network=mautrix -v $PWD/mautrix-whatsapp:/data:z \
dock.mau.dev/mautrix/whatsapp:latest
cp mautrix-whatsapp/registration.yaml synapse-data/whatsapp-registration.yaml
chown 991:991 synapse-data/whatsapp-registration.yaml
# Add to synapse-data/homeserver.yaml:
echo "app_service_config_files:" >> synapse-data/homeserver.yaml
echo " - /data/whatsapp-registration.yaml" >> synapse-data/homeserver.yaml
docker restart synapse-synapse-1
docker compose up -d mautrix-whatsappGet API credentials from https://my.telegram.org/apps
docker run --rm --network=mautrix -v $PWD/mautrix-telegram:/data:z \
dock.mau.dev/mautrix/telegram:latest
nano mautrix-telegram/config.yamlRequired changes:
homeserver:
address: https://yourdomain.com
domain: yourdomain.com
appservice:
address: http://mautrix-telegram:29317
hostname: 0.0.0.0
port: 29317
database:
type: postgres
uri: postgres://synapse_user:your_secure_password@db/telegram?sslmode=disable
telegram:
api_id: YOUR_API_ID
api_hash: YOUR_API_HASH
bridge:
permissions:
"*": relaybot
"yourdomain.com": user
"@admin:yourdomain.com": adminFinalize:
docker run --rm --network=mautrix -v $PWD/mautrix-telegram:/data:z \
dock.mau.dev/mautrix/telegram:latest
cp mautrix-telegram/registration.yaml synapse-data/telegram-registration.yaml
chown 991:991 synapse-data/telegram-registration.yaml
# Add to homeserver.yaml
nano synapse-data/homeserver.yaml
# Add: - /data/telegram-registration.yaml
docker restart synapse-synapse-1
docker compose up -d mautrix-telegramdocker run --rm --network=mautrix -v $PWD/mautrix-discord:/data:z \
dock.mau.dev/mautrix/discord:latest
nano mautrix-discord/config.yamlRequired changes:
homeserver:
address: https://yourdomain.com
domain: yourdomain.com
appservice:
address: http://mautrix-discord:29334
hostname: 0.0.0.0
port: 29334
database:
type: postgres
uri: postgres://synapse_user:your_secure_password@db/discord?sslmode=disable
bridge:
permissions:
"*": relay
"yourdomain.com": user
"@admin:yourdomain.com": adminFinalize:
docker run --rm --network=mautrix -v $PWD/mautrix-discord:/data:z \
dock.mau.dev/mautrix/discord:latest
cp mautrix-discord/registration.yaml synapse-data/discord-registration.yaml
chown 991:991 synapse-data/discord-registration.yaml
# Add to homeserver.yaml
nano synapse-data/homeserver.yaml
# Add: - /data/discord-registration.yaml
docker restart synapse-synapse-1
docker compose up -d mautrix-discord- Message
@whatsappbot:yourdomain.com - Send:
login - Scan QR code with WhatsApp
- Message
@telegrambot:yourdomain.com - Send:
login - Enter phone number and verification code
- Message
@discordbot:yourdomain.com - Send:
login-qr - Scan QR code with Discord mobile
- Message
@signalbot:yourdomain.com - Send:
link - Scan QR code with Signal
