at 16.09-beta 19 kB view raw
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 mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${if r.compress then "true" else "false"}}''; 9 mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${if l.tls then "true" else "false"}, x_forwarded: ${if l.x_forwarded then "true" else "false"}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}''; 10 configFile = pkgs.writeText "homeserver.yaml" '' 11tls_certificate_path: "${cfg.tls_certificate_path}" 12${optionalString (cfg.tls_private_key_path != null) '' 13tls_private_key_path: "${cfg.tls_private_key_path}" 14''} 15tls_dh_params_path: "${cfg.tls_dh_params_path}" 16no_tls: ${if cfg.no_tls then "true" else "false"} 17${optionalString (cfg.bind_port != null) '' 18bind_port: ${toString cfg.bind_port} 19''} 20${optionalString (cfg.unsecure_port != null) '' 21unsecure_port: ${toString cfg.unsecure_port} 22''} 23${optionalString (cfg.bind_host != null) '' 24bind_host: "${cfg.bind_host}" 25''} 26server_name: "${cfg.server_name}" 27pid_file: "/var/run/matrix-synapse.pid" 28web_client: ${if cfg.web_client then "true" else "false"} 29${optionalString (cfg.public_baseurl != null) '' 30public_baseurl: "${cfg.public_baseurl}" 31''} 32listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}] 33database: { 34 name: "${cfg.database_type}", 35 args: { 36 ${concatStringsSep ",\n " ( 37 mapAttrsToList (n: v: "\"${n}\": ${v}") cfg.database_args 38 )} 39 } 40} 41event_cache_size: "${cfg.event_cache_size}" 42verbose: ${cfg.verbose} 43log_file: "/var/log/matrix-synapse/homeserver.log" 44log_config: "${logConfigFile}" 45rc_messages_per_second: ${cfg.rc_messages_per_second} 46rc_message_burst_count: ${cfg.rc_message_burst_count} 47federation_rc_window_size: ${cfg.federation_rc_window_size} 48federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit} 49federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay} 50federation_rc_reject_limit: ${cfg.federation_rc_reject_limit} 51federation_rc_concurrent: ${cfg.federation_rc_concurrent} 52media_store_path: "/var/lib/matrix-synapse/media" 53uploads_path: "/var/lib/matrix-synapse/uploads" 54max_upload_size: "${cfg.max_upload_size}" 55max_image_pixels: "${cfg.max_image_pixels}" 56dynamic_thumbnails: ${if cfg.dynamic_thumbnails then "true" else "false"} 57url_preview_enabled: False 58recaptcha_private_key: "${cfg.recaptcha_private_key}" 59recaptcha_public_key: "${cfg.recaptcha_public_key}" 60enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"} 61turn_uris: ${builtins.toJSON cfg.turn_uris} 62turn_shared_secret: "${cfg.turn_shared_secret}" 63enable_registration: ${if cfg.enable_registration then "true" else "false"} 64${optionalString (cfg.registration_shared_secret != null) '' 65registration_shared_secret: "${cfg.registration_shared_secret}" 66''} 67recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify" 68turn_user_lifetime: "${cfg.turn_user_lifetime}" 69user_creation_max_duration: ${cfg.user_creation_max_duration} 70bcrypt_rounds: ${cfg.bcrypt_rounds} 71allow_guest_access: {if cfg.allow_guest_access then "true" else "false"} 72enable_metrics: ${if cfg.enable_metrics then "true" else "false"} 73report_stats: ${if cfg.report_stats then "true" else "false"} 74signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key" 75key_refresh_interval: "${cfg.key_refresh_interval}" 76perspectives: 77 servers: { 78 ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' 79 "${n}": { 80 "verify_keys": { 81 ${concatStringsSep "},\n" (mapAttrsToList (n: v: '' 82 "${n}": { 83 "key": "${v}" 84 }'') v)} 85 } 86 '') cfg.servers)} 87 } 88 } 89app_service_config_files: ${builtins.toJSON cfg.app_service_config_files} 90 91${cfg.extraConfig} 92''; 93in { 94 options = { 95 services.matrix-synapse = { 96 enable = mkEnableOption "matrix.org synapse"; 97 package = mkOption { 98 type = types.package; 99 default = pkgs.matrix-synapse; 100 defaultText = "pkgs.matrix-synapse"; 101 description = '' 102 Overridable attribute of the matrix synapse server package to use. 103 ''; 104 }; 105 no_tls = mkOption { 106 type = types.bool; 107 default = false; 108 description = '' 109 Don't bind to the https port 110 ''; 111 }; 112 bind_port = mkOption { 113 type = types.nullOr types.int; 114 default = null; 115 example = 8448; 116 description = '' 117 DEPRECATED: Use listeners instead. 118 The port to listen for HTTPS requests on. 119 For when matrix traffic is sent directly to synapse. 120 ''; 121 }; 122 unsecure_port = mkOption { 123 type = types.nullOr types.int; 124 default = null; 125 example = 8008; 126 description = '' 127 DEPRECATED: Use listeners instead. 128 The port to listen for HTTP requests on. 129 For when matrix traffic passes through loadbalancer that unwraps TLS. 130 ''; 131 }; 132 bind_host = mkOption { 133 type = types.nullOr types.str; 134 default = null; 135 description = '' 136 DEPRECATED: Use listeners instead. 137 Local interface to listen on. 138 The empty string will cause synapse to listen on all interfaces. 139 ''; 140 }; 141 tls_certificate_path = mkOption { 142 type = types.str; 143 default = "/var/lib/matrix-synapse/homeserver.tls.crt"; 144 description = '' 145 PEM encoded X509 certificate for TLS. 146 You can replace the self-signed certificate that synapse 147 autogenerates on launch with your own SSL certificate + key pair 148 if you like. Any required intermediary certificates can be 149 appended after the primary certificate in hierarchical order. 150 ''; 151 }; 152 tls_private_key_path = mkOption { 153 type = types.nullOr types.str; 154 default = "/var/lib/matrix-synapse/homeserver.tls.key"; 155 example = null; 156 description = '' 157 PEM encoded private key for TLS. Specify null if synapse is not 158 speaking TLS directly. 159 ''; 160 }; 161 tls_dh_params_path = mkOption { 162 type = types.str; 163 default = "/var/lib/matrix-synapse/homeserver.tls.dh"; 164 description = '' 165 PEM dh parameters for ephemeral keys 166 ''; 167 }; 168 server_name = mkOption { 169 type = types.str; 170 example = "example.com"; 171 description = '' 172 The domain name of the server, with optional explicit port. 173 This is used by remote servers to connect to this server, 174 e.g. matrix.org, localhost:8080, etc. 175 This is also the last part of your UserID. 176 ''; 177 }; 178 web_client = mkOption { 179 type = types.bool; 180 default = false; 181 description = '' 182 Whether to serve a web client from the HTTP/HTTPS root resource. 183 ''; 184 }; 185 public_baseurl = mkOption { 186 type = types.nullOr types.str; 187 default = null; 188 example = "https://example.com:8448/"; 189 description = '' 190 The public-facing base URL for the client API (not including _matrix/...) 191 ''; 192 }; 193 listeners = mkOption { 194 type = types.listOf (types.submodule { 195 options = { 196 port = mkOption { 197 type = types.int; 198 example = 8448; 199 description = '' 200 The port to listen for HTTP(S) requests on. 201 ''; 202 }; 203 bind_address = mkOption { 204 type = types.str; 205 default = ""; 206 example = "203.0.113.42"; 207 description = '' 208 Local interface to listen on. 209 The empty string will cause synapse to listen on all interfaces. 210 ''; 211 }; 212 type = mkOption { 213 type = types.str; 214 default = "http"; 215 description = '' 216 Type of listener. 217 ''; 218 }; 219 tls = mkOption { 220 type = types.bool; 221 default = true; 222 description = '' 223 Whether to listen for HTTPS connections rather than HTTP. 224 ''; 225 }; 226 x_forwarded = mkOption { 227 type = types.bool; 228 default = false; 229 description = '' 230 Use the X-Forwarded-For (XFF) header as the client IP and not the 231 actual client IP. 232 ''; 233 }; 234 resources = mkOption { 235 type = types.listOf (types.submodule { 236 options = { 237 names = mkOption { 238 type = types.listOf types.str; 239 description = '' 240 List of resources to host on this listener. 241 ''; 242 example = ["client" "webclient" "federation"]; 243 }; 244 compress = mkOption { 245 type = types.bool; 246 description = '' 247 Should synapse compress HTTP responses to clients that support it? 248 This should be disabled if running synapse behind a load balancer 249 that can do automatic compression. 250 ''; 251 }; 252 }; 253 }); 254 description = '' 255 List of HTTP resources to serve on this listener. 256 ''; 257 }; 258 }; 259 }); 260 default = [{ 261 port = 8448; 262 bind_address = ""; 263 type = "http"; 264 tls = true; 265 x_forwarded = false; 266 resources = [ 267 { names = ["client" "webclient"]; compress = true; } 268 { names = ["federation"]; compress = false; } 269 ]; 270 }]; 271 description = '' 272 List of ports that Synapse should listen on, their purpose and their configuration. 273 ''; 274 }; 275 verbose = mkOption { 276 type = types.str; 277 default = "0"; 278 description = "Logging verbosity level."; 279 }; 280 rc_messages_per_second = mkOption { 281 type = types.str; 282 default = "0.2"; 283 description = "Number of messages a client can send per second"; 284 }; 285 rc_message_burst_count = mkOption { 286 type = types.str; 287 default = "10.0"; 288 description = "Number of message a client can send before being throttled"; 289 }; 290 federation_rc_window_size = mkOption { 291 type = types.str; 292 default = "1000"; 293 description = "The federation window size in milliseconds"; 294 }; 295 federation_rc_sleep_limit = mkOption { 296 type = types.str; 297 default = "10"; 298 description = '' 299 The number of federation requests from a single server in a window 300 before the server will delay processing the request. 301 ''; 302 }; 303 federation_rc_sleep_delay = mkOption { 304 type = types.str; 305 default = "500"; 306 description = '' 307 The duration in milliseconds to delay processing events from 308 remote servers by if they go over the sleep limit. 309 ''; 310 }; 311 federation_rc_reject_limit = mkOption { 312 type = types.str; 313 default = "50"; 314 description = '' 315 The maximum number of concurrent federation requests allowed 316 from a single server 317 ''; 318 }; 319 federation_rc_concurrent = mkOption { 320 type = types.str; 321 default = "3"; 322 description = "The number of federation requests to concurrently process from a single server"; 323 }; 324 database_type = mkOption { 325 type = types.enum [ "sqlite3" "psycopg2" ]; 326 default = "sqlite3"; 327 description = '' 328 The database engine name. Can be sqlite or psycopg2. 329 ''; 330 }; 331 database_args = mkOption { 332 type = types.attrs; 333 default = { 334 database = "/var/lib/matrix-synapse/homeserver.db"; 335 }; 336 description = '' 337 Arguments to pass to the engine. 338 ''; 339 }; 340 event_cache_size = mkOption { 341 type = types.str; 342 default = "10K"; 343 description = "Number of events to cache in memory."; 344 }; 345 recaptcha_private_key = mkOption { 346 type = types.str; 347 default = ""; 348 description = '' 349 This Home Server's ReCAPTCHA private key. 350 ''; 351 }; 352 recaptcha_public_key = mkOption { 353 type = types.str; 354 default = ""; 355 description = '' 356 This Home Server's ReCAPTCHA public key. 357 ''; 358 }; 359 enable_registration_captcha = mkOption { 360 type = types.bool; 361 default = false; 362 description = '' 363 Enables ReCaptcha checks when registering, preventing signup 364 unless a captcha is answered. Requires a valid ReCaptcha 365 public/private key. 366 ''; 367 }; 368 turn_uris = mkOption { 369 type = types.listOf types.str; 370 default = []; 371 description = '' 372 The public URIs of the TURN server to give to clients 373 ''; 374 }; 375 turn_shared_secret = mkOption { 376 type = types.str; 377 default = ""; 378 description = '' 379 The shared secret used to compute passwords for the TURN server 380 ''; 381 }; 382 turn_user_lifetime = mkOption { 383 type = types.str; 384 default = "1h"; 385 description = "How long generated TURN credentials last"; 386 }; 387 enable_registration = mkOption { 388 type = types.bool; 389 default = false; 390 description = '' 391 Enable registration for new users. 392 ''; 393 }; 394 registration_shared_secret = mkOption { 395 type = types.nullOr types.str; 396 default = null; 397 description = '' 398 If set, allows registration by anyone who also has the shared 399 secret, even if registration is otherwise disabled. 400 ''; 401 }; 402 enable_metrics = mkOption { 403 type = types.bool; 404 default = false; 405 description = '' 406 Enable collection and rendering of performance metrics 407 ''; 408 }; 409 report_stats = mkOption { 410 type = types.bool; 411 default = false; 412 description = '' 413 ''; 414 }; 415 servers = mkOption { 416 type = types.attrsOf (types.attrsOf types.str); 417 default = { 418 "matrix.org" = { 419 "ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; 420 }; 421 }; 422 description = '' 423 The trusted servers to download signing keys from. 424 ''; 425 }; 426 max_upload_size = mkOption { 427 type = types.str; 428 default = "10M"; 429 description = "The largest allowed upload size in bytes"; 430 }; 431 max_image_pixels = mkOption { 432 type = types.str; 433 default = "32M"; 434 description = "Maximum number of pixels that will be thumbnailed"; 435 }; 436 dynamic_thumbnails = mkOption { 437 type = types.bool; 438 default = false; 439 description = '' 440 Whether to generate new thumbnails on the fly to precisely match 441 the resolution requested by the client. If true then whenever 442 a new resolution is requested by the client the server will 443 generate a new thumbnail. If false the server will pick a thumbnail 444 from a precalculated list. 445 ''; 446 }; 447 user_creation_max_duration = mkOption { 448 type = types.str; 449 default = "1209600000"; 450 description = '' 451 Sets the expiry for the short term user creation in 452 milliseconds. The default value is two weeks. 453 ''; 454 }; 455 bcrypt_rounds = mkOption { 456 type = types.str; 457 default = "12"; 458 description = '' 459 Set the number of bcrypt rounds used to generate password hash. 460 Larger numbers increase the work factor needed to generate the hash. 461 ''; 462 }; 463 allow_guest_access = mkOption { 464 type = types.bool; 465 default = false; 466 description = '' 467 Allows users to register as guests without a password/email/etc, and 468 participate in rooms hosted on this server which have been made 469 accessible to anonymous users. 470 ''; 471 }; 472 key_refresh_interval = mkOption { 473 type = types.str; 474 default = "1d"; 475 description = '' 476 How long key response published by this server is valid for. 477 Used to set the valid_until_ts in /key/v2 APIs. 478 Determines how quickly servers will query to check which keys 479 are still valid. 480 ''; 481 }; 482 app_service_config_files = mkOption { 483 type = types.listOf types.path; 484 default = [ ]; 485 description = '' 486 A list of application service config file to use 487 ''; 488 }; 489 extraConfig = mkOption { 490 type = types.lines; 491 default = ""; 492 description = '' 493 Extra config options for matrix-synapse. 494 ''; 495 }; 496 logConfig = mkOption { 497 type = types.lines; 498 default = readFile ./matrix-synapse-log_config.yaml; 499 description = '' 500 A yaml python logging config file 501 ''; 502 }; 503 }; 504 }; 505 506 config = mkIf cfg.enable { 507 users.extraUsers = [ 508 { name = "matrix-synapse"; 509 group = "matrix-synapse"; 510 home = "/var/lib/matrix-synapse"; 511 createHome = true; 512 shell = "${pkgs.bash}/bin/bash"; 513 uid = config.ids.uids.matrix-synapse; 514 } ]; 515 516 users.extraGroups = [ 517 { name = "matrix-synapse"; 518 gid = config.ids.gids.matrix-synapse; 519 } ]; 520 521 systemd.services.matrix-synapse = { 522 after = [ "network.target" ]; 523 wantedBy = [ "multi-user.target" ]; 524 preStart = '' 525 if ! test -e /var/lib/matrix-synapse; then 526 mkdir -p /var/lib/matrix-synapse 527 chmod 700 /var/lib/matrix-synapse 528 chown -R matrix-synapse:matrix-synapse /var/lib/matrix-synapse 529 ${cfg.package}/bin/homeserver --config-path ${configFile} --keys-directory /var/lib/matrix-synapse/ --generate-keys 530 fi 531 ''; 532 serviceConfig = { 533 Type = "simple"; 534 User = "matrix-synapse"; 535 Group = "matrix-synapse"; 536 WorkingDirectory = "/var/lib/matrix-synapse"; 537 PermissionsStartOnly = true; 538 ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile}"; 539 }; 540 }; 541 }; 542}