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

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

سعی می‌کنم تا جای ممکن همه چیزو خلاصه پیش ببرم چون وضعیت اتصال خودمم در حال حاضر بگیر نگیر داره. پس برای شروع فرض من بر اینه که:

۱. شما یه دامنه مثلا mysite.com دارید و براش یه زیردامنه به اسم matrix.mysite.com درست کردید.

۲. دسترسی به یه VPS با حداقل ۱ گیگ و بهتر ۲ گیگ مموری دارید.

۳. دامنه به VPS متصله و کارای معمول لینوکسی و ادمینی رو بلدید.

۴. داکر و کامپوز رو نصب دارید و کار باهاشو بلدید.

۵. کارای مربوط به SSL و TLS و این داستانا رو انجام دادید.

۶. یه وب‌سرور مثل Nginx نصب کردید برای ریورس پروکسی و کار باهاشو بلدید.

مهمی‌جات:

  • هر جا هر چیزی رو می‌گم «فرض می‌کنم» خودتون براساس نیاز تغییرش بدید.
  • هر جا هر چیزی داخل {} بود با مقدار مورد نظر خودتون جایگزینش کنید و آکولاد رو هم حذف کنید. مثلا https://{matrix.mysite.com} میشه https://matrix.blabla.com

خب حالا از اینجا به بعد شروع می‌کنیم.

چیزایی که مهمه بدونید رو توضیح می‌دم بقیشو برید خودتون تو مستنداتش بخونید. همین‌طور ترتیب و توالی کانفیگ‌ها رو هم رعایت نکردم چون این یه آموزش نیست و فقط می‌خوام بگم چه طوری خیلی سریع بیاریدش بالا.

من فرض می‌کنم دارید ماتریکس یا سینپس رو توی /opt/matrix/ کانفیگ می‌کنید. یه فایل docker-compose.yml تو همون فولدر ایجاد کنید. این چیزیه که من توش دارم:

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={matrix.mysite.com}
      - 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://{matrix.mysite.com}/livekit/sfu
      - LIVEKIT_SECRET={LIVEKIT_SECRET}
      - LIVEKIT_KEY=mykey
      - LIVEKIT_LOCAL_HOMESERVERS={matrix.mysite.com}
      - LIVEKIT_FULL_ACCESS_HOMESERVERS={matrix.mysite.com}
    networks:
      - matrix-network

networks:
  matrix-network:
    name: matrix_network

یادآوری: مقادیر DB_PASSWORD، matrix.mysite.com، LIVEKIT_SECRET رو تغییر بدید.

یه توضیح کوچیک: می‌تونید نسخه جدیدتری از pg رو هم استفاده کنید. سینپس سرور اصلی ماتریکسه و livekit و jwt-service کار تماس رو تو المنت X هندل می‌کنن. اگه نمی‌خواید تماس المنت X رو رو سرور خودتون پشتیبانی کنید می‌تونید کلا کانفیگشو پاک کنید و هر جای دیگه هم اشاره به Livekit بود حذف کنید. در این صورت تماسا به سرور خود المنت منتقل میشه که فیلتره. تو این کانفیگ من سرور Turn هم دارم که با ترکیب Turn و Livekit تماس هم روی المنت و هم روی المنت X مقدوره.

ادامه بدیم…

یه فایل element-config.json تو همون فولدر ایجاد کنید و اینا رو بریزید توش و جایگذاری‌ها فراموش نشه:

{
  "default_server_config": {
    "m.homeserver": {
      "base_url": "https://{matrix.mysite.com}",
      "server_name": "{matrix.mysite.com}"
    },
    "m.identity_server": {
      "base_url": "https://vector.im"
    }
  },
  "brand": "Element",
  "integrations_ui_url": "https://scalar.vector.im/",
  "integrations_rest_url": "https://scalar.vector.im/api",
  "integrations_widgets_urls": [
    "https://scalar.vector.im/_matrix/integrations/v1",
    "https://scalar.vector.im/api",
    "https://scalar-staging.vector.im/_matrix/integrations/v1",
    "https://scalar-staging.vector.im/api",
    "https://scalar-staging.riot.im/scalar/api"
  ],
  "hosting_signup_link": "https://element.io/matrix-services?utm_source=element-web&utm_medium=web",
  "bug_report_endpoint_url": "https://element.io/bugreports/submit",
  "uisi_autorageshake_app": "element-auto-uisi",
  "showLabsSettings": true,
  "piwik": {
    "url": "https://piwik.riot.im/",
    "siteId": 1,
    "policyUrl": "https://element.io/cookie-policy"
  },
  "roomDirectory": {
    "servers": [
      "matrix.org",
      "gitter.im",
      "libera.chat"
    ]
  },
  "enable_presence_by_hs_url": {
    "https://matrix.org": false,
    "https://matrix-client.matrix.org": false
  },
  "terms_and_conditions_links": [
    {
      "url": "https://element.io/privacy",
      "text": "Privacy Policy"
    },
    {
      "url": "https://element.io/cookie-policy",
      "text": "Cookie Policy"
    }
  ],
  "hostSignup": {
    "brand": "Element Home",
    "cookiePolicyUrl": "https://element.io/cookie-policy",
    "domains": [
      "matrix.org"
    ],
    "privacyPolicyUrl": "https://element.io/privacy",
    "termsOfServiceUrl": "https://element.io/terms-of-service",
    "url": "https://ems.element.io/element-home/in-app-loader"
  },
  "sentry": {
    "dsn": "https://029a0eb289f942508ae0fb17935bd8c5@sentry.matrix.org/6",
    "environment": "develop"
  },
  "posthog": {
    "projectApiKey": "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO",
    "apiHost": "https://posthog.element.io"
  },
  "features": {
    "feature_spotlight": true
  },
  "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

اگه می‌خواید تماس المنت قدیمی رو پشتیبانی کنید یه فایل turnserver.conf همونجا بسازید و اینو بریزید توش:

use-auth-secret
static-auth-secret={MY_AUTH_SECRET}
realm={matrix.mysite.com}
listening-port=3478
tls-listening-port=5349
min-port=49160
max-port=49200
verbose
allow-loopback-peers
cli-password={MY_CLI_PASSWORD}
external-ip={SERVER_EXTERNAL_IP}

اگه تماس المنت X رو پشتیبانی می‌کنید، یه فولدر داخل همین فولدر بسازید به اسم synapse-data و داخلش دوباره یه فولدر دیگه به اسم livekit-config و یه فایل livekit.yaml. پس شد synapse-data/livekit-config/livekit.yaml

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: "{MY_KEY}"

حالا یه فایل هم تو آدرس synapse-data/_data/homeserver.yaml بسازید:

# 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: "{matrix.mysite.com}"
pid_file: /data/homeserver.pid
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    resources:
      - names: [client, federation]
        compress: false
database:
  name: psycopg2
  args:
    user: matrix
    password: {DB_PASSWORD}
    database: synapse
    host: pg
    cp_min: 5
    cp_max: 10
log_config: "/data/{matrix.mysite.com}.log.config"
media_store_path: /data/media_store
max_upload_size: 200M
registration_shared_secret: "{SHARED_SECRET}"
report_stats: false
macaroon_secret_key: "{MACAROON_SECRET_KEY}"
form_secret: "{FORM_SECRET}"
signing_key_path: "/data/{matrix.mysite.com}.signing.key"
trusted_key_servers:
  - server_name: "matrix.org"

enable_registration: true

## 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"

turn_uris: 
  - "turn:{matrix.mysite.com}:3478?transport=udp"
  - "turn:{matrix.mysite.com}:3478?transport=tcp"
  - "turns:{matrix.mysite.com}:3478?transport=udp"
  - "turns:{matrix.mysite.com}:3478?transport=tcp"

turn_shared_secret: "{TURN_SHARED_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

تنظیمات مربوط به Recaptcha یا باز بودن ثبت‌نام یا Turn رو براساس نیاز انجام بدید. حتما به https://matrix-org.github.io/synapse/develop/usage/configuration/config_documentation.html برای توضیحات بیشتر مراجعه کنید.

نهایتا میریم برای ریورس پروکسی که من با Nginx انجامش دادم:

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

    server_name {matrix.mysite.com};

    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": "{matrix.mysite.com}:443"}';
    }

    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://{matrix.mysite.com}"
            },
            "org.matrix.msc4143.rtc_foci": [{
                "type": "livekit",
                "livekit_service_url": "https://{matrix.mysite.com}/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/;
    }

    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/{matrix.mysite.com}/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/{matrix.mysite.com}/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

}

تنظیمات ssl رو متناسب با شرایط خودتون تغییر بدید. اگه نمی‌خواید سرورتون فدریت بشه تنظیمات مربوط به اونو هم حذف کنید. من از synapse-admin برای یه سری کارای ساده مدیریتی استفاده می‌کنم یه پروژه ساده‌اس که می‌تونید اونو هم کنار سینپس داشته باشید (به کانفیگ لوکیشن /assets دقت کنید و به گیت‌هابش برای روش کانفیگش که خیلی ساده‌اس مراجعه کنید).

حالا کافیه یه docker compose up بزنید ببینید کار می‌کنه همه چی یا نه :))

اگه سوالی داشتید و من هم می‌تونستم بیام اینجا جواب بدم بپرسید.