2023-12-17 19:44:40 +08:00
|
|
|
# port from nixpkgs#70dc536a
|
2023-08-29 22:15:58 +08:00
|
|
|
inputs:
|
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
options.nixos.services.synapse.instances = let inherit (inputs.lib) mkOption types; in mkOption
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
type = types.attrsOf (types.submodule (submoduleInputs: { options =
|
2023-12-17 19:44:40 +08:00
|
|
|
{
|
|
|
|
autoStart = mkOption { type = types.bool; default = true; };
|
|
|
|
port = mkOption { type = types.ints.unsigned; default = 8008; };
|
2023-12-17 19:50:09 +08:00
|
|
|
redisPort = mkOption { type = types.ints.unsigned; default = 6379; };
|
2023-12-20 14:31:42 +08:00
|
|
|
slidingSyncPort = mkOption { type = types.ints.unsigned; default = 9000; };
|
|
|
|
hostname = mkOption
|
|
|
|
{
|
|
|
|
type = types.nonEmptyStr;
|
|
|
|
default = "${submoduleInputs.config._module.args.name}.chn.moe";
|
|
|
|
};
|
2023-12-17 19:44:40 +08:00
|
|
|
matrixHostname = mkOption { type = types.nonEmptyStr; default = "chn.moe"; };
|
2023-12-20 14:31:42 +08:00
|
|
|
slidingSyncHostname = mkOption
|
|
|
|
{
|
|
|
|
type = types.nonEmptyStr;
|
|
|
|
default = "syncv3.${submoduleInputs.config.hostname}";
|
|
|
|
};
|
2023-12-19 21:39:04 +08:00
|
|
|
# , synapse_homeserver --config-path homeserver.yaml --generate-config --report-stats=yes --server-name xxx
|
2023-12-20 14:31:42 +08:00
|
|
|
};}));
|
2023-12-17 19:44:40 +08:00
|
|
|
default = {};
|
2023-09-01 21:05:26 +08:00
|
|
|
};
|
|
|
|
config =
|
|
|
|
let
|
2023-10-03 20:11:43 +08:00
|
|
|
inherit (inputs.config.nixos.services) synapse;
|
2023-12-17 19:44:40 +08:00
|
|
|
inherit (inputs.lib) mkIf mkMerge;
|
2023-12-20 14:31:42 +08:00
|
|
|
inherit (builtins) map listToAttrs replaceStrings concatLists;
|
2023-12-17 19:44:40 +08:00
|
|
|
inherit (inputs.localLib) attrsToList;
|
|
|
|
in
|
2023-10-03 20:11:43 +08:00
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
users = mkMerge (map
|
|
|
|
(instance:
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
users."synapse-${instance.name}" =
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
uid = inputs.config.nixos.system.user.user."synapse-${instance.name}";
|
|
|
|
group = "synapse-${instance.name}";
|
|
|
|
home = "/var/lib/synapse/${instance.name}";
|
|
|
|
createHome = true;
|
|
|
|
isSystemUser = true;
|
|
|
|
shell = "${inputs.pkgs.bash}/bin/bash";
|
2023-09-01 21:05:26 +08:00
|
|
|
};
|
2023-12-17 19:44:40 +08:00
|
|
|
groups."synapse-${instance.name}".gid = inputs.config.nixos.system.user.group."synapse-${instance.name}";
|
|
|
|
})
|
|
|
|
(attrsToList synapse.instances));
|
|
|
|
systemd = mkMerge (map
|
|
|
|
(instance: let workdir = "/var/lib/synapse/${instance.name}"; in
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
services =
|
|
|
|
{
|
|
|
|
"synapse-${instance.name}" =
|
|
|
|
let
|
|
|
|
package = inputs.pkgs.matrix-synapse.override
|
|
|
|
{ extras = [ "url-preview" "postgres" "redis" ]; plugins = []; };
|
|
|
|
config = inputs.config.sops.templates."synapse/${instance.name}/config.yaml".path;
|
|
|
|
homeserver = "${package}/bin/synapse_homeserver";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
description = "synapse-${instance.name}";
|
|
|
|
enable = instance.value.autoStart;
|
|
|
|
after = [ "network-online.target" "postgresql.service" ];
|
|
|
|
requires = [ "postgresql.service" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
serviceConfig =
|
|
|
|
{
|
|
|
|
ExecStart = "${homeserver} --config-path ${config} --keys-directory ${workdir}";
|
|
|
|
Type = "notify";
|
|
|
|
User = "synapse-${instance.name}";
|
|
|
|
Group = "synapse-${instance.name}";
|
|
|
|
WorkingDirectory = workdir;
|
|
|
|
ExecReload = "${inputs.pkgs.util-linux}/bin/kill -HUP $MAINPID";
|
|
|
|
Restart = "on-failure";
|
|
|
|
UMask = "0077";
|
|
|
|
CapabilityBoundingSet = [ "" ];
|
|
|
|
|
|
|
|
# hardening
|
|
|
|
LockPersonality = true;
|
|
|
|
NoNewPrivileges = true;
|
|
|
|
PrivateDevices = true;
|
|
|
|
PrivateTmp = true;
|
|
|
|
PrivateUsers = true;
|
|
|
|
ProcSubset = "pid";
|
|
|
|
ProtectClock = true;
|
|
|
|
ProtectControlGroups = true;
|
|
|
|
ProtectHome = true;
|
|
|
|
ProtectHostname = true;
|
|
|
|
ProtectKernelLogs = true;
|
|
|
|
ProtectKernelModules = true;
|
|
|
|
ProtectKernelTunables = true;
|
|
|
|
ProtectProc = "invisible";
|
|
|
|
ProtectSystem = "strict";
|
|
|
|
ReadWritePaths = [ workdir ];
|
|
|
|
RemoveIPC = true;
|
|
|
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
|
|
|
RestrictNamespaces = true;
|
|
|
|
RestrictRealtime = true;
|
|
|
|
RestrictSUIDSGID = true;
|
|
|
|
SystemCallArchitectures = "native";
|
|
|
|
SystemCallFilter = [ "@system-service" "~@resources" "~@privileged" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
"synapse-sliding-sync-${instance.name}" =
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
after = [ "synapse-${instance.name}.service" ];
|
|
|
|
wants = [ "synapse-${instance.name}.service" ];
|
2023-12-17 19:44:40 +08:00
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
serviceConfig =
|
2023-09-01 21:05:26 +08:00
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
User = "synapse-${instance.name}";
|
|
|
|
Group = "synapse-${instance.name}";
|
2023-12-20 14:31:42 +08:00
|
|
|
EnvironmentFile = inputs.config.sops.templates."synapse/${instance.name}-sliding-sync/env".path;
|
|
|
|
ExecStart = inputs.lib.getExe inputs.pkgs.matrix-sliding-sync;
|
|
|
|
WorkingDirectory = workdir + "-sliding-sync";
|
2023-12-17 19:44:40 +08:00
|
|
|
Restart = "on-failure";
|
2023-12-20 14:31:42 +08:00
|
|
|
RestartSec = "1s";
|
2023-09-01 21:05:26 +08:00
|
|
|
};
|
2023-10-03 20:11:43 +08:00
|
|
|
};
|
2023-12-20 14:31:42 +08:00
|
|
|
};
|
2023-12-17 19:44:40 +08:00
|
|
|
tmpfiles.rules =
|
|
|
|
[
|
|
|
|
"d /var/lib/synapse 0755 root root"
|
|
|
|
"d ${workdir} 0700 synapse-${instance.name} synapse-${instance.name}"
|
|
|
|
"Z ${workdir} - synapse-${instance.name} synapse-${instance.name}"
|
2023-12-20 14:31:42 +08:00
|
|
|
"d ${workdir}-sliding-sync 0700 synapse-${instance.name} synapse-${instance.name}"
|
|
|
|
"Z ${workdir}-sliding-sync - synapse-${instance.name} synapse-${instance.name}"
|
2023-12-17 19:44:40 +08:00
|
|
|
];
|
|
|
|
})
|
|
|
|
(attrsToList synapse.instances));
|
|
|
|
sops = mkMerge (map
|
|
|
|
(instance:
|
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
templates =
|
2023-12-17 19:44:40 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
"synapse/${instance.name}/config.yaml" =
|
|
|
|
{
|
|
|
|
owner = "synapse-${instance.name}";
|
|
|
|
group = "synapse-${instance.name}";
|
|
|
|
content =
|
|
|
|
let
|
|
|
|
inherit (inputs.config.sops) placeholder;
|
|
|
|
in builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "${instance.name}.yaml"
|
2023-12-17 19:44:40 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
server_name = instance.value.matrixHostname;
|
2023-12-20 15:26:35 +08:00
|
|
|
public_baseurl = "https://${instance.value.hostname}/";
|
2023-12-20 14:31:42 +08:00
|
|
|
listeners =
|
|
|
|
[{
|
|
|
|
bind_addresses = [ "127.0.0.1" ];
|
|
|
|
inherit (instance.value) port;
|
|
|
|
resources = [{ names = [ "client" "federation" ]; compress = false; }];
|
|
|
|
tls = false;
|
|
|
|
type = "http";
|
|
|
|
x_forwarded = true;
|
|
|
|
}];
|
|
|
|
database =
|
2023-12-17 19:44:40 +08:00
|
|
|
{
|
2023-12-20 14:31:42 +08:00
|
|
|
name = "psycopg2";
|
|
|
|
args =
|
|
|
|
{
|
|
|
|
user = "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}";
|
|
|
|
password = placeholder."postgresql/synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}";
|
|
|
|
database = "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}";
|
|
|
|
host = "127.0.0.1";
|
|
|
|
port = "5432";
|
|
|
|
};
|
|
|
|
allow_unsafe_locale = true;
|
2023-12-17 19:44:40 +08:00
|
|
|
};
|
2023-12-20 14:31:42 +08:00
|
|
|
redis =
|
|
|
|
{
|
|
|
|
enabled = true;
|
|
|
|
port = instance.value.redisPort;
|
|
|
|
password = placeholder."redis/synapse-${instance.name}";
|
|
|
|
};
|
|
|
|
turn_shared_secret = placeholder."synapse/${instance.name}/coturn";
|
|
|
|
registration_shared_secret = placeholder."synapse/${instance.name}/registration";
|
|
|
|
macaroon_secret_key = placeholder."synapse/${instance.name}/macaroon";
|
|
|
|
form_secret = placeholder."synapse/${instance.name}/form";
|
|
|
|
signing_key_path = inputs.config.sops.secrets."synapse/${instance.name}/signing-key".path;
|
|
|
|
email =
|
|
|
|
{
|
|
|
|
smtp_host = "mail.chn.moe";
|
|
|
|
smtp_port = 25;
|
|
|
|
smtp_user = "bot@chn.moe";
|
|
|
|
smtp_pass = placeholder."mail/bot";
|
|
|
|
require_transport_security = true;
|
|
|
|
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
|
|
|
|
app_name = "Haonan Chen's synapse";
|
|
|
|
};
|
|
|
|
admin_contact = "mailto:chn@chn.moe";
|
|
|
|
enable_registration = true;
|
|
|
|
registrations_require_3pid = [ "email" ];
|
|
|
|
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
|
|
|
|
max_upload_size = "1024M";
|
|
|
|
web_client_location = "https://element.chn.moe/";
|
|
|
|
extra_well_known_client_content."org.matrix.msc3575.proxy".url =
|
|
|
|
"https://${instance.value.slidingSyncHostname}";
|
|
|
|
report_stats = true;
|
|
|
|
trusted_key_servers =
|
|
|
|
[{
|
|
|
|
server_name = "matrix.org";
|
|
|
|
verify_keys."ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
|
|
|
|
}];
|
|
|
|
suppress_key_server_warning = true;
|
|
|
|
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
|
|
|
|
{
|
|
|
|
version = 1;
|
|
|
|
formatters.precise.format =
|
|
|
|
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
|
|
|
|
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
|
|
|
|
root = { level = "INFO"; handlers = [ "console" ]; };
|
|
|
|
disable_existing_loggers = true;
|
|
|
|
};
|
|
|
|
pid_file = "/run/synapse-${instance.name}.pid";
|
|
|
|
media_store_path = "/var/lib/synapse/${instance.name}/media_store";
|
|
|
|
presence.enabled = true;
|
|
|
|
url_preview_enabled = true;
|
|
|
|
url_preview_ip_range_blacklist =
|
|
|
|
[
|
|
|
|
"10.0.0.0/8" "100.64.0.0/10" "127.0.0.0/8" "169.254.0.0/16" "172.16.0.0/12" "192.0.0.0/24"
|
|
|
|
"192.0.2.0/24" "192.168.0.0/16" "192.88.99.0/24" "198.18.0.0/15" "198.51.100.0/24" "2001:db8::/32"
|
|
|
|
"203.0.113.0/24" "224.0.0.0/4" "::1/128" "fc00::/7" "fe80::/10" "fec0::/10" "ff00::/8"
|
|
|
|
];
|
|
|
|
max_image_pixels = "32M";
|
|
|
|
dynamic_thumbnails = false;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
"synapse/${instance.name}-sliding-sync/env" =
|
|
|
|
{
|
|
|
|
owner = "synapse-${instance.name}";
|
|
|
|
group = "synapse-${instance.name}";
|
|
|
|
content =
|
|
|
|
let
|
|
|
|
inherit (inputs.config.sops) placeholder;
|
|
|
|
pgString = "postgresql://"
|
|
|
|
+ "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}"
|
|
|
|
+ ":${placeholder."postgresql/synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}"}"
|
|
|
|
+ "@127.0.0.1:5432"
|
2023-12-20 14:39:23 +08:00
|
|
|
+ "/synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}_sliding_sync"
|
|
|
|
+ "?sslmode=disable";
|
2023-12-20 14:31:42 +08:00
|
|
|
in
|
|
|
|
''
|
|
|
|
SYNCV3_SERVER=https://${instance.value.hostname}
|
|
|
|
SYNCV3_DB=${pgString}
|
|
|
|
SYNCV3_SECRET=${placeholder."synapse/${instance.name}/sliding-sync"}
|
|
|
|
SYNCV3_BINDADDR=127.0.0.1:${toString instance.value.slidingSyncPort}
|
|
|
|
'';
|
|
|
|
};
|
2023-12-17 19:44:40 +08:00
|
|
|
};
|
|
|
|
secrets = (listToAttrs (map
|
|
|
|
(secret: { name = "synapse/${instance.name}/${secret}"; value = {}; })
|
2023-12-20 14:31:42 +08:00
|
|
|
[ "coturn" "registration" "macaroon" "form" "sliding-sync" ]))
|
2023-12-17 19:44:40 +08:00
|
|
|
// { "synapse/${instance.name}/signing-key".owner = "synapse-${instance.name}"; }
|
|
|
|
// { "mail/bot" = {}; };
|
|
|
|
})
|
|
|
|
(attrsToList synapse.instances));
|
2023-11-09 20:52:15 +08:00
|
|
|
nixos.services =
|
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
postgresql =
|
|
|
|
{
|
|
|
|
enable = mkIf (synapse.instances != {}) true;
|
2023-12-20 14:31:42 +08:00
|
|
|
instances = listToAttrs (concatLists (map
|
2023-12-20 12:10:51 +08:00
|
|
|
(instance:
|
2023-12-20 14:31:42 +08:00
|
|
|
[
|
|
|
|
{
|
|
|
|
name = "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}";
|
|
|
|
value.initializeFlags = { TEMPLATE = "template0"; LC_CTYPE = "C"; LC_COLLATE = "C"; };
|
|
|
|
}
|
|
|
|
{
|
|
|
|
name = "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}_sliding_sync";
|
|
|
|
value.user = "synapse_${replaceStrings [ "-" ] [ "_" ] instance.name}";
|
|
|
|
}
|
|
|
|
])
|
|
|
|
(attrsToList synapse.instances)));
|
2023-12-17 19:44:40 +08:00
|
|
|
};
|
2023-12-17 19:50:09 +08:00
|
|
|
redis.instances = listToAttrs (map
|
|
|
|
(instance: { name = "synapse-${instance.name}"; value.port = instance.value.redisPort; })
|
|
|
|
(attrsToList synapse.instances));
|
2023-11-09 20:52:15 +08:00
|
|
|
nginx =
|
|
|
|
{
|
2023-12-17 19:44:40 +08:00
|
|
|
enable = mkIf (synapse.instances != {}) true;
|
2023-12-20 14:31:42 +08:00
|
|
|
https = listToAttrs (concatLists (map
|
2023-12-17 19:44:40 +08:00
|
|
|
(instance: with instance.value;
|
2023-12-20 14:31:42 +08:00
|
|
|
[
|
|
|
|
{
|
|
|
|
name = hostname;
|
2023-12-20 15:47:28 +08:00
|
|
|
value.location =
|
|
|
|
{
|
|
|
|
"/".proxy = { upstream = "http://127.0.0.1:${toString port}"; websocket = true; };
|
|
|
|
"/.well-known/matrix/server".static =
|
|
|
|
{
|
|
|
|
root = builtins.toString (inputs.pkgs.writeTextFile
|
|
|
|
{
|
|
|
|
name = "server";
|
|
|
|
text = builtins.toJSON
|
|
|
|
{
|
|
|
|
"m.server" = "${hostname}:443";
|
|
|
|
};
|
|
|
|
destination = "/.well-known/matrix/server";
|
|
|
|
});
|
|
|
|
};
|
|
|
|
};
|
2023-12-20 14:31:42 +08:00
|
|
|
}
|
|
|
|
{
|
|
|
|
name = slidingSyncHostname;
|
|
|
|
value.location."/".proxy =
|
|
|
|
{ upstream = "http://127.0.0.1:${toString slidingSyncPort}"; websocket = true; };
|
|
|
|
}
|
|
|
|
])
|
|
|
|
(attrsToList synapse.instances)));
|
2023-11-09 20:52:15 +08:00
|
|
|
};
|
|
|
|
};
|
2023-10-03 20:11:43 +08:00
|
|
|
};
|
2023-08-29 22:15:58 +08:00
|
|
|
}
|