From bf94f7872a1df293bd904bbd2c1ef7229f4f98a8 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Thu, 14 Dec 2023 20:54:57 +0100 Subject: Run Matrix services in OCI containers --- tw/services/matrix.scm | 131 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 22 deletions(-) (limited to 'tw/services/matrix.scm') diff --git a/tw/services/matrix.scm b/tw/services/matrix.scm index 6b184f49..0e7cff61 100644 --- a/tw/services/matrix.scm +++ b/tw/services/matrix.scm @@ -1,27 +1,114 @@ (define-module (tw services matrix) + #:use-module (gnu) + #:use-module ((gnu packages admin) #:select (shadow)) #:use-module (gnu services) - #:use-module (tw services web)) + #:use-module (gnu services certbot) + #:use-module (gnu services configuration) + #:use-module (gnu services databases) + #:use-module (gnu services docker) + #:use-module (gnu services web) + #:use-module (guix records) + #:use-module (tw services web) + #:use-module (tw services docker) + #:export (matrix-service-type + matrix-configuration + matrix-well-known-nginx-locations)) -(define-public %matrix-services - (list (simple-service 'synapse-reverse-proxy https-reverse-proxy-service-type +(define %matrix-user "matrix") +(define %matrix-uid 1337) ; match Mautrix bridge containers +(define %conduit-port 6167) + +(define-maybe/no-serialization string) + +(define-configuration/no-serialization matrix-configuration + (domain (string "localhost") "The external domain on which the Matrix server +will actually be hosted. If a different display domain is desired for +usernames, use @code{matrix-well-known-nginx-locations}.") + (server-name maybe-string "The external display name of the server where the +Matrix server is hosted. Usernames will include this hostname. If not given, +@code{domain} is used.") + (data-path (string "/var/lib/matrix") "The path to store data inside.")) + +(define (matrix-oci-containers config) + (match-record config (domain server-name data-path) + (list (oci-container-configuration + (provision "conduit") + (image "registry.gitlab.com/famedly/conduit/matrix-conduit:v0.6.0") + ;; We can't use %matrix-user, since the container's internal user + ;; has UID 1000, and that's already taken on the host system. + (container-user (number->string %matrix-uid)) + (network "host") ; allow access to localhost-bound conduit port + ;; https://gitlab.com/famedly/conduit/-/blob/next/docker/README.md + ;; https://gitlab.com/famedly/conduit/-/blob/next/conduit-example.toml + (environment `(("CONDUIT_CONFIG" . "") ; use only env vars + ("CONDUIT_SERVER_NAME" . ,(maybe-value server-name domain)) + ("CONDUIT_ADDRESS" . "127.0.0.1") + ("CONDUIT_PORT" . ,(number->string %conduit-port)) + ("CONDUIT_DATABASE_BACKEND" . "rocksdb") + ("CONDUIT_ALLOW_REGISTRATION" . "false") + ("CONDUIT_ALLOW_FEDERATION" . "false") + ("CONDUIT_ALLOW_CHECK_FOR_UPDATES" . "false") + ("CONDUIT_ENABLE_LIGHTNING_BOLT" . "false") + ("CONDUIT_MAX_REQUEST_SIZE" . "100_000_000") + ("CONDUIT_TRUSTED_SERVERS" . "[\"matrix.org\"]"))) + (volumes `((,(string-append data-path "/conduit") . "/var/lib/matrix-conduit"))))))) + +(define (matrix-accounts config) + (match-record config (data-path) + (list (user-account + (name %matrix-user) + (uid %matrix-uid) + (group "nogroup") + (comment "Matrix server user") + (system? #t) + (home-directory data-path) + (shell (file-append shadow "/sbin/nologin")))))) + +(define (matrix-well-known-nginx-locations config) + (match-record config (domain) + (list (nginx-location-configuration + (uri "/.well-known/matrix/server") + (body `(("return 200 '{\"m.server\": \"" ,domain "\"}';") + "types { } default_type \"application/json; charset=utf-8\";"))) + (nginx-location-configuration + (uri "/.well-known/matrix/client") + (body `("return 200 '{\"m.homeserver\": {\"base_url\": \"https://matrix.twilken.net\"}}';" + "types { } default_type \"application/json; charset=utf-8\";" + "add_header \"Access-Control-Allow-Origin\" *;")))))) + +(define (matrix-reverse-proxy config) + (match-record config (domain) + ;; https://gitlab.com/famedly/conduit/-/blob/next/DEPLOY.md#nginx + (list (nginx-server-configuration + (listen '("443 ssl http2" "8448 ssl http2")) + (server-name (list domain)) + (ssl-certificate (string-append "/etc/letsencrypt/live/" domain "/fullchain.pem")) + (ssl-certificate-key (string-append "/etc/letsencrypt/live/" domain "/privkey.pem")) + (server-tokens? #f) + (locations + (list (nginx-location-configuration + (uri "/_matrix") + (body `(("proxy_pass http://127.0.0.1:" + ,(number->string %conduit-port) "$request_uri;") + "proxy_set_header Host $http_host;" + "proxy_buffering off;" + "proxy_read_timeout 5m;"))))))))) + +(define (matrix-certificates config) + (match-record config (domain) + (list (certificate-configuration + (domains (list domain)) + (deploy-hook %nginx-cert-deploy-hook))))) + +(define matrix-service-type + (service-type + (name 'matrix) + (extensions + (list (service-extension oci-container-service-type matrix-oci-containers) + (service-extension account-service-type matrix-accounts) ;; Synapse can't access certbot certs, but nginx can, so proxy HTTPS ;; access through. Also, it's good to have Synapse available on :443. - (list (https-reverse-proxy-configuration - (domains '("matrix.twilken.net")) - (destination-port 48448)))) - - ;; TODO: Postgres for Synapse - ;; (service postgresql-service-type - ;; (postgresql-configuration - ;; (postgresql postgresql-15) - ;; (data-directory "/var/lib/postgresql/data"))) - - ;; (service postgresql-role-service-type - ;; (postgresql-role-configuration - ;; (roles (list (postgresql-role - ;; (name "synapse") ; TODO - ;; (create-database? #t)))))) - - ;; TODO: Matrix/Synapse - ;; TODO: Matrix bridges - )) + (service-extension nginx-service-type matrix-reverse-proxy) + (service-extension certbot-service-type matrix-certificates))) + (default-value (matrix-configuration)) + (description "Run a matrix server with various bridges."))) -- cgit v1.2.3