Compare commits
23 Commits
7.1.0+v1.1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 94e7c31369 | |||
| 5fc9296e61 | |||
| 3e838734de | |||
| 74f1adaccb | |||
| 17a399ba25 | |||
| b63dde1275 | |||
| f836c74386 | |||
| e257349b37 | |||
| 5b21a6b4f9 | |||
| b730cadb06 | |||
| 59ad89cfb4 | |||
| d75ca4f11f | |||
| cff6cfb001 | |||
| d82d539424 | |||
| b4c3db38c3 | |||
| f66bfef727 | |||
| a809333dcb | |||
| b39c60d594 | |||
| 4830b0596c | |||
| 43d68aefb4 | |||
| 91efd92d31 | |||
| 3fab725957 | |||
| a5a3a1938d |
26
.env.sample
26
.env.sample
@ -71,11 +71,11 @@ ENABLE_REGISTRATION=false
|
|||||||
### Matrix Authentication Service (MAS) — Element X / OIDC-native auth
|
### Matrix Authentication Service (MAS) — Element X / OIDC-native auth
|
||||||
|
|
||||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.mas.yml"
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.mas.yml"
|
||||||
#MAS_ENABLED=1
|
#MAS_ENABLED=1 # Leave commented if you plan to migrate an existing homeserver
|
||||||
#PASSWORD_LOGIN_ENABLED=false
|
#PASSWORD_LOGIN_ENABLED=false
|
||||||
#SECRET_MAS_ENCRYPTION_VERSION=v1 # length=64 # charset=hex
|
#SECRET_MAS_ENCRYPTION_VERSION=v1 # length=64 charset=hex
|
||||||
#SECRET_MAS_SYNAPSE_SHARED_VERSION=v1 # length=64 # charset=hex
|
#SECRET_MAS_SYNAPSE_SHARED_VERSION=v1 # length=64 charset=hex
|
||||||
# PEM private key: abra cannot generate this format — insert only (e.g. openssl genrsa 2048 | abra app secret insert …)
|
# 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
|
#SECRET_MAS_SIGNING_RSA_VERSION=v1 # generate=false
|
||||||
|
|
||||||
#### MAS upstream OIDC provider (e.g. Authentik)
|
#### MAS upstream OIDC provider (e.g. Authentik)
|
||||||
@ -87,7 +87,7 @@ ENABLE_REGISTRATION=false
|
|||||||
#MAS_UPSTREAM_HUMAN_NAME=Authentik
|
#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.
|
# 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=
|
#MAS_UPSTREAM_SYNAPSE_IDP_ID=
|
||||||
#SECRET_MAS_UPSTREAM_CLIENT_SECRET_VERSION=v1
|
#SECRET_MAS_UPSTREAM_CLIENT_VERSION=v1
|
||||||
|
|
||||||
### Shared secret auth (bridges / automation)
|
### Shared secret auth (bridges / automation)
|
||||||
|
|
||||||
@ -99,9 +99,15 @@ ENABLE_REGISTRATION=false
|
|||||||
|
|
||||||
#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
|
# Set "true" to enable federation endpoint on $DOMAIN/.well-known/matrix/server
|
||||||
SERVE_SERVER_WELLKNOWN=false
|
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
|
ALLOW_PUBLIC_ROOMS_FEDERATION=false
|
||||||
|
|
||||||
## Room auto-join
|
## Room auto-join
|
||||||
@ -143,6 +149,9 @@ ENCRYPTED_BY_DEFAULT=all
|
|||||||
#SESSION_LIFETIME=60d
|
#SESSION_LIFETIME=60d
|
||||||
#TRACK_PUPPETED_USER_IPS=true
|
#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
|
## Retention
|
||||||
|
|
||||||
@ -238,6 +247,13 @@ RETENTION_MAX_LIFETIME=4w
|
|||||||
## Web Client (Redirect)
|
## Web Client (Redirect)
|
||||||
#WEB_CLIENT_LOCATION=https://element-web.example.com
|
#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
|
## Admin interface at /admin
|
||||||
#COMPOSE_FILE="$COMPOSE_FILE:compose.admin.yml"
|
#COMPOSE_FILE="$COMPOSE_FILE:compose.admin.yml"
|
||||||
|
|||||||
106
README.md
106
README.md
@ -39,26 +39,116 @@
|
|||||||
|
|
||||||
### Enabling federation
|
### Enabling federation
|
||||||
|
|
||||||
See [`#27`](https://git.coopcloud.tech/coop-cloud/matrix-synapse/pulls/27) for more. Depending on your setup, using `SERVE_SERVER_WELLKNOWN=true` might work to start federating. Make sure you don't leave `DISABLE_FEDERATION=1` set!
|
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).
|
||||||
|
|
||||||
|
#### 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
SERVER_NAME=example.com
|
||||||
|
DOMAIN=matrix.example.com
|
||||||
|
SERVE_SERVER_WELLKNOWN=false
|
||||||
|
```
|
||||||
|
|
||||||
|
The two paths that must be served on `SERVER_NAME` are:
|
||||||
|
|
||||||
|
- `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`:
|
||||||
|
|
||||||
|
```
|
||||||
|
COMPOSE_FILE="$COMPOSE_FILE:compose.wellknown.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
```
|
||||||
|
_matrix-fed._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # modern
|
||||||
|
_matrix._tcp.example.com. 3600 IN SRV 10 0 8448 matrix.example.com. # deprecated, for older peers
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- **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). This could be implemented in this recipe but we haven't merged it in yet. Change sets are welcome.
|
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.
|
||||||
|
|
||||||
### Matrix Authentication Service (MAS)
|
### 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`.
|
[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:**
|
**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.
|
- 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 secret generate YOURAPPDOMAIN`
|
||||||
- **Manually insert** the PEM RSA key for `SECRET_MAS_SIGNING_RSA_VERSION` (`generate=false` in `.env.sample`) — abra cannot generate that format; see the comment there (e.g. `openssl genrsa 2048` piped to `abra app secret insert`).
|
- `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 cmd YOURAPPDOMAIN db ensure_mas_database` (once, creates the `mas` database in Postgres)
|
||||||
- `abra app deploy YOURAPPDOMAIN`
|
- `abra app deploy YOURAPPDOMAIN`
|
||||||
|
|
||||||
**If you plan to migrate an existing homeserver with `syn2mas`:** deploy and configure MAS as above, 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.
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>Migrating an existing server (<code>syn2mas</code>)</strong></summary>
|
<summary><strong>Migrating an existing server (<code>syn2mas</code>)</strong></summary>
|
||||||
|
|
||||||
@ -78,11 +168,9 @@ Requires PostgreSQL on Synapse and a dedicated MAS database. Backup Postgres (an
|
|||||||
```
|
```
|
||||||
Use the real service name from `docker service ls` (suffix `_app`).
|
Use the real service name from `docker service ls` (suffix `_app`).
|
||||||
|
|
||||||
4. **Migration:** with MAS still running and Synapse at zero replicas,
|
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
|
```bash
|
||||||
abra app run YOURAPPDOMAIN mas -- mas-cli syn2mas migrate \
|
abra app cmd YOURAPPDOMAIN run_mas_migration
|
||||||
--config /etc/mas/config.yaml \
|
|
||||||
--synapse-config /tmp/homeserver.yaml
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
259
abra.sh
259
abra.sh
@ -1,6 +1,6 @@
|
|||||||
export DISCORD_BRIDGE_YAML_VERSION=v2
|
export DISCORD_BRIDGE_YAML_VERSION=v2
|
||||||
export ENTRYPOINT_CONF_VERSION=v3
|
export ENTRYPOINT_CONF_VERSION=v3
|
||||||
export HOMESERVER_YAML_VERSION=v36
|
export HOMESERVER_YAML_VERSION=v37
|
||||||
export LOG_CONFIG_VERSION=v2
|
export LOG_CONFIG_VERSION=v2
|
||||||
export SHARED_SECRET_AUTH_VERSION=v2
|
export SHARED_SECRET_AUTH_VERSION=v2
|
||||||
export SIGNAL_BRIDGE_YAML_VERSION=v6
|
export SIGNAL_BRIDGE_YAML_VERSION=v6
|
||||||
@ -8,9 +8,216 @@ export TELEGRAM_BRIDGE_YAML_VERSION=v6
|
|||||||
export NGINX_CONFIG_VERSION=v13
|
export NGINX_CONFIG_VERSION=v13
|
||||||
export WK_SERVER_VERSION=v1
|
export WK_SERVER_VERSION=v1
|
||||||
export WK_CLIENT_VERSION=v2
|
export WK_CLIENT_VERSION=v2
|
||||||
export MAS_CONFIG_VERSION=v1
|
export MAS_CONFIG_VERSION=v2
|
||||||
export PG_BACKUP_VERSION=v2
|
export PG_BACKUP_VERSION=v2
|
||||||
export ADMIN_CONFIG_VERSION=v1
|
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 () {
|
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
|
if ! psql -U synapse -d postgres -v ON_ERROR_STOP=1 -Atqc "SELECT 1 FROM pg_database WHERE datname = 'mas'" | grep -qx 1
|
||||||
@ -19,9 +226,33 @@ ensure_mas_database () {
|
|||||||
fi
|
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.
|
# Local helper: fetch homeserver.yaml from app, push to mas, then syn2mas check + dry-run.
|
||||||
prepare_mas_migration () {
|
prepare_mas_migration () {
|
||||||
local hs_local syn_cfg
|
local syn_cfg
|
||||||
|
|
||||||
syn_cfg=/tmp/homeserver.yaml
|
syn_cfg=/tmp/homeserver.yaml
|
||||||
|
|
||||||
@ -56,6 +287,28 @@ prepare_mas_migration () {
|
|||||||
|
|
||||||
trap - EXIT
|
trap - EXIT
|
||||||
cleanup_prepare_mas_migration
|
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 () {
|
set_admin () {
|
||||||
|
|||||||
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
|
||||||
@ -13,9 +13,9 @@ services:
|
|||||||
- MAS_UPSTREAM_HUMAN_NAME
|
- MAS_UPSTREAM_HUMAN_NAME
|
||||||
- MAS_UPSTREAM_SYNAPSE_IDP_ID
|
- MAS_UPSTREAM_SYNAPSE_IDP_ID
|
||||||
secrets:
|
secrets:
|
||||||
- mas_upstream_client_secret
|
- mas_upstream_client
|
||||||
|
|
||||||
secrets:
|
secrets:
|
||||||
mas_upstream_client_secret:
|
mas_upstream_client:
|
||||||
external: true
|
external: true
|
||||||
name: ${STACK_NAME}_mas_upstream_client_secret_${SECRET_MAS_UPSTREAM_CLIENT_SECRET_VERSION}
|
name: ${STACK_NAME}_mas_upstream_client_${SECRET_MAS_UPSTREAM_CLIENT_VERSION}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ version: "3.8"
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
mas:
|
mas:
|
||||||
image: ghcr.io/element-hq/matrix-authentication-service:1.14.0
|
image: ghcr.io/element-hq/matrix-authentication-service:1.18.0
|
||||||
command: ["server", "--config=/etc/mas/config.yaml"]
|
command: ["server", "--config=/etc/mas/config.yaml"]
|
||||||
environment:
|
environment:
|
||||||
- DOMAIN
|
- DOMAIN
|
||||||
|
|||||||
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"
|
||||||
18
compose.yml
18
compose.yml
@ -3,7 +3,7 @@ version: "3.8"
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
image: nginx:1.29.6
|
image: nginx:1.31.1
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
- internal
|
- internal
|
||||||
@ -30,6 +30,11 @@ services:
|
|||||||
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)"
|
- "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`)"
|
||||||
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
|
- "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure"
|
||||||
- "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}"
|
- "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:
|
healthcheck:
|
||||||
test: curl -f http://${STACK_NAME}_app:8008/health || exit 1
|
test: curl -f http://${STACK_NAME}_app:8008/health || exit 1
|
||||||
interval: 30s
|
interval: 30s
|
||||||
@ -38,7 +43,7 @@ services:
|
|||||||
start_period: 2m
|
start_period: 2m
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: "matrixdotorg/synapse:v1.149.1"
|
image: "matrixdotorg/synapse:v1.154.0"
|
||||||
volumes:
|
volumes:
|
||||||
- "data:/data"
|
- "data:/data"
|
||||||
secrets:
|
secrets:
|
||||||
@ -92,6 +97,7 @@ services:
|
|||||||
- LOGIN_LIMIT_IP_BURST=${LOGIN_LIMIT_IP_BURST:-5}
|
- LOGIN_LIMIT_IP_BURST=${LOGIN_LIMIT_IP_BURST:-5}
|
||||||
- LOGIN_LIMIT_ACCOUNT_PER_SECOND=${LOGIN_LIMIT_ACCOUNT_PER_SECOND:-0.003}
|
- LOGIN_LIMIT_ACCOUNT_PER_SECOND=${LOGIN_LIMIT_ACCOUNT_PER_SECOND:-0.003}
|
||||||
- LOGIN_LIMIT_ACCOUNT_BURST=${LOGIN_LIMIT_ACCOUNT_BURST:-5}
|
- LOGIN_LIMIT_ACCOUNT_BURST=${LOGIN_LIMIT_ACCOUNT_BURST:-5}
|
||||||
|
- ROOM_COMPLEXITY_LIMIT=${ROOM_COMPLEXITY_LIMIT:-100.0}
|
||||||
- WEB_CLIENT_LOCATION
|
- WEB_CLIENT_LOCATION
|
||||||
networks:
|
networks:
|
||||||
- internal
|
- internal
|
||||||
@ -108,7 +114,7 @@ services:
|
|||||||
restart_policy:
|
restart_policy:
|
||||||
condition: on-failure
|
condition: on-failure
|
||||||
labels:
|
labels:
|
||||||
- "coop-cloud.${STACK_NAME}.version=7.1.0+v1.149.1"
|
- "coop-cloud.${STACK_NAME}.version=7.2.0+v1.154.0"
|
||||||
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT}"
|
- "coop-cloud.${STACK_NAME}.timeout=${TIMEOUT}"
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8008/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:8008/health"]
|
||||||
@ -118,10 +124,14 @@ services:
|
|||||||
start_period: 1m
|
start_period: 1m
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: pgautoupgrade/pgautoupgrade:17-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_COLLATE=C
|
||||||
- LC_CTYPE=C
|
- LC_CTYPE=C
|
||||||
- POSTGRES_DB=synapse
|
- POSTGRES_DB=synapse
|
||||||
|
|||||||
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
|
||||||
@ -79,7 +79,7 @@ admin_contact: 'mailto:{{ env "ADMIN_EMAIL" }}'
|
|||||||
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#limit_remote_rooms
|
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#limit_remote_rooms
|
||||||
limit_remote_rooms:
|
limit_remote_rooms:
|
||||||
enabled: true
|
enabled: true
|
||||||
complexity: 200.0
|
complexity: {{ env "ROOM_COMPLEXITY_LIMIT" }}
|
||||||
|
|
||||||
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#max_avatar_size
|
# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html#max_avatar_size
|
||||||
max_avatar_size: 10M
|
max_avatar_size: 10M
|
||||||
|
|||||||
@ -57,7 +57,7 @@ upstream_oauth2:
|
|||||||
human_name: {{ or (env "MAS_UPSTREAM_HUMAN_NAME") "SSO" }}
|
human_name: {{ or (env "MAS_UPSTREAM_HUMAN_NAME") "SSO" }}
|
||||||
issuer: {{ env "MAS_UPSTREAM_ISSUER" }}
|
issuer: {{ env "MAS_UPSTREAM_ISSUER" }}
|
||||||
client_id: {{ env "MAS_UPSTREAM_CLIENT_ID" }}
|
client_id: {{ env "MAS_UPSTREAM_CLIENT_ID" }}
|
||||||
client_secret_file: /run/secrets/mas_upstream_client_secret
|
client_secret_file: /run/secrets/mas_upstream_client
|
||||||
token_endpoint_auth_method: client_secret_basic
|
token_endpoint_auth_method: client_secret_basic
|
||||||
scope: "openid profile email"
|
scope: "openid profile email"
|
||||||
claims_imports:
|
claims_imports:
|
||||||
|
|||||||
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"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user