Start working on Synapse + Element

This commit is contained in:
Daniel Berteaud 2023-12-16 00:32:03 +01:00
parent 0655d3af74
commit c6a728fa70
20 changed files with 593 additions and 0 deletions

4
bundles.yml Normal file
View File

@ -0,0 +1,4 @@
---
dependencies:
- url: ../common.git

View File

@ -0,0 +1,3 @@
Kind = "service-defaults"
Name = "[[ .instance ]][[ .consul.suffix ]]"
Protocol = "http"

View File

@ -0,0 +1,16 @@
Kind = "service-intentions"
Name = "[[ .instance ]][[ .consul.suffix ]]"
Sources = [
{
Name = "[[ .traefik.instance ]]"
Permissions = [
{
Action = "allow"
HTTP {
PathRegex = "^/_(matrix|synapse)/.*"
Methods = ["GET", "HEAD", "POST", "OPTIONS", "PUT", "DELETE"]
}
}
]
}
]

View File

@ -0,0 +1,17 @@
FROM nginxinc/nginx-unprivileged:alpine
MAINTAINER [[ .docker.maintainer ]]
ARG ELEMENT_VERSION=1.11.51
ENV ELEMENT_NGINX_BIND_ADDR=0.0.0.0 \
ELEMENT_NGINX_BIND_PORT=8710
USER root
RUN set -eux &&\
mkdir -p /opt/element &&\
curl -sSL https://github.com/element-hq/element-web/releases/download/v${ELEMENT_VERSION}/element-v${ELEMENT_VERSION}.tar.gz |\
tar xvz -C /opt/element/ --strip-components 1
USER nginx
EXPOSE ${ELEMENT_BIND_PORT}

View File

@ -0,0 +1,15 @@
server {
listen ${ELEMENT_NGINX_BIND_ADDR}:${ELEMENT_NGINX_BIND_PORT} default_server;
location / {
root /opt/element;
index index.html index.htm;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@ -0,0 +1,65 @@
# syntax=docker/dockerfile:labs
FROM python:3.11-alpine AS builder
ARG SYNAPSE_VERSION=1.98.0
RUN set -euxo pipefail &&\
apk --no-cache add \
curl \
ca-certificates \
postgresql15-dev \
build-base \
&&\
mkdir /opt/synapse &&\
cd /opt/synapse &&\
python3 -m venv venv &&\
source venv/bin/activate &&\
pip --no-cache install \
bleach \
matrix-synapse-ldap3 \
psycopg2 \
authlib \
lxml \
twisted \
txacme \
Jinja2 \
pysaml2 \
&&\
pip --no-cache install matrix-synapse==${SYNAPSE_VERSION}
FROM python:3.11-alpine
MAINTAINER [[ .docker.maintainer ]]
ENV PATH=/opt/synapse/venv/bin:${PATH} \
LANG=[[ .locale.lang ]] \
TZ=[[ .locale.tz ]] \
SYNAPSE_LISTEN_ADDR=0.0.0.0 \
SYNAPSE_CONFIG=/data/conf/homeserver.yml \
SYNAPSE_PG_DB=synapse \
SYNAPSE_PG_HOST=127.0.0.1 \
SYNAPSE_PG_PORT=5432 \
SYNAPSE_PG_USER=synapse \
SYNAPSE_PG_PASSWORD=synapse
ADD https://git.lapiole.org/nomad/base_tools.git#master /
COPY --from=builder /opt /opt
RUN set -euxo pipefail &&\
apk --no-cache add \
tini \
libpq \
&&\
addgroup --gid 8008 synapse &&\
adduser --system --ingroup synapse --disabled-password --uid 8008 --home /opt/synapse --shell /sbin/nologin synapse &&\
mkdir /data &&\
chown synapse:synapse /data &&\
chmod 700 /data
COPY root/ /
EXPOSE 8008
USER synapse
ENTRYPOINT ["tini", "--", "/entrypoint.sh"]
CMD ["matrix-synapse"]

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -euo pipefail
mkdir -p /data/uploads /data/media_store /data/conf

View File

@ -0,0 +1,3 @@
#!/bin/sh
export SYNAPSE_PUBLIC_URL=${SYNAPSE_PUBLIC_URL:-https://${SYNAPSE_SERVER_NAME}}

View File

@ -0,0 +1,23 @@
#!/bin/sh
set -euo pipefail
source /opt/synapse/venv/bin/activate
if [ ! -e "${SYNAPSE_CONFIG}" ]; then
echo "Generating a default ${SYNAPSE_CONFIG}"
if [ -z "${SYNAPSE_SERVER_NAME}" ]; then
echo "You must set SYNAPSE_SERVER_NAME environment variable"
exit 1
fi
envsubst < /opt/synapse/templates/homeserver.yml > ${SYNAPSE_CONFIG}
fi
echo "Generate missing keys if needed"
python3 -m synapse.app.homeserver \
--config-path ${SYNAPSE_CONFIG} \
--generate-missing-configs \
--report-stats=no \
--config-directory=/data/conf \
--keys-directory=/data/conf \
--data-directory=/data

View File

@ -0,0 +1,41 @@
server_name: "${SYNAPSE_SERVER_NAME}"
public_baseurl: '${SYNAPSE_PUBLIC_URL}'
listeners:
- port: 8008
tls: false
type: http
x_forwarded: true
bind_addresses: [${SYNAPSE_LISTEN_ADDR}]
resources:
- names: [client, federation]
compress: false
database:
name: psycopg2
args:
database: '${SYNAPSE_PG_DB}'
host: '${SYNAPSE_PG_HOST}'
port: ${SYNAPSE_PG_PORT}
user: '${SYNAPSE_PG_USER}'
password: '${SYNAPSE_PG_PASSWORD}'
web_client: False
soft_file_limit: 0
filter_timeline_limit: 5000
log_config: /opt/synapse/templates/logging.conf
media_store_path: /data/media_store
uploads_path: /data/uploads
registration_shared_secret: "${SYNAPSE_SHARED_SECRET}"
macaroon_secret_key: "${SYNAPSE_MACAROON_SECRET}"
form_secret: "${SYNAPSE_FORM_SECERT}"
signing_key_path: "/data/conf/signing.key"
report_stats: false
trusted_key_servers:
- server_name: "matrix.org"
suppress_key_server_warning: true
serve_server_wellknown: true

View File

@ -0,0 +1,30 @@
version: 1
formatters:
precise:
format: '%(name)s - %(lineno)d - %(levelname)s - %(request)s- %(message)s'
filters:
context:
(): synapse.util.logcontext.LoggingContextFilter
request: ""
handlers:
console:
class: logging.StreamHandler
formatter: precise
filters: [context]
loggers:
synapse:
level: ERROR
synapse.storage.SQL:
# beware: increasing this to DEBUG will make synapse log sensitive
# information such as access tokens.
level: ERROR
root:
level: ERROR
handlers: [console]

View File

@ -0,0 +1,6 @@
#!/bin/sh
set -euo pipefail
source /opt/synapse/venv/bin/activate
exec python3 -m synapse.app.homeserver -c ${SYNAPSE_CONFIG}

8
init/vault-database Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -euo pipefail
[[- template "common/vault.mkpgrole.sh.tpl"
dict "ctx" .
"config" (dict "role" (printf "%s-synapse" .instance) "database" "postgres")
]]

130
matrix.nomad.hcl Normal file
View File

@ -0,0 +1,130 @@
[[ $c := merge .matrix.synapse . -]]
job [[ .instance | toJSON ]] {
[[ template "common/job_start" $c ]]
group "matrix" {
network {
mode = "bridge"
}
[[ template "common/volumes" .matrix.volumes ]]
service {
name = "[[ .instance ]][[ .consul.suffix ]]"
port = 8008
check {
type = "http"
path = "/health"
expose = true
interval = "10s"
timeout = "5s"
task = "synapse"
check_restart {
limit = 12
grace = "10m"
}
}
[[ template "common/connect" merge .matrix . ]]
}
[[ template "common/task.wait_for" $c ]]
task "synapse" {
driver = [[ $c.nomad.driver | toJSON ]]
leader = true
config {
image = [[ $c.image | toJSON ]]
pids_limit = 200
readonly_rootfs = true
}
vault {
policies = ["[[ .instance ]]-synapse[[ .consul.suffix ]]"]
env = false
disable_file = true
}
env {
SYNAPSE_CONFIG = "/secrets/homeserver.yml"
[[ template "common/proxy_env" $c ]]
}
[[ template "common/file_env" $c.env ]]
template {
data =<<_EOT
[[ (merge $c.config ((tmpl.Exec "matrix/homeserver.yml.tpl" .) | yaml)) | toYAML ]]
_EOT
destination = "secrets/homeserver.yml"
uid = 100000
gid = 108008
perms = 0640
}
volume_mount {
volume = "data"
destination = "/data"
}
[[ template "common/resources" $c.resources ]]
}
[[ $c = merge .matrix.element . ]]
task "element" {
driver = [[ $c.nomad.driver | toJSON ]]
lifecycle {
hook = "prestart"
sidecar = true
}
config {
image = [[ $c.image | toJSON ]]
readonly_rootfs = true
pids_limit = 100
[[ template "common/tmpfs" dict "size" "5000000" "target" "/tmp" ]]
}
env {
ELEMENT_BIND_ADDR = "127.0.0.1"
ELEMENT_NGINX_BIND_PORT = "8710"
}
[[ template "common/resources" $c.resources ]]
}
[[ $c = merge .matrix.nginx . ]]
task "nginx" {
driver = [[ $c.nomad.driver | toJSON ]]
lifecycle {
hook = "prestart"
sidecar = true
}
config {
image = [[ $c.image | toJSON ]]
readonly_rootfs = true
pids_limit = 100
volumes = [
"local/nginx.conf:/etc/nginx/conf.d/default.conf"
]
[[ template "common/tmpfs" dict "size" "5000000" "target" "/tmp" ]]
}
template {
data =<<_EOT
[[ template "matrix/nginx.conf.tpl" ]]
_EOT
destination = "local/nginx.conf"
}
[[ template "common/resources" $c.resources ]]
}
}
}

1
prep.d/10-mv-conf.sh Executable file
View File

@ -0,0 +1 @@
[[ template "common/mv_conf.sh.tpl" dict "ctx" . "services" (dict "matrix" .instance) ]]

18
prep.d/20-rand-pwd.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/sh
set -euo pipefail
# Initialize random passwords if needed
if ! vault kv list [[ .vault.prefix ]]kv/service 2>/dev/null | grep -q -E '^[[ .instance ]]$'; then
vault kv put [[ .vault.prefix ]]kv/service/[[ .instance ]] \
macaroon_secret_key=$(pwgen -s -n 50 1) \
form_secret=$(pwgen -s -n 50 1)
fi
for PWD in macaroon_secret_key form_secret; do
if ! vault kv get -field ${PWD} [[ .vault.prefix ]]kv/service/[[ .instance ]] >/dev/null 2>&1; then
vault kv patch [[ .vault.prefix ]]kv/service/[[ .instance ]] \
${PWD}=$(pwgen -s -n 50 1)
fi
done

View File

@ -0,0 +1,98 @@
---
server_name: [[ .matrix.server_name ]]
public_baseurl: [[ .matrix.public_url ]]
serve_server_wellknown: true
report_stats: false
web_client: false
listeners:
- path: /alloc/tmp/synapse.sock
type: http
resources:
- names:
- client
- federation
compress: false
database:
name: psycopg2
args:
database: '[[ .matrix.synapse.db.name ]]'
host: '[[ .matrix.synapse.db.host ]]'
port: '[[ .matrix.synapse.db.port ]]'
user: '[[ .matrix.synapse.db.user ]]'
password: '[[ .matrix.synapse.db.password ]]'
trusted_key_servers:
- server_name: "matrix.org"
suppress_key_server_warning: True
email:
enable_notifs: true
smtp_host: 127.0.0.1
smtp_port: 25
require_transport_security: false
notif_from: "%(app)s <no-reply@[[ .consul.domain ]]>"
notif_for_new_users: true
client_base_url: [[ .matrix.public_url ]]
delete_stale_devices_after: 180d
max_avatar_size: 4M
allowed_avatar_mimetypes:
- image/png
- image/jpeg
- image/gif
forgotten_room_retention_period: 15d
request_token_inhibit_3pid_errors: true
media_store_path: /data/media_store
media_retention:
local_media_lifetime: 730d
remote_media_lifetime: 14d
url_preview_enabled: true
url_preview_ip_range_blacklist:
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '192.0.0.0/24'
- '169.254.0.0/16'
- '192.88.99.0/24'
- '198.18.0.0/15'
- '192.0.2.0/24'
- '198.51.100.0/24'
- '203.0.113.0/24'
- '224.0.0.0/4'
url_preview_url_blacklist:
- username: '*'
- netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
default_identity_server: https://matrix.org
macaroon_secret_key: '[[ .matrix.synapse.macaroon_secret_key ]]'
form_secret: '[[ .matrix.synapse.form_secret ]]'
sso:
client_whitelist:
- [[ .matrix.public_url ]]
update_profile_information: true
password_config:
enabled: false
push:
include_content: event_id_only
server_notices:
system_mxid_localpart: server
system_mxid_display_name: "Notification bot"
alias_creation_rules:
- user_id: '*'
alias: '*'
action: allow

43
templates/nginx.conf.tpl Normal file
View File

@ -0,0 +1,43 @@
upstream synapse {
server unix:/alloc/tmp/synapse.sock;
}
upstream element {
server 127.0.0.1:8710;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 127.0.0.1:8008 default_server;
server_tokens off;
root /usr/share/html;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_socket_keepalive on;
client_max_body_size 100m;
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
location /_matrix {
proxy_pass http://synapse;
proxy_read_timeout 600;
}
location /_synapse {
proxy_pass http://synapse;
proxy_read_timeout 600;
}
location /health {
proxy_pass http://synapse;
}
location / {
proxy_pass http://element;
}
}

60
variables.yml Normal file
View File

@ -0,0 +1,60 @@
---
instance: matrix
matrix:
server_name: matrix.[[ .consul.domain ]]
public_url: https://matrix.[[ .consul.domain ]]
consul:
connect:
upstreams:
- destination_name: postgres[[ .consul.suffix ]]
local_bind_port: 5432
synapse:
image: '[[ .docker.repo ]]matrix-synapse:latest'
env: {}
config: {}
macaroon_secret_key: '{{ with secret "[[ .vault.prefix ]]kv/service/[[ .instance ]]" }}{{ .Data.data.macaroon_secret_key }}{{ end }}'
form_secret: '{{ with secret "[[ .vault.prefix ]]kv/service/[[ .instance ]]" }}{{ .Data.data.form_secret }}{{ end }}'
db:
host: 127.0.0.1
port: 5432
name: '[[ .instance ]]-synapse'
user: '{{ with secret "[[ .vault.prefix ]]database/creds/[[ .instance ]]-synapse" }}{{ .Data.username }}{{ end }}'
password: '{{ with secret "[[ .vault.prefix ]]database/creds/[[ .instance ]]-synapse" }}{{ .Data.password }}{{ end }}'
wait_for:
- service: postgres[[ .consul.suffix ]]
resources:
cpu: 500
memory: 384
element:
image: '[[ .docker.repo ]]matrix-element:latest'
env: {}
resources:
cpu: 20
memory: 16
nginx:
image: nginxinc/nginx-unprivileged:alpine
resources:
cpu: 20
memory: 16
volumes:
data:
type: csi
source: "[[ .instance ]]-synapse-data"

View File

@ -0,0 +1,7 @@
path "[[ .vault.prefix ]]kv/data/service/[[ .instance ]]" {
capabilities = ["read"]
}
path "[[ .vault.prefix ]]database/creds/[[ .instance ]]-synapse" {
capabilities = ["read"]
}