1
0
forked from clan/clan-core

Merge pull request 'clanModules: Init nginx module. matrix-synapse: don't assume domain names' (#1906) from Qubasa/clan-core:Qubasa-new-main into main

This commit is contained in:
clan-bot 2024-08-19 10:59:16 +00:00
commit b29f649343
9 changed files with 278 additions and 27 deletions

View File

@ -22,7 +22,11 @@
enableACME = lib.mkForce false;
forceSSL = lib.mkForce false;
};
clan.matrix-synapse.domain = "clan.test";
security.acme.defaults.email = "admin@clan.test";
clan.matrix-synapse.domain = {
server = "matrix.clan.test";
client = "element.clan.test";
};
clan.matrix-synapse.users.admin.admin = true;
clan.matrix-synapse.users.someuser = { };

View File

@ -143,6 +143,7 @@ in
"dyndns"
"enable"
] "Just define clan.dyndns.settings to enable it")
../nginx
];
config = lib.mkMerge [
@ -158,11 +159,6 @@ in
createHome = true;
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.server.enable [
80
443
];
services.nginx = lib.mkIf cfg.server.enable {
enable = true;
virtualHosts = {
@ -249,7 +245,6 @@ in
PrivateDevices = "yes";
ProtectKernelModules = "yes";
ProtectKernelTunables = "yes";
WorkingDirectory = "/var/lib/${name}";
ReadWritePaths = [
"/proc/self"

View File

@ -15,6 +15,7 @@
moonlight = ./moonlight;
mumble = ./mumble;
packages = ./packages;
nginx = ./nginx;
postgresql = ./postgresql;
root-password = ./root-password;
single-disk = ./single-disk;
@ -26,6 +27,7 @@
thelounge = ./thelounge;
trusted-nix-caches = ./trusted-nix-caches;
user-password = ./user-password;
vaultwarden = ./vaultwarden;
xfce = ./xfce;
zerotier-static-peers = ./zerotier-static-peers;
zt-tcp-relay = ./zt-tcp-relay;

View File

@ -6,25 +6,31 @@
}:
let
cfg = config.clan.matrix-synapse;
nginx-vhost = "matrix.${config.clan.matrix-synapse.domain}";
element-web =
pkgs.runCommand "element-web-with-config" { nativeBuildInputs = [ pkgs.buildPackages.jq ]; }
''
cp -r ${pkgs.element-web} $out
chmod -R u+w $out
jq '."default_server_config"."m.homeserver" = { "base_url": "https://${nginx-vhost}:443", "server_name": "${config.clan.matrix-synapse.domain}" }' \
jq '."default_server_config"."m.homeserver" = { "base_url": "https://${cfg.domain.server}:443", "server_name": "${cfg.domain.server}" }' \
> $out/config.json < ${pkgs.element-web}/config.json
ln -s $out/config.json $out/config.${nginx-vhost}.json
ln -s $out/config.json $out/config.${cfg.domain.server}.json
'';
in
# FIXME: This was taken from upstream. Drop this when our patch is upstream
{
options.services.matrix-synapse.package = lib.mkOption { readOnly = false; };
options.clan.matrix-synapse = {
domain = lib.mkOption {
type = lib.types.str;
description = "The domain name of the matrix server";
example = "example.com";
domain = {
server = lib.mkOption {
type = lib.types.str;
description = "The domain name of the matrix server";
example = "matrix.example.com";
};
client = lib.mkOption {
type = lib.types.str;
description = "The domain name of the matrix client";
example = "element.example.com";
};
};
users = lib.mkOption {
default = { };
@ -61,14 +67,14 @@ in
"matrix-synapse"
"enable"
] "Importing the module will already enable the service.")
../postgresql
../nginx
];
config = {
services.matrix-synapse = {
enable = true;
settings = {
server_name = cfg.domain;
server_name = cfg.domain.server;
enable_registration = false;
database = {
args.user = "matrix-synapse";
args.database = "matrix-synapse";
@ -169,18 +175,13 @@ in
];
};
networking.firewall.allowedTCPPorts = [
80
443
];
services.nginx = {
enable = true;
virtualHosts = {
${cfg.domain} = {
"${cfg.domain.server}" = {
locations."= /.well-known/matrix/server".extraConfig = ''
add_header Content-Type application/json;
return 200 '${builtins.toJSON { "m.server" = "matrix.${cfg.domain}:443"; }}';
return 200 '${builtins.toJSON { "m.server" = "${cfg.domain.server}:443"; }}';
'';
locations."= /.well-known/matrix/client".extraConfig = ''
add_header Content-Type application/json;
@ -188,7 +189,7 @@ in
return 200 '${
builtins.toJSON {
"m.homeserver" = {
"base_url" = "https://${nginx-vhost}";
"base_url" = "https://${cfg.domain.server}";
};
"m.identity_server" = {
"base_url" = "https://vector.im";
@ -196,12 +197,14 @@ in
}
}';
'';
};
${nginx-vhost} = {
forceSSL = true;
enableACME = true;
locations."/_matrix".proxyPass = "http://localhost:8008";
locations."/_synapse".proxyPass = "http://localhost:8008";
};
"${cfg.domain.client}" = {
forceSSL = true;
enableACME = true;
locations."/".root = element-web;
};
};

View File

@ -0,0 +1,3 @@
---
description = "Good defaults for the nginx webserver"
---

View File

@ -0,0 +1,75 @@
{ config, lib, ... }:
let
nginx_acme_email = "nginx-acme";
in
{
imports = [
(lib.mkRemovedOptionModule [
"clan"
"nginx"
"enable"
] "Importing the module will already enable the service.")
];
config = {
clan.core.facts.services."${nginx_acme_email}" = {
public."${nginx_acme_email}" = { };
generator.prompt = "Please enter your email address for Let's Encrypt certificate generation";
generator.script = ''
echo -n $prompt_value | tr -d "\n" > "$facts"/${nginx_acme_email}
'';
};
security.acme.acceptTerms = true;
security.acme.defaults.email = lib.mkDefault (
let
path = config.clan.core.facts.services."${nginx_acme_email}".public."${nginx_acme_email}".path;
in
if builtins.pathExists path then builtins.readFile path else null
);
networking.firewall.allowedTCPPorts = [
443
80
];
services.nginx = {
enable = true;
statusPage = lib.mkDefault true;
recommendedBrotliSettings = lib.mkDefault true;
recommendedGzipSettings = lib.mkDefault true;
recommendedOptimisation = lib.mkDefault true;
recommendedProxySettings = lib.mkDefault true;
recommendedTlsSettings = lib.mkDefault true;
recommendedZstdSettings = lib.mkDefault true;
# Nginx sends all the access logs to /var/log/nginx/access.log by default.
# instead of going to the journal!
commonHttpConfig = "access_log syslog:server=unix:/dev/log;";
resolver.addresses =
let
isIPv6 = addr: builtins.match ".*:.*:.*" addr != null;
escapeIPv6 = addr: if isIPv6 addr then "[${addr}]" else addr;
cloudflare = [
"1.1.1.1"
"2606:4700:4700::1111"
];
resolvers =
if config.networking.nameservers == [ ] then cloudflare else config.networking.nameservers;
in
map escapeIPv6 resolvers;
sslDhparam = config.security.dhparams.params.nginx.path;
};
security.dhparams = {
enable = true;
params.nginx = { };
};
};
}

View File

@ -0,0 +1,3 @@
---
description = "The server for the password manager bitwarden"
---

View File

@ -0,0 +1,164 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.clan.vaultwarden;
module_name = "vaultwarden";
admin_pwd_secret = "${module_name}-admin";
admin_pwd_hash_secret = "${admin_pwd_secret}-hash";
smtp_pwd_secret = "${module_name}-smtp";
smtp_pwd_secret_path =
config.clan.core.facts.services."${smtp_pwd_secret}".secret."${smtp_pwd_secret}".path;
admin_secret_cfg_path =
config.clan.core.facts.services."${admin_pwd_secret}".secret."${admin_pwd_hash_secret}".path;
in
{
imports = [
../postgresql
(lib.mkRemovedOptionModule [
"clan"
"vaultwarden"
"enable"
] "Importing the module will already enable the service.")
../nginx
];
options.clan."${module_name}" = {
domain = lib.mkOption {
type = lib.types.str;
example = "bitwarden.example.com";
description = "The domain to use for Vaultwarden";
};
port = lib.mkOption {
type = lib.types.int;
default = 3011;
description = "The port to use for Vaultwarden";
};
allow_signups = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Allow signups for new users";
};
smtp = {
host = lib.mkOption {
type = lib.types.str;
example = "smtp.example.com";
description = "The email server domain address";
};
from = lib.mkOption {
type = lib.types.str;
example = "foobar@example.com";
description = "From whom the email is coming from";
};
username = lib.mkOption {
type = lib.types.str;
example = "foobar@example.com";
description = "The email server username";
};
};
};
config = {
clan.postgresql.users.vaultwarden = { };
clan.postgresql.databases.vaultwarden.create.options = {
TEMPLATE = "template0";
LC_COLLATE = "C";
LC_CTYPE = "C";
ENCODING = "UTF8";
OWNER = "vaultwarden";
};
clan.postgresql.databases.vaultwarden.restore.stopOnRestore = [ "vaultwarden" ];
services.nginx = {
enable = true;
virtualHosts = {
"${cfg.domain}" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
client_max_body_size 128M;
'';
locations."/" = {
proxyPass = "http://localhost:${builtins.toString cfg.port}";
proxyWebsockets = true;
};
locations."/notifications/hub" = {
proxyPass = "http://localhost:${builtins.toString cfg.port}";
proxyWebsockets = true;
};
locations."/notifications/hub/negotiate" = {
proxyPass = "http://localhost:${builtins.toString cfg.port}";
proxyWebsockets = true;
};
};
};
};
clan.core.facts.services = {
"${admin_pwd_secret}" = {
secret."${admin_pwd_secret}" = { };
secret."${admin_pwd_hash_secret}" = { };
generator.path = with pkgs; [
coreutils
pwgen
libargon2
openssl
];
generator.script = ''
ADMIN_PWD=$(pwgen 16 -n1 | tr -d "\n")
ADMIN_HASH=$(echo -n "$ADMIN_PWD" | argon2 "$(openssl rand -base64 32)" -e -id -k 65540 -t 3 -p 4)
config="
ADMIN_TOKEN=\"$ADMIN_HASH\"
"
echo -n "$ADMIN_PWD" > $secrets/${admin_pwd_secret}
echo -n "$config" > $secrets/${admin_pwd_hash_secret}
'';
};
"${smtp_pwd_secret}" = {
secret."${smtp_pwd_secret}" = { };
generator.prompt = "${cfg.smtp.from} SMTP password";
generator.path = with pkgs; [ coreutils ];
generator.script = ''
config="
SMTP_PASSWORD="$prompt_value"
"
echo -n "$config" > $secrets/${smtp_pwd_secret}
'';
};
};
systemd.services."${module_name}" = {
serviceConfig = {
EnvironmentFile = [ smtp_pwd_secret_path ];
};
};
services."${module_name}" = {
enable = true;
dbBackend = "postgresql";
environmentFile = admin_secret_cfg_path; # TODO: Make this upstream an array
config = {
SMTP_SECURITY = "force_tls";
SMTP_HOST = cfg.smtp.host;
SMTP_FROM = cfg.smtp.from;
SMTP_USERNAME = cfg.smtp.username;
DOMAIN = "https://${cfg.domain}";
SIGNUPS_ALLOWED = cfg.allow_signups;
ROCKET_PORT = builtins.toString cfg.port;
DATABASE_URL = "postgresql://"; # TODO: This should be set upstream if dbBackend is set to postgresql
ENABLE_WEBSOCKET = true;
ROCKET_ADDRESS = "127.0.0.1";
};
};
};
}

View File

@ -59,6 +59,8 @@ nav:
- reference/clanModules/borgbackup.md
- reference/clanModules/deltachat.md
- reference/clanModules/dyndns.md
- reference/clanModules/nginx.md
- reference/clanModules/vaultwarden.md
- reference/clanModules/ergochat.md
- reference/clanModules/garage.md
- reference/clanModules/golem-provider.md