1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.services.matrix-synapse; 7 logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig; 8 configFile = pkgs.writeText "homeserver.yaml" '' 9tls_certificate_path: "${cfg.tls_certificate_path}" 10tls_private_key_path: "${cfg.tls_private_key_path}" 11tls_dh_params_path: "${cfg.tls_dh_params_path}" 12no_tls: ${if cfg.no_tls then "true" else "false"} 13bind_port: ${toString cfg.bind_port} 14unsecure_port: ${toString cfg.unsecure_port} 15bind_host: "${cfg.bind_host}" 16server_name: "${cfg.server_name}" 17pid_file: "/var/run/matrix-synapse.pid" 18web_client: ${if cfg.web_client then "true" else "false"} 19database: { 20 name: "${cfg.database_type}", 21 args: { 22 ${concatStringsSep ",\n " ( 23 mapAttrsToList (n: v: "\"${n}\": ${v}") cfg.database_args 24 )} 25 } 26} 27log_file: "/var/log/matrix-synapse/homeserver.log" 28log_config: "${logConfigFile}" 29media_store_path: "/var/lib/matrix-synapse/media" 30recaptcha_private_key: "${cfg.recaptcha_private_key}" 31recaptcha_public_key: "${cfg.recaptcha_public_key}" 32enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"} 33turn_uris: ${if (length cfg.turn_uris) == 0 then "[]" else ("\n" + (concatStringsSep "\n" (map (s: "- " + s) cfg.turn_uris)))} 34turn_shared_secret: "${cfg.turn_shared_secret}" 35enable_registration: ${if cfg.enable_registration then "true" else "false"} 36${optionalString (cfg.registration_shared_secret != "") '' 37registration_shared_secret: "${cfg.registration_shared_secret}" 38''} 39enable_metrics: ${if cfg.enable_metrics then "true" else "false"} 40report_stats: ${if cfg.report_stats then "true" else "false"} 41signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key" 42perspectives: 43 servers: { 44 ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' 45 "${n}": { 46 "verify_keys": { 47 ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' 48 "${n}": { 49 "key": "${v}" 50 }'') v)} 51 } 52 '') cfg.servers)} 53 } 54 } 55${cfg.extraConfig} 56''; 57in { 58 options = { 59 services.matrix-synapse = { 60 enable = mkEnableOption "matrix.org synapse"; 61 package = mkOption { 62 type = types.package; 63 default = pkgs.matrix-synapse; 64 defaultText = "pkgs.matrix-synapse"; 65 description = '' 66 Overridable attribute of the matrix synapse server package to use. 67 ''; 68 }; 69 no_tls = mkOption { 70 type = types.bool; 71 default = false; 72 description = '' 73 Don't bind to the https port 74 ''; 75 }; 76 tls_certificate_path = mkOption { 77 type = types.path; 78 default = "/var/lib/matrix-synapse/homeserver.tls.crt"; 79 description = '' 80 PEM encoded X509 certificate for TLS 81 ''; 82 }; 83 tls_private_key_path = mkOption { 84 type = types.path; 85 default = "/var/lib/matrix-synapse/homeserver.tls.key"; 86 description = '' 87 PEM encoded private key for TLS 88 ''; 89 }; 90 tls_dh_params_path = mkOption { 91 type = types.path; 92 default = "/var/lib/matrix-synapse/homeserver.tls.dh"; 93 description = '' 94 PEM dh parameters for ephemeral keys 95 ''; 96 }; 97 bind_port = mkOption { 98 type = types.int; 99 default = 8448; 100 description = '' 101 The port to listen for HTTPS requests on. 102 For when matrix traffic is sent directly to synapse. 103 ''; 104 }; 105 unsecure_port = mkOption { 106 type = types.int; 107 default = 8008; 108 description = '' 109 The port to listen for HTTP requests on. 110 For when matrix traffic passes through loadbalancer that unwraps TLS. 111 ''; 112 }; 113 bind_host = mkOption { 114 type = types.str; 115 default = ""; 116 description = '' 117 Local interface to listen on. 118 The empty string will cause synapse to listen on all interfaces. 119 ''; 120 }; 121 server_name = mkOption { 122 type = types.str; 123 description = '' 124 The domain name of the server, with optional explicit port. 125 This is used by remote servers to connect to this server, 126 e.g. matrix.org, localhost:8080, etc. 127 This is also the last part of your UserID. 128 ''; 129 }; 130 web_client = mkOption { 131 type = types.bool; 132 default = false; 133 description = '' 134 Whether to serve a web client from the HTTP/HTTPS root resource. 135 ''; 136 }; 137 database_type = mkOption { 138 type = types.enum [ "sqlite3" "psycopg2" ]; 139 default = "sqlite3"; 140 description = '' 141 The database engine name. Can be sqlite or psycopg2. 142 ''; 143 }; 144 database_args = mkOption { 145 type = types.attrs; 146 default = { 147 database = "/var/lib/matrix-synapse/homeserver.db"; 148 }; 149 description = '' 150 Arguments to pass to the engine. 151 ''; 152 }; 153 recaptcha_private_key = mkOption { 154 type = types.str; 155 default = ""; 156 description = '' 157 This Home Server's ReCAPTCHA private key. 158 ''; 159 }; 160 recaptcha_public_key = mkOption { 161 type = types.str; 162 default = ""; 163 description = '' 164 This Home Server's ReCAPTCHA public key. 165 ''; 166 }; 167 enable_registration_captcha = mkOption { 168 type = types.bool; 169 default = false; 170 description = '' 171 Enables ReCaptcha checks when registering, preventing signup 172 unless a captcha is answered. Requires a valid ReCaptcha 173 public/private key. 174 ''; 175 }; 176 turn_uris = mkOption { 177 type = types.listOf types.str; 178 default = []; 179 description = '' 180 The public URIs of the TURN server to give to clients 181 ''; 182 }; 183 turn_shared_secret = mkOption { 184 type = types.str; 185 default = ""; 186 description = '' 187 The shared secret used to compute passwords for the TURN server 188 ''; 189 }; 190 enable_registration = mkOption { 191 type = types.bool; 192 default = false; 193 description = '' 194 Enable registration for new users. 195 ''; 196 }; 197 registration_shared_secret = mkOption { 198 type = types.str; 199 default = ""; 200 description = '' 201 If set, allows registration by anyone who also has the shared 202 secret, even if registration is otherwise disabled. 203 ''; 204 }; 205 enable_metrics = mkOption { 206 type = types.bool; 207 default = false; 208 description = '' 209 Enable collection and rendering of performance metrics 210 ''; 211 }; 212 report_stats = mkOption { 213 type = types.bool; 214 default = false; 215 description = '' 216 ''; 217 }; 218 servers = mkOption { 219 type = types.attrs; 220 default = { 221 "matrix.org" = { 222 "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; 223 }; 224 }; 225 description = '' 226 The trusted servers to download signing keys from. 227 ''; 228 }; 229 extraConfig = mkOption { 230 type = types.lines; 231 default = ""; 232 description = '' 233 Extra config options for matrix-synapse. 234 ''; 235 }; 236 logConfig = mkOption { 237 type = types.lines; 238 default = readFile ./matrix-synapse-log_config.yaml; 239 description = '' 240 A yaml python logging config file 241 ''; 242 }; 243 }; 244 }; 245 246 config = mkIf cfg.enable { 247 users.extraUsers = [ 248 { name = "matrix-synapse"; 249 group = "matrix-synapse"; 250 home = "/var/lib/matrix-synapse"; 251 createHome = true; 252 shell = "${pkgs.bash}/bin/bash"; 253 uid = config.ids.uids.matrix-synapse; 254 } ]; 255 256 users.extraGroups = [ 257 { name = "matrix-synapse"; 258 gid = config.ids.gids.matrix-synapse; 259 } ]; 260 261 systemd.services.matrix-synapse = { 262 after = [ "network.target" ]; 263 wantedBy = [ "multi-user.target" ]; 264 preStart = '' 265 mkdir -p /var/lib/matrix-synapse 266 chmod 700 /var/lib/matrix-synapse 267 chown -R matrix-synapse:matrix-synapse /var/lib/matrix-synapse 268 ${cfg.package}/bin/homeserver --config-path ${configFile} --generate-keys 269 ''; 270 serviceConfig = { 271 Type = "simple"; 272 User = "matrix-synapse"; 273 Group = "matrix-synapse"; 274 WorkingDirectory = "/var/lib/matrix-synapse"; 275 PermissionsStartOnly = true; 276 ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile}"; 277 }; 278 }; 279 }; 280}