کانفیگ دم دستی خودمیزبانی ماتریکس + المنت

هدف از این پست بی‌ربط به موضوع بلاگ، اشتراک‌گذاری کانفیگیه که خودم برای خودمیزبانی (سلف‌هاست) ماتریکس یا دقیق‌تر بگم Synapse استفاده کردم. که می‌تونه تو این شرایط کمک کنه تا ارتباطات داخلی و بعضا بین‌المللی حفظ بشه.

پیش‌نیاز‌ها و نکات

  • یه دامنه به ترجیح خودتون - به دلیل نیاز به احراز هویت ir. رو توصیه نمی‌کنم.
  • برای میزبانی از تعداد کاربر کم تا حدود ۵۰ نفر یه سرور با مموری ۱ گیگ هم جواب میده به خصوص اگه نخواید تماس رو خودتون میزبانی کنید. در غیر این صورت مموری ۲ گیگ نقطه امن‌تریه.
  • ترجیحا از دبیان استفاده کنید چون میرورهایی هم داخل ایران داره که وقتی نت محدوده به کار میاد.
  • یه وب‌سرور مثل Nginx برای ریورس پروکسی کردن نصب کنید.
  • اگه می‌خواید فدریشن (ارتباط با بقیه سرور‌های ماتریکس) برقرار باشه، که اکیدا پیشنهاد می‌کنمش، ssl رو راه‌اندازی کنید. برای این کار می‌تونید certbot رو دانلود و اجرا کنید.
  • داکر رو نصب کنید.
  • اگه سرور دسترسی به نت آزاد و داکرهاب داره که هیچ، اگر نه، یا از میرور‌های داخلی استفاده کنید یا ایمیج‌های داکر رو روی یه دستگاه دیگه بگیرید و با دستور docker save {image_name} > image.tar سیو کنید و روی سرور آپلود کنید. ایمیج‌های ضروری synapse و postgres ئه و اگر تماس رو خودتون میزبانی می‌کنید به ایمیج‌های livekit و jwt هم نیاز دارید. در غیر این صورت تماسا از طریق سرور اصلی خود المنت انجام میشه.
  • تو این آموزش من نسخه وب المنت رو هاست نمی‌کنم. اگه بهش نیاز دارید به مستندات اصلی خودش مراجعه کنید که نکته خاصی هم نداره. در صورتی که این کارو کردید حتما از recaptcha استفاده کنید که البته وقتی نت داخلیه کار نمی‌کنه و به همین دلیل و دلایل واضح دیگه من کلا نسخه وب رو آوردم پایین.
  • من فرض می‌کنم می‌خوایم ماتریکس رو تو این مسیر اجرا کنیم و بهش میگم “فولدر ماتریکس”: /opt/matrix

کانفیگ کامپوز

version: '3'

services:
  pg:
    image: "postgres:14"
    restart: always
    volumes:
      - ./pg-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=synapse
      - POSTGRES_USER=matrix
      - POSTGRES_PASSWORD={DB_PASSWORD}
      - POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
    networks:
      - matrix-network

  synapse:
    image: docker.io/matrixdotorg/synapse:latest
    restart: always
    ports:
      - "8008:8008"
    volumes:
      - ./synapse-data/_data:/data
    environment:
      - SYNAPSE_SERVER_NAME={SERVER_ADDRESS}
      - SYNAPSE_REPORT_STATS="no"
    depends_on:
      - pg
    networks:
      - matrix-network
      
  livekit:
    image: livekit/livekit-server:latest
    command: --config /etc/livekit.yaml
    restart: always
    volumes:
      - ./synapse-data/livekit-config/livekit.yaml:/etc/livekit.yaml:ro
    ports:
      - 7880:7880/tcp
      - 7881:7881/tcp
      - 50100-50200:50100-50200/udp
    networks:
      - matrix-network
     
  jwt-service:
    image: ghcr.io/element-hq/lk-jwt-service:latest
    restart: always
    ports:
      - 58080:8080
    environment:
      - LK_JWT_PORT=8080
      - LIVEKIT_URL=https:/{SERVER_ADDRESS}/livekit/sfu
      - LIVEKIT_SECRET={LIVEKIT_SECRET}
      - LIVEKIT_KEY=mykey
      - LIVEKIT_LOCAL_HOMESERVERS={SERVER_ADDRESS}
      - LIVEKIT_FULL_ACCESS_HOMESERVERS={SERVER_ADDRESS}
    networks:
      - matrix-network

networks:
  matrix-network:
    name: matrix_network
  • فایل docker-compose.yml رو تو “فولدر ماتریکس” بسازید.
  • اگه نمی‌خواید تماس رو خودتون میزبانی کنید، کانفیگ مربوط به livekit و jwt-service رو حذف کنید.
  • این مقادیر رو توش عوض کنید: {DB_PASSWORD} - {SERVER_ADDRESS} که چند جا تکرار شده - {LIVEKIT_SECRET} در صورتی که داریدش. مقدار {SERVER_ADDRESS} باید جایی باشه که ماتریکس رو میزبانی می‌کنید. مثلا matrix.mywebsite.com.
  • یه فولدر به اسم synapse-data تو “فولدر ماتریکس” بسازید و توش یه فولدر برای یوزر 991 به اسم data_ بسازید. اگه تماس دارید تو فولدر ماتریکس یه فولدر به اسم livekit-config هم بسازید:

mkdir -p synapse-data/_data && sudo chown 991:991 synapse-data/_data mkdir synapse-data/livekit-config

کانفیگ homeserver

# Configuration file for Synapse.
#
# This is a YAML file: see [1] for a quick introduction. Note in particular
# that *indentation is important*: all the elements of a list or dictionary
# should have the same indentation.
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
#
# For more information on how to configure Synapse, including a complete accounting of
# each option, go to docs/usage/configuration/config_documentation.md or
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html
server_name: "{SERVER_ADDRESS}"
pid_file: /data/homeserver.pid
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false
#database:
#  name: sqlite3
#  args:
#    database: /data/homeserver.db
database:
  name: psycopg2
  args:
    user: matrix
    password: {DB_PASSWORD}
    database: synapse
    host: pg
    cp_min: 5
    cp_max: 10
log_config: "/data/{SERVER_ADDRESS}.log.config"
media_store_path: /data/media_store
max_upload_size: 200M
registration_shared_secret: "{REGISTRATION_SECRET}"
report_stats: false
macaroon_secret_key: "{MACAROON_SECRET}"
form_secret: "{FORM_SECRET}"
signing_key_path: "/data/{SERVER_ADDRESS}.signing.key"
trusted_key_servers:
  - server_name: "matrix.org"

enable_registration: false

## Captcha ##
# See docs/CAPTCHA_SETUP for full details of configuring this.

# This Home Server's ReCAPTCHA public key.
# recaptcha_public_key: "{RECAPTCHA_PUBLIC_KEY}"

# This Home Server's ReCAPTCHA private key.
# recaptcha_private_key: "{RECAPTCHA_PRIVATE_KEY}"

# Enables ReCaptcha checks when registering, preventing signup
# unless a captcha is answered. Requires a valid ReCaptcha
# public/private key.
# enable_registration_captcha: true

# A secret key used to bypass the captcha test entirely.
#captcha_bypass_secret: "YOUR_SECRET_HERE"

# The API endpoint to use for verifying m.login.recaptcha responses.
# recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"

# For legacy calls you need a Turn server like Coturn
# turn_uris: 
#  - "turn:{SERVER_ADDRESS}:3478?transport=udp"
#  - "turn:{SERVER_ADDRESS}:3478?transport=tcp"
#  - "turns:{SERVER_ADDRESS}:5349?transport=udp"
#  - "turns:{SERVER_ADDRESS}:5349?transport=tcp"

# turn_shared_secret: "{TURN_SECRET}"
# turn_user_lifetime: 86400000
# turn_allow_guests: true

# vim:ft=yaml

experimental_features:
  # MSC3266: Room summary API. Used for knocking over federation
  msc3266_enabled: true
  # MSC4222: needed for syncv2 state_after. This allows clients to
  # correctly track the state of the room.
  msc4222_enabled: true
  # MSC4140: Delayed events are required for proper call participation signalling. If disabled it is very likely that you end up with stuck calls in Matrix rooms
  msc4140_enabled: true

# The maximum allowed duration by which sent events can be delayed, as
# per MSC4140.
max_event_delay_duration: 24h

rc_message:
  # This needs to match at least e2ee key sharing frequency plus a bit of headroom
  # Note key sharing events are bursty
  per_second: 0.5
  burst_count: 30
  # This needs to match at least the heart-beat frequency plus a bit of headroom
  # Currently the heart-beat is every 5 seconds which translates into a rate of 0.2s
rc_delayed_event_mgmt:
  per_second: 1
  burst_count: 20

فایل synapse-data/_data/homeserver.yaml رو بسازید و تنظیمات مورد نظرتون رو مثل الگوی بالا ست کنید.

  • کانفیگای مربوط به turn واسه تماس قدیمیه که دیگه کنار گذاشته شده و من کامنتشون کردم. اگه به ارور خوردید از کامنت خارج کنید و مقادیرشو الکی ست کنید.
  • از تنظیمات experimental_features تا انتهای فایل homeserver من، کانفیگ تماسای جدیده (livekit) که اونا رو هم اگه تماس ندارید می‌تونید کامنت کنید.
  • اگه می‌خواید خودتون واسه کاربرا اکانت بسازید مثل من و سرورو پابلیک نکنید، تنظیمات recaptcha رو هم می‌تونید کامنت کنید و enable_registration رو false بذارید، در غیر این صورت باید حتما recaptcha ست کنید.
  • پس عملا تنظیمات مهم میشه از اول تا enable_registration تو فایل homeserver من.
  • هر مقداری که داخل {} گذاشتم رو با مقادیر خودتون پر کنید.
  • مقدار max_upload_size رو یادتون باشه هر چی گذاشتید بعدا تو nginx بهش نیاز داریم.

کانفیگ livekit (اگه تماس ندارید از روش رد شید)

port: 7880
bind_addresses:
  - "0.0.0.0"
rtc:
  tcp_port: 7881
  port_range_start: 50100
  port_range_end: 50200
  use_external_ip: false
room:
  auto_create: false
logging:
  level: info
turn:
  enabled: false
  domain: localhost
  cert_file: ""
  key_file: ""
  tls_port: 5349
  udp_port: 443
  external_tls: true
keys:
  mykey: "{LIVEKIT_SECRET}"

فایل synapse-data/livekit-config/livekit.yaml رو بسازید و به عنوان الگو به livekit.yaml که اینجا گذاشتم نگاه کنید و تنظیمات مورد نظرتون رو ست کنید.

نصب یا لود ایمیج‌ها

اگه به داکرهاب دسترسی دارید: تو “فولدر ماتریکس” دستور docker compose up -d رو اجرا کنید تا ایمیجا دانلود بشن. اگه ایمیجا رو دستی دانلود کردید: اینا رو اجرا کنید:

docker load < synapse.tar && docker load < postgres.tar
# در صورت نیاز به تماس:
docker load < livekit.tar && docker load < jwt.tar

docker compose up -d

می‌تونید لاگا رو هم چک کنید که اروری نداشته باشیم: docker compose logs --follow. نهایتا یه یوزر ادمین هم بسازید: docker compose exec synapse register_new_matrix_user -c /data/homeserver.yaml --admin

  • اگه بعد از بالا آوردن پروژه اروری در مورد permission لاگ‌ها دریافت کردید این باگ مربوط به یه نسخه از سینپسه، لاگ فایل رو با این کانفیگ به لاگ کنسول تغییر بدید. فایل synapse-data/_data/{SERVER_ADDRESS}.log.config رو ادیت کنید و اینو بذارید جاش:
version: 1

formatters:
  precise:
    format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'

handlers:
  console:
    class: logging.StreamHandler
    formatter: precise

loggers:
    synapse.storage.SQL:
        # beware: increasing this to DEBUG will make synapse log sensitive
        # information such as access tokens.
        level: INFO

root:
    level: INFO
    handlers: [console]

ریورس پروکسی

فایلی که قبلا برای تنظیم سرتیفیکیت زیردامنه matrix یا هر اسمی که روش گذاشتید تو nginx رو باز کنید و شبیه نمونه زیر کانفیگش کنید:

server {
    # For the federation port
    listen 8448 ssl http2;
    listen [::]:8448 ssl http2;

    server_name {SERVER_ADDRESS};
    
    include /etc/nginx/default.d/*.conf;

    location /synapse-admin {
        root         /opt/synapse-admin;
        try_files $uri $uri/ /index.html;
    }

    location /assets {
        root         /opt/synapse-admin/synapse-admin;
        try_files $uri $uri/ /index.html;
    }

    location /.well-known/matrix/server {
        default_type application/json;
        return 200 '{"m.server": "{SERVER_ADDRESS}:443"}';
    }
    
    ##### Live kit calls - Section start #####
    location /.well-known/matrix/client {
        default_type application/json;
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
        add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';

        return 200 '{
            "m.homeserver": {
                "base_url": "https://{SERVER_ADDRESS}"
            },
            "org.matrix.msc4143.rtc_foci": [{
                "type": "livekit",
                "livekit_service_url": "https://{SERVER_ADDRESS}/livekit/jwt/"
            }]
        }';
    }

    location ^~ /livekit/jwt/ {    
       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_pass http://localhost:58080/;
    }
    
    location ^~ /livekit/sfu/ {
        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_send_timeout 120;
        proxy_read_timeout 120;
        proxy_buffering off;

        proxy_set_header Accept-Encoding gzip;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    
        proxy_pass http://localhost:7880/;
    }
    ##### Live kit calls - Section end #####

    location ~ ^(/_matrix|/_synapse/client|/_synapse/admin) {
        # note: do not add a path (even a single /) after the port in `proxy_pass`,
        # otherwise nginx will canonicalise the URI and cause signature verification
        # errors.
        proxy_pass http://localhost:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;

        # Nginx by default only allows file uploads up to 1M in size
        # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
        client_max_body_size 200M;

	# Synapse responses may be chunked, which is an HTTP/1.1 feature.
    	proxy_http_version 1.1;
    }

    listen 443 ssl http2; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/{SERVER_CERT_ADDRESS}/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/{SERVER_PRIVATE_KEY_ADDRESS}/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = {SERVER_ADDRESS}) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    server_name {SERVER_ADDRESS};

    listen 80;
    return 404; # managed by Certbot
}
  • اگه تماس ندارید سکشن مربوط به call رو کلا با این جایگزین کنید:
    location /.well-known/matrix/client {
        default_type application/json;
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
        add_header Access-Control-Allow-Headers 'X-Requested-With, Content-Type, Authorization';

        return 200 '{
            "m.homeserver": {
                "base_url": "https://{SERVER_ADDRESS}"
            }
        }';
    }
  • اون client_max_body_size رو بر اساس عددی که برای اندازه آپلود فایلا انتخاب کردید ست کنید.
  • آدرس synapse-admin/ و assets/ رو بر اساس جایی که می‌خواین ادمین پنلتونو سرو کنید بزنید.
  • بقیه مقادیر داخل {} رو هم مثل قبل درست کنید. مثلا آدرس سرتیفیکیتتون یادتون نره اگه جای دیگه‌ایه عوضش کنید.
  • نهایتا nginx -s reload تا کانفیگا ریلود بشه.

ادمین پنل

  • پروژه synapse-admin رو می‌تونید از گیت‌هابش بگیرید.
  • فایل tar.gz. اش رو داخل opt/synapse-admin/synapse-admin/ اکسترکت کنید (یا هر جای دیگه - فقط تنظیمات nginx رو هم بر اساس همون عوض کنید).
  • فایل config.json رو داخلش باز کنید و اینو بذارید توش:
{
  "restrictBaseUrl": "https://{SERVER_ADDRESS}"
}