Compare commits
237 Commits
1.2.0+v1.5
...
upgrade-c0
| Author | SHA1 | Date | |
|---|---|---|---|
| c04a8583bf | |||
| 35a981ca5b | |||
| 037002f05a | |||
| 53c6bab5c4 | |||
| 94e7c31369 | |||
| 5fc9296e61 | |||
| 3e838734de | |||
| 74f1adaccb | |||
| 17a399ba25 | |||
| b63dde1275 | |||
| f836c74386 | |||
| e257349b37 | |||
| 5b21a6b4f9 | |||
| b730cadb06 | |||
| 59ad89cfb4 | |||
| d75ca4f11f | |||
| cff6cfb001 | |||
| d82d539424 | |||
| b4c3db38c3 | |||
| 3f488167bc | |||
| f66bfef727 | |||
| a809333dcb | |||
| b39c60d594 | |||
| 4830b0596c | |||
| 43d68aefb4 | |||
| 91efd92d31 | |||
| 3fab725957 | |||
| c71dc162cb | |||
| 625b0381f8 | |||
| 7492e8bd4e | |||
| 60bd8b1b49 | |||
| 6f47fca73b | |||
| dd92cd4bd7 | |||
| cf30cebf8e | |||
| 5481b7e31c | |||
| 8a7978b388 | |||
| d0d5cfb1bc | |||
| 3d13505330 | |||
| 68fd515297 | |||
| 01e3feb1cf | |||
| c51120c41a | |||
| b81fecdd23 | |||
| a5a3a1938d | |||
| 18b658c452 | |||
| 553fee0e9d | |||
| 61f357b49e | |||
| 0e55594727 | |||
| 460f5a969c | |||
| 8640abbe79 | |||
| 3e0c9063c4 | |||
| db6440b317 | |||
| 24f7e0cb35 | |||
| 6d1397562b | |||
| e0c0861c16 | |||
| 41fdcafaa0 | |||
| 730dbc4569 | |||
| 809055dadb | |||
| 7703bbbce7 | |||
| e3df032bda | |||
| 0cf9d0a244 | |||
| 86a44afd19 | |||
| cf47a9c1b0 | |||
| aaa59a7718 | |||
| e072cf0766 | |||
| 22cc356a56 | |||
| 160b0eb2cf | |||
| af7f7eca2f | |||
| 5808fef48d | |||
| a8483dccf9 | |||
| 8e82c16e3d | |||
| dafb17aace | |||
| 237e2c832b | |||
| bf4de0df97 | |||
| 61222baaa0 | |||
| 32721ace23 | |||
| 5a7b7f04ed | |||
| 8809f25ab1 | |||
| 0645a9f487 | |||
| a1d7fdad2d | |||
| a90ccaa65b | |||
| 7c0e822940 | |||
| d6178fd380 | |||
| 2a18291f48 | |||
| 943ed58db4 | |||
| 09b60947ee | |||
| bff6fe9b09 | |||
| 6f4efd64e8 | |||
| 202af642cf | |||
| 29f31e0a7b | |||
| 5c6985596e | |||
| dfe893160f | |||
| 99bce91794 | |||
| 599a219a5f | |||
| 0498d8006f | |||
| 28ccd46ef1 | |||
| 8c60f7e5d5 | |||
| 77ffb17f86 | |||
| eae5c82d88 | |||
| 68ff2b64da | |||
| ef6e35ba3a | |||
| 8c4d88b20c | |||
| 6bd2f0b779 | |||
| 8f9c66e95d | |||
| e2bec9e4b4 | |||
| da95b5c70d | |||
| f13856b14c | |||
| 2c8dc7c960 | |||
| c36c147dff | |||
| 8a37984e15 | |||
| 63a1abb2c0 | |||
| 86106b6b6f | |||
| 8250916051 | |||
| e007bda255 | |||
| 951fc56434 | |||
| 6fe14edef7 | |||
| a0a9c2b863 | |||
| bdf8e11dc5 | |||
| 2658fed366 | |||
| 72b59ce4ad | |||
| dfed1e54da | |||
| d4ccb3588b | |||
| 11f70b7878 | |||
| fd601c23f3 | |||
| b9097c1f94 | |||
| 75d1303118 | |||
| 90c8d0dbba | |||
| a85310346b | |||
| 116840623b | |||
| 919aaf0116 | |||
| 43a3502fad | |||
| 08b49c14d9 | |||
| 7683ebd189 | |||
| a3c9dfd65b | |||
| 6dacecbfac | |||
| 4770a03cb7 | |||
| 7ead29b750 | |||
| 3c772cc1e5 | |||
| e146435394 | |||
| 795c2eb685 | |||
| 7b1b5c37ed | |||
| 84204b03a7 | |||
| b57b73d5d6 | |||
| 66bd6be8fc | |||
| dda7f2a369 | |||
| d22a8257fb | |||
| 2445d9f33a | |||
| 2a45273541 | |||
| 48efb7de51 | |||
| b2e8bf9c8b | |||
| d02981a2bf | |||
| c6f9b117e2 | |||
| ade6147f35 | |||
| 50e0aa06cc | |||
| f3732c8392 | |||
| e171ce052e | |||
| 5d5bd70818 | |||
| fd1a6c7a4a | |||
| 39a47a2515 | |||
| 6e556c8b2d | |||
| 74fb8014fa | |||
| 787e0fb3a9 | |||
| ead52c1acd | |||
| fca551b735 | |||
| f43a47d4c8 | |||
| beeb1e47b1 | |||
| 931e89f5f5 | |||
| 5a72540db2 | |||
| 703b8d91d2 | |||
| 05e9ee0732 | |||
| ec22040bd3 | |||
| d5c70f5567 | |||
| 4445e0249f | |||
| 89f5069aa2 | |||
| 77b3dbdaa9 | |||
| 1a0211b743 | |||
| eb541c41ee | |||
| 008ec1126b | |||
| 0c26ea22f9 | |||
| e3bf165da0 | |||
| 245e81e4bb | |||
| 9b12e4a0eb | |||
| e7f81cb9ea | |||
| 88bcc2186b | |||
| 9b3e1793e0 | |||
| ee6d1e92f4 | |||
| 3e3c239c88 | |||
| e905c24eb2 | |||
| 91d29cfe92 | |||
| 9eb0856888 | |||
| 2cc70498f6 | |||
| 92a9ea2f22 | |||
| ca2e0d7dc0 | |||
| 09ff470ba6 | |||
| 09c4ca146f | |||
| 99f45636f5 | |||
| 1e8b616cba | |||
| 13edf77ece | |||
| f56d9db3f6 | |||
| 4cae5f5b75 | |||
| 77170432eb | |||
| c423db2cb7 | |||
| e59de33d5b | |||
| 998583c2a5 | |||
| 0dff883beb | |||
| cd0f6359b1 | |||
| edf72453a6 | |||
| f18f098b45 | |||
| 0838cb819e | |||
| 0e3c286eaf | |||
| 2beb6e4bf0 | |||
| bf3db9999f | |||
| 00b0375b1c | |||
| 1832911526 | |||
| 2bac1aa31c | |||
| dd4841dbe0 | |||
| 467a35e7b9 | |||
| 06381aceaf | |||
| d9c5248f8c | |||
| 786bf0587f | |||
| 840f532376 | |||
| dcc9ec543d | |||
| 65a149eac3 | |||
| 6041ad6112 | |||
| 1afa8cf7b7 | |||
| b5831114f4 | |||
| 02d78e9aa9 | |||
| af3c8fd252 | |||
| 40d6b1df4e | |||
| 0378e8d89f | |||
| c542629264 | |||
| 005ce43f61 | |||
| bca2a983c0 | |||
| 89892ed818 | |||
| 1b32621af9 | |||
| 919e9253ae | |||
| c71f3bc519 | |||
| e9b5a5360f |
53
.drone.yml
Normal file
53
.drone.yml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: deploy to swarm-test.autonomic.zone
|
||||||
|
steps:
|
||||||
|
- name: deployment
|
||||||
|
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
|
||||||
|
settings:
|
||||||
|
host: swarm-test.autonomic.zone
|
||||||
|
stack: matrix-synapse
|
||||||
|
generate_secrets: true
|
||||||
|
purge: true
|
||||||
|
deploy_key:
|
||||||
|
from_secret: drone_ssh_swarm_test
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
environment:
|
||||||
|
DOMAIN: matrix-synapse.swarm-test.autonomic.zone
|
||||||
|
STACK_NAME: matrix-synapse
|
||||||
|
LETS_ENCRYPT_ENV: production
|
||||||
|
DISCORD_BRIDGE_YAML_VERSION: v2
|
||||||
|
ENTRYPOINT_CONF_VERSION: v3
|
||||||
|
HOMESERVER_YAML_VERSION: v29
|
||||||
|
LOG_CONFIG_VERSION: v2
|
||||||
|
SHARED_SECRET_AUTH_VERSION: v2
|
||||||
|
SIGNAL_BRIDGE_YAML_VERSION: v5
|
||||||
|
TELEGRAM_BRIDGE_YAML_VERSION: v6
|
||||||
|
PG_BACKUP_VERSION: v1
|
||||||
|
WK_CLIENT_VERSION: v1
|
||||||
|
WK_SERVER_VERSION: v1
|
||||||
|
NGINX_CONFIG_VERSION: v8
|
||||||
|
SECRET_DB_PASSWORD_VERSION: v1
|
||||||
|
SECRET_FORM_SECRET_VERSION: v1
|
||||||
|
SECRET_MACAROON_VERSION: v1
|
||||||
|
SECRET_REGISTRATION_VERSION: v1
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
name: generate recipe catalogue
|
||||||
|
steps:
|
||||||
|
- name: release a new version
|
||||||
|
image: plugins/downstream
|
||||||
|
settings:
|
||||||
|
server: https://build.coopcloud.tech
|
||||||
|
token:
|
||||||
|
from_secret: drone_abra-bot_token
|
||||||
|
fork: true
|
||||||
|
repositories:
|
||||||
|
- toolshed/auto-recipes-catalogue-json
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
event: tag
|
||||||
242
.env.sample
242
.env.sample
@ -1,52 +1,191 @@
|
|||||||
TYPE=matrix-synapse
|
TYPE=matrix-synapse
|
||||||
|
DOMAIN=matrix-synapse.example.com
|
||||||
DOMAIN=matrix.example.com
|
# SERVER_NAME=example.com
|
||||||
|
TIMEOUT=300
|
||||||
|
ENABLE_AUTO_UPDATE=true
|
||||||
LETS_ENCRYPT_ENV=production
|
LETS_ENCRYPT_ENV=production
|
||||||
|
COMPOSE_FILE="compose.yml"
|
||||||
|
# POST_DEPLOY_CMDS="db set_admin"
|
||||||
|
ENABLE_BACKUPS=true
|
||||||
|
|
||||||
|
## Admin details
|
||||||
|
|
||||||
|
ADMIN_EMAIL=admin@example.com
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
SECRET_DB_PASSWORD_VERSION=v1
|
SECRET_DB_PASSWORD_VERSION=v1
|
||||||
|
|
||||||
SYNAPSE_ADMIN_EMAIL=admin@example.com
|
|
||||||
|
|
||||||
SECRET_REGISTRATION_SHARED_SECRET_VERSION=v1
|
|
||||||
SECRET_MACAROON_SECRET_KEY_VERSION=v1
|
|
||||||
SECRET_FORM_SECRET_VERSION=v1
|
SECRET_FORM_SECRET_VERSION=v1
|
||||||
|
SECRET_MACAROON_VERSION=v1
|
||||||
|
SECRET_REGISTRATION_VERSION=v1
|
||||||
|
|
||||||
COMPOSE_FILE="compose.yml"
|
## Authentication
|
||||||
|
|
||||||
|
# All login / SSO / MAS-related toggles in one place.
|
||||||
|
|
||||||
|
### Local password & registration (Synapse native)
|
||||||
|
|
||||||
|
# With MAS_ENABLED=1 you must set PASSWORD_LOGIN_ENABLED=false — Synapse forbids legacy password DB alongside matrix_authentication_service.
|
||||||
|
PASSWORD_LOGIN_ENABLED=true
|
||||||
|
ENABLE_REGISTRATION=false
|
||||||
|
|
||||||
|
# Token based registration. Enable ADMIN_INTERFACE (below) to use the admin interface to generate tokens.
|
||||||
|
#REGISTRATION_REQUIRES_TOKEN=true
|
||||||
|
|
||||||
|
### OIDC via Keycloak-shaped API (e.g. Authentik)
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.keycloak.yml"
|
||||||
|
#KEYCLOAK_ENABLED=1
|
||||||
|
#KEYCLOAK_ID=keycloak
|
||||||
|
#KEYCLOAK_NAME=
|
||||||
|
#KEYCLOAK_URL=
|
||||||
|
#KEYCLOAK_CLIENT_ID=
|
||||||
|
#KEYCLOAK_CLIENT_DOMAIN=
|
||||||
|
#KEYCLOAK_ALLOW_EXISTING_USERS=false
|
||||||
|
#SECRET_KEYCLOAK_CLIENT_SECRET_VERSION=v1
|
||||||
|
|
||||||
|
### Second OIDC provider (compose.keycloak2.yml)
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.keycloak2.yml"
|
||||||
|
#KEYCLOAK2_ENABLED=1
|
||||||
|
#KEYCLOAK2_ID=keycloak2
|
||||||
|
#KEYCLOAK2_NAME=
|
||||||
|
#KEYCLOAK2_URL=
|
||||||
|
#KEYCLOAK2_CLIENT_ID=
|
||||||
|
#KEYCLOAK2_CLIENT_DOMAIN=
|
||||||
|
#KEYCLOAK2_ALLOW_EXISTING_USERS=false
|
||||||
|
#SECRET_KEYCLOAK2_CLIENT_SECRET_VERSION=v1
|
||||||
|
|
||||||
|
### Third OIDC provider (compose.keycloak3.yml)
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.keycloak3.yml"
|
||||||
|
#KEYCLOAK3_ENABLED=1
|
||||||
|
#KEYCLOAK3_ID=keycloak3
|
||||||
|
#KEYCLOAK3_NAME=
|
||||||
|
#KEYCLOAK3_URL=
|
||||||
|
#KEYCLOAK3_CLIENT_ID=
|
||||||
|
#KEYCLOAK3_CLIENT_DOMAIN=
|
||||||
|
#KEYCLOAK3_ALLOW_EXISTING_USERS=false
|
||||||
|
#SECRET_KEYCLOAK3_CLIENT_SECRET_VERSION=v1
|
||||||
|
|
||||||
|
### Matrix Authentication Service (MAS) — Element X / OIDC-native auth
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.mas.yml"
|
||||||
|
#MAS_ENABLED=1 # Leave commented if you plan to migrate an existing homeserver
|
||||||
|
#PASSWORD_LOGIN_ENABLED=false
|
||||||
|
#SECRET_MAS_ENCRYPTION_VERSION=v1 # length=64 charset=hex
|
||||||
|
#SECRET_MAS_SYNAPSE_SHARED_VERSION=v1 # length=64 charset=hex
|
||||||
|
# PEM private key: abra cannot generate this format — use `abra app cmd -l YOURAPPDOMAIN generate_mas_signing_rsa`
|
||||||
|
#SECRET_MAS_SIGNING_RSA_VERSION=v1 # generate=false
|
||||||
|
|
||||||
|
#### MAS upstream OIDC provider (e.g. Authentik)
|
||||||
|
# Create a new OAuth2 app in your IdP with redirect URI: https://<DOMAIN>/upstream/callback/<MAS_UPSTREAM_PROVIDER_ID>
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.mas-upstream.yml"
|
||||||
|
#MAS_UPSTREAM_PROVIDER_ID= # ULID, e.g. 01JSHPZHAXC50QBKH67MH33TNF — generate at https://www.ulidtools.com
|
||||||
|
#MAS_UPSTREAM_ISSUER= # e.g. https://auth.example.com/application/o/matrix-mas/
|
||||||
|
#MAS_UPSTREAM_CLIENT_ID=
|
||||||
|
#MAS_UPSTREAM_HUMAN_NAME=Authentik
|
||||||
|
# For migration from previous direct Keycloud-style config: set to oidc-<your old KEYCLOAK_ID> so syn2mas maps users correctly.
|
||||||
|
#MAS_UPSTREAM_SYNAPSE_IDP_ID=
|
||||||
|
#SECRET_MAS_UPSTREAM_CLIENT_VERSION=v1
|
||||||
|
|
||||||
|
### Shared secret auth (bridges / automation)
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.shared_secret_auth.yml"
|
||||||
|
#SHARED_SECRET_AUTH_ENABLED=1
|
||||||
|
#SECRET_SHARED_SECRET_AUTH_VERSION=v1 # length=128
|
||||||
|
|
||||||
|
## Federation
|
||||||
|
|
||||||
#DISABLE_FEDERATION=1
|
#DISABLE_FEDERATION=1
|
||||||
|
|
||||||
|
# SERVE_SERVER_WELLKNOWN only works if SERVER_NAME and DOMAIN are the same
|
||||||
|
# if they are different, then a different federation method is needed (like compose.wellknown.yml)
|
||||||
|
# Set "true" to enable federation endpoint on $DOMAIN/.well-known/matrix/server
|
||||||
|
SERVE_SERVER_WELLKNOWN=false
|
||||||
|
|
||||||
|
# Serve /.well-known/matrix/{server,client} on SERVER_NAME via Traefik.
|
||||||
|
# Can be used when SERVER_NAME is other than DOMAIN and SERVER_NAME is served by Traefik.
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.wellknown.yml"
|
||||||
|
|
||||||
|
ALLOW_PUBLIC_ROOMS_FEDERATION=false
|
||||||
|
|
||||||
|
## Room auto-join
|
||||||
|
|
||||||
#AUTO_JOIN_ROOM_ENABLED=1
|
#AUTO_JOIN_ROOM_ENABLED=1
|
||||||
#AUTO_JOIN_ROOM="#example:example.com"
|
#AUTO_JOIN_ROOM="#example:example.com"
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
# for the homserver
|
||||||
SQL_LOG_LEVEL=WARN
|
SQL_LOG_LEVEL=WARN
|
||||||
ROOT_LOG_LEVEL=WARN
|
ROOT_LOG_LEVEL=WARN
|
||||||
|
|
||||||
REDACTION_RETENTION_PERIOD=7d
|
# for nginx
|
||||||
|
NGINX_ACCESS_LOG_LOCATION="/dev/null"
|
||||||
|
NGINX_ERROR_LOG_LOCATION="/dev/null"
|
||||||
|
# Comment the previous two lines and uncomment these to enable logging
|
||||||
|
#NGINX_ACCESS_LOG_LOCATION="/dev/stdout"
|
||||||
|
#NGINX_ERROR_LOG_LOCATION="/dev/stderr"
|
||||||
|
|
||||||
RETENTION_MAX_LIFETIME=1m
|
## Privacy
|
||||||
|
|
||||||
ENABLE_3PID_LOOKUP=true
|
ENABLE_3PID_LOOKUP=true
|
||||||
|
|
||||||
USER_IPS_MAX_AGE=1d
|
USER_IPS_MAX_AGE=1d
|
||||||
|
|
||||||
|
ENCRYPTED_BY_DEFAULT=all
|
||||||
|
|
||||||
#ENABLE_ALLOWLIST=1
|
#ENABLE_ALLOWLIST=1
|
||||||
#FEDERATION_ALLOWLIST="[]"
|
#FEDERATION_ALLOWLIST="[]"
|
||||||
|
|
||||||
#COMPOSE_FILE="compose.yml:compose.keycloak.yml"
|
# Set these to keyservers you trust - usually the same as your federation allowlist
|
||||||
#KEYCLOAK_ENABLED=1
|
#TRUSTED_KEYSERVERS="trusted_key_servers:\n - server_name: 'example.com'\n - server_name: 'example2.com'"
|
||||||
#KEYCLOAK_NAME=
|
|
||||||
#KEYCLOAK_URL=
|
|
||||||
#KEYCLOAK_CLIENT_ID=
|
|
||||||
#KEYCLOAK_CLIENT_DOMAIN=
|
|
||||||
#SECRET_KEYCLOAK_CLIENT_SECRET_VERSION=v1
|
|
||||||
|
|
||||||
#COMPOSE_FILE="compose.yml:compose.turn.yml"
|
# some optional configs to increase privacy and security
|
||||||
|
#REQUIRE_AUTH_FOR_PROFILE_REQUESTS=true
|
||||||
|
#LIMIT_PROFILE_REQUESTS_TO_USERS_WHO_SHARE_ROOMS=true
|
||||||
|
#DELETE_STALE_DEVICES_AFTER=1y
|
||||||
|
#SESSION_LIFETIME=60d
|
||||||
|
#TRACK_PUPPETED_USER_IPS=true
|
||||||
|
|
||||||
|
## Room complexity limit (prevents joining large remote rooms that cause DB bloat)
|
||||||
|
## complexity ≈ state_events / 500. Default 100.0 blocks rooms with >50000 state events.
|
||||||
|
#ROOM_COMPLEXITY_LIMIT=100.0
|
||||||
|
|
||||||
|
## Retention
|
||||||
|
|
||||||
|
ALLOWED_LIFETIME_MAX=4w
|
||||||
|
|
||||||
|
REDACTION_RETENTION_PERIOD=7d
|
||||||
|
RETENTION_MAX_LIFETIME=4w
|
||||||
|
|
||||||
|
#MEDIA_RETENTION_LOCAL_LIFETIME=30d
|
||||||
|
#MEDIA_RETENTION_REMOTE_LIFETIME=14d
|
||||||
|
|
||||||
|
## Old Signing Key
|
||||||
|
#OLD_SIGNING_KEY_ID=a_OLDKEYID
|
||||||
|
#OLD_SIGNING_KEY=base64string
|
||||||
|
#OLD_SIGNING_KEY_EXPIRES=123456789123
|
||||||
|
|
||||||
|
## Ratelimit
|
||||||
|
|
||||||
|
#LOGIN_LIMIT_IP_PER_SECOND=5
|
||||||
|
#LOGIN_LIMIT_IP_BURST=15
|
||||||
|
#LOGIN_LIMIT_ACCOUNT_PER_SECOND=1
|
||||||
|
#LOGIN_LIMIT_ACCOUNT_BURST=10
|
||||||
|
|
||||||
|
## TURN
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.turn.yml"
|
||||||
#TURN_ENABLED=1
|
#TURN_ENABLED=1
|
||||||
#TURN_URIS="[\"turns:coturn.foo.zone?transport=udp\", \"turns:coturn.foo.zone?transport=tcp\"]"
|
#TURN_URIS="[\"turns:coturn.foo.zone?transport=udp\", \"turns:coturn.foo.zone?transport=tcp\"]"
|
||||||
#TURN_ALLOW_GUESTS=true
|
#TURN_ALLOW_GUESTS=true
|
||||||
#SECRET_TURN_SHARED_SECRET_VERSION=v1
|
#SECRET_TURN_SHARED_SECRET_VERSION=v1
|
||||||
|
|
||||||
#COMPOSE_FILE="compose.yml:compose.smtp.yml"
|
## SMTP
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.smtp.yml"
|
||||||
#SMTP_ENABLED=1
|
#SMTP_ENABLED=1
|
||||||
#SMTP_APP_NAME=
|
#SMTP_APP_NAME=
|
||||||
#SMTP_FROM=
|
#SMTP_FROM=
|
||||||
@ -54,3 +193,68 @@ USER_IPS_MAX_AGE=1d
|
|||||||
#SMTP_PORT=
|
#SMTP_PORT=
|
||||||
#SMTP_USER=
|
#SMTP_USER=
|
||||||
#SECRET_SMTP_PASSWORD_VERSION=v1
|
#SECRET_SMTP_PASSWORD_VERSION=v1
|
||||||
|
|
||||||
|
## USER-DIRECTORY
|
||||||
|
|
||||||
|
#USER_DIRECTORY_ENABLED=true
|
||||||
|
#USER_DIRECTORY_SEARCH_ALL_USERS=true
|
||||||
|
#USER_DIRECTORY_PREFER_LOCAL_USERS=true
|
||||||
|
#USER_DIRECTORY_SHOW_LOCKED_USERS=false
|
||||||
|
|
||||||
|
## App services
|
||||||
|
|
||||||
|
#APP_SERVICES_ENABLED=1
|
||||||
|
#APP_SERVICE_CONFIGS="[\"...\"]"
|
||||||
|
|
||||||
|
## Telegram bridge
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.telegram.yml"
|
||||||
|
#APP_SERVICE_BOT_USERNAME=telegrambot
|
||||||
|
#APP_SERVICE_DISPLAY_NAME="Telegram bridge bot"
|
||||||
|
#APP_SERVICE_ID=
|
||||||
|
#HOMESERVER_DOMAIN=$DOMAIN
|
||||||
|
#HOMESERVER_URL=https://$DOMAIN
|
||||||
|
#VERIFY_SSL=false
|
||||||
|
#ENABLE_ENCRYPTION=true
|
||||||
|
#TELEGRAM_APP_ID=
|
||||||
|
#TELEGRAM_BRIDGE_PERMISSIONS="{ \"*\": \"relay\", \"@foo:matrix.example.com\": \"admin\" }"
|
||||||
|
#TELEGRAM_SYNC_CHANNEL_MEMBERS=true
|
||||||
|
#SECRET_TELEGRAM_DB_PASSWORD_VERSION=v1
|
||||||
|
#SECRET_TELEGRAM_API_HASH_VERSION=v1
|
||||||
|
#SECRET_TELEGRAM_BOT_TOKEN_VERSION=v1
|
||||||
|
#SECRET_TELEGRAM_AS_TOKEN_VERSION=v1
|
||||||
|
#SECRET_TELEGRAM_HS_TOKEN_VERSION=v1
|
||||||
|
|
||||||
|
## Discord bridge
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.discord.yml"
|
||||||
|
#DISCORD_CLIENT_ID=
|
||||||
|
#DISCORD_BRIDGE_ADMIN=
|
||||||
|
#SECRET_DISCORD_BOT_TOKEN_VERSION=v1
|
||||||
|
#SECRET_DISCORD_DB_PASSWORD_VERSION=v1
|
||||||
|
|
||||||
|
## Signal bridge
|
||||||
|
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.signal.yml"
|
||||||
|
#SIGNAL_ENABLE_ENCRYPTION=true
|
||||||
|
#SIGNAL_DEFAULT_ENCRYPTION=true
|
||||||
|
#SIGNAL_BRIDGE_PERMISSIONS="{ \"*\": \"relay\" }"
|
||||||
|
#SECRET_SIGNAL_AS_TOKEN_VERSION=v1
|
||||||
|
#SECRET_SIGNAL_DB_PASSWORD_VERSION=v1
|
||||||
|
#SECRET_SIGNAL_HS_TOKEN_VERSION=v1
|
||||||
|
#SECRET_SIGNAL_PICKLE_KEY_VERSION=v1
|
||||||
|
|
||||||
|
## Web Client (Redirect)
|
||||||
|
#WEB_CLIENT_LOCATION=https://element-web.example.com
|
||||||
|
|
||||||
|
## State compression (reduces database bloat from federation)
|
||||||
|
## Runs synapse_auto_compressor daily, built from source on first start
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.compress-state.yml"
|
||||||
|
# See https://github.com/matrix-org/rust-synapse-compress-state#running-options
|
||||||
|
#STATE_COMPRESS_CHUNK_SIZE=500
|
||||||
|
#STATE_COMPRESS_CHUNKS=100
|
||||||
|
#STATE_COMPRESS_SCHEDULE=0 3 * * *
|
||||||
|
|
||||||
|
## Admin interface at /admin
|
||||||
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.admin.yml"
|
||||||
|
#ADMIN_INTERFACE_ENABLED=1
|
||||||
|
|||||||
269
README.md
269
README.md
@ -18,58 +18,265 @@
|
|||||||
1. Set up Docker Swarm and [`abra`](https://docs.coopcloud.tech/abra/)
|
1. Set up Docker Swarm and [`abra`](https://docs.coopcloud.tech/abra/)
|
||||||
2. Deploy [`coop-cloud/traefik`](https://git.coopcloud.tech/coop-cloud/traefik)
|
2. Deploy [`coop-cloud/traefik`](https://git.coopcloud.tech/coop-cloud/traefik)
|
||||||
3. `abra app new matrix-synapse --secrets` (optionally with `--pass` if you'd like to save secrets in `pass`)
|
3. `abra app new matrix-synapse --secrets` (optionally with `--pass` if you'd like to save secrets in `pass`)
|
||||||
4. `abra app YOURAPPDOMAIN config` - be sure to change `$DOMAIN` to something that resolves to your Docker swarm box
|
4. `abra app config YOURAPPDOMAIN` - be sure to change `$DOMAIN` to something that resolves to your Docker swarm box
|
||||||
5. `abra app YOURAPPDOMAIN deploy`
|
5. `abra app deploy YOURAPPDOMAIN`
|
||||||
6. Create an initial user: `abra app YOURAPPDOMAIN run app register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008`
|
6. Create an initial user: `abra app run YOURAPPDOMAIN app register_new_matrix_user -c /data/homeserver.yaml http://localhost:8008`
|
||||||
|
|
||||||
## Tips & Tricks
|
## Tips & Tricks
|
||||||
|
|
||||||
|
### Create User
|
||||||
|
|
||||||
|
`register_new_matrix_user -u <username> -k $(cat /var/run/secrets/registration) -p <password>`
|
||||||
|
|
||||||
|
### Set Admin User
|
||||||
|
|
||||||
|
`abra app cmd YOURAPPDOMAIN db set_admin <adminuser>`
|
||||||
|
|
||||||
### Disabling federation
|
### Disabling federation
|
||||||
|
|
||||||
> We're not sure this does it exactly and there is still a discussion running
|
- Use `DISABLE_FEDERATION=1` to turn off federation listeners
|
||||||
> upstrem about whether this is the right way to do it & whether it could be
|
- Don't use [`compose.matrix.yml`](https://git.coopcloud.tech/coop-cloud/traefik/src/branch/master/compose.matrix.yml) in your traefik config to keep the federation ports closed
|
||||||
> more convenient. We welcome issues / change sets to close up more federation
|
|
||||||
> functionality.
|
|
||||||
|
|
||||||
- use `DISABLE_FEDERATION=1` to turn off federation listeners
|
### Enabling federation
|
||||||
- don't use [`compose.matrix.yml`](https://git.coopcloud.tech/coop-cloud/traefik/src/branch/master/compose.matrix.yml) in your traefik config to keep the federation ports closed
|
|
||||||
|
|
||||||
### Seeing what changed in `homeserver.yaml` between versions
|
Federation is on by default (`DISABLE_FEDERATION=0`). Remote homeservers need a way to discover the host:port that serves your `SERVER_NAME`.
|
||||||
|
There are three supported approaches. At least one needs to be working for federation to work (and matrix will fallback between them).
|
||||||
|
|
||||||
Change the version range to suit your needs.
|
#### Option 1: built-in well-known (`SERVER_NAME` = `DOMAIN`)
|
||||||
|
|
||||||
|
Set `SERVE_SERVER_WELLKNOWN=true` and leave `SERVER_NAME` unset (defaults to `DOMAIN`). The recipe's nginx serves `/.well-known/matrix/server` and `/.well-known/matrix/client` on `DOMAIN`.
|
||||||
|
|
||||||
|
Suitable when users are e.g. `@alice:matrix.example.com`.
|
||||||
|
|
||||||
|
#### Option 2: external well-known on `SERVER_NAME`
|
||||||
|
|
||||||
|
Use when you want users to be e.g. `@alice:example.com` while Synapse runs at `matrix.example.com` (and SERVER_NAME is served by the same machine that Synapse is running on). Set:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/matrix-org/synapse
|
SERVER_NAME=example.com
|
||||||
cd synapse/docs
|
DOMAIN=matrix.example.com
|
||||||
git log --follow -p v1.48.0..v1.51.0 sample_config.yaml
|
SERVE_SERVER_WELLKNOWN=false
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generating a new `homeserver.yaml`
|
The two paths that must be served on `SERVER_NAME` are:
|
||||||
|
|
||||||
The default is also available to see [here](https://matrix-org.github.io/synapse/latest/usage/configuration/homeserver_sample_config.html).
|
- `https://example.com/.well-known/matrix/server` → `{"m.server": "matrix.example.com:443"}`
|
||||||
|
- `https://example.com/.well-known/matrix/client` → `{"m.homeserver": {"base_url": "https://matrix.example.com"}}`
|
||||||
|
|
||||||
|
**Recommended — let this recipe serve them via Traefik** by enabling `compose.wellknown.yml`:
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -it \
|
COMPOSE_FILE="$COMPOSE_FILE:compose.wellknown.yml"
|
||||||
--entrypoint="" \
|
|
||||||
-e SYNAPSE_SERVER_NAME=foo.com \
|
|
||||||
-e SYNAPSE_REPORT_STATS=no \
|
|
||||||
matrixdotorg/synapse:v1.48.0 \
|
|
||||||
sh -c '/start.py generate; cat /data/homeserver.yaml' > homeserver.yaml.tmpl`
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generating a new `<server>.log.config`
|
This publishes a Traefik router `Host(${SERVER_NAME}) && PathPrefix(/.well-known/matrix)`
|
||||||
|
pointing at the matrix nginx, which already serves both files. The path-scoped, high-priority
|
||||||
|
rule coexists with any apex website that also serves `Host(${SERVER_NAME})` — that site keeps
|
||||||
|
serving everything except `/.well-known/matrix`. `SERVER_NAME` must resolve to this Traefik so
|
||||||
|
ACME can issue its certificate.
|
||||||
|
|
||||||
|
**Alternative** — serve the two files yourself from whatever already hosts `example.com`.
|
||||||
|
|
||||||
|
|
||||||
|
#### Option 3: Traefik `matrix-federation` entrypoint (port 8448)
|
||||||
|
|
||||||
|
Use when `SERVER_NAME` ≠ `DOMAIN` but you have no separate web service at `SERVER_NAME`. Remote homeservers fall back to `SERVER_NAME:8448` when there's no delegation (also requires SERVER_NAME pointing to same server that matrix is running on).
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- [traefik](https://git.coopcloud.tech/coop-cloud/traefik) `>= 5.1.2+v3.6.15` with `MATRIX_FEDERATION_ENABLED=1` and `compose.matrix.yml` enabled.
|
||||||
|
- `SERVER_NAME` set in your matrix-synapse env (used by the federation router's Host rule).
|
||||||
|
|
||||||
|
With these in place, the recipe publishes a Traefik router on `Host(${SERVER_NAME})` via the `matrix-federation` entrypoint, reusing the existing matrix nginx → synapse path.
|
||||||
|
|
||||||
|
|
||||||
|
#### Option 4: DNS SRV records (usually not viable here)
|
||||||
|
|
||||||
|
For reasons explained below, I might be confused, but I think SRV records usually don't help with co-op cloud matrix deployments.
|
||||||
|
|
||||||
|
You should probably prefer Option 2 (well known), but the possibility of SRV is explained below:
|
||||||
|
|
||||||
|
Federation can also be delegated with a DNS `SRV` record on `SERVER_NAME` instead of well-known:
|
||||||
|
|
||||||
```
|
```
|
||||||
docker run -it \
|
_matrix-fed._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # modern
|
||||||
--entrypoint="" \
|
_matrix._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # deprecated, for older peers
|
||||||
-e SYNAPSE_SERVER_NAME=foo.com \
|
```
|
||||||
-e SYNAPSE_REPORT_STATS=no \
|
|
||||||
matrixdotorg/synapse:v1.48.0 \
|
The catch is TLS: on the SRV path a remote validates the certificate against **`SERVER_NAME`**, *not* the SRV target. This recipe's Traefik only issues a cert for **`DOMAIN`**, so:
|
||||||
sh -c '/start.py generate; cat /data/foo.com.log.config' > log.config
|
|
||||||
|
- **SRV → `DOMAIN`:443 fails** — the presented cert is for `DOMAIN`, but the peer requires one for `SERVER_NAME`.
|
||||||
|
- **SRV → `SERVER_NAME`:443 collides** — Traefik routes TLS by SNI, and `Host(SERVER_NAME)` on `:443` is already owned by whatever apex site serves `SERVER_NAME`.
|
||||||
|
- **SRV → `SERVER_NAME`:8448 works** — the Option 3 `matrix-federation` router holds a cert for `SERVER_NAME` — but that's just Option 3 made explicit (the `:8448` fallback already works with no SRV record).
|
||||||
|
|
||||||
|
|
||||||
|
#### Verifying
|
||||||
|
|
||||||
|
The canonical test:
|
||||||
|
|
||||||
|
- https://federationtester.matrix.org/#YOUR_SERVER_NAME
|
||||||
|
|
||||||
|
Or check the underlying paths directly. They should all return JSON:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Options 1 & 2 — delegation
|
||||||
|
curl https://SERVER_NAME/.well-known/matrix/server
|
||||||
|
|
||||||
|
# Option 3 — federation endpoint via 8448
|
||||||
|
curl https://SERVER_NAME:8448/_matrix/key/v2/server
|
||||||
|
|
||||||
|
# Confirms Synapse itself is healthy (independent of the path remote servers use)
|
||||||
|
curl https://DOMAIN/_matrix/key/v2/server
|
||||||
```
|
```
|
||||||
|
|
||||||
### Getting client discovery on a custom domain
|
### Getting client discovery on a custom domain
|
||||||
|
|
||||||
You'll need to deploy something like [this](https://git.autonomic.zone/ruangrupa/well-known-uris).
|
Enable `compose.wellknown.yml` (see Option 2 above) — it serves `/.well-known/matrix/client`
|
||||||
|
on `SERVER_NAME` too, so clients signing in as `@alice:example.com` auto-discover the homeserver.
|
||||||
|
|
||||||
This could be implemented in this recipe but we haven't merged it in yet. Chang sets are welcome.
|
### Matrix Authentication Service (MAS)
|
||||||
|
|
||||||
|
[MAS](https://element-hq.github.io/matrix-authentication-service/) is Element’s OAuth/OIDC-native auth service for Matrix: it handles login, tokens, and upstream IdPs while Synapse delegates authentication via `matrix_authentication_service`.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **If you plan to migrate an existing homeserver with `syn2mas`:** deploy and configure MAS as below, but **leave `MAS_ENABLED=1` commented** until migration and cutover are done, so Synapse keeps using your current login path until you intentionally switch. You cannot use Synapse legacy OIDC/Keycloak SSO alongside MAS; plan IdP apps and envs accordingly.
|
||||||
|
|
||||||
|
**Enable the stack:**
|
||||||
|
|
||||||
|
- In `.env`, uncomment `compose.mas.yml` (and `compose.mas-upstream.yml` plus upstream envs if you use an external IdP), and uncomment the `SECRET_MAS_*` version lines.
|
||||||
|
- `abra app secret generate YOURAPPDOMAIN`
|
||||||
|
- `abra app cmd -l YOURAPPDOMAIN generate_mas_signing_rsa` — generates and inserts the PEM RSA key for `SECRET_MAS_SIGNING_RSA_VERSION`. Requires `openssl` on the local machine.
|
||||||
|
- `abra app cmd YOURAPPDOMAIN db ensure_mas_database` (once, creates the `mas` database in Postgres)
|
||||||
|
- `abra app deploy YOURAPPDOMAIN`
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Migrating an existing server (<code>syn2mas</code>)</strong></summary>
|
||||||
|
|
||||||
|
Requires PostgreSQL on Synapse and a dedicated MAS database. Backup Postgres (and configs) before you start. Official background: [MAS migration guide](https://element-hq.github.io/matrix-authentication-service/setup/migration.html).
|
||||||
|
|
||||||
|
1. **Prepare (Synapse still running):** With MAS in `COMPOSE_FILE` but **`MAS_ENABLED` still off**, deploy, then run checks from your machine:
|
||||||
|
```bash
|
||||||
|
abra app cmd YOURAPPDOMAIN prepare_mas_migration
|
||||||
|
```
|
||||||
|
This fetches rendered `homeserver.yaml` into the MAS container, runs `syn2mas check`, then `migrate --dry-run` (the dry run rolls back MAS data at the end). The file stays in the MAS container until next restart, so you can repeat this step to provide the file for the actual migration.
|
||||||
|
|
||||||
|
2. **Optional snapshot:** save a copy of the rendered config while `app` is up, e.g. `abra app run -t YOURAPPDOMAIN app cat /data/homeserver.yaml > homeserver.snapshot.yaml`.
|
||||||
|
|
||||||
|
3. **Downtime — stop Synapse:** run on the **host** with Docker/Swarm access (not inside a container), e.g.:
|
||||||
|
```bash
|
||||||
|
docker service scale <STACK_NAME>_app=0
|
||||||
|
```
|
||||||
|
Use the real service name from `docker service ls` (suffix `_app`).
|
||||||
|
|
||||||
|
4. **Migration:** with MAS still running and Synapse at zero replicas, run `run_mas_migration` from your machine. The homeserver snapshot at `/tmp/homeserver.yaml` in `mas` must still be present from step 1.
|
||||||
|
```bash
|
||||||
|
abra app cmd YOURAPPDOMAIN run_mas_migration
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Cutover:** in `.env`, set `MAS_ENABLED=1`, `PASSWORD_LOGIN_ENABLED=false`, remove legacy Keycloak/SSO envs, then `abra app deploy YOURAPPDOMAIN` (Synapse comes back with MAS delegation). `syn2mas` does not write to the Synapse database; if you abort before serving traffic through MAS, you can often drop and recreate the MAS DB and revert env.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Bridges
|
||||||
|
For all Bridges:
|
||||||
|
- Setting it up is a bit of a chicken/egg & chasing cats moment.
|
||||||
|
- Make sure to uncomment `APP_SERVICES_ENABLED`, `HOMESERVER_URL`, `HOMESERVER_DOMAIN`, `compose.shared_secret_auth.yml`, `SHARED_SECRET_AUTH_ENABLED` and `SECRET_SHARED_SECRET_AUTH_VERSION`
|
||||||
|
- include the registration in synapse, e.g. `APP_SERVICE_CONFIGS="[\"/telegram-data/registration.yaml\"]"`
|
||||||
|
- and set yourself as admin, e.g.: `TELEGRAM_BRIDGE_PERMISSIONS="{ \"*\": \"relaybot\", \"@akadmin:example.com\": \"admin\"}"`
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> The shared secret authenticator may break when matrix-synapse uses a newer python version with an error stating something like "module not found". You have to fix the path in the compose.shared_secret_auth.yml like [here](https://git.coopcloud.tech/coop-cloud/matrix-synapse/commit/3d1350533079ce1ad3bea92039fe003684589b95)
|
||||||
|
|
||||||
|
### Telegram bridging
|
||||||
|
|
||||||
|
You need to get your bot setup on the telegram side first by creating a [telegram app](https://my.telegram.org/apps) and a [telegram bot](https://docs.mau.fi/bridges/python/telegram/relay-bot.html#setup) and have these values:
|
||||||
|
|
||||||
|
```
|
||||||
|
api_id: ...
|
||||||
|
api_hash: ...
|
||||||
|
telegram_bot_token: ...
|
||||||
|
```
|
||||||
|
Experimental script for a automated token replacement:
|
||||||
|
```
|
||||||
|
DOMAIN=<domain>
|
||||||
|
abra app secret insert $DOMAIN telegram_api_hash v1 <secret>
|
||||||
|
abra app secret insert $DOMAIN telegram_bot_token v1 <secret>
|
||||||
|
abra app secret generate -a $DOMAIN
|
||||||
|
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
abra app cmd -l $DOMAIN set_bridge_tokens telegram
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively a manual guide for the necessary steps:
|
||||||
|
|
||||||
|
```
|
||||||
|
DOMAIN=<domain>
|
||||||
|
abra app secret insert $DOMAIN telegram_api_hash v1 <secret>
|
||||||
|
abra app secret insert $DOMAIN telegram_bot_token v1 <secret>
|
||||||
|
abra app secret generate -a $DOMAIN
|
||||||
|
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
abra app run $DOMAIN telegrambridge cat /data/registration.yaml
|
||||||
|
abra app undeploy $DOMAIN
|
||||||
|
|
||||||
|
abra app secret rm $DOMAIN telegram_as_token
|
||||||
|
abra app secret insert $DOMAIN telegram_as_token v1 <secret>
|
||||||
|
|
||||||
|
abra app secret rm $DOMAIN telegram_hs_token
|
||||||
|
abra app secret insert $DOMAIN telegram_hs_token v1 <secret>
|
||||||
|
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
```
|
||||||
|
|
||||||
|
Some helpful documentation:
|
||||||
|
|
||||||
|
- [`docs.mau.fi`](https://docs.mau.fi/bridges/python/setup/docker.html?bridge=telegram)
|
||||||
|
- [`example-config.yaml`](https://mau.dev/mautrix/telegram/-/blob/master/mautrix_telegram/example-config.yaml)
|
||||||
|
|
||||||
|
### Discord bridging
|
||||||
|
|
||||||
|
> WIP docs
|
||||||
|
|
||||||
|
Just as messy as the Telegram bridging above! Rough guide:
|
||||||
|
|
||||||
|
- get a local copy of [`config.yaml`](https://github.com/matrix-org/matrix-appservice-discord/blob/develop/config/config.sample.yaml)
|
||||||
|
- fill it out with the values you need, all the discord token stuff, etc.
|
||||||
|
- run `mkdir -p data && cp config.yaml data/` then `docker run --rm -v data:/data halfshot/matrix-appservice-discord:v1.0.0 sh -c "cd /data && node /build/src/discordas.js -r -u "http://discordbridge:9005" -c config.yaml"`
|
||||||
|
- this generates the app service registration configuration you need to feed to the homeserver
|
||||||
|
- run secret generation for the `discord_db_password`, insert your `discord_bot_token`
|
||||||
|
- run `abra app cp <domain> discord-registration.yaml app:/discord-data` (it has to be called `discord-registration.yaml`)
|
||||||
|
- deploy the bridge & happy hacking
|
||||||
|
|
||||||
|
Some helpful documentation:
|
||||||
|
|
||||||
|
- [`matrix-org/matrix-appservice-discord` docs](https://github.com/matrix-org/matrix-appservice-discord#bridging-a-room)
|
||||||
|
- [`t2bot.io/discord`](https://t2bot.io/discord/)
|
||||||
|
|
||||||
|
### Signal bridging
|
||||||
|
|
||||||
|
Experimental script for a more automated token replacement:
|
||||||
|
```
|
||||||
|
DOMAIN=<domain>
|
||||||
|
abra app secret generate -a $DOMAIN
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
abra app cmd -l $DOMAIN set_bridge_tokens signal
|
||||||
|
```
|
||||||
|
Alternatively a manual guide for the necessary steps:
|
||||||
|
```
|
||||||
|
DOMAIN=<domain>
|
||||||
|
abra app secret insert $DOMAIN signal_hs_token v1 foo
|
||||||
|
abra app secret insert $DOMAIN signal_as_token v1 foo
|
||||||
|
abra app secret generate $DOMAIN -a
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
abra app run $DOMAIN signalbridge cat /data/registration.yaml
|
||||||
|
|
||||||
|
abra app secret rm $DOMAIN signal_as_token
|
||||||
|
abra app secret insert $DOMAIN signal_as_token v1 <secret>
|
||||||
|
abra app secret rm $DOMAIN signal_hs_token
|
||||||
|
abra app secret insert $DOMAIN signal_hs_token v1 <secret>
|
||||||
|
|
||||||
|
abra app deploy $DOMAIN
|
||||||
|
```
|
||||||
|
|
||||||
|
- message `@signalbot:example.com` to test
|
||||||
|
- See the [docs](https://docs.mau.fi/bridges/go/signal/authentication.html) for authentication
|
||||||
|
|||||||
355
abra.sh
355
abra.sh
@ -1,3 +1,354 @@
|
|||||||
export ENTRYPOINT_CONF_VERSION=v1
|
export DISCORD_BRIDGE_YAML_VERSION=v2
|
||||||
export HOMESERVER_YAML_VERSION=v3
|
export ENTRYPOINT_CONF_VERSION=v3
|
||||||
|
export HOMESERVER_YAML_VERSION=v37
|
||||||
export LOG_CONFIG_VERSION=v2
|
export LOG_CONFIG_VERSION=v2
|
||||||
|
export SHARED_SECRET_AUTH_VERSION=v2
|
||||||
|
export SIGNAL_BRIDGE_YAML_VERSION=v6
|
||||||
|
export TELEGRAM_BRIDGE_YAML_VERSION=v6
|
||||||
|
export NGINX_CONFIG_VERSION=v13
|
||||||
|
export WK_SERVER_VERSION=v1
|
||||||
|
export WK_CLIENT_VERSION=v2
|
||||||
|
export MAS_CONFIG_VERSION=v2
|
||||||
|
export PG_BACKUP_VERSION=v2
|
||||||
|
export ADMIN_CONFIG_VERSION=v1
|
||||||
|
export COMPRESS_STATE_ENTRYPOINT_VERSION=v5
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Database maintenance — shrink a bloated Synapse database
|
||||||
|
#
|
||||||
|
# See https://levans.fr/shrink-synapse-database.html
|
||||||
|
#
|
||||||
|
# Recommended steps to reclaim disk space:
|
||||||
|
# 1. abra app cmd <domain> compress-state run_compressor 500 10000
|
||||||
|
# (compress redundant state — safe while Synapse is running)
|
||||||
|
# 2. abra app cmd <domain> db reindex
|
||||||
|
# (rebuild indexes — stop Synapse first)
|
||||||
|
# 3. abra app cmd <domain> db vacuum_full
|
||||||
|
# (rewrite tables and reclaim disk — stop Synapse first)
|
||||||
|
#
|
||||||
|
# Diagnostic commands (safe to run anytime):
|
||||||
|
# abra app cmd <domain> db db_size
|
||||||
|
# abra app cmd <domain> db state_bloat
|
||||||
|
# abra app cmd <domain> db empty_rooms
|
||||||
|
#
|
||||||
|
# Purge commands (require an admin token):
|
||||||
|
# abra app cmd <domain> app register_admin <user> <pass>
|
||||||
|
# abra app cmd <domain> app get_token <user> <pass>
|
||||||
|
# abra app cmd <domain> app purge_remote_media <days> <token>
|
||||||
|
# abra app cmd <domain> app purge_empty_rooms <token>
|
||||||
|
# abra app cmd <domain> app purge_room <room_id> <token>
|
||||||
|
# abra app cmd <domain> app purge_history <room_id> <days> <token>
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# --- Diagnostics (db) ---
|
||||||
|
|
||||||
|
db_size() {
|
||||||
|
echo "=== Database size ==="
|
||||||
|
psql -U synapse -d synapse -c "SELECT pg_size_pretty(pg_database_size('synapse')) AS db_size;"
|
||||||
|
echo ""
|
||||||
|
echo "=== Top 10 largest tables ==="
|
||||||
|
psql -U synapse -d synapse -c "
|
||||||
|
SELECT nspname || '.' || relname AS table,
|
||||||
|
pg_size_pretty(pg_total_relation_size(C.oid)) AS total_size
|
||||||
|
FROM pg_class C
|
||||||
|
LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
|
||||||
|
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
|
||||||
|
ORDER BY pg_total_relation_size(C.oid) DESC
|
||||||
|
LIMIT 10;"
|
||||||
|
}
|
||||||
|
|
||||||
|
state_bloat() {
|
||||||
|
echo "=== Rooms with most state bloat ==="
|
||||||
|
psql -U synapse -d synapse -c "
|
||||||
|
SELECT room_id, count(*) AS state_entries
|
||||||
|
FROM state_groups_state
|
||||||
|
GROUP BY room_id
|
||||||
|
ORDER BY state_entries DESC
|
||||||
|
LIMIT 20;"
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_rooms() {
|
||||||
|
echo "=== Rooms with no local members ==="
|
||||||
|
psql -U synapse -d synapse -c "
|
||||||
|
SELECT room_id, room_version
|
||||||
|
FROM rooms
|
||||||
|
WHERE room_id NOT IN (
|
||||||
|
SELECT room_id FROM local_current_membership WHERE membership = 'join'
|
||||||
|
);"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Compression (compress-state) ---
|
||||||
|
|
||||||
|
run_compressor() {
|
||||||
|
CHUNK_SIZE="${1:-${STATE_COMPRESS_CHUNK_SIZE:-500}}"
|
||||||
|
CHUNKS="${2:-${STATE_COMPRESS_CHUNKS:-100}}"
|
||||||
|
DB_PASS=$(cat /run/secrets/db_password)
|
||||||
|
echo "Running synapse_auto_compressor (chunk_size=$CHUNK_SIZE, chunks=$CHUNKS)..."
|
||||||
|
/build/synapse_auto_compressor \
|
||||||
|
-p "postgresql://synapse:${DB_PASS}@db:5432/synapse" \
|
||||||
|
-c "$CHUNK_SIZE" -n "$CHUNKS"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Maintenance (db) — stop Synapse before running these ---
|
||||||
|
|
||||||
|
reindex() {
|
||||||
|
echo "WARNING: REINDEX locks tables. Synapse should be stopped before running this."
|
||||||
|
echo "Running REINDEX on synapse database..."
|
||||||
|
psql -U synapse -d synapse -c "REINDEX (VERBOSE) DATABASE synapse;"
|
||||||
|
echo "REINDEX complete."
|
||||||
|
psql -U synapse -d synapse -c "SELECT pg_size_pretty(pg_database_size('synapse')) AS db_size;"
|
||||||
|
}
|
||||||
|
|
||||||
|
vacuum_full() {
|
||||||
|
echo "WARNING: VACUUM FULL locks tables and requires temporary disk space."
|
||||||
|
echo "Synapse should be stopped before running this."
|
||||||
|
echo "Running VACUUM FULL on synapse database..."
|
||||||
|
psql -U synapse -d synapse -c "VACUUM FULL;"
|
||||||
|
echo "VACUUM FULL complete."
|
||||||
|
psql -U synapse -d synapse -c "SELECT pg_size_pretty(pg_database_size('synapse')) AS db_size;"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Purge commands (app) — require an admin access token ---
|
||||||
|
|
||||||
|
register_admin() {
|
||||||
|
USER="${1}"
|
||||||
|
PASS="${2}"
|
||||||
|
if [ -z "$USER" ] || [ -z "$PASS" ]; then
|
||||||
|
echo "Usage: register_admin <username> <password>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
register_new_matrix_user -u "$USER" -p "$PASS" -a -c /data/homeserver.yaml http://localhost:8008
|
||||||
|
}
|
||||||
|
|
||||||
|
get_token() {
|
||||||
|
USER="${1}"
|
||||||
|
PASS="${2}"
|
||||||
|
if [ -z "$USER" ] || [ -z "$PASS" ]; then
|
||||||
|
echo "Usage: get_token <username> <password>"
|
||||||
|
echo "Returns an admin access token for use with purge commands."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
curl -s -X POST "http://localhost:8008/_matrix/client/r0/login" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"type\":\"m.login.password\",\"user\":\"$USER\",\"password\":\"$PASS\"}" \
|
||||||
|
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('access_token', d.get('error', 'unknown error')))"
|
||||||
|
}
|
||||||
|
|
||||||
|
purge_remote_media() {
|
||||||
|
DAYS="${1:-30}"
|
||||||
|
TOKEN="${2}"
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
echo "Usage: purge_remote_media <days> <admin_token>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
BEFORE_TS=$(( $(date +%s) * 1000 - DAYS * 86400000 ))
|
||||||
|
echo "Purging remote media older than $DAYS days..."
|
||||||
|
curl -s -X POST "http://localhost:8008/_synapse/admin/v1/purge_media_cache?before_ts=$BEFORE_TS" \
|
||||||
|
-H "Authorization: Bearer $TOKEN"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
purge_room() {
|
||||||
|
ROOM_ID="${1}"
|
||||||
|
TOKEN="${2}"
|
||||||
|
if [ -z "$ROOM_ID" ] || [ -z "$TOKEN" ]; then
|
||||||
|
echo "Usage: purge_room <room_id> <admin_token>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "Purging room $ROOM_ID..."
|
||||||
|
curl -s -X DELETE "http://localhost:8008/_synapse/admin/v1/rooms/$ROOM_ID" \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"purge": true}'
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
purge_history() {
|
||||||
|
ROOM_ID="${1}"
|
||||||
|
DAYS="${2:-90}"
|
||||||
|
TOKEN="${3}"
|
||||||
|
if [ -z "$ROOM_ID" ] || [ -z "$TOKEN" ]; then
|
||||||
|
echo "Usage: purge_history <room_id> <days> <admin_token>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
BEFORE_TS=$(( $(date +%s) * 1000 - DAYS * 86400000 ))
|
||||||
|
echo "Purging history older than $DAYS days from $ROOM_ID..."
|
||||||
|
curl -s -X POST "http://localhost:8008/_synapse/admin/v1/purge_history/$ROOM_ID" \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"purge_up_to_ts\": $BEFORE_TS}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
purge_empty_rooms() {
|
||||||
|
TOKEN="${1}"
|
||||||
|
if [ -z "$TOKEN" ]; then
|
||||||
|
echo "Usage: purge_empty_rooms <admin_token>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "Fetching rooms with no local members..."
|
||||||
|
ROOMS=$(curl -s "http://localhost:8008/_synapse/admin/v1/rooms?limit=1000" \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
| python3 -c "
|
||||||
|
import sys, json
|
||||||
|
data = json.load(sys.stdin)
|
||||||
|
for r in data.get('rooms', []):
|
||||||
|
if r.get('joined_local_members', 0) == 0:
|
||||||
|
print(r['room_id'])
|
||||||
|
")
|
||||||
|
COUNT=$(echo "$ROOMS" | grep -c '.' || true)
|
||||||
|
echo "Found $COUNT empty rooms."
|
||||||
|
if [ "$COUNT" -eq 0 ]; then
|
||||||
|
echo "Nothing to purge."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "$ROOMS"
|
||||||
|
echo ""
|
||||||
|
echo "Purging..."
|
||||||
|
for ROOM_ID in $ROOMS; do
|
||||||
|
echo " Purging $ROOM_ID"
|
||||||
|
curl -s -X DELETE "http://localhost:8008/_synapse/admin/v1/rooms/$ROOM_ID" \
|
||||||
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"purge": true}' > /dev/null
|
||||||
|
done
|
||||||
|
echo "Done."
|
||||||
|
}
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Other commands
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
ensure_mas_database () {
|
||||||
|
if ! psql -U synapse -d postgres -v ON_ERROR_STOP=1 -Atqc "SELECT 1 FROM pg_database WHERE datname = 'mas'" | grep -qx 1
|
||||||
|
then
|
||||||
|
psql -U synapse -d postgres -v ON_ERROR_STOP=1 -c "CREATE DATABASE mas OWNER synapse"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a PEM RSA private key and insert it as the MAS signing secret.
|
||||||
|
# `abra app secret generate` can only produce random hex/charset strings, so this
|
||||||
|
# secret is marked `generate=false` in .env.sample and handled here instead.
|
||||||
|
generate_mas_signing_rsa() {
|
||||||
|
if ! command -v openssl &> /dev/null; then
|
||||||
|
echo "openssl is required on your local machine to generate the MAS signing key."
|
||||||
|
echo "It could not be found in your PATH, please install openssl to proceed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KEY=$(openssl genrsa 2048 2>/dev/null)
|
||||||
|
if [ -z "$KEY" ]; then
|
||||||
|
echo "Failed to generate RSA private key with openssl."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if printf '%s\n' "$KEY" | abra app secret insert -C "$APP_NAME" mas_signing_rsa v1; then
|
||||||
|
echo "MAS signing RSA key generated and inserted as v1."
|
||||||
|
else
|
||||||
|
echo "Failed to insert MAS signing RSA key."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local helper: fetch homeserver.yaml from app, push to mas, then syn2mas check + dry-run.
|
||||||
|
prepare_mas_migration () {
|
||||||
|
local syn_cfg
|
||||||
|
|
||||||
|
syn_cfg=/tmp/homeserver.yaml
|
||||||
|
|
||||||
|
cleanup_prepare_mas_migration() {
|
||||||
|
rm -f "homeserver.yaml"
|
||||||
|
}
|
||||||
|
trap cleanup_prepare_mas_migration EXIT
|
||||||
|
|
||||||
|
echo "Fetching /data/homeserver.yaml from app to homeserver.yaml (abra app run … cat)..."
|
||||||
|
if ! abra app run -t "$DOMAIN" app cat /data/homeserver.yaml > "homeserver.yaml"
|
||||||
|
then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ ! -s "homeserver.yaml" ]; then
|
||||||
|
echo "Error: fetched homeserver.yaml is empty." >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Copying into mas:/tmp"
|
||||||
|
abra app cp "$DOMAIN" "homeserver.yaml" "mas:/tmp" || return 1
|
||||||
|
|
||||||
|
echo "Running mas-cli syn2mas check..."
|
||||||
|
abra app run -t "$DOMAIN" mas -- mas-cli syn2mas check \
|
||||||
|
--config /etc/mas/config.yaml \
|
||||||
|
--synapse-config "$syn_cfg" || return 1
|
||||||
|
|
||||||
|
echo "Running mas-cli syn2mas migrate --dry-run..."
|
||||||
|
abra app run -t "$DOMAIN" mas -- mas-cli syn2mas migrate \
|
||||||
|
--config /etc/mas/config.yaml \
|
||||||
|
--synapse-config "$syn_cfg" \
|
||||||
|
--dry-run || return 1
|
||||||
|
|
||||||
|
trap - EXIT
|
||||||
|
cleanup_prepare_mas_migration
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Next migration step: stop Synapse (downtime) ==="
|
||||||
|
echo "Run on a host whose Docker CLI targets this Swarm (same machine you use for 'abra app deploy')."
|
||||||
|
if [ -n "${STACK_NAME:-}" ]; then
|
||||||
|
echo " docker service scale ${STACK_NAME}_app=0"
|
||||||
|
else
|
||||||
|
echo "STACK_NAME is not set here; resolve the Synapse service name with 'docker service ls' on that host, then:"
|
||||||
|
echo "docker service scale <STACK_NAME>_app=0"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run syn2mas migrate for real (writes MAS data). Run from your operator machine as MAS image is distroless.
|
||||||
|
# Requires /tmp/homeserver.yaml in the mas container (e.g. from prepare_mas_migration) and
|
||||||
|
# Synapse scaled down before migrate.
|
||||||
|
run_mas_migration () {
|
||||||
|
local syn_cfg=/tmp/homeserver.yaml
|
||||||
|
|
||||||
|
echo "Running mas-cli syn2mas migrate in mas via abra app run..."
|
||||||
|
abra app run -t "$DOMAIN" mas -- mas-cli syn2mas migrate \
|
||||||
|
--config /etc/mas/config.yaml \
|
||||||
|
--synapse-config "$syn_cfg"
|
||||||
|
}
|
||||||
|
|
||||||
|
set_admin () {
|
||||||
|
admin=akadmin
|
||||||
|
if [ -n "$1" ]
|
||||||
|
then
|
||||||
|
admin=$1
|
||||||
|
fi
|
||||||
|
psql -U synapse -c "UPDATE users SET admin = 1 WHERE name = '@$admin:$DOMAIN'";
|
||||||
|
}
|
||||||
|
|
||||||
|
set_bridge_tokens() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Error: Missing parameter. Usage: set_bridge_tokens <BRIDGETYPE>"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
BRIDGETYPE=$1
|
||||||
|
echo "retrieve tokens from registration.yaml..."
|
||||||
|
output=$(abra app run $DOMAIN app cat /${BRIDGETYPE}-data/registration.yaml)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Error: Failed to retrieve registration.yaml for ${BRIDGETYPE} bridge:"
|
||||||
|
echo "$output"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
hs_token=$(echo "$output" | sed -n 's/^hs_token:[[:space:]]*\(.*\)$/\1/p')
|
||||||
|
as_token=$(echo "$output" | sed -n 's/^as_token:[[:space:]]*\(.*\)$/\1/p')
|
||||||
|
|
||||||
|
echo "HS Token: $hs_token"
|
||||||
|
echo "AS Token: $as_token"
|
||||||
|
echo "UNDEPLOY $DOMAIN?"
|
||||||
|
abra app undeploy $DOMAIN
|
||||||
|
|
||||||
|
echo "Replacing tokens:"
|
||||||
|
abra app secret rm $DOMAIN ${BRIDGETYPE}_as_token
|
||||||
|
abra app secret insert $DOMAIN ${BRIDGETYPE}_as_token v1 $as_token
|
||||||
|
abra app secret rm $DOMAIN ${BRIDGETYPE}_hs_token
|
||||||
|
abra app secret insert $DOMAIN ${BRIDGETYPE}_hs_token v1 $hs_token
|
||||||
|
|
||||||
|
echo "Redeploying $DOMAIN..."
|
||||||
|
abra app deploy -n $DOMAIN
|
||||||
|
}
|
||||||
|
|||||||
3
admin.conf.tmpl
Normal file
3
admin.conf.tmpl
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"restrictBaseUrl": "https://{{ env "DOMAIN" }}"
|
||||||
|
}
|
||||||
15
alaconnect.yml
Normal file
15
alaconnect.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
authentik:
|
||||||
|
env:
|
||||||
|
KEYCLOAK_ID: authentik
|
||||||
|
KEYCLOAK_NAME: sso
|
||||||
|
KEYCLOAK_URL: https://authentik.example.com/application/o/matrix/
|
||||||
|
KEYCLOAK_CLIENT_DOMAIN: https://element-web.example.com
|
||||||
|
KEYCLOAK_ALLOW_EXISTING_USERS: "true"
|
||||||
|
KEYCLOAK_CLIENT_ID: matrix
|
||||||
|
uncomment:
|
||||||
|
- compose.keycloak.yml
|
||||||
|
- KEYCLOAK_ENABLED
|
||||||
|
- KEYCLOAK_CLIENT_ID
|
||||||
|
- SECRET_KEYCLOAK_CLIENT_SECRET_VERSION
|
||||||
|
shared_secrets:
|
||||||
|
matrix_secret: keycloak_client_secret
|
||||||
46
compose.admin.yml
Normal file
46
compose.admin.yml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
admin:
|
||||||
|
image: awesometechnologies/synapse-admin:0.11.4
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.swarm.network=proxy"
|
||||||
|
- "traefik.http.services.${STACK_NAME}_admin.loadbalancer.server.port=80"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}_admin.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})&&PathPrefix(`/admin`)"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}_admin.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}_admin.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}_admin.middlewares=admin,admin_path"
|
||||||
|
- "traefik.http.middlewares.admin.redirectregex.regex=^(.*)/admin/?"
|
||||||
|
- "traefik.http.middlewares.admin.redirectregex.replacement=$${1}/admin/"
|
||||||
|
- "traefik.http.middlewares.admin_path.stripprefix.prefixes=/admin"
|
||||||
|
environment:
|
||||||
|
- DOMAIN
|
||||||
|
configs:
|
||||||
|
- source: admin_config
|
||||||
|
target: /app/config.json
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 10
|
||||||
|
start_period: 1m
|
||||||
|
web:
|
||||||
|
environment:
|
||||||
|
- ADMIN_INTERFACE_ENABLED
|
||||||
|
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
configs:
|
||||||
|
admin_config:
|
||||||
|
name: ${STACK_NAME}_admin_config_${ADMIN_CONFIG_VERSION}
|
||||||
|
file: admin.conf.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
|
||||||
31
compose.compress-state.yml
Normal file
31
compose.compress-state.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
compress-state:
|
||||||
|
image: rust:1-alpine
|
||||||
|
entrypoint: /compress_state_entrypoint.sh
|
||||||
|
environment:
|
||||||
|
- STATE_COMPRESS_CHUNK_SIZE=${STATE_COMPRESS_CHUNK_SIZE:-500}
|
||||||
|
- STATE_COMPRESS_CHUNKS=${STATE_COMPRESS_CHUNKS:-100}
|
||||||
|
- STATE_COMPRESS_SCHEDULE=${STATE_COMPRESS_SCHEDULE:-0 3 * * *}
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
configs:
|
||||||
|
- source: compress_entrypoint
|
||||||
|
target: /compress_state_entrypoint.sh
|
||||||
|
mode: 0555
|
||||||
|
volumes:
|
||||||
|
- compress_state_build:/build
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
compress_state_build:
|
||||||
|
|
||||||
|
configs:
|
||||||
|
compress_entrypoint:
|
||||||
|
name: ${STACK_NAME}_compress_ep_${COMPRESS_STATE_ENTRYPOINT_VERSION}
|
||||||
|
file: compress_state_entrypoint.sh
|
||||||
66
compose.discord.yml
Normal file
66
compose.discord.yml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- APP_SERVICES_ENABLED
|
||||||
|
- APP_SERVICE_CONFIGS
|
||||||
|
volumes:
|
||||||
|
- discord-data:/discord-data
|
||||||
|
|
||||||
|
discordbridge:
|
||||||
|
image: halfshot/matrix-appservice-discord:v1.0.0
|
||||||
|
depends_on:
|
||||||
|
- discorddb
|
||||||
|
configs:
|
||||||
|
- source: discord_bridge_yaml
|
||||||
|
target: /data/config.yaml
|
||||||
|
environment:
|
||||||
|
- DISCORD_CLIENT_ID
|
||||||
|
- DISCORD_BRIDGE_ADMIN
|
||||||
|
- HOMESERVER_DOMAIN
|
||||||
|
- HOMESERVER_URL
|
||||||
|
secrets:
|
||||||
|
- discord_bot_token
|
||||||
|
- discord_db_password
|
||||||
|
volumes:
|
||||||
|
- discord-data:/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
discorddb:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
secrets:
|
||||||
|
- discord_db_password
|
||||||
|
environment:
|
||||||
|
- LC_COLLATE=C
|
||||||
|
- LC_CTYPE=C
|
||||||
|
- POSTGRES_DB=discordbridge
|
||||||
|
- POSTGRES_INITDB_ARGS="-E \"UTF8\""
|
||||||
|
- POSTGRES_PASSWORD_FILE=/run/secrets/discord_db_password
|
||||||
|
- POSTGRES_USER=discordbridge
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "$POSTGRES_USER" ]
|
||||||
|
volumes:
|
||||||
|
- discord-postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
configs:
|
||||||
|
discord_bridge_yaml:
|
||||||
|
name: ${STACK_NAME}_discord_bridge_yaml_${DISCORD_BRIDGE_YAML_VERSION}
|
||||||
|
file: discord_bridge.yaml.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
discord-data:
|
||||||
|
discord-postgres:
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
discord_db_password:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_discord_db_password_${SECRET_DISCORD_DB_PASSWORD_VERSION}
|
||||||
|
discord_bot_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_discord_bot_token_${SECRET_DISCORD_BOT_TOKEN_VERSION}
|
||||||
@ -7,14 +7,16 @@ services:
|
|||||||
- db_password
|
- db_password
|
||||||
- form_secret
|
- form_secret
|
||||||
- keycloak_client_secret
|
- keycloak_client_secret
|
||||||
- macaroon_secret_key
|
- macaroon
|
||||||
- registration_shared_secret
|
- registration
|
||||||
environment:
|
environment:
|
||||||
- KEYCLOAK_CLIENT_DOMAIN
|
- KEYCLOAK_CLIENT_DOMAIN
|
||||||
- KEYCLOAK_CLIENT_ID
|
- KEYCLOAK_CLIENT_ID
|
||||||
- KEYCLOAK_ENABLED
|
- KEYCLOAK_ENABLED
|
||||||
- KEYCLOAK_NAME
|
- KEYCLOAK_NAME
|
||||||
|
- KEYCLOAK_ID
|
||||||
- KEYCLOAK_URL
|
- KEYCLOAK_URL
|
||||||
|
- KEYCLOAK_ALLOW_EXISTING_USERS
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
keycloak_client_secret:
|
keycloak_client_secret:
|
||||||
|
|||||||
19
compose.keycloak2.yml
Normal file
19
compose.keycloak2.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
secrets:
|
||||||
|
- keycloak2_client_secret
|
||||||
|
environment:
|
||||||
|
- KEYCLOAK2_ALLOW_EXISTING_USERS
|
||||||
|
- KEYCLOAK2_CLIENT_ID
|
||||||
|
- KEYCLOAK2_ENABLED
|
||||||
|
- KEYCLOAK2_ID
|
||||||
|
- KEYCLOAK2_NAME
|
||||||
|
- KEYCLOAK2_URL
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
keycloak2_client_secret:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_keycloak2_client_secret_${SECRET_KEYCLOAK2_CLIENT_SECRET_VERSION}
|
||||||
19
compose.keycloak3.yml
Normal file
19
compose.keycloak3.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
secrets:
|
||||||
|
- keycloak3_client_secret
|
||||||
|
environment:
|
||||||
|
- KEYCLOAK3_ALLOW_EXISTING_USERS
|
||||||
|
- KEYCLOAK3_CLIENT_ID
|
||||||
|
- KEYCLOAK3_ENABLED
|
||||||
|
- KEYCLOAK3_ID
|
||||||
|
- KEYCLOAK3_NAME
|
||||||
|
- KEYCLOAK3_URL
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
keycloak3_client_secret:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_keycloak3_client_secret_${SECRET_KEYCLOAK3_CLIENT_SECRET_VERSION}
|
||||||
21
compose.mas-upstream.yml
Normal file
21
compose.mas-upstream.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
# Upstream OIDC provider for MAS (e.g. Authentik, Keycloak).
|
||||||
|
# Requires compose.mas.yml. Adds the client secret and env vars needed by mas.config.yaml.tmpl.
|
||||||
|
|
||||||
|
services:
|
||||||
|
mas:
|
||||||
|
environment:
|
||||||
|
- MAS_UPSTREAM_PROVIDER_ID
|
||||||
|
- MAS_UPSTREAM_ISSUER
|
||||||
|
- MAS_UPSTREAM_CLIENT_ID
|
||||||
|
- MAS_UPSTREAM_HUMAN_NAME
|
||||||
|
- MAS_UPSTREAM_SYNAPSE_IDP_ID
|
||||||
|
secrets:
|
||||||
|
- mas_upstream_client
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
mas_upstream_client:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_mas_upstream_client_${SECRET_MAS_UPSTREAM_CLIENT_VERSION}
|
||||||
64
compose.mas.yml
Normal file
64
compose.mas.yml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
# Matrix Authentication Service (MAS) — optional overlay for Element X / OIDC-native auth.
|
||||||
|
|
||||||
|
services:
|
||||||
|
mas:
|
||||||
|
image: ghcr.io/element-hq/matrix-authentication-service:1.19.0
|
||||||
|
command: ["server", "--config=/etc/mas/config.yaml"]
|
||||||
|
environment:
|
||||||
|
- DOMAIN
|
||||||
|
- SERVER_NAME
|
||||||
|
- STACK_NAME
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
configs:
|
||||||
|
- source: mas_config
|
||||||
|
target: /etc/mas/config.yaml
|
||||||
|
secrets:
|
||||||
|
- db_password
|
||||||
|
- mas_encryption
|
||||||
|
- mas_synapse_shared
|
||||||
|
- mas_signing_rsa
|
||||||
|
# Official image is distroless (no curl/wget); upstream suggests `mas-cli config check` for probes.
|
||||||
|
# See https://github.com/element-hq/matrix-authentication-service/issues/3741 — validates config, not HTTP.
|
||||||
|
# GET /health is still served (resource `health` in mas.config.yaml.tmpl) for probes from other images.
|
||||||
|
healthcheck:
|
||||||
|
test:
|
||||||
|
[
|
||||||
|
"CMD",
|
||||||
|
"/usr/local/bin/mas-cli",
|
||||||
|
"--config",
|
||||||
|
"/etc/mas/config.yaml",
|
||||||
|
"config",
|
||||||
|
"check",
|
||||||
|
]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
|
||||||
|
app:
|
||||||
|
secrets:
|
||||||
|
- mas_synapse_shared
|
||||||
|
|
||||||
|
configs:
|
||||||
|
mas_config:
|
||||||
|
name: ${STACK_NAME}_mas_config_${MAS_CONFIG_VERSION}
|
||||||
|
file: mas.config.yaml.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
mas_encryption:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_mas_encryption_${SECRET_MAS_ENCRYPTION_VERSION}
|
||||||
|
mas_synapse_shared:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_mas_synapse_shared_${SECRET_MAS_SYNAPSE_SHARED_VERSION}
|
||||||
|
mas_signing_rsa:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_mas_signing_rsa_${SECRET_MAS_SIGNING_RSA_VERSION}
|
||||||
22
compose.shared_secret_auth.yml
Normal file
22
compose.shared_secret_auth.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- SHARED_SECRET_AUTH_ENABLED
|
||||||
|
secrets:
|
||||||
|
- shared_secret_auth
|
||||||
|
configs:
|
||||||
|
- source: shared_secret_auth
|
||||||
|
target: /usr/local/lib/python3.13/site-packages/shared_secret_authenticator.py
|
||||||
|
|
||||||
|
configs:
|
||||||
|
shared_secret_auth:
|
||||||
|
name: ${STACK_NAME}_shared_secret_auth_${SHARED_SECRET_AUTH_VERSION}
|
||||||
|
file: shared_secret_authenticator.py
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
shared_secret_auth:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_shared_secret_auth_${SECRET_SHARED_SECRET_AUTH_VERSION}
|
||||||
86
compose.signal.yml
Normal file
86
compose.signal.yml
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- APP_SERVICES_ENABLED
|
||||||
|
- APP_SERVICE_CONFIGS
|
||||||
|
volumes:
|
||||||
|
- signal-data:/signal-data
|
||||||
|
|
||||||
|
signalbridge:
|
||||||
|
image: dock.mau.dev/mautrix/signal:v0.2606.0
|
||||||
|
depends_on:
|
||||||
|
- signaldb
|
||||||
|
configs:
|
||||||
|
- source: signal_bridge_yaml
|
||||||
|
target: /data/config.yaml
|
||||||
|
environment:
|
||||||
|
- HOMESERVER_DOMAIN
|
||||||
|
- HOMESERVER_URL
|
||||||
|
- SIGNAL_BRIDGE_PERMISSIONS
|
||||||
|
- SIGNAL_ENABLE_ENCRYPTION
|
||||||
|
- SIGNAL_DEFAULT_ENCRYPTION=${SIGNAL_DEFAULT_ENCRYPTION:-false}
|
||||||
|
- VERIFY_SSL
|
||||||
|
secrets:
|
||||||
|
- signal_as_token
|
||||||
|
- signal_db_password
|
||||||
|
- signal_hs_token
|
||||||
|
- shared_secret_auth
|
||||||
|
- signal_pickle_key
|
||||||
|
volumes:
|
||||||
|
- signal-data:/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
signaldb:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
secrets:
|
||||||
|
- signal_db_password
|
||||||
|
environment:
|
||||||
|
- LC_COLLATE=C
|
||||||
|
- LC_CTYPE=C
|
||||||
|
- POSTGRES_DB=signalbridge
|
||||||
|
- POSTGRES_INITDB_ARGS="-E \"UTF8\""
|
||||||
|
- POSTGRES_PASSWORD_FILE=/run/secrets/signal_db_password
|
||||||
|
- POSTGRES_USER=signalbridge
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "$POSTGRES_USER" ]
|
||||||
|
volumes:
|
||||||
|
- signal-postgres:/var/lib/postgresql/data
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
backupbot.backup.pre-hook: "/pg_backup.sh backup"
|
||||||
|
backupbot.backup.volumes.signal-postgres.path: "backup.sql"
|
||||||
|
backupbot.restore.post-hook: '/pg_backup.sh restore'
|
||||||
|
configs:
|
||||||
|
- source: pg_backup
|
||||||
|
target: /pg_backup.sh
|
||||||
|
mode: 0555
|
||||||
|
|
||||||
|
configs:
|
||||||
|
signal_bridge_yaml:
|
||||||
|
name: ${STACK_NAME}_signal_bridge_yaml_${SIGNAL_BRIDGE_YAML_VERSION}
|
||||||
|
file: signal_bridge.yaml.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
signal-data:
|
||||||
|
signal-postgres:
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
signal_db_password:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_signal_db_password_${SECRET_SIGNAL_DB_PASSWORD_VERSION}
|
||||||
|
signal_as_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_signal_as_token_${SECRET_SIGNAL_AS_TOKEN_VERSION}
|
||||||
|
signal_hs_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_signal_hs_token_${SECRET_SIGNAL_HS_TOKEN_VERSION}
|
||||||
|
signal_pickle_key:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_signal_pickle_key_${SECRET_SIGNAL_PICKLE_KEY_VERSION}
|
||||||
@ -6,8 +6,8 @@ services:
|
|||||||
secrets:
|
secrets:
|
||||||
- db_password
|
- db_password
|
||||||
- form_secret
|
- form_secret
|
||||||
- macaroon_secret_key
|
- macaroon
|
||||||
- registration_shared_secret
|
- registration
|
||||||
- smtp_password
|
- smtp_password
|
||||||
environment:
|
environment:
|
||||||
- SMTP_APP_NAME
|
- SMTP_APP_NAME
|
||||||
|
|||||||
94
compose.telegram.yml
Normal file
94
compose.telegram.yml
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
environment:
|
||||||
|
- APP_SERVICES_ENABLED
|
||||||
|
- APP_SERVICE_CONFIGS
|
||||||
|
volumes:
|
||||||
|
- telegram-data:/telegram-data
|
||||||
|
|
||||||
|
telegrambridge:
|
||||||
|
image: dock.mau.dev/mautrix/telegram:v0.2606.0
|
||||||
|
depends_on:
|
||||||
|
- telegramdb
|
||||||
|
configs:
|
||||||
|
- source: telegram_bridge_yaml
|
||||||
|
target: /data/config.yaml
|
||||||
|
environment:
|
||||||
|
- APP_SERVICE_BOT_USERNAME
|
||||||
|
- APP_SERVICE_DISPLAY_NAME
|
||||||
|
- APP_SERVICE_ID
|
||||||
|
- ENABLE_ENCRYPTION
|
||||||
|
- HOMESERVER_DOMAIN
|
||||||
|
- HOMESERVER_URL
|
||||||
|
- TELEGRAM_APP_ID
|
||||||
|
- TELEGRAM_BRIDGE_PERMISSIONS
|
||||||
|
- TELEGRAM_SYNC_CHANNEL_MEMBERS
|
||||||
|
- VERIFY_SSL
|
||||||
|
secrets:
|
||||||
|
- telegram_api_hash
|
||||||
|
- telegram_as_token
|
||||||
|
- telegram_bot_token
|
||||||
|
- telegram_db_password
|
||||||
|
- telegram_hs_token
|
||||||
|
- shared_secret_auth
|
||||||
|
volumes:
|
||||||
|
- telegram-data:/data
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
|
||||||
|
telegramdb:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
secrets:
|
||||||
|
- telegram_db_password
|
||||||
|
environment:
|
||||||
|
- LC_COLLATE=C
|
||||||
|
- LC_CTYPE=C
|
||||||
|
- POSTGRES_DB=telegrambridge
|
||||||
|
- POSTGRES_INITDB_ARGS="-E \"UTF8\""
|
||||||
|
- POSTGRES_PASSWORD_FILE=/run/secrets/telegram_db_password
|
||||||
|
- POSTGRES_USER=telegrambridge
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "$POSTGRES_USER" ]
|
||||||
|
volumes:
|
||||||
|
- telegram-postgres:/var/lib/postgresql/data
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
backupbot.backup.pre-hook: "/pg_backup.sh backup"
|
||||||
|
backupbot.backup.volumes.telegram-postgres.path: "backup.sql"
|
||||||
|
backupbot.restore.post-hook: '/pg_backup.sh restore'
|
||||||
|
configs:
|
||||||
|
- source: pg_backup
|
||||||
|
target: /pg_backup.sh
|
||||||
|
mode: 0555
|
||||||
|
|
||||||
|
configs:
|
||||||
|
telegram_bridge_yaml:
|
||||||
|
name: ${STACK_NAME}_telegram_bridge_yaml_${TELEGRAM_BRIDGE_YAML_VERSION}
|
||||||
|
file: telegram_bridge.yaml.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
telegram-data:
|
||||||
|
telegram-postgres:
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
telegram_db_password:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_telegram_db_password_${SECRET_TELEGRAM_DB_PASSWORD_VERSION}
|
||||||
|
telegram_api_hash:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_telegram_api_hash_${SECRET_TELEGRAM_API_HASH_VERSION}
|
||||||
|
telegram_bot_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_telegram_bot_token_${SECRET_TELEGRAM_BOT_TOKEN_VERSION}
|
||||||
|
telegram_as_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_telegram_as_token_${SECRET_TELEGRAM_AS_TOKEN_VERSION}
|
||||||
|
telegram_hs_token:
|
||||||
|
external: true
|
||||||
|
name: ${STACK_NAME}_telegram_hs_token_${SECRET_TELEGRAM_HS_TOKEN_VERSION}
|
||||||
@ -6,8 +6,8 @@ services:
|
|||||||
secrets:
|
secrets:
|
||||||
- db_password
|
- db_password
|
||||||
- form_secret
|
- form_secret
|
||||||
- macaroon_secret_key
|
- macaroon
|
||||||
- registration_shared_secret
|
- registration
|
||||||
- turn_shared_secret
|
- turn_shared_secret
|
||||||
environment:
|
environment:
|
||||||
- TURN_ALLOW_GUESTS
|
- TURN_ALLOW_GUESTS
|
||||||
|
|||||||
24
compose.wellknown.yml
Normal file
24
compose.wellknown.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
# Serve /.well-known/matrix/{server,client} on SERVER_NAME via Traefik, routed to
|
||||||
|
# the matrix nginx (`web`) — so server/client delegation works without hand-placing
|
||||||
|
# files on whatever else hosts SERVER_NAME.
|
||||||
|
#
|
||||||
|
# Enable when SERVER_NAME != DOMAIN (users are @alice:example.com, Synapse runs at
|
||||||
|
# matrix.example.com). The PathPrefix rule is more specific than a bare Host()
|
||||||
|
# router, and the explicit high priority guarantees it wins over any apex website
|
||||||
|
# that also serves Host(SERVER_NAME) — so the two coexist, the apex site keeps
|
||||||
|
# serving everything except /.well-known/matrix.
|
||||||
|
#
|
||||||
|
# Requires SERVER_NAME to resolve to this Traefik so ACME can issue its cert.
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.rule=Host(`${SERVER_NAME}`) && PathPrefix(`/.well-known/matrix`)"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.tls=true"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.service=${STACK_NAME}"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-wellknown.priority=1000"
|
||||||
143
compose.yml
143
compose.yml
@ -2,26 +2,89 @@
|
|||||||
version: "3.8"
|
version: "3.8"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:1.31.2
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
- internal
|
||||||
|
environment:
|
||||||
|
- DOMAIN
|
||||||
|
- STACK_NAME
|
||||||
|
- MAS_ENABLED
|
||||||
|
- NGINX_ACCESS_LOG_LOCATION
|
||||||
|
- NGINX_ERROR_LOG_LOCATION
|
||||||
|
- MAX_UPLOAD_SIZE
|
||||||
|
configs:
|
||||||
|
- source: nginx_config
|
||||||
|
target: /etc/nginx/nginx.conf
|
||||||
|
- source: wk_server
|
||||||
|
target: /var/www/.well-known/matrix/server
|
||||||
|
- source: wk_client
|
||||||
|
target: /var/www/.well-known/matrix/client
|
||||||
|
deploy:
|
||||||
|
restart_policy:
|
||||||
|
condition: any
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=80"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-federation.rule=Host(`${SERVER_NAME}`)"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-federation.entrypoints=matrix-federation"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-federation.tls=true"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-federation.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
||||||
|
- "traefik.http.routers.${STACK_NAME}-federation.service=${STACK_NAME}"
|
||||||
|
healthcheck:
|
||||||
|
test: curl -f http://${STACK_NAME}_app:8008/health || exit 1
|
||||||
|
interval: 30s
|
||||||
|
timeout: 15s
|
||||||
|
retries: 90
|
||||||
|
start_period: 2m
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: "matrixdotorg/synapse:v1.52.0"
|
image: "matrixdotorg/synapse:v1.155.0"
|
||||||
volumes:
|
volumes:
|
||||||
- "data:/data"
|
- "data:/data"
|
||||||
secrets:
|
secrets:
|
||||||
- db_password
|
- db_password
|
||||||
- registration_shared_secret
|
- registration
|
||||||
- macaroon_secret_key
|
- macaroon
|
||||||
- form_secret
|
- form_secret
|
||||||
environment:
|
environment:
|
||||||
|
- MAS_ENABLED
|
||||||
|
- ALLOWED_LIFETIME_MAX
|
||||||
|
- ALLOW_PUBLIC_ROOMS_FEDERATION
|
||||||
- AUTO_JOIN_ROOM
|
- AUTO_JOIN_ROOM
|
||||||
- AUTO_JOIN_ROOM_ENABLED
|
- AUTO_JOIN_ROOM_ENABLED
|
||||||
- DISABLE_FEDERATION
|
- DISABLE_FEDERATION
|
||||||
- DOMAIN
|
- DOMAIN
|
||||||
- ENABLE_3PID_LOOKUP
|
- ENABLE_3PID_LOOKUP
|
||||||
- ENABLE_ALLOWLIST
|
- ENABLE_ALLOWLIST
|
||||||
|
- ENABLE_REGISTRATION
|
||||||
|
- REGISTRATION_REQUIRES_TOKEN
|
||||||
|
- ENCRYPTED_BY_DEFAULT
|
||||||
|
- OLD_SIGNING_KEY
|
||||||
|
- OLD_SIGNING_KEY_ID
|
||||||
|
- OLD_SIGNING_KEY_EXPIRES
|
||||||
|
- USER_DIRECTORY_ENABLED=${USER_DIRECTORY_ENABLED:-true}
|
||||||
|
- USER_DIRECTORY_SEARCH_ALL_USERS=${USER_DIRECTORY_SEARCH_ALL_USERS:-true}
|
||||||
|
- USER_DIRECTORY_PREFER_LOCAL_USERS=${USER_DIRECTORY_PREFER_LOCAL_USERS:-true}
|
||||||
|
- USER_DIRECTORY_SHOW_LOCKED_USERS=${USER_DIRECTORY_SHOW_LOCKED_USERS:-false}
|
||||||
- FEDERATION_ALLOWLIST
|
- FEDERATION_ALLOWLIST
|
||||||
|
- REQUIRE_AUTH_FOR_PROFILE_REQUESTS=${REQUIRE_AUTH_FOR_PROFILE_REQUESTS:-false}
|
||||||
|
- LIMIT_PROFILE_REQUESTS_TO_USERS_WHO_SHARE_ROOMS=${LIMIT_PROFILE_REQUESTS_TO_USERS_WHO_SHARE_ROOMS:-false}
|
||||||
|
- DELETE_STALE_DEVICES_AFTER
|
||||||
|
- SESSION_LIFETIME
|
||||||
|
- TRACK_PUPPETED_USER_IPS=${TRACK_PUPPETED_USER_IPS:-false}
|
||||||
- LETSENCRYPT_HOST=${DOMAIN}
|
- LETSENCRYPT_HOST=${DOMAIN}
|
||||||
|
- MEDIA_RETENTION_LOCAL_LIFETIME
|
||||||
|
- MEDIA_RETENTION_REMOTE_LIFETIME
|
||||||
|
- PASSWORD_LOGIN_ENABLED
|
||||||
- REDACTION_RETENTION_PERIOD
|
- REDACTION_RETENTION_PERIOD
|
||||||
|
- RETENTION_MAX_LIFETIME
|
||||||
- ROOT_LOG_LEVEL
|
- ROOT_LOG_LEVEL
|
||||||
|
- SERVE_SERVER_WELLKNOWN
|
||||||
- SQL_LOG_LEVEL
|
- SQL_LOG_LEVEL
|
||||||
- STACK_NAME
|
- STACK_NAME
|
||||||
- SYNAPSE_ADMIN_EMAIL
|
- SYNAPSE_ADMIN_EMAIL
|
||||||
@ -30,8 +93,13 @@ services:
|
|||||||
- USER_IPS_MAX_AGE
|
- USER_IPS_MAX_AGE
|
||||||
- VIRTUAL_HOST=${DOMAIN}
|
- VIRTUAL_HOST=${DOMAIN}
|
||||||
- VIRTUAL_PORT=8008
|
- VIRTUAL_PORT=8008
|
||||||
|
- LOGIN_LIMIT_IP_PER_SECOND=${LOGIN_LIMIT_IP_PER_SECOND:-0.003}
|
||||||
|
- LOGIN_LIMIT_IP_BURST=${LOGIN_LIMIT_IP_BURST:-5}
|
||||||
|
- LOGIN_LIMIT_ACCOUNT_PER_SECOND=${LOGIN_LIMIT_ACCOUNT_PER_SECOND:-0.003}
|
||||||
|
- LOGIN_LIMIT_ACCOUNT_BURST=${LOGIN_LIMIT_ACCOUNT_BURST:-5}
|
||||||
|
- ROOM_COMPLEXITY_LIMIT=${ROOM_COMPLEXITY_LIMIT:-100.0}
|
||||||
|
- WEB_CLIENT_LOCATION
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
|
||||||
- internal
|
- internal
|
||||||
entrypoint: /docker-entrypoint.sh
|
entrypoint: /docker-entrypoint.sh
|
||||||
configs:
|
configs:
|
||||||
@ -46,28 +114,50 @@ services:
|
|||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "coop-cloud.${STACK_NAME}.version=7.2.1+v1.155.0"
|
||||||
- "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=8008"
|
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT}"
|
||||||
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)"
|
healthcheck:
|
||||||
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
|
test: ["CMD", "curl", "-f", "http://localhost:8008/health"]
|
||||||
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
interval: 30s
|
||||||
- "coop-cloud.${STACK_NAME}.version=1.2.0+v1.52.0"
|
timeout: 10s
|
||||||
|
retries: 30
|
||||||
|
start_period: 1m
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:13-alpine
|
image: pgautoupgrade/pgautoupgrade:18-alpine
|
||||||
secrets:
|
secrets:
|
||||||
- db_password
|
- db_password
|
||||||
environment:
|
environment:
|
||||||
|
# postgres:18 relocated the default PGDATA to /var/lib/postgresql/18/docker.
|
||||||
|
# Pin it to the legacy path so pgautoupgrade finds the existing cluster on the
|
||||||
|
# mounted volume and upgrades it in place, instead of init'ing an empty one.
|
||||||
|
- PGDATA=/var/lib/postgresql/data
|
||||||
|
- LC_COLLATE=C
|
||||||
|
- LC_CTYPE=C
|
||||||
- POSTGRES_DB=synapse
|
- POSTGRES_DB=synapse
|
||||||
- POSTGRES_INITDB_ARGS="--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
- POSTGRES_INITDB_ARGS=-E UTF8
|
||||||
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
|
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
|
||||||
- POSTGRES_USER=synapse
|
- POSTGRES_USER=synapse
|
||||||
|
- DOMAIN
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "pg_isready", "-U", "synapse"]
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 20
|
||||||
|
start_period: 1m
|
||||||
volumes:
|
volumes:
|
||||||
- postgres:/var/lib/postgresql/data
|
- postgres:/var/lib/postgresql/data
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
backupbot.backup: "${ENABLE_BACKUPS:-true}"
|
||||||
|
backupbot.backup.pre-hook: "/pg_backup.sh backup"
|
||||||
|
backupbot.backup.volumes.postgres.path: "backup.sql"
|
||||||
|
backupbot.restore.post-hook: "/pg_backup.sh restore"
|
||||||
|
configs:
|
||||||
|
- source: pg_backup
|
||||||
|
target: /pg_backup.sh
|
||||||
|
mode: 0555
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
@ -84,24 +174,39 @@ configs:
|
|||||||
file: entrypoint.sh.tmpl
|
file: entrypoint.sh.tmpl
|
||||||
template_driver: golang
|
template_driver: golang
|
||||||
homeserver_yaml:
|
homeserver_yaml:
|
||||||
name: ${STACK_NAME}_homserver_yaml_${HOMESERVER_YAML_VERSION}
|
name: ${STACK_NAME}_homeserver_yaml_${HOMESERVER_YAML_VERSION}
|
||||||
file: homeserver.yaml.tmpl
|
file: homeserver.yaml.tmpl
|
||||||
template_driver: golang
|
template_driver: golang
|
||||||
log_config:
|
log_config:
|
||||||
name: ${STACK_NAME}_log_config_${LOG_CONFIG_VERSION}
|
name: ${STACK_NAME}_log_config_${LOG_CONFIG_VERSION}
|
||||||
file: log.config.tmpl
|
file: log.config.tmpl
|
||||||
template_driver: golang
|
template_driver: golang
|
||||||
|
nginx_config:
|
||||||
|
name: ${STACK_NAME}_nginx_config_${NGINX_CONFIG_VERSION}
|
||||||
|
file: nginx.conf.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
wk_server:
|
||||||
|
name: ${STACK_NAME}_wk_server_${WK_SERVER_VERSION}
|
||||||
|
file: well_known_server.conf.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
wk_client:
|
||||||
|
name: ${STACK_NAME}_wk_client_${WK_CLIENT_VERSION}
|
||||||
|
file: well_known_client.conf.tmpl
|
||||||
|
template_driver: golang
|
||||||
|
pg_backup:
|
||||||
|
name: ${STACK_NAME}_pg_backup_${PG_BACKUP_VERSION}
|
||||||
|
file: pg_backup.sh
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
db_password:
|
db_password:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_db_password_${SECRET_DB_PASSWORD_VERSION}
|
name: ${STACK_NAME}_db_password_${SECRET_DB_PASSWORD_VERSION}
|
||||||
registration_shared_secret:
|
registration:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_db_password_${SECRET_REGISTRATION_SHARED_SECRET_VERSION}
|
name: ${STACK_NAME}_registration_${SECRET_REGISTRATION_VERSION}
|
||||||
macaroon_secret_key:
|
macaroon:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_db_password_${SECRET_MACAROON_SECRET_KEY_VERSION}
|
name: ${STACK_NAME}_macaroon_${SECRET_MACAROON_VERSION}
|
||||||
form_secret:
|
form_secret:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_db_password_${SECRET_FORM_SECRET_VERSION}
|
name: ${STACK_NAME}_form_secret_${SECRET_FORM_SECRET_VERSION}
|
||||||
|
|||||||
46
compress_state_entrypoint.sh
Normal file
46
compress_state_entrypoint.sh
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BINARY="/build/synapse_auto_compressor"
|
||||||
|
REPO_DIR="/build/rust-synapse-compress-state"
|
||||||
|
DB_PASS=$(cat /run/secrets/db_password)
|
||||||
|
CONN="postgresql://synapse:${DB_PASS}@db:5432/synapse"
|
||||||
|
CHUNK_SIZE="${STATE_COMPRESS_CHUNK_SIZE:-500}"
|
||||||
|
CHUNKS="${STATE_COMPRESS_CHUNKS:-100}"
|
||||||
|
SCHEDULE="${STATE_COMPRESS_SCHEDULE:-0 3 * * *}"
|
||||||
|
|
||||||
|
# Build from source if binary doesn't exist
|
||||||
|
if [ ! -f "$BINARY" ]; then
|
||||||
|
echo "[compress-state] Binary not found, building from source..."
|
||||||
|
apk add --no-cache git openssl-dev openssl-libs-static perl make musl-dev jemalloc-dev
|
||||||
|
rm -rf "$REPO_DIR"
|
||||||
|
git clone https://github.com/matrix-org/rust-synapse-compress-state "$REPO_DIR"
|
||||||
|
cd "$REPO_DIR"
|
||||||
|
cargo build --release -p synapse_auto_compressor
|
||||||
|
cp target/release/synapse_auto_compressor "$BINARY"
|
||||||
|
echo "[compress-state] Build complete"
|
||||||
|
# Clean up source to save space
|
||||||
|
rm -rf "$REPO_DIR"
|
||||||
|
else
|
||||||
|
echo "[compress-state] Using cached binary"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run once at startup
|
||||||
|
echo "[compress-state] Running initial compression at $(date)"
|
||||||
|
"$BINARY" -p "$CONN" -c "$CHUNK_SIZE" -n "$CHUNKS" || echo "[compress-state] Error: $?"
|
||||||
|
|
||||||
|
# Set up cron job
|
||||||
|
CRON_SCRIPT="/build/run_compressor.sh"
|
||||||
|
cat > "$CRON_SCRIPT" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
echo "[compress-state] Running at \$(date)"
|
||||||
|
$BINARY -p "$CONN" -c $CHUNK_SIZE -n $CHUNKS || echo "[compress-state] Error: \$?"
|
||||||
|
echo "[compress-state] Done at \$(date)"
|
||||||
|
EOF
|
||||||
|
chmod +x "$CRON_SCRIPT"
|
||||||
|
|
||||||
|
echo "$SCHEDULE $CRON_SCRIPT" | crontab -
|
||||||
|
echo "[compress-state] Cron scheduled: $SCHEDULE"
|
||||||
|
|
||||||
|
# Run crond in the foreground
|
||||||
|
exec crond -f -l 2
|
||||||
123
discord_bridge.yaml.tmpl
Normal file
123
discord_bridge.yaml.tmpl
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
bridge:
|
||||||
|
# Domain part of the bridge, e.g. matrix.org
|
||||||
|
domain: "{{ env "HOMESERVER_DOMAIN" }}"
|
||||||
|
# This should be your publicly-facing URL because Discord may use it to
|
||||||
|
# fetch media from the media store.
|
||||||
|
homeserverUrl: "{{ env "HOMESERVER_URL" }}"
|
||||||
|
# The TCP port on which the appservice runs on.
|
||||||
|
port: 9005
|
||||||
|
# Interval at which to process users in the 'presence queue'. If you have
|
||||||
|
# 5 users, one user will be processed every 500 milliseconds according to the
|
||||||
|
# value below. This has a minimum value of 250.
|
||||||
|
# WARNING: This has a high chance of spamming the homeserver with presence
|
||||||
|
# updates since it will send one each time somebody changes state or is online.
|
||||||
|
presenceInterval: 500
|
||||||
|
# Disable setting presence for 'ghost users' which means Discord users on Matrix
|
||||||
|
# will not be shown as away or online.
|
||||||
|
disablePresence: false
|
||||||
|
# Disable sending typing notifications when somebody on Discord types.
|
||||||
|
disableTypingNotifications: false
|
||||||
|
# Disable deleting messages on Discord if a message is redacted on Matrix.
|
||||||
|
disableDeletionForwarding: false
|
||||||
|
# Disable portal bridging, where Matrix users can search for unbridged Discord
|
||||||
|
# rooms on their Matrix server.
|
||||||
|
disablePortalBridging: false
|
||||||
|
# Enable users to bridge rooms using !discord commands. See
|
||||||
|
# https://t2bot.io/discord for instructions.
|
||||||
|
enableSelfServiceBridging: true
|
||||||
|
# Disable sending of read receipts for Matrix events which have been
|
||||||
|
# successfully bridged to Discord.
|
||||||
|
disableReadReceipts: false
|
||||||
|
# Disable Join Leave echos from matrix
|
||||||
|
disableJoinLeaveNotifications: false
|
||||||
|
# Disable Invite echos from matrix
|
||||||
|
disableInviteNotifications: false
|
||||||
|
# Auto-determine the language of code blocks (this can be CPU-intensive)
|
||||||
|
determineCodeLanguage: false
|
||||||
|
# MXID of an admin user that will be PMd if the bridge experiences problems. Optional
|
||||||
|
adminMxid: '{{ env "DISCORD_BRIDGE_ADMIN" }}'
|
||||||
|
# The message to send to the bridge admin if the Discord token is not valid
|
||||||
|
invalidTokenMessage: 'Your Discord bot token seems to be invalid, and the bridge cannot function. Please update it in your bridge settings and restart the bridge'
|
||||||
|
|
||||||
|
# Authentication configuration for the discord bot.
|
||||||
|
auth:
|
||||||
|
# This MUST be a string (wrapped in quotes)
|
||||||
|
clientID: "{{ env "DISCORD_CLIENT_ID" }}"
|
||||||
|
botToken: "{{ secret "discord_bot_token" }}"
|
||||||
|
# You must enable "Privileged Gateway Intents" in your bot settings on discord.com (e.g. https://discord.com/developers/applications/12345/bot)
|
||||||
|
# for this to work
|
||||||
|
usePrivilegedIntents: false
|
||||||
|
|
||||||
|
logging:
|
||||||
|
# What level should the logger output to the console at.
|
||||||
|
console: "error" #silly, verbose, info, http, warn, error, silent
|
||||||
|
lineDateFormat: "MMM-D HH:mm:ss.SSS" # This is in moment.js format
|
||||||
|
files:
|
||||||
|
- file: "debug.log"
|
||||||
|
disable:
|
||||||
|
- "PresenceHandler" # Will not capture presence logging
|
||||||
|
- file: "warn.log" # Will capture warnings
|
||||||
|
level: "warn"
|
||||||
|
- file: "botlogs.log" # Will capture logs from DiscordBot
|
||||||
|
level: "info"
|
||||||
|
enable:
|
||||||
|
- "DiscordBot"
|
||||||
|
|
||||||
|
database:
|
||||||
|
# You may either use SQLite or Postgresql for the bridge database, which contains
|
||||||
|
# important mappings for events and user puppeting configurations.
|
||||||
|
# Use the filename option for SQLite, or connString for Postgresql.
|
||||||
|
# If you are migrating, see https://github.com/Half-Shot/matrix-appservice-discord/blob/master/docs/howto.md#migrate-to-postgres-from-sqlite
|
||||||
|
# WARNING: You will almost certainly be fine with sqlite unless your bridge
|
||||||
|
# is in heavy demand and you suffer from IO slowness.
|
||||||
|
connString: "postgres://discordbridge:{{ secret "discord_db_password" }}@discorddb/discordbridge"
|
||||||
|
|
||||||
|
room:
|
||||||
|
# Set the default visibility of alias rooms, defaults to "public".
|
||||||
|
# One of: "public", "private"
|
||||||
|
defaultVisibility: "public"
|
||||||
|
|
||||||
|
channel:
|
||||||
|
# Pattern of the name given to bridged rooms.
|
||||||
|
# Can use :guild for the guild name and :name for the channel name.
|
||||||
|
namePattern: "[Discord] :guild :name"
|
||||||
|
# Changes made to rooms when a channel is deleted.
|
||||||
|
deleteOptions:
|
||||||
|
# Prefix the room name with a string.
|
||||||
|
#namePrefix: "[Deleted]"
|
||||||
|
# Prefix the room topic with a string.
|
||||||
|
#topicPrefix: "This room has been deleted"
|
||||||
|
# Disable people from talking in the room by raising the event PL to 50
|
||||||
|
disableMessaging: false
|
||||||
|
# Remove the discord alias from the room.
|
||||||
|
unsetRoomAlias: true
|
||||||
|
# Remove the room from the directory.
|
||||||
|
unlistFromDirectory: true
|
||||||
|
# Set the room to be unavailable for joining without an invite.
|
||||||
|
setInviteOnly: true
|
||||||
|
# Make all the discord users leave the room.
|
||||||
|
ghostsLeave: true
|
||||||
|
|
||||||
|
limits:
|
||||||
|
# Delay in milliseconds between discord users joining a room.
|
||||||
|
roomGhostJoinDelay: 6000
|
||||||
|
# Lock timeout in milliseconds before sending messages to discord to avoid
|
||||||
|
# echos. Default is rather high as the lock will most likely time out
|
||||||
|
# before anyways.
|
||||||
|
# echos = (Copies of a sent message may arrive from discord before we've
|
||||||
|
# fininished handling it, causing us to echo it back to the room)
|
||||||
|
discordSendDelay: 1500
|
||||||
|
# Set a maximum of rooms to be bridged.
|
||||||
|
# roomCount: 20
|
||||||
|
|
||||||
|
ghosts:
|
||||||
|
# Pattern for the ghosts nick, available is :nick, :username, :tag and :id
|
||||||
|
nickPattern: ":nick"
|
||||||
|
# Pattern for the ghosts username, available is :username, :tag and :id
|
||||||
|
usernamePattern: ":username#:tag"
|
||||||
|
|
||||||
|
# Prometheus-compatible metrics endpoint
|
||||||
|
metrics:
|
||||||
|
enable: false
|
||||||
|
port: 9001
|
||||||
|
host: "127.0.0.1"
|
||||||
@ -6,6 +6,11 @@ chown 991:991 /data
|
|||||||
|
|
||||||
if [[ ! -f /data/{{ env "DOMAIN" }}.signing.key ]]; then
|
if [[ ! -f /data/{{ env "DOMAIN" }}.signing.key ]]; then
|
||||||
/start.py generate
|
/start.py generate
|
||||||
|
chown -R 991:991 /data/*.config /data/*.key
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d /signal-data ]]; then
|
||||||
|
chown -R 991:991 /signal-data
|
||||||
fi
|
fi
|
||||||
|
|
||||||
/start.py
|
/start.py
|
||||||
|
|||||||
3009
homeserver.yaml.tmpl
3009
homeserver.yaml.tmpl
File diff suppressed because it is too large
Load Diff
73
mas.config.yaml.tmpl
Normal file
73
mas.config.yaml.tmpl
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Docs: https://element-hq.github.io/matrix-authentication-service/
|
||||||
|
|
||||||
|
http:
|
||||||
|
public_base: https://{{ env "DOMAIN" }}/
|
||||||
|
trusted_proxies:
|
||||||
|
- 10.0.0.0/8
|
||||||
|
- 172.16.0.0/12
|
||||||
|
- 192.168.0.0/16
|
||||||
|
- 127.0.0.0/8
|
||||||
|
- fd00::/8
|
||||||
|
- ::1/128
|
||||||
|
listeners:
|
||||||
|
- name: web
|
||||||
|
resources:
|
||||||
|
- name: discovery
|
||||||
|
- name: human
|
||||||
|
- name: oauth
|
||||||
|
- name: compat
|
||||||
|
- name: graphql
|
||||||
|
playground: false
|
||||||
|
- name: assets
|
||||||
|
# https://element-hq.github.io/matrix-authentication-service/reference/configuration.html#httplisteners
|
||||||
|
- name: health
|
||||||
|
binds:
|
||||||
|
- address: "[::]:8080"
|
||||||
|
|
||||||
|
database:
|
||||||
|
uri: postgresql://synapse:{{ secret "db_password" }}@{{ env "STACK_NAME" }}_db:5432/mas?sslmode=disable
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
kind: synapse
|
||||||
|
homeserver: {{ or (env "SERVER_NAME") (env "DOMAIN") }}
|
||||||
|
endpoint: http://{{ env "STACK_NAME" }}_app:8008/
|
||||||
|
secret_file: /run/secrets/mas_synapse_shared
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
# Plain hex in file (abra: length=64 charset=hex). See .env.sample modifiers.
|
||||||
|
encryption_file: /run/secrets/mas_encryption
|
||||||
|
keys:
|
||||||
|
- key_file: /run/secrets/mas_signing_rsa
|
||||||
|
|
||||||
|
passwords:
|
||||||
|
enabled: true
|
||||||
|
schemes:
|
||||||
|
- version: 1
|
||||||
|
algorithm: bcrypt
|
||||||
|
unicode_normalization: true
|
||||||
|
- version: 2
|
||||||
|
algorithm: argon2id
|
||||||
|
|
||||||
|
{{ if env "MAS_UPSTREAM_PROVIDER_ID" }}
|
||||||
|
# https://element-hq.github.io/matrix-authentication-service/setup/sso.html
|
||||||
|
upstream_oauth2:
|
||||||
|
providers:
|
||||||
|
- id: {{ env "MAS_UPSTREAM_PROVIDER_ID" }}
|
||||||
|
{{ if env "MAS_UPSTREAM_SYNAPSE_IDP_ID" }}synapse_idp_id: {{ env "MAS_UPSTREAM_SYNAPSE_IDP_ID" }}{{ end }}
|
||||||
|
human_name: {{ or (env "MAS_UPSTREAM_HUMAN_NAME") "SSO" }}
|
||||||
|
issuer: {{ env "MAS_UPSTREAM_ISSUER" }}
|
||||||
|
client_id: {{ env "MAS_UPSTREAM_CLIENT_ID" }}
|
||||||
|
client_secret_file: /run/secrets/mas_upstream_client
|
||||||
|
token_endpoint_auth_method: client_secret_basic
|
||||||
|
scope: "openid profile email"
|
||||||
|
claims_imports:
|
||||||
|
localpart:
|
||||||
|
action: require
|
||||||
|
template: "{{ "{{ user.preferred_username }}" }}"
|
||||||
|
displayname:
|
||||||
|
action: suggest
|
||||||
|
template: "{{ "{{ user.name }}" }}"
|
||||||
|
email:
|
||||||
|
action: suggest
|
||||||
|
template: "{{ "{{ user.email }}" }}"
|
||||||
|
{{ end }}
|
||||||
96
nginx.conf.tmpl
Normal file
96
nginx.conf.tmpl
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
user www-data;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 768;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
|
||||||
|
resolver 127.0.0.11 valid=30s ipv6=off;
|
||||||
|
resolver_timeout 5s;
|
||||||
|
|
||||||
|
upstream matrix_upstream {
|
||||||
|
zone matrix_upstream 64k;
|
||||||
|
server {{ env "STACK_NAME"}}_app:8008 resolve;
|
||||||
|
keepalive 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ if eq (env "MAS_ENABLED") "1" }}
|
||||||
|
upstream mas_upstream {
|
||||||
|
zone mas_upstream 64k;
|
||||||
|
server {{ env "STACK_NAME"}}_mas:8080 resolve;
|
||||||
|
keepalive 8;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
|
||||||
|
access_log {{ or (env "NGINX_ACCESS_LOG_LOCATION") "/dev/null" }};
|
||||||
|
error_log {{ or (env "NGINX_ERROR_LOG_LOCATION") "/dev/null" }};
|
||||||
|
|
||||||
|
server_name {{ env "DOMAIN" }};
|
||||||
|
|
||||||
|
location = / {
|
||||||
|
proxy_pass http://matrix_upstream;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
client_max_body_size 50M;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ if eq (env "MAS_ENABLED") "1" }}
|
||||||
|
# MAS on same Host as Synapse (public_base = https://$DOMAIN/): browser/OIDC paths live at repo root, not only under /_matrix/
|
||||||
|
# Router reference: element-hq/matrix-authentication-service crates/router/src/endpoints.rs
|
||||||
|
# https://element-hq.github.io/matrix-authentication-service/setup/reverse-proxy.html
|
||||||
|
location ~ ^/(complete-compat-sso/|oauth2/|\.well-known/(openid-configuration|webfinger|change-password)|authorize|login|logout|register(/|$)|account/|upstream/|consent/|link(\?|/|$)|device/|recover(/|$)|assets/|graphql(/|$)|api/) {
|
||||||
|
proxy_pass http://mas_upstream;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
client_max_body_size 50M;
|
||||||
|
}
|
||||||
|
# Matrix CS API compat (login / logout / refresh and subpaths, e.g. …/login/sso/redirect) — before generic /_matrix
|
||||||
|
location ~ ^/_matrix/client/[^/]+/(login|logout|refresh)(/.*)?$ {
|
||||||
|
proxy_pass http://mas_upstream;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
client_max_body_size 50M;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
location ~* ^(\/_matrix|\/_synapse\/client|\/_synapse\/mas) {
|
||||||
|
proxy_pass http://matrix_upstream;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
client_max_body_size 50M;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /.well-known/matrix/ {
|
||||||
|
root /var/www/;
|
||||||
|
default_type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ if eq (env "ADMIN_INTERFACE_ENABLED") "1" }}
|
||||||
|
location ^~ /_synapse/admin {
|
||||||
|
if ($http_referer !~ "^https://{{ env "DOMAIN" }}/admin/") {
|
||||||
|
return 403;
|
||||||
|
}
|
||||||
|
proxy_pass http://matrix_upstream;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
client_max_body_size 50M;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
34
pg_backup.sh
Normal file
34
pg_backup.sh
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BACKUP_FILE='/var/lib/postgresql/data/backup.sql'
|
||||||
|
|
||||||
|
function backup {
|
||||||
|
export PGPASSWORD=$(cat $POSTGRES_PASSWORD_FILE)
|
||||||
|
pg_dump -U ${POSTGRES_USER} ${POSTGRES_DB} | gzip > $BACKUP_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
function restore {
|
||||||
|
cd /var/lib/postgresql/data/
|
||||||
|
restore_config(){
|
||||||
|
# Restore allowed connections
|
||||||
|
cat pg_hba.conf.bak > pg_hba.conf
|
||||||
|
su postgres -c 'pg_ctl reload'
|
||||||
|
}
|
||||||
|
# Don't allow any other connections than local
|
||||||
|
cp pg_hba.conf pg_hba.conf.bak
|
||||||
|
echo "local all all trust" > pg_hba.conf
|
||||||
|
su postgres -c 'pg_ctl reload'
|
||||||
|
trap restore_config EXIT INT TERM
|
||||||
|
|
||||||
|
# Recreate Database
|
||||||
|
psql -U ${POSTGRES_USER} -d postgres -c "DROP DATABASE ${POSTGRES_DB} WITH (FORCE);"
|
||||||
|
createdb -U ${POSTGRES_USER} ${POSTGRES_DB}
|
||||||
|
gunzip -c $BACKUP_FILE | psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -1 -f -
|
||||||
|
|
||||||
|
trap - EXIT INT TERM
|
||||||
|
restore_config
|
||||||
|
}
|
||||||
|
|
||||||
|
$@
|
||||||
6
release/1.3.0+v1.55.2
Normal file
6
release/1.3.0+v1.55.2
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
The deployment failed due to the app/db getting confused. I think this is just
|
||||||
|
due to the recipe not having good healthcheck config. After the app container
|
||||||
|
flapped a bit, everything came up nicely. d1 @ autonomic co-op.
|
||||||
|
|
||||||
|
Same thing happened to me when deploying this for another instance. Also d1 @
|
||||||
|
autonomic co-op.
|
||||||
9
release/2.0.0+v1.58.1
Normal file
9
release/2.0.0+v1.58.1
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
This upgrade adds new env variables for homeserver.yml, please add them to your .env file:
|
||||||
|
|
||||||
|
```
|
||||||
|
ENCRYPTED_BY_DEFAULT=all
|
||||||
|
SERVE_SERVER_WELLKNOWN=false
|
||||||
|
|
||||||
|
#KEYCLOAK_ID=keycloak
|
||||||
|
#KEYCLOAK_ALLOW_EXISTING_USERS=false
|
||||||
|
```
|
||||||
9
release/2.1.0+v1.62.0
Normal file
9
release/2.1.0+v1.62.0
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
If you're using the horrendous `compose.keycloak2.yml` (as creator of this
|
||||||
|
horrible hack, I am allowed to call it horrendous ;)), you will need to
|
||||||
|
re-check the new ~/.abra/recipes/matrix-synapse/.env.sample, there are some new
|
||||||
|
default env vars which you'll have to add in (e.g. KEYCLOAK2_ID=...).
|
||||||
|
|
||||||
|
You'll also need to add `KEYCLOAK_ID=keycloak` if using `compose.keycloak.yml`,
|
||||||
|
it isn't vendored any more.
|
||||||
|
|
||||||
|
@decentral1se
|
||||||
17
release/3.0.0+v1.74.0
Normal file
17
release/3.0.0+v1.74.0
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
WARNING: There are a lot of config breaking changes in this one, watch out!
|
||||||
|
|
||||||
|
* KEYCLOAK2* env vars have gone away, they were experimental.
|
||||||
|
|
||||||
|
* TELEGRAM_BRIDGE_ADMIN* is replaced by TELEGRAM_BRIDGE_PERMISSIONS.
|
||||||
|
|
||||||
|
* SIGNAL_BRIDGE_ADMIN* is replaced by SIGNAL_BRIDGE_PERMISSIONS.
|
||||||
|
|
||||||
|
* The homeserver config has been trimmed, see coop-cloud/matrix-synapse#33 for more.
|
||||||
|
|
||||||
|
* Bridge logging is only ERROR level now to minimise leaking plaintext.
|
||||||
|
|
||||||
|
* It is possible to use SSO & federation env vars in combination now.
|
||||||
|
|
||||||
|
* Media retention is now configurable with #MEDIA_RETENTION_* env vars.
|
||||||
|
|
||||||
|
@decentral1se
|
||||||
10
release/4.0.0+v1.93.0
Normal file
10
release/4.0.0+v1.93.0
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
We had to rename some secrets: https://git.coopcloud.tech/coop-cloud/matrix-synapse/issues/35
|
||||||
|
|
||||||
|
Copy the secrets:
|
||||||
|
|
||||||
|
* `registration_shared_secret` to `registration`
|
||||||
|
* `macaroon_secret_key` to `macaroon`
|
||||||
|
|
||||||
|
The easiest way to do this is to run `abra app run <matrix.example.com> app bash` BEFORE this upgrade, then `cat /run/secrets/registration_shared_secret`. If you haven't saved the secrets yet, and would like to, please Ctrl+C out of this upgrade and do that first.
|
||||||
|
|
||||||
|
Regeneration of these secrets should also work.
|
||||||
1
release/5.0.0+v1.93.0
Normal file
1
release/5.0.0+v1.93.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
It's recommended not to upgrade / downgrade directly to this version (or other 5.y.z versions), because of service renaming which was reverted in 6.0.0+v1.100.0.
|
||||||
6
release/5.0.1+v1.93.0
Normal file
6
release/5.0.1+v1.93.0
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
Logging is now disabled by default. If you want to reënable it, set these options:
|
||||||
|
|
||||||
|
```
|
||||||
|
NGINX_ACCESS_LOG_LOCATION="/dev/stdout"
|
||||||
|
NGINX_ERROR_LOG_LOCATION="/dev/stderr"
|
||||||
|
```
|
||||||
1
release/6.0.0+v1.100.0
Normal file
1
release/6.0.0+v1.100.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
If you are upgrading from verison 5.y.z of this recipe, you will need to `undeploy` then `deploy`, because of a service rename which was reverted.
|
||||||
1
release/6.6.1+v1.124.0
Normal file
1
release/6.6.1+v1.124.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
added env REGISTRATION_REQUIRES_TOKEN
|
||||||
1
release/6.6.2+v1.124.0
Normal file
1
release/6.6.2+v1.124.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
new optional env vars for user_directory and privacy options
|
||||||
1
release/6.6.3+v1.124.0
Normal file
1
release/6.6.3+v1.124.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
added env for old-signing-keys
|
||||||
1
release/6.7.1+v1.133.0
Normal file
1
release/6.7.1+v1.133.0
Normal file
@ -0,0 +1 @@
|
|||||||
|
This patch contains a critical nginx fix, to allow resolving docker internal hosts.
|
||||||
1
release/6.8.2+v1.139.2
Normal file
1
release/6.8.2+v1.139.2
Normal file
@ -0,0 +1 @@
|
|||||||
|
this patch is a reset to the state of the last known deploying version 6.8.0 – so better skip 6.8.1
|
||||||
2
release/7.0.0+v1.149.1
Normal file
2
release/7.0.0+v1.149.1
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
WARNING: Backup your database!
|
||||||
|
This upgrade switches the database image from postgres to pgautoupgrade and performs an in-place database upgrades from version 13 to 17.
|
||||||
1
release/7.1.0+v1.149.1
Normal file
1
release/7.1.0+v1.149.1
Normal file
@ -0,0 +1 @@
|
|||||||
|
added matrix-authentication-service as opt-in to the recipe, see readme for details
|
||||||
6
renovate.json
Normal file
6
renovate.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:recommended"
|
||||||
|
]
|
||||||
|
}
|
||||||
123
shared_secret_authenticator.py
Normal file
123
shared_secret_authenticator.py
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Shared Secret Authenticator module for Matrix Synapse
|
||||||
|
# Copyright (C) 2018 Slavi Pantaleev
|
||||||
|
#
|
||||||
|
# https://devture.com/
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from typing import Awaitable, Callable, Optional, Tuple
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import hmac
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import synapse
|
||||||
|
from synapse import module_api
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class SharedSecretAuthProvider:
|
||||||
|
def __init__(self, config: dict, api: module_api):
|
||||||
|
for k in ('shared_secret',):
|
||||||
|
if k not in config:
|
||||||
|
raise KeyError('Required `{0}` configuration key not found'.format(k))
|
||||||
|
|
||||||
|
m_login_password_support_enabled = bool(config['m_login_password_support_enabled']) if 'm_login_password_support_enabled' in config else False
|
||||||
|
com_devture_shared_secret_auth_support_enabled = bool(config['com_devture_shared_secret_auth_support_enabled']) if 'com_devture_shared_secret_auth_support_enabled' in config else True
|
||||||
|
|
||||||
|
self.api = api
|
||||||
|
self.shared_secret = config['shared_secret']
|
||||||
|
|
||||||
|
auth_checkers: Optional[Dict[Tuple[str, Tuple], CHECK_AUTH_CALLBACK]] = {}
|
||||||
|
if com_devture_shared_secret_auth_support_enabled:
|
||||||
|
auth_checkers[("com.devture.shared_secret_auth", ("token",))] = self.check_com_devture_shared_secret_auth
|
||||||
|
if m_login_password_support_enabled:
|
||||||
|
auth_checkers[("m.login.password", ("password",))] = self.check_m_login_password
|
||||||
|
|
||||||
|
enabled_login_types = [k[0] for k in auth_checkers]
|
||||||
|
|
||||||
|
if len(enabled_login_types) == 0:
|
||||||
|
raise RuntimeError('At least one login type must be enabled')
|
||||||
|
|
||||||
|
logger.info('Enabled login types: %s', enabled_login_types)
|
||||||
|
|
||||||
|
api.register_password_auth_provider_callbacks(
|
||||||
|
auth_checkers=auth_checkers,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def check_com_devture_shared_secret_auth(
|
||||||
|
self,
|
||||||
|
username: str,
|
||||||
|
login_type: str,
|
||||||
|
login_dict: "synapse.module_api.JsonDict",
|
||||||
|
) -> Optional[
|
||||||
|
Tuple[
|
||||||
|
str,
|
||||||
|
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||||
|
]
|
||||||
|
]:
|
||||||
|
if login_type != "com.devture.shared_secret_auth":
|
||||||
|
return None
|
||||||
|
return await self._log_in_username_with_token("com.devture.shared_secret_auth", username, login_dict.get("token"))
|
||||||
|
|
||||||
|
async def check_m_login_password(
|
||||||
|
self,
|
||||||
|
username: str,
|
||||||
|
login_type: str,
|
||||||
|
login_dict: "synapse.module_api.JsonDict",
|
||||||
|
) -> Optional[
|
||||||
|
Tuple[
|
||||||
|
str,
|
||||||
|
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||||
|
]
|
||||||
|
]:
|
||||||
|
if login_type != "m.login.password":
|
||||||
|
return None
|
||||||
|
return await self._log_in_username_with_token("m.login.password", username, login_dict.get("password"))
|
||||||
|
|
||||||
|
async def _log_in_username_with_token(
|
||||||
|
self,
|
||||||
|
login_type: str,
|
||||||
|
username: str,
|
||||||
|
token: str,
|
||||||
|
) -> Optional[
|
||||||
|
Tuple[
|
||||||
|
str,
|
||||||
|
Optional[Callable[["synapse.module_api.LoginResponse"], Awaitable[None]]],
|
||||||
|
]
|
||||||
|
]:
|
||||||
|
logger.info('Authenticating user `%s` with login type `%s`', username, login_type)
|
||||||
|
|
||||||
|
full_user_id = self.api.get_qualified_user_id(username)
|
||||||
|
|
||||||
|
# The password (token) is supposed to be an HMAC of the full user id, keyed with the shared secret.
|
||||||
|
given_hmac = token.encode('utf-8')
|
||||||
|
|
||||||
|
h = hmac.new(self.shared_secret.encode('utf-8'), full_user_id.encode('utf-8'), hashlib.sha512)
|
||||||
|
computed_hmac = h.hexdigest().encode('utf-8')
|
||||||
|
|
||||||
|
if not hmac.compare_digest(computed_hmac, given_hmac):
|
||||||
|
logger.info('Bad hmac value for user: %s', full_user_id)
|
||||||
|
return None
|
||||||
|
|
||||||
|
user_info = await self.api.get_userinfo_by_id(full_user_id)
|
||||||
|
if user_info is None:
|
||||||
|
logger.info('Refusing to authenticate missing user: %s', full_user_id)
|
||||||
|
return None
|
||||||
|
|
||||||
|
logger.info('Authenticated user: %s', full_user_id)
|
||||||
|
|
||||||
|
return full_user_id, None
|
||||||
411
signal_bridge.yaml.tmpl
Normal file
411
signal_bridge.yaml.tmpl
Normal file
@ -0,0 +1,411 @@
|
|||||||
|
# Network-specific config options
|
||||||
|
network:
|
||||||
|
# Displayname template for Signal users.
|
||||||
|
# {{ "{{.ProfileName}}" }} - The Signal profile name set by the user.
|
||||||
|
# {{ "{{.ContactName}}" }} - The name for the user from your phone's contact list. This is not safe on multi-user instances.
|
||||||
|
# {{ "{{.PhoneNumber}}" }} - The phone number of the user.
|
||||||
|
# {{ "{{.UUID}}" }} - The UUID of the Signal user.
|
||||||
|
# {{ "{{.AboutEmoji}}" }} - The emoji set by the user in their profile.
|
||||||
|
displayname_template: '{{ "{{or .ProfileName .PhoneNumber \"Unknown user\"}}" }}'
|
||||||
|
# Should avatars from the user's contact list be used? This is not safe on multi-user instances.
|
||||||
|
use_contact_avatars: false
|
||||||
|
# Should the bridge request the user's contact list from the phone on startup?
|
||||||
|
sync_contacts_on_startup: true
|
||||||
|
# Should the bridge sync ghost user info even if profile fetching fails? This is not safe on multi-user instances.
|
||||||
|
use_outdated_profiles: false
|
||||||
|
# Should the Signal user's phone number be included in the room topic in private chat portal rooms?
|
||||||
|
number_in_topic: true
|
||||||
|
# Default device name that shows up in the Signal app.
|
||||||
|
device_name: mautrix-signal
|
||||||
|
# Avatar image for the Note to Self room.
|
||||||
|
note_to_self_avatar: mxc://maunium.net/REBIVrqjZwmaWpssCZpBlmlL
|
||||||
|
# Format for generating URLs from location messages for sending to Signal.
|
||||||
|
# Google Maps: 'https://www.google.com/maps/place/%[1]s,%[2]s'
|
||||||
|
# OpenStreetMap: 'https://www.openstreetmap.org/?mlat=%[1]s&mlon=%[2]s'
|
||||||
|
location_format: 'https://www.google.com/maps/place/%[1]s,%[2]s'
|
||||||
|
|
||||||
|
|
||||||
|
# Config options that affect the central bridge module.
|
||||||
|
bridge:
|
||||||
|
# The prefix for commands. Only required in non-management rooms.
|
||||||
|
command_prefix: '!signal'
|
||||||
|
# Should the bridge create a space for each login containing the rooms that account is in?
|
||||||
|
personal_filtering_spaces: true
|
||||||
|
# Whether the bridge should set names and avatars explicitly for DM portals.
|
||||||
|
# This is only necessary when using clients that don't support MSC4171.
|
||||||
|
private_chat_portal_meta: false
|
||||||
|
|
||||||
|
# Should leaving Matrix rooms be bridged as leaving groups on the remote network?
|
||||||
|
bridge_matrix_leave: false
|
||||||
|
# Should room tags only be synced when creating the portal? Tags mean things like favorite/pin and archive/low priority.
|
||||||
|
# Tags currently can't be synced back to the remote network, so a continuous sync means tagging from Matrix will be undone.
|
||||||
|
tag_only_on_create: true
|
||||||
|
# Should room mute status only be synced when creating the portal?
|
||||||
|
# Like tags, mutes can't currently be synced back to the remote network.
|
||||||
|
mute_only_on_create: true
|
||||||
|
|
||||||
|
# What should be done to portal rooms when a user logs out or is logged out?
|
||||||
|
# Permitted values:
|
||||||
|
# nothing - Do nothing, let the user stay in the portals
|
||||||
|
# kick - Remove the user from the portal rooms, but don't delete them
|
||||||
|
# unbridge - Remove all ghosts in the room and disassociate it from the remote chat
|
||||||
|
# delete - Remove all ghosts and users from the room (i.e. delete it)
|
||||||
|
cleanup_on_logout:
|
||||||
|
# Should cleanup on logout be enabled at all?
|
||||||
|
enabled: false
|
||||||
|
# Settings for manual logouts (explicitly initiated by the Matrix user)
|
||||||
|
manual:
|
||||||
|
# Action for private portals which will never be shared with other Matrix users.
|
||||||
|
private: nothing
|
||||||
|
# Action for portals with a relay user configured.
|
||||||
|
relayed: nothing
|
||||||
|
# Action for portals which may be shared, but don't currently have any other Matrix users.
|
||||||
|
shared_no_users: nothing
|
||||||
|
# Action for portals which have other logged-in Matrix users.
|
||||||
|
shared_has_users: nothing
|
||||||
|
# Settings for credentials being invalidated (initiated by the remote network, possibly through user action).
|
||||||
|
# Keys have the same meanings as in the manual section.
|
||||||
|
bad_credentials:
|
||||||
|
private: nothing
|
||||||
|
relayed: nothing
|
||||||
|
shared_no_users: nothing
|
||||||
|
shared_has_users: nothing
|
||||||
|
|
||||||
|
# Settings for relay mode
|
||||||
|
relay:
|
||||||
|
# Whether relay mode should be allowed. If allowed, the set-relay command can be used to turn any
|
||||||
|
# authenticated user into a relaybot for that chat.
|
||||||
|
enabled: true
|
||||||
|
# Should only admins be allowed to set themselves as relay users?
|
||||||
|
# If true, non-admins can only set users listed in default_relays as relays in a room.
|
||||||
|
admin_only: true
|
||||||
|
# List of user login IDs which anyone can set as a relay, as long as the relay user is in the room.
|
||||||
|
default_relays: []
|
||||||
|
# The formats to use when sending messages via the relaybot.
|
||||||
|
# Available variables:
|
||||||
|
# .Sender.UserID - The Matrix user ID of the sender.
|
||||||
|
# .Sender.Displayname - The display name of the sender (if set).
|
||||||
|
# .Sender.RequiresDisambiguation - Whether the sender's name may be confused with the name of another user in the room.
|
||||||
|
# .Sender.DisambiguatedName - The disambiguated name of the sender. This will be the displayname if set,
|
||||||
|
# plus the user ID in parentheses if the displayname is not unique.
|
||||||
|
# If the displayname is not set, this is just the user ID.
|
||||||
|
# .Message - The `formatted_body` field of the message.
|
||||||
|
# .Caption - The `formatted_body` field of the message, if it's a caption. Otherwise an empty string.
|
||||||
|
# .FileName - The name of the file being sent.
|
||||||
|
message_formats:
|
||||||
|
m.text: "{{`{{ .Sender.DisambiguatedName }}: {{ .Message }}`}}"
|
||||||
|
m.notice: "{{`{{ .Sender.DisambiguatedName }}: {{ .Message }}`}}"
|
||||||
|
m.emote: "{{`* {{ .Sender.DisambiguatedName }} {{ .Message }}`}}"
|
||||||
|
m.file: "{{`{{ .Sender.DisambiguatedName }} sent a file{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.image: "{{`{{ .Sender.DisambiguatedName }} sent an image{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.audio: "{{`{{ .Sender.DisambiguatedName }} sent an audio file{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.video: "{{`{{ .Sender.DisambiguatedName }} sent a video{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.location: "{{`{{ .Sender.DisambiguatedName }} sent a location{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
# For networks that support per-message displaynames (i.e. Slack and Discord), the template for those names.
|
||||||
|
# This has all the Sender variables available under message_formats (but without the .Sender prefix).
|
||||||
|
# Note that you need to manually remove the displayname from message_formats above.
|
||||||
|
displayname_format: "{{`{{ .DisambiguatedName }}`}}"
|
||||||
|
|
||||||
|
|
||||||
|
# Permissions for using the bridge.
|
||||||
|
# Permitted values:
|
||||||
|
# relay - Talk through the relaybot (if enabled), no access otherwise
|
||||||
|
# commands - Access to use commands in the bridge, but not login.
|
||||||
|
# user - Access to use the bridge with puppeting.
|
||||||
|
# admin - Full access, user level with some additional administration tools.
|
||||||
|
# Permitted keys:
|
||||||
|
# * - All Matrix users
|
||||||
|
# domain - All users on that homeserver
|
||||||
|
# mxid - Specific user
|
||||||
|
permissions: {{ env "SIGNAL_BRIDGE_PERMISSIONS" }}
|
||||||
|
|
||||||
|
# Config for the bridge's database.
|
||||||
|
database:
|
||||||
|
# The database type. "sqlite3-fk-wal" and "postgres" are supported.
|
||||||
|
type: postgres
|
||||||
|
# The database URI.
|
||||||
|
# SQLite: A raw file path is supported, but `file:<path>?_txlock=immediate` is recommended.
|
||||||
|
# https://github.com/mattn/go-sqlite3#connection-string
|
||||||
|
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
|
||||||
|
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
|
||||||
|
uri: postgres://signalbridge:{{ secret "signal_db_password" }}@signaldb/signalbridge?sslmode=disable
|
||||||
|
# Maximum number of connections.
|
||||||
|
max_open_conns: 5
|
||||||
|
max_idle_conns: 1
|
||||||
|
# Maximum connection idle time and lifetime before they're closed. Disabled if null.
|
||||||
|
# Parsed with https://pkg.go.dev/time#ParseDuration
|
||||||
|
max_conn_idle_time: null
|
||||||
|
max_conn_lifetime: null
|
||||||
|
|
||||||
|
# Homeserver details.
|
||||||
|
homeserver:
|
||||||
|
# The address that this appservice can use to connect to the homeserver.
|
||||||
|
# Local addresses without HTTPS are generally recommended when the bridge is running on the same machine,
|
||||||
|
# but https also works if they run on different machines.
|
||||||
|
address: {{ env "HOMESERVER_URL" }}
|
||||||
|
# The domain of the homeserver (also known as server_name, used for MXIDs, etc).
|
||||||
|
domain: {{ env "HOMESERVER_DOMAIN" }}
|
||||||
|
|
||||||
|
# What software is the homeserver running?
|
||||||
|
# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.
|
||||||
|
software: standard
|
||||||
|
# The URL to push real-time bridge status to.
|
||||||
|
# If set, the bridge will make POST requests to this URL whenever a user's remote network connection state changes.
|
||||||
|
# The bridge will use the appservice as_token to authorize requests.
|
||||||
|
status_endpoint: null
|
||||||
|
# Endpoint for reporting per-message status.
|
||||||
|
# If set, the bridge will make POST requests to this URL when processing a message from Matrix.
|
||||||
|
# It will make one request when receiving the message (step BRIDGE), one after decrypting if applicable
|
||||||
|
# (step DECRYPTED) and one after sending to the remote network (step REMOTE). Errors will also be reported.
|
||||||
|
# The bridge will use the appservice as_token to authorize requests.
|
||||||
|
message_send_checkpoint_endpoint:
|
||||||
|
# Does the homeserver support https://github.com/matrix-org/matrix-spec-proposals/pull/2246?
|
||||||
|
async_media: false
|
||||||
|
|
||||||
|
# Should the bridge use a websocket for connecting to the homeserver?
|
||||||
|
# The server side is currently not documented anywhere and is only implemented by mautrix-wsproxy,
|
||||||
|
# mautrix-asmux (deprecated), and hungryserv (proprietary).
|
||||||
|
websocket: false
|
||||||
|
# How often should the websocket be pinged? Pinging will be disabled if this is zero.
|
||||||
|
ping_interval_seconds: 0
|
||||||
|
|
||||||
|
# Application service host/registration related details.
|
||||||
|
# Changing these values requires regeneration of the registration (except when noted otherwise)
|
||||||
|
appservice:
|
||||||
|
# The address that the homeserver can use to connect to this appservice.
|
||||||
|
address: http://signalbridge:29328
|
||||||
|
# A public address that external services can use to reach this appservice.
|
||||||
|
# This value doesn't affect the registration file.
|
||||||
|
public_address: https://bridge.example.com
|
||||||
|
|
||||||
|
# The hostname and port where this appservice should listen.
|
||||||
|
hostname: 0.0.0.0
|
||||||
|
port: 29328
|
||||||
|
|
||||||
|
# The unique ID of this appservice.
|
||||||
|
id: signal
|
||||||
|
# Appservice bot details.
|
||||||
|
bot:
|
||||||
|
# Username of the appservice bot.
|
||||||
|
username: signalbot
|
||||||
|
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
|
||||||
|
# to leave display name/avatar as-is.
|
||||||
|
displayname: Signal bridge bot
|
||||||
|
avatar: mxc://maunium.net/wPJgTQbZOtpBFmDNkiNEMDUp
|
||||||
|
|
||||||
|
# Whether to receive ephemeral events via appservice transactions.
|
||||||
|
ephemeral_events: true
|
||||||
|
# Should incoming events be handled asynchronously?
|
||||||
|
# This may be necessary for large public instances with lots of messages going through.
|
||||||
|
# However, messages will not be guaranteed to be bridged in the same order they were sent in.
|
||||||
|
# This value doesn't affect the registration file.
|
||||||
|
async_transactions: false
|
||||||
|
|
||||||
|
# Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
|
||||||
|
as_token: "{{ secret "signal_as_token" }}"
|
||||||
|
hs_token: "{{ secret "signal_hs_token" }}"
|
||||||
|
|
||||||
|
# Localpart template of MXIDs for remote users.
|
||||||
|
# {{ "{{.}}" }} is replaced with the internal ID of the user.
|
||||||
|
username_template: signal_{{ "{{.}}" }}
|
||||||
|
|
||||||
|
# Config options that affect the Matrix connector of the bridge.
|
||||||
|
matrix:
|
||||||
|
# Whether the bridge should send the message status as a custom com.beeper.message_send_status event.
|
||||||
|
message_status_events: false
|
||||||
|
# Whether the bridge should send a read receipt after successfully bridging a message.
|
||||||
|
delivery_receipts: false
|
||||||
|
# Whether the bridge should send error notices via m.notice events when a message fails to bridge.
|
||||||
|
message_error_notices: true
|
||||||
|
# Whether the bridge should update the m.direct account data event when double puppeting is enabled.
|
||||||
|
sync_direct_chat_list: false
|
||||||
|
# Whether created rooms should have federation enabled. If false, created portal rooms
|
||||||
|
# will never be federated. Changing this option requires recreating rooms.
|
||||||
|
federate_rooms: true
|
||||||
|
|
||||||
|
# Settings for provisioning API
|
||||||
|
provisioning:
|
||||||
|
# Prefix for the provisioning API paths.
|
||||||
|
prefix: /_matrix/provision
|
||||||
|
# Shared secret for authentication. If set to "generate" or null, a random secret will be generated,
|
||||||
|
# or if set to "disable", the provisioning API will be disabled.
|
||||||
|
shared_secret: generate
|
||||||
|
# Whether to allow provisioning API requests to be authed using Matrix access tokens.
|
||||||
|
# This follows the same rules as double puppeting to determine which server to contact to check the token,
|
||||||
|
# which means that by default, it only works for users on the same server as the bridge.
|
||||||
|
allow_matrix_auth: true
|
||||||
|
# Enable debug API at /debug with provisioning authentication.
|
||||||
|
debug_endpoints: false
|
||||||
|
|
||||||
|
# Some networks require publicly accessible media download links (e.g. for user avatars when using Discord webhooks).
|
||||||
|
# These settings control whether the bridge will provide such public media access.
|
||||||
|
public_media:
|
||||||
|
# Should public media be enabled at all?
|
||||||
|
# The public_address field under the appservice section MUST be set when enabling public media.
|
||||||
|
enabled: false
|
||||||
|
# A key for signing public media URLs.
|
||||||
|
# If set to "generate", a random key will be generated.
|
||||||
|
signing_key: generate
|
||||||
|
# Number of seconds that public media URLs are valid for.
|
||||||
|
# If set to 0, URLs will never expire.
|
||||||
|
expiry: 0
|
||||||
|
# Length of hash to use for public media URLs. Must be between 0 and 32.
|
||||||
|
hash_length: 32
|
||||||
|
|
||||||
|
# Settings for converting remote media to custom mxc:// URIs instead of reuploading.
|
||||||
|
# More details can be found at https://docs.mau.fi/bridges/go/discord/direct-media.html
|
||||||
|
direct_media:
|
||||||
|
# Should custom mxc:// URIs be used instead of reuploading media?
|
||||||
|
enabled: false
|
||||||
|
# The server name to use for the custom mxc:// URIs.
|
||||||
|
# This server name will effectively be a real Matrix server, it just won't implement anything other than media.
|
||||||
|
# You must either set up .well-known delegation from this domain to the bridge, or proxy the domain directly to the bridge.
|
||||||
|
server_name: discord-media.example.com
|
||||||
|
# Optionally a custom .well-known response. This defaults to `server_name:443`
|
||||||
|
well_known_response:
|
||||||
|
# Optionally specify a custom prefix for the media ID part of the MXC URI.
|
||||||
|
media_id_prefix:
|
||||||
|
# If the remote network supports media downloads over HTTP, then the bridge will use MSC3860/MSC3916
|
||||||
|
# media download redirects if the requester supports it. Optionally, you can force redirects
|
||||||
|
# and not allow proxying at all by setting this to false.
|
||||||
|
# This option does nothing if the remote network does not support media downloads over HTTP.
|
||||||
|
allow_proxy: true
|
||||||
|
# Matrix server signing key to make the federation tester pass, same format as synapse's .signing.key file.
|
||||||
|
# This key is also used to sign the mxc:// URIs to ensure only the bridge can generate them.
|
||||||
|
server_key: generate
|
||||||
|
|
||||||
|
# Settings for backfilling messages.
|
||||||
|
# Note that the exact way settings are applied depends on the network connector.
|
||||||
|
# See https://docs.mau.fi/bridges/general/backfill.html for more details.
|
||||||
|
backfill:
|
||||||
|
# Whether to do backfilling at all.
|
||||||
|
enabled: false
|
||||||
|
# Maximum number of messages to backfill in empty rooms.
|
||||||
|
max_initial_messages: 50
|
||||||
|
# Maximum number of missed messages to backfill after bridge restarts.
|
||||||
|
max_catchup_messages: 500
|
||||||
|
# If a backfilled chat is older than this number of hours,
|
||||||
|
# mark it as read even if it's unread on the remote network.
|
||||||
|
unread_hours_threshold: 720
|
||||||
|
# Settings for backfilling threads within other backfills.
|
||||||
|
threads:
|
||||||
|
# Maximum number of messages to backfill in a new thread.
|
||||||
|
max_initial_messages: 50
|
||||||
|
# Settings for the backwards backfill queue. This only applies when connecting to
|
||||||
|
# Beeper as standard Matrix servers don't support inserting messages into history.
|
||||||
|
queue:
|
||||||
|
# Should the backfill queue be enabled?
|
||||||
|
enabled: false
|
||||||
|
# Number of messages to backfill in one batch.
|
||||||
|
batch_size: 100
|
||||||
|
# Delay between batches in seconds.
|
||||||
|
batch_delay: 20
|
||||||
|
# Maximum number of batches to backfill per portal.
|
||||||
|
# If set to -1, all available messages will be backfilled.
|
||||||
|
max_batches: -1
|
||||||
|
# Optional network-specific overrides for max batches.
|
||||||
|
# Interpretation of this field depends on the network connector.
|
||||||
|
max_batches_override: {}
|
||||||
|
|
||||||
|
# Settings for enabling double puppeting
|
||||||
|
double_puppet:
|
||||||
|
# Servers to always allow double puppeting from.
|
||||||
|
# This is only for other servers and should NOT contain the server the bridge is on.
|
||||||
|
servers:
|
||||||
|
{{ env "HOMESERVER_DOMAIN" }}: {{ env "HOMESERVER_URL" }}
|
||||||
|
# Whether to allow client API URL discovery for other servers. When using this option,
|
||||||
|
# users on other servers can use double puppeting even if their server URLs aren't
|
||||||
|
# explicitly added to the servers map above.
|
||||||
|
allow_discovery: false
|
||||||
|
# Shared secrets for automatic double puppeting.
|
||||||
|
# See https://docs.mau.fi/bridges/general/double-puppeting.html for instructions.
|
||||||
|
secrets:
|
||||||
|
{{ env "HOMESERVER_DOMAIN" }}: {{ secret "shared_secret_auth" }}
|
||||||
|
|
||||||
|
# End-to-bridge encryption support options.
|
||||||
|
#
|
||||||
|
# See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info.
|
||||||
|
encryption:
|
||||||
|
# Whether to enable encryption at all. If false, the bridge will not function in encrypted rooms.
|
||||||
|
allow: {{ env "SIGNAL_ENABLE_ENCRYPTION" }}
|
||||||
|
# Whether to force-enable encryption in all bridged rooms.
|
||||||
|
default: {{ env "SIGNAL_DEFAULT_ENCRYPTION" }}
|
||||||
|
# Whether to require all messages to be encrypted and drop any unencrypted messages.
|
||||||
|
require: false
|
||||||
|
# Whether to use MSC2409/MSC3202 instead of /sync long polling for receiving encryption-related data.
|
||||||
|
# This option is not yet compatible with standard Matrix servers like Synapse and should not be used.
|
||||||
|
appservice: false
|
||||||
|
# Enable key sharing? If enabled, key requests for rooms where users are in will be fulfilled.
|
||||||
|
# You must use a client that supports requesting keys from other users to use this feature.
|
||||||
|
allow_key_sharing: false
|
||||||
|
# Pickle key for encrypting encryption keys in the bridge database.
|
||||||
|
# If set to generate, a random key will be generated.
|
||||||
|
pickle_key: {{ secret "signal_pickle_key" }}
|
||||||
|
# Options for deleting megolm sessions from the bridge.
|
||||||
|
delete_keys:
|
||||||
|
# Beeper-specific: delete outbound sessions when hungryserv confirms
|
||||||
|
# that the user has uploaded the key to key backup.
|
||||||
|
delete_outbound_on_ack: false
|
||||||
|
# Don't store outbound sessions in the inbound table.
|
||||||
|
dont_store_outbound: false
|
||||||
|
# Ratchet megolm sessions forward after decrypting messages.
|
||||||
|
ratchet_on_decrypt: false
|
||||||
|
# Delete fully used keys (index >= max_messages) after decrypting messages.
|
||||||
|
delete_fully_used_on_decrypt: false
|
||||||
|
# Delete previous megolm sessions from same device when receiving a new one.
|
||||||
|
delete_prev_on_new_session: false
|
||||||
|
# Delete megolm sessions received from a device when the device is deleted.
|
||||||
|
delete_on_device_delete: false
|
||||||
|
# Periodically delete megolm sessions when 2x max_age has passed since receiving the session.
|
||||||
|
periodically_delete_expired: false
|
||||||
|
# Delete inbound megolm sessions that don't have the received_at field used for
|
||||||
|
# automatic ratcheting and expired session deletion. This is meant as a migration
|
||||||
|
# to delete old keys prior to the bridge update.
|
||||||
|
delete_outdated_inbound: false
|
||||||
|
# What level of device verification should be required from users?
|
||||||
|
#
|
||||||
|
# Valid levels:
|
||||||
|
# unverified - Send keys to all device in the room.
|
||||||
|
# cross-signed-untrusted - Require valid cross-signing, but trust all cross-signing keys.
|
||||||
|
# cross-signed-tofu - Require valid cross-signing, trust cross-signing keys on first use (and reject changes).
|
||||||
|
# cross-signed-verified - Require valid cross-signing, plus a valid user signature from the bridge bot.
|
||||||
|
# Note that creating user signatures from the bridge bot is not currently possible.
|
||||||
|
# verified - Require manual per-device verification
|
||||||
|
# (currently only possible by modifying the `trust` column in the `crypto_device` database table).
|
||||||
|
verification_levels:
|
||||||
|
# Minimum level for which the bridge should send keys to when bridging messages from the remote network to Matrix.
|
||||||
|
receive: unverified
|
||||||
|
# Minimum level that the bridge should accept for incoming Matrix messages.
|
||||||
|
send: unverified
|
||||||
|
# Minimum level that the bridge should require for accepting key requests.
|
||||||
|
share: cross-signed-tofu
|
||||||
|
# Options for Megolm room key rotation. These options allow you to configure the m.room.encryption event content.
|
||||||
|
# See https://spec.matrix.org/v1.10/client-server-api/#mroomencryption for more information about that event.
|
||||||
|
rotation:
|
||||||
|
# Enable custom Megolm room key rotation settings. Note that these
|
||||||
|
# settings will only apply to rooms created after this option is set.
|
||||||
|
enable_custom: false
|
||||||
|
# The maximum number of milliseconds a session should be used
|
||||||
|
# before changing it. The Matrix spec recommends 604800000 (a week)
|
||||||
|
# as the default.
|
||||||
|
milliseconds: 604800000
|
||||||
|
# The maximum number of messages that should be sent with a given a
|
||||||
|
# session before changing it. The Matrix spec recommends 100 as the
|
||||||
|
# default.
|
||||||
|
messages: 100
|
||||||
|
# Disable rotating keys when a user's devices change?
|
||||||
|
# You should not enable this option unless you understand all the implications.
|
||||||
|
disable_device_change_key_rotation: false
|
||||||
|
|
||||||
|
# Logging config. See https://github.com/tulir/zeroconfig for details.
|
||||||
|
logging:
|
||||||
|
min_level: debug
|
||||||
|
writers:
|
||||||
|
- type: stdout
|
||||||
|
format: pretty-colored
|
||||||
|
- type: file
|
||||||
|
format: json
|
||||||
|
filename: ./logs/bridge.log
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 10
|
||||||
|
compress: false
|
||||||
625
telegram_bridge.yaml.tmpl
Normal file
625
telegram_bridge.yaml.tmpl
Normal file
@ -0,0 +1,625 @@
|
|||||||
|
# Network-specific config options
|
||||||
|
network:
|
||||||
|
# Get your own API keys at https://my.telegram.org/apps
|
||||||
|
api_id: {{ env "TELEGRAM_APP_ID" }}
|
||||||
|
api_hash: {{ secret "telegram_api_hash" }}
|
||||||
|
|
||||||
|
# Device info shown in the Telegram device list.
|
||||||
|
device_info:
|
||||||
|
device_model: mautrix-telegram
|
||||||
|
system_version:
|
||||||
|
app_version: auto
|
||||||
|
lang_code: en
|
||||||
|
system_lang_code: en
|
||||||
|
|
||||||
|
# Settings for converting animated stickers.
|
||||||
|
animated_sticker:
|
||||||
|
# Format to which animated stickers should be converted.
|
||||||
|
#
|
||||||
|
# disable - no conversion, send as-is (gzipped lottie)
|
||||||
|
# png - converts to non-animated png (fastest),
|
||||||
|
# gif - converts to animated gif
|
||||||
|
# webm - converts to webm video, requires ffmpeg executable with vp9 codec
|
||||||
|
# and webm container support
|
||||||
|
# webp - converts to animated webp, requires ffmpeg executable with webp
|
||||||
|
# codec/container support
|
||||||
|
target: gif
|
||||||
|
# Should video stickers be converted to the specified format as well?
|
||||||
|
convert_from_webm: false
|
||||||
|
# Arguments for converter. All converters take width and height.
|
||||||
|
args:
|
||||||
|
width: 256
|
||||||
|
height: 256
|
||||||
|
fps: 25 # only for webm, webp and gif (2, 5, 10, 20 or 25 recommended)
|
||||||
|
|
||||||
|
# Settings for syncing the member list for portals.
|
||||||
|
member_list:
|
||||||
|
# Maximum number of members to sync per portal when starting up. Other
|
||||||
|
# members will be synced when they send messages. The maximum is 10000,
|
||||||
|
# after which the Telegram server will not send any more members.
|
||||||
|
#
|
||||||
|
# -1 means no limit (which means it's limited to 10000 by the server)
|
||||||
|
max_initial_sync: 100
|
||||||
|
# Whether or not to sync the member list in broadcast channels. If
|
||||||
|
# disabled, members will still be synced when they send messages.
|
||||||
|
#
|
||||||
|
# If no channel admins have logged into the bridge, the bridge won't be
|
||||||
|
# able to sync the member list regardless of this setting.
|
||||||
|
sync_broadcast_channels: {{ env "TELEGRAM_SYNC_CHANNEL_MEMBERS" }}
|
||||||
|
# Whether or not to skip deleted members when syncing members.
|
||||||
|
skip_deleted: true
|
||||||
|
|
||||||
|
# Settings for pings to the Telegram server.
|
||||||
|
ping:
|
||||||
|
# The interval (in seconds) between pings.
|
||||||
|
interval_seconds: 30
|
||||||
|
# The timeout (in seconds) for a single ping.
|
||||||
|
timeout_seconds: 10
|
||||||
|
|
||||||
|
# Proxy settings
|
||||||
|
proxy:
|
||||||
|
# Allowed types: disabled, socks5, mtproxy
|
||||||
|
type: disabled
|
||||||
|
# Proxy IP address/domain name and port.
|
||||||
|
address: "127.0.0.1:1080"
|
||||||
|
# Proxy authentication (optional). Put MTProxy secret in password field.
|
||||||
|
username:
|
||||||
|
password:
|
||||||
|
|
||||||
|
sync:
|
||||||
|
# Number of most recently active dialogs to check when syncing chats.
|
||||||
|
# Set to -1 to remove limit.
|
||||||
|
update_limit: 100
|
||||||
|
# Number of most recently active dialogs to create portals for when syncing chats.
|
||||||
|
# Set to -1 to remove limit.
|
||||||
|
create_limit: 15
|
||||||
|
# Number of chats to sync immediately on login before the data export is accepted.
|
||||||
|
# The create_limit above still applies. This is ignored if takeout.dialog_sync is false.
|
||||||
|
login_sync_limit: 15
|
||||||
|
# Whether or not to sync and create portals for direct chats at startup.
|
||||||
|
direct_chats: true
|
||||||
|
|
||||||
|
takeout:
|
||||||
|
# Should the bridge use the data export mode for syncing the full chat list?
|
||||||
|
# If true, login_sync_limit of chats is synced immediately on login,
|
||||||
|
# then the rest are synced after the takeout is accepted.
|
||||||
|
dialog_sync: false
|
||||||
|
# Should the bridge use the data export mode for forward backfilling messages?
|
||||||
|
# This should be set to true if the forward backfill limits are set to high values,
|
||||||
|
# but is probably not necessary otherwise.
|
||||||
|
forward_backfill: false
|
||||||
|
# Should the bridge use the data export mode for backward backfilling messages?
|
||||||
|
# This only affects the backfill queue, which is only available on Beeper.
|
||||||
|
backward_backfill: false
|
||||||
|
|
||||||
|
# Maximum number of participants in chats to bridge. Only applies when the
|
||||||
|
# portal is being created. If there are more members when trying to create
|
||||||
|
# a room, the room creation will be cancelled.
|
||||||
|
#
|
||||||
|
# -1 means no limit (which means all chats can be bridged)
|
||||||
|
max_member_count: -1
|
||||||
|
# Should personal avatars (that are only visible to specific users) be allowed?
|
||||||
|
contact_avatars: false
|
||||||
|
# Should contact names be updated from any source even if a name is already set?
|
||||||
|
# Note that contact names will still be used if there's no other name available.
|
||||||
|
contact_names: false
|
||||||
|
# Should the bridge send all unicode reactions as custom emoji reactions to
|
||||||
|
# Telegram? By default, the bridge only uses custom emojis for unicode emojis
|
||||||
|
# that aren't allowed in reactions.
|
||||||
|
always_custom_emoji_reaction: false
|
||||||
|
# The avatar to use for the Telegram Saved Messages chat
|
||||||
|
saved_message_avatar: mxc://maunium.net/XhhfHoPejeneOngMyBbtyWDk
|
||||||
|
# Create a new room and tombstone the old one when upgrading rooms
|
||||||
|
always_tombstone_on_supergroup_migration: false
|
||||||
|
# Maximum number of pixels in an image before sending to Telegram as a
|
||||||
|
# document. Defaults to 4096x4096 = 16777216.
|
||||||
|
image_as_file_pixels: 16777216
|
||||||
|
# Should view-once messages be disabled entirely?
|
||||||
|
disable_view_once: false
|
||||||
|
# Should video URL previews be bridged as m.video messages to Matrix?
|
||||||
|
# By default, video URL previews will not be bridged.
|
||||||
|
video_url_preview_as_file: false
|
||||||
|
# Displayname template for Telegram users.
|
||||||
|
# {{ "{{ .FullName }}" }} - the full name of the Telegram user
|
||||||
|
# {{ "{{ .FirstName }}" }} - the first name of the Telegram user
|
||||||
|
# {{ "{{ .LastName }}" }} - the last name of the Telegram user
|
||||||
|
# {{ "{{ .Username }}" }} - the primary username of the Telegram user, if the user has one
|
||||||
|
# {{ "{{ .UserID }}" }} - the internal user ID of the Telegram user
|
||||||
|
# {{ "{{ .Deleted }}" }} - true if the user has been deleted, false otherwise
|
||||||
|
displayname_template: '{{ "{{ if .Deleted }}Deleted account {{ .UserID }}{{ else }}{{ .FullName }}{{ end }}" }}'
|
||||||
|
|
||||||
|
|
||||||
|
# Config options that affect the central bridge module.
|
||||||
|
bridge:
|
||||||
|
# The prefix for commands. Only required in non-management rooms.
|
||||||
|
command_prefix: '!tg'
|
||||||
|
# Should the bridge create a space for each login containing the rooms that account is in?
|
||||||
|
personal_filtering_spaces: true
|
||||||
|
# Whether the bridge should set names and avatars explicitly for DM portals.
|
||||||
|
# This is only necessary when using clients that don't support MSC4171.
|
||||||
|
private_chat_portal_meta: true
|
||||||
|
# Should events be handled asynchronously within portal rooms?
|
||||||
|
# If true, events may end up being out of order, but slow events won't block other ones.
|
||||||
|
# This is not yet safe to use.
|
||||||
|
async_events: false
|
||||||
|
# Should every user have their own portals rather than sharing them?
|
||||||
|
# By default, users who are in the same group on the remote network will be
|
||||||
|
# in the same Matrix room bridged to that group. If this is set to true,
|
||||||
|
# every user will get their own Matrix room instead.
|
||||||
|
# SETTING THIS IS IRREVERSIBLE AND POTENTIALLY DESTRUCTIVE IF PORTALS ALREADY EXIST.
|
||||||
|
split_portals: false
|
||||||
|
# Should the bridge resend `m.bridge` events to all portals on startup?
|
||||||
|
resend_bridge_info: false
|
||||||
|
# Should `m.bridge` events be sent without a state key?
|
||||||
|
# By default, the bridge uses a unique key that won't conflict with other bridges.
|
||||||
|
no_bridge_info_state_key: false
|
||||||
|
# Should bridge connection status be sent to the management room as `m.notice` events?
|
||||||
|
# These contain the same data that can be posted to an external HTTP server using homeserver -> status_endpoint.
|
||||||
|
# Allowed values: none, errors, all
|
||||||
|
bridge_status_notices: errors
|
||||||
|
# How long after an unknown error should the bridge attempt a full reconnect?
|
||||||
|
# Must be at least 1 minute. The bridge will add an extra ±20% jitter to this value.
|
||||||
|
unknown_error_auto_reconnect: null
|
||||||
|
# Maximum number of times to do the auto-reconnect above.
|
||||||
|
# The counter is per login, but is never reset except on logout and restart.
|
||||||
|
unknown_error_max_auto_reconnects: 10
|
||||||
|
|
||||||
|
# Should leaving Matrix rooms be bridged as leaving groups on the remote network?
|
||||||
|
bridge_matrix_leave: false
|
||||||
|
# Should `m.notice` messages be bridged?
|
||||||
|
bridge_notices: false
|
||||||
|
# Should room tags only be synced when creating the portal? Tags mean things like favorite/pin and archive/low priority.
|
||||||
|
# Tags currently can't be synced back to the remote network, so a continuous sync means tagging from Matrix will be undone.
|
||||||
|
tag_only_on_create: true
|
||||||
|
# List of tags to allow bridging. If empty, no tags will be bridged.
|
||||||
|
only_bridge_tags: [m.favourite, m.lowpriority]
|
||||||
|
# Should room mute status only be synced when creating the portal?
|
||||||
|
# Like tags, mutes can't currently be synced back to the remote network.
|
||||||
|
mute_only_on_create: true
|
||||||
|
# Should the bridge check the db to ensure that incoming events haven't been handled before
|
||||||
|
deduplicate_matrix_messages: false
|
||||||
|
# Should cross-room reply metadata be bridged?
|
||||||
|
# Most Matrix clients don't support this and servers may reject such messages too.
|
||||||
|
cross_room_replies: false
|
||||||
|
# If a state event fails to bridge, should the bridge revert any state changes made by that event?
|
||||||
|
revert_failed_state_changes: false
|
||||||
|
# In portals with no relay set, should Matrix users be kicked if they're
|
||||||
|
# not logged into an account that's in the remote chat?
|
||||||
|
kick_matrix_users: true
|
||||||
|
# Should the bridge listen to com.beeper.state_request events?
|
||||||
|
# This is not necessary for anything outside of Beeper.
|
||||||
|
enable_send_state_requests: false
|
||||||
|
# Should the com.beeper.bridge.identifiers list in global ghost profiles include phone numbers?
|
||||||
|
phone_numbers_in_profile: false
|
||||||
|
|
||||||
|
# What should be done to portal rooms when a user logs out or is logged out?
|
||||||
|
# Permitted values:
|
||||||
|
# nothing - Do nothing, let the user stay in the portals
|
||||||
|
# kick - Remove the user from the portal rooms, but don't delete them
|
||||||
|
# unbridge - Remove all ghosts in the room and disassociate it from the remote chat
|
||||||
|
# delete - Remove all ghosts and users from the room (i.e. delete it)
|
||||||
|
cleanup_on_logout:
|
||||||
|
# Should cleanup on logout be enabled at all?
|
||||||
|
enabled: false
|
||||||
|
# Settings for manual logouts (explicitly initiated by the Matrix user)
|
||||||
|
manual:
|
||||||
|
# Action for private portals which will never be shared with other Matrix users.
|
||||||
|
private: nothing
|
||||||
|
# Action for portals with a relay user configured.
|
||||||
|
relayed: nothing
|
||||||
|
# Action for portals which may be shared, but don't currently have any other Matrix users.
|
||||||
|
shared_no_users: nothing
|
||||||
|
# Action for portals which have other logged-in Matrix users.
|
||||||
|
shared_has_users: nothing
|
||||||
|
# Settings for credentials being invalidated (initiated by the remote network, possibly through user action).
|
||||||
|
# Keys have the same meanings as in the manual section.
|
||||||
|
bad_credentials:
|
||||||
|
private: nothing
|
||||||
|
relayed: nothing
|
||||||
|
shared_no_users: nothing
|
||||||
|
shared_has_users: nothing
|
||||||
|
|
||||||
|
# Settings for relay mode
|
||||||
|
relay:
|
||||||
|
# Whether relay mode should be allowed. If allowed, the set-relay command can be used to turn any
|
||||||
|
# authenticated user into a relaybot for that chat.
|
||||||
|
enabled: true
|
||||||
|
# Should only admins be allowed to set themselves as relay users?
|
||||||
|
# If true, non-admins can only set users listed in default_relays as relays in a room.
|
||||||
|
admin_only: true
|
||||||
|
# Should default relays be preferred when an explicit login ID isn't specified even if the user is logged in?
|
||||||
|
# This applies to the set-relay and bridge commands sent by any user, including admins.
|
||||||
|
prefer_default: true
|
||||||
|
# Should non-admins be allowed to use the bridge and sync-chat commands via default relays specified below?
|
||||||
|
allow_bridge: true
|
||||||
|
# List of user login IDs which anyone can set as a relay, as long as the relay user is in the room.
|
||||||
|
default_relays: []
|
||||||
|
# The formats to use when sending messages via the relaybot.
|
||||||
|
# Available variables:
|
||||||
|
# .Sender.UserID - The Matrix user ID of the sender.
|
||||||
|
# .Sender.Displayname - The display name of the sender (if set).
|
||||||
|
# .Sender.RequiresDisambiguation - Whether the sender's name may be confused with the name of another user in the room.
|
||||||
|
# .Sender.DisambiguatedName - The disambiguated name of the sender. This will be the displayname if set,
|
||||||
|
# plus the user ID in parentheses if the displayname is not unique.
|
||||||
|
# If the displayname is not set, this is just the user ID.
|
||||||
|
# .Message - The `formatted_body` field of the message.
|
||||||
|
# .Caption - The `formatted_body` field of the message, if it's a caption. Otherwise an empty string.
|
||||||
|
# .FileName - The name of the file being sent.
|
||||||
|
message_formats:
|
||||||
|
m.text: "{{`{{ .Sender.DisambiguatedName }}: {{ .Message }}`}}"
|
||||||
|
m.notice: "{{`{{ .Sender.DisambiguatedName }}: {{ .Message }}`}}"
|
||||||
|
m.emote: "{{`* {{ .Sender.DisambiguatedName }} {{ .Message }}`}}"
|
||||||
|
m.file: "{{`{{ .Sender.DisambiguatedName }} sent a file{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.image: "{{`{{ .Sender.DisambiguatedName }} sent an image{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.audio: "{{`{{ .Sender.DisambiguatedName }} sent an audio file{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.video: "{{`{{ .Sender.DisambiguatedName }} sent a video{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
m.location: "{{`{{ .Sender.DisambiguatedName }} sent a location{{ if .Caption }}: {{ .Caption }}{{ end }}`}}"
|
||||||
|
# For networks that support per-message displaynames (i.e. Slack and Discord), the template for those names.
|
||||||
|
# This has all the Sender variables available under message_formats (but without the .Sender prefix).
|
||||||
|
# Note that you need to manually remove the displayname from message_formats above.
|
||||||
|
displayname_format: "{{`{{ .DisambiguatedName }}`}}"
|
||||||
|
|
||||||
|
# Filter for automatically creating portals.
|
||||||
|
portal_create_filter:
|
||||||
|
# The mode for filtering, either `deny` or `allow`
|
||||||
|
mode: deny
|
||||||
|
# The list of portal IDs to deny or allow depending on the mode config.
|
||||||
|
# Items here can either be the plain portal ID as a string, or an object with `id` and `receiver` fields.
|
||||||
|
# The receiver field is necessary if you want to target a specific DM portal for example.
|
||||||
|
list: []
|
||||||
|
# A list of user login IDs from which to always deny creating portals.
|
||||||
|
# This is meant to be used with default relays, such that the relay bot
|
||||||
|
# being added to a group wouldn't automatically trigger portal creation.
|
||||||
|
always_deny_from_login: []
|
||||||
|
|
||||||
|
# Permissions for using the bridge.
|
||||||
|
# Permitted values:
|
||||||
|
# relay - Talk through the relaybot (if enabled), no access otherwise
|
||||||
|
# commands - Access to use commands in the bridge, but not login.
|
||||||
|
# user - Access to use the bridge with puppeting.
|
||||||
|
# admin - Full access, user level with some additional administration tools.
|
||||||
|
# Permitted keys:
|
||||||
|
# * - All Matrix users
|
||||||
|
# domain - All users on that homeserver
|
||||||
|
# mxid - Specific user
|
||||||
|
permissions: {{ env "TELEGRAM_BRIDGE_PERMISSIONS" }}
|
||||||
|
|
||||||
|
# Config for the bridge's database.
|
||||||
|
database:
|
||||||
|
# The database type. "sqlite3-fk-wal" and "postgres" are supported.
|
||||||
|
type: postgres
|
||||||
|
# The database URI.
|
||||||
|
# SQLite: A raw file path is supported, but `file:<path>?_txlock=immediate` is recommended.
|
||||||
|
# https://github.com/mattn/go-sqlite3#connection-string
|
||||||
|
# Postgres: Connection string. For example, postgres://user:password@host/database?sslmode=disable
|
||||||
|
# To connect via Unix socket, use something like postgres:///dbname?host=/var/run/postgresql
|
||||||
|
uri: postgres://telegrambridge:{{ secret "telegram_db_password" }}@telegramdb/telegrambridge?sslmode=disable
|
||||||
|
# Maximum number of connections.
|
||||||
|
max_open_conns: 5
|
||||||
|
max_idle_conns: 1
|
||||||
|
# Maximum connection idle time and lifetime before they're closed. Disabled if null.
|
||||||
|
# Parsed with https://pkg.go.dev/time#ParseDuration
|
||||||
|
max_conn_idle_time: null
|
||||||
|
max_conn_lifetime: null
|
||||||
|
|
||||||
|
# Homeserver details.
|
||||||
|
homeserver:
|
||||||
|
# The address that this appservice can use to connect to the homeserver.
|
||||||
|
# Local addresses without HTTPS are generally recommended when the bridge is running on the same machine,
|
||||||
|
# but https also works if they run on different machines.
|
||||||
|
address: {{ env "HOMESERVER_URL" }}
|
||||||
|
# The domain of the homeserver (also known as server_name, used for MXIDs, etc).
|
||||||
|
domain: {{ env "HOMESERVER_DOMAIN" }}
|
||||||
|
|
||||||
|
# What software is the homeserver running?
|
||||||
|
# Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here.
|
||||||
|
software: standard
|
||||||
|
# The URL to push real-time bridge status to.
|
||||||
|
# If set, the bridge will make POST requests to this URL whenever a user's remote network connection state changes.
|
||||||
|
# The bridge will use the appservice as_token to authorize requests.
|
||||||
|
status_endpoint:
|
||||||
|
# Endpoint for reporting per-message status.
|
||||||
|
# If set, the bridge will make POST requests to this URL when processing a message from Matrix.
|
||||||
|
# It will make one request when receiving the message (step BRIDGE), one after decrypting if applicable
|
||||||
|
# (step DECRYPTED) and one after sending to the remote network (step REMOTE). Errors will also be reported.
|
||||||
|
# The bridge will use the appservice as_token to authorize requests.
|
||||||
|
message_send_checkpoint_endpoint:
|
||||||
|
# Does the homeserver support https://github.com/matrix-org/matrix-spec-proposals/pull/2246?
|
||||||
|
async_media: false
|
||||||
|
|
||||||
|
# Should the bridge use a websocket for connecting to the homeserver?
|
||||||
|
# The server side is currently not documented anywhere and is only implemented by mautrix-wsproxy,
|
||||||
|
# mautrix-asmux (deprecated), and hungryserv (proprietary).
|
||||||
|
websocket: false
|
||||||
|
# How often should the websocket be pinged? Pinging will be disabled if this is zero.
|
||||||
|
ping_interval_seconds: 0
|
||||||
|
# When requests to the homeserver fail with a 502/503/504/429 status or a network error,
|
||||||
|
# how many times should the bridge retry the request before giving up?
|
||||||
|
retry_limit: 4
|
||||||
|
|
||||||
|
# Application service host/registration related details.
|
||||||
|
# Changing these values requires regeneration of the registration (except when noted otherwise)
|
||||||
|
appservice:
|
||||||
|
# The address that the homeserver can use to connect to this appservice.
|
||||||
|
# Like the homeserver address, a local non-https address is recommended when the bridge is on the same machine.
|
||||||
|
# If the bridge is elsewhere, you must secure the connection yourself (e.g. with https or wireguard)
|
||||||
|
# If you want to use https, you need to use a reverse proxy. The bridge does not have TLS support built in.
|
||||||
|
address: http://telegrambridge:29317
|
||||||
|
# A public address that external services can use to reach this appservice.
|
||||||
|
# This is only needed for things like public media. A reverse proxy is generally necessary when using this field.
|
||||||
|
# This value doesn't affect the registration file.
|
||||||
|
public_address: https://bridge.example.com
|
||||||
|
|
||||||
|
# The hostname and port where this appservice should listen.
|
||||||
|
# For Docker, you generally have to change the hostname to 0.0.0.0.
|
||||||
|
hostname: 0.0.0.0
|
||||||
|
port: 29317
|
||||||
|
|
||||||
|
# The unique ID of this appservice.
|
||||||
|
id: {{ env "APP_SERVICE_ID" }}
|
||||||
|
# Appservice bot details.
|
||||||
|
bot:
|
||||||
|
# Username of the appservice bot.
|
||||||
|
username: {{ env "APP_SERVICE_BOT_USERNAME" }}
|
||||||
|
# Display name and avatar for bot. Set to "remove" to remove display name/avatar, leave empty
|
||||||
|
# to leave display name/avatar as-is.
|
||||||
|
displayname: {{ env "APP_SERVICE_DISPLAY_NAME" }}
|
||||||
|
avatar: mxc://maunium.net/tJCRmUyJDsgRNgqhOgoiHWbX
|
||||||
|
|
||||||
|
# Whether to receive ephemeral events via appservice transactions.
|
||||||
|
ephemeral_events: true
|
||||||
|
# Should incoming events be handled asynchronously?
|
||||||
|
# This may be necessary for large public instances with lots of messages going through.
|
||||||
|
# However, messages will not be guaranteed to be bridged in the same order they were sent in.
|
||||||
|
# This value doesn't affect the registration file.
|
||||||
|
async_transactions: false
|
||||||
|
|
||||||
|
# Authentication tokens for AS <-> HS communication. Autogenerated; do not modify.
|
||||||
|
as_token: "{{ secret "telegram_as_token" }}"
|
||||||
|
hs_token: "{{ secret "telegram_hs_token" }}"
|
||||||
|
|
||||||
|
# Localpart template of MXIDs for remote users.
|
||||||
|
# {{ "{{.}}" }} is replaced with the internal ID of the user.
|
||||||
|
username_template: telegram_{{ "{{.}}" }}
|
||||||
|
|
||||||
|
# Config options that affect the Matrix connector of the bridge.
|
||||||
|
matrix:
|
||||||
|
# Whether the bridge should send the message status as a custom com.beeper.message_send_status event.
|
||||||
|
message_status_events: false
|
||||||
|
# Whether the bridge should send a read receipt after successfully bridging a message.
|
||||||
|
delivery_receipts: false
|
||||||
|
# Whether the bridge should send error notices via m.notice events when a message fails to bridge.
|
||||||
|
message_error_notices: true
|
||||||
|
# Whether the bridge should update the m.direct account data event when double puppeting is enabled.
|
||||||
|
sync_direct_chat_list: true
|
||||||
|
# Whether created rooms should have federation enabled. If false, created portal rooms
|
||||||
|
# will never be federated. Changing this option requires recreating rooms.
|
||||||
|
federate_rooms: true
|
||||||
|
# The threshold as bytes after which the bridge should roundtrip uploads via the disk
|
||||||
|
# rather than keeping the whole file in memory.
|
||||||
|
upload_file_threshold: 5242880
|
||||||
|
# Should the bridge set additional custom profile info for ghosts?
|
||||||
|
# This can make a lot of requests, as there's no batch profile update endpoint.
|
||||||
|
ghost_extra_profile_info: false
|
||||||
|
|
||||||
|
# Segment-compatible analytics endpoint for tracking some events, like provisioning API login and encryption errors.
|
||||||
|
analytics:
|
||||||
|
# API key to send with tracking requests. Tracking is disabled if this is null.
|
||||||
|
token: null
|
||||||
|
# Address to send tracking requests to.
|
||||||
|
url: https://api.segment.io/v1/track
|
||||||
|
# Optional user ID for tracking events. If null, defaults to using Matrix user ID.
|
||||||
|
user_id: null
|
||||||
|
|
||||||
|
# Settings for provisioning API
|
||||||
|
provisioning:
|
||||||
|
# Shared secret for authentication. If set to "generate" or null, a random secret will be generated,
|
||||||
|
# or if set to "disable", the provisioning API will be disabled. Must be at least 16 characters.
|
||||||
|
shared_secret: generate
|
||||||
|
# Whether to allow provisioning API requests to be authed using Matrix access tokens.
|
||||||
|
# This follows the same rules as double puppeting to determine which server to contact to check the token,
|
||||||
|
# which means that by default, it only works for users on the same server as the bridge.
|
||||||
|
allow_matrix_auth: true
|
||||||
|
# Enable debug API at /debug with provisioning authentication.
|
||||||
|
debug_endpoints: false
|
||||||
|
# Enable session transfers between bridges. Note that this only validates Matrix or shared secret
|
||||||
|
# auth before passing live network client credentials down in the response.
|
||||||
|
enable_session_transfers: false
|
||||||
|
|
||||||
|
# Some networks require publicly accessible media download links (e.g. for user avatars when using Discord webhooks).
|
||||||
|
# These settings control whether the bridge will provide such public media access.
|
||||||
|
public_media:
|
||||||
|
# Should public media be enabled at all?
|
||||||
|
# The public_address field under the appservice section MUST be set when enabling public media.
|
||||||
|
enabled: false
|
||||||
|
# A key for signing public media URLs.
|
||||||
|
# If set to "generate", a random key will be generated.
|
||||||
|
signing_key: generate
|
||||||
|
# Number of seconds that public media URLs are valid for.
|
||||||
|
# If set to 0, URLs will never expire.
|
||||||
|
expiry: 0
|
||||||
|
# Length of hash to use for public media URLs. Must be between 0 and 32.
|
||||||
|
hash_length: 32
|
||||||
|
# The path prefix for generated URLs. Note that this will NOT change the path where media is actually served.
|
||||||
|
# If you change this, you must configure your reverse proxy to rewrite the path accordingly.
|
||||||
|
path_prefix: /_mautrix/publicmedia
|
||||||
|
# Should the bridge store media metadata in the database in order to support encrypted media and generate shorter URLs?
|
||||||
|
# If false, the generated URLs will just have the MXC URI and a HMAC signature.
|
||||||
|
# The hash_length field will be used to decide the length of the generated URL.
|
||||||
|
# This also allows invalidating URLs by deleting the database entry.
|
||||||
|
use_database: false
|
||||||
|
|
||||||
|
# Settings for converting remote media to custom mxc:// URIs instead of reuploading.
|
||||||
|
# More details can be found at https://docs.mau.fi/bridges/go/discord/direct-media.html
|
||||||
|
direct_media:
|
||||||
|
# Should custom mxc:// URIs be used instead of reuploading media?
|
||||||
|
enabled: false
|
||||||
|
# The server name to use for the custom mxc:// URIs.
|
||||||
|
# This server name will effectively be a real Matrix server, it just won't implement anything other than media.
|
||||||
|
# You must either set up .well-known delegation from this domain to the bridge, or proxy the domain directly to the bridge.
|
||||||
|
server_name: discord-media.example.com
|
||||||
|
# Optionally a custom .well-known response. This defaults to `server_name:443`
|
||||||
|
well_known_response:
|
||||||
|
# Optionally specify a custom prefix for the media ID part of the MXC URI.
|
||||||
|
media_id_prefix:
|
||||||
|
# If the remote network supports media downloads over HTTP, then the bridge will use MSC3860/MSC3916
|
||||||
|
# media download redirects if the requester supports it. Optionally, you can force redirects
|
||||||
|
# and not allow proxying at all by setting this to false.
|
||||||
|
# This option does nothing if the remote network does not support media downloads over HTTP.
|
||||||
|
allow_proxy: true
|
||||||
|
# Matrix server signing key to make the federation tester pass, same format as synapse's .signing.key file.
|
||||||
|
# This key is also used to sign the mxc:// URIs to ensure only the bridge can generate them.
|
||||||
|
server_key: generate
|
||||||
|
|
||||||
|
# Settings for backfilling messages.
|
||||||
|
# Note that the exact way settings are applied depends on the network connector.
|
||||||
|
# See https://docs.mau.fi/bridges/general/backfill.html for more details.
|
||||||
|
backfill:
|
||||||
|
# Whether to do backfilling at all.
|
||||||
|
enabled: false
|
||||||
|
# Maximum number of messages to backfill in empty rooms.
|
||||||
|
# If this is zero or negative, backfill will be disabled in new rooms.
|
||||||
|
max_initial_messages: 50
|
||||||
|
# Maximum number of missed messages to backfill after bridge restarts.
|
||||||
|
max_catchup_messages: 500
|
||||||
|
# If a backfilled chat is older than this number of hours,
|
||||||
|
# mark it as read even if it's unread on the remote network.
|
||||||
|
unread_hours_threshold: 720
|
||||||
|
# Settings for backfilling threads within other backfills.
|
||||||
|
threads:
|
||||||
|
# Maximum number of messages to backfill in a new thread.
|
||||||
|
max_initial_messages: 50
|
||||||
|
# Settings for the backwards backfill queue. This only applies when connecting to
|
||||||
|
# Beeper as standard Matrix servers don't support inserting messages into history.
|
||||||
|
queue:
|
||||||
|
# Should the backfill queue be enabled?
|
||||||
|
enabled: false
|
||||||
|
# Should manual calls to backfill queue tasks be allowed?
|
||||||
|
manual: false
|
||||||
|
# Number of messages to backfill in one batch.
|
||||||
|
batch_size: 100
|
||||||
|
# Delay between batches in seconds.
|
||||||
|
batch_delay: 20
|
||||||
|
# Maximum number of batches to backfill per portal.
|
||||||
|
# If set to -1, all available messages will be backfilled.
|
||||||
|
max_batches: -1
|
||||||
|
# Optional network-specific overrides for max batches.
|
||||||
|
# Interpretation of this field depends on the network connector.
|
||||||
|
max_batches_override: {}
|
||||||
|
|
||||||
|
# Settings for enabling double puppeting
|
||||||
|
double_puppet:
|
||||||
|
# Servers to always allow double puppeting from.
|
||||||
|
# This is only for other servers and should NOT contain the server the bridge is on.
|
||||||
|
servers:
|
||||||
|
{{ env "HOMESERVER_DOMAIN" }}: {{ env "HOMESERVER_URL" }}
|
||||||
|
# Whether to allow client API URL discovery for other servers. When using this option,
|
||||||
|
# users on other servers can use double puppeting even if their server URLs aren't
|
||||||
|
# explicitly added to the servers map above.
|
||||||
|
allow_discovery: false
|
||||||
|
# Shared secrets for automatic double puppeting.
|
||||||
|
# See https://docs.mau.fi/bridges/general/double-puppeting.html for instructions.
|
||||||
|
secrets:
|
||||||
|
{{ env "HOMESERVER_DOMAIN" }}: {{ secret "shared_secret_auth" }}
|
||||||
|
|
||||||
|
# End-to-bridge encryption support options.
|
||||||
|
#
|
||||||
|
# See https://docs.mau.fi/bridges/general/end-to-bridge-encryption.html for more info.
|
||||||
|
encryption:
|
||||||
|
# Whether to enable encryption at all. If false, the bridge will not function in encrypted rooms.
|
||||||
|
allow: {{ env "ENABLE_ENCRYPTION" }}
|
||||||
|
# Whether to force-enable encryption in all bridged rooms.
|
||||||
|
default: false
|
||||||
|
# Whether to require all messages to be encrypted and drop any unencrypted messages.
|
||||||
|
require: false
|
||||||
|
# Whether to use MSC3202/MSC4203 instead of /sync long polling for receiving encryption-related data.
|
||||||
|
# This is an experimental option, see the docs for more info.
|
||||||
|
# Changing this option requires updating the appservice registration file.
|
||||||
|
appservice: false
|
||||||
|
# Whether to use MSC4190 instead of appservice login to create the bridge bot device.
|
||||||
|
# Requires the homeserver to support MSC4190 and the device masquerading parts of MSC3202.
|
||||||
|
# Only relevant when using end-to-bridge encryption, required when using encryption with next-gen auth (MSC3861).
|
||||||
|
msc4190: false
|
||||||
|
# Whether to encrypt reactions and reply metadata as per MSC4392.
|
||||||
|
# This is not supported by most clients.
|
||||||
|
msc4392: false
|
||||||
|
# Should the bridge bot generate a recovery key and cross-signing keys and verify itself?
|
||||||
|
# Note that without the latest version of MSC4190, this will fail if you reset the bridge database.
|
||||||
|
# The generated recovery key will be saved in the kv_store table under `recovery_key`.
|
||||||
|
self_sign: false
|
||||||
|
# Enable key sharing? If enabled, key requests for rooms where users are in will be fulfilled.
|
||||||
|
# You must use a client that supports requesting keys from other users to use this feature.
|
||||||
|
allow_key_sharing: true
|
||||||
|
# Should m.mentions be sent in the unencrypted content? This is non-standard and should not be enabled.
|
||||||
|
plaintext_mentions: false
|
||||||
|
# Pickle key for encrypting encryption keys in the bridge database.
|
||||||
|
# If set to generate, a random key will be generated.
|
||||||
|
pickle_key: generate
|
||||||
|
# Options for deleting megolm sessions from the bridge.
|
||||||
|
delete_keys:
|
||||||
|
# Beeper-specific: delete outbound sessions when hungryserv confirms
|
||||||
|
# that the user has uploaded the key to key backup.
|
||||||
|
delete_outbound_on_ack: false
|
||||||
|
# Don't store outbound sessions in the inbound table.
|
||||||
|
dont_store_outbound: false
|
||||||
|
# Ratchet megolm sessions forward after decrypting messages.
|
||||||
|
ratchet_on_decrypt: false
|
||||||
|
# Delete fully used keys (index >= max_messages) after decrypting messages.
|
||||||
|
delete_fully_used_on_decrypt: false
|
||||||
|
# Delete previous megolm sessions from same device when receiving a new one.
|
||||||
|
delete_prev_on_new_session: false
|
||||||
|
# Delete megolm sessions received from a device when the device is deleted.
|
||||||
|
delete_on_device_delete: false
|
||||||
|
# Periodically delete megolm sessions when 2x max_age has passed since receiving the session.
|
||||||
|
periodically_delete_expired: false
|
||||||
|
# Delete inbound megolm sessions that don't have the received_at field used for
|
||||||
|
# automatic ratcheting and expired session deletion. This is meant as a migration
|
||||||
|
# to delete old keys prior to the bridge update.
|
||||||
|
delete_outdated_inbound: false
|
||||||
|
# What level of device verification should be required from users?
|
||||||
|
#
|
||||||
|
# Valid levels:
|
||||||
|
# unverified - Send keys to all device in the room.
|
||||||
|
# cross-signed-untrusted - Require valid cross-signing, but trust all cross-signing keys.
|
||||||
|
# cross-signed-tofu - Require valid cross-signing, trust cross-signing keys on first use (and reject changes).
|
||||||
|
# cross-signed-verified - Require valid cross-signing, plus a valid user signature from the bridge bot.
|
||||||
|
# Note that creating user signatures from the bridge bot is not currently possible.
|
||||||
|
# verified - Require manual per-device verification
|
||||||
|
# (currently only possible by modifying the `trust` column in the `crypto_device` database table).
|
||||||
|
verification_levels:
|
||||||
|
# Minimum level for which the bridge should send keys to when bridging messages from the remote network to Matrix.
|
||||||
|
receive: unverified
|
||||||
|
# Minimum level that the bridge should accept for incoming Matrix messages.
|
||||||
|
send: unverified
|
||||||
|
# Minimum level that the bridge should require for accepting key requests.
|
||||||
|
share: cross-signed-tofu
|
||||||
|
# Options for Megolm room key rotation. These options allow you to configure the m.room.encryption event content.
|
||||||
|
# See https://spec.matrix.org/v1.10/client-server-api/#mroomencryption for more information about that event.
|
||||||
|
rotation:
|
||||||
|
# Enable custom Megolm room key rotation settings. Note that these
|
||||||
|
# settings will only apply to rooms created after this option is set.
|
||||||
|
enable_custom: false
|
||||||
|
# The maximum number of milliseconds a session should be used
|
||||||
|
# before changing it. The Matrix spec recommends 604800000 (a week)
|
||||||
|
# as the default.
|
||||||
|
milliseconds: 604800000
|
||||||
|
# The maximum number of messages that should be sent with a given a
|
||||||
|
# session before changing it. The Matrix spec recommends 100 as the
|
||||||
|
# default.
|
||||||
|
messages: 100
|
||||||
|
# Disable rotating keys when a user's devices change?
|
||||||
|
# You should not enable this option unless you understand all the implications.
|
||||||
|
disable_device_change_key_rotation: false
|
||||||
|
|
||||||
|
# Logging config. See https://github.com/tulir/zeroconfig for details.
|
||||||
|
logging:
|
||||||
|
min_level: debug
|
||||||
|
writers:
|
||||||
|
- type: stdout
|
||||||
|
format: pretty-colored
|
||||||
|
- type: file
|
||||||
|
format: json
|
||||||
|
filename: ./logs/bridge.log
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 10
|
||||||
|
compress: false
|
||||||
8
well_known_client.conf.tmpl
Normal file
8
well_known_client.conf.tmpl
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"m.homeserver": {
|
||||||
|
"base_url": "https://{{ env "DOMAIN" }}"
|
||||||
|
}{{ if eq (env "MAS_ENABLED") "1" }},
|
||||||
|
"org.matrix.msc2965.authentication": {
|
||||||
|
"issuer": "https://{{ env "DOMAIN" }}/"
|
||||||
|
}{{ end }}
|
||||||
|
}
|
||||||
3
well_known_server.conf.tmpl
Normal file
3
well_known_server.conf.tmpl
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"m.server": "{{ env "DOMAIN" }}:443"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user