Merge pull request 'clanModules: Add vaultwarden module. Add nginx module. Make matrix-synapse subdomain configurable' (#1942) from Qubasa/clan-core:main into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/1942
This commit is contained in:
@@ -22,7 +22,11 @@
|
|||||||
enableACME = lib.mkForce false;
|
enableACME = lib.mkForce false;
|
||||||
forceSSL = lib.mkForce false;
|
forceSSL = lib.mkForce false;
|
||||||
};
|
};
|
||||||
clan.matrix-synapse.domain = "clan.test";
|
security.acme.defaults.email = "admin@clan.test";
|
||||||
|
clan.matrix-synapse = {
|
||||||
|
server_tld = "clan.test";
|
||||||
|
app_domain = "matrix.clan.test";
|
||||||
|
};
|
||||||
clan.matrix-synapse.users.admin.admin = true;
|
clan.matrix-synapse.users.admin.admin = true;
|
||||||
clan.matrix-synapse.users.someuser = { };
|
clan.matrix-synapse.users.someuser = { };
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ in
|
|||||||
"dyndns"
|
"dyndns"
|
||||||
"enable"
|
"enable"
|
||||||
] "Just define clan.dyndns.settings to enable it")
|
] "Just define clan.dyndns.settings to enable it")
|
||||||
|
../nginx
|
||||||
];
|
];
|
||||||
|
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
@@ -158,11 +159,6 @@ in
|
|||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = lib.mkIf cfg.server.enable [
|
|
||||||
80
|
|
||||||
443
|
|
||||||
];
|
|
||||||
|
|
||||||
services.nginx = lib.mkIf cfg.server.enable {
|
services.nginx = lib.mkIf cfg.server.enable {
|
||||||
enable = true;
|
enable = true;
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
@@ -249,7 +245,6 @@ in
|
|||||||
PrivateDevices = "yes";
|
PrivateDevices = "yes";
|
||||||
ProtectKernelModules = "yes";
|
ProtectKernelModules = "yes";
|
||||||
ProtectKernelTunables = "yes";
|
ProtectKernelTunables = "yes";
|
||||||
|
|
||||||
WorkingDirectory = "/var/lib/${name}";
|
WorkingDirectory = "/var/lib/${name}";
|
||||||
ReadWritePaths = [
|
ReadWritePaths = [
|
||||||
"/proc/self"
|
"/proc/self"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
moonlight = ./moonlight;
|
moonlight = ./moonlight;
|
||||||
mumble = ./mumble;
|
mumble = ./mumble;
|
||||||
packages = ./packages;
|
packages = ./packages;
|
||||||
|
nginx = ./nginx;
|
||||||
postgresql = ./postgresql;
|
postgresql = ./postgresql;
|
||||||
root-password = ./root-password;
|
root-password = ./root-password;
|
||||||
single-disk = ./single-disk;
|
single-disk = ./single-disk;
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
thelounge = ./thelounge;
|
thelounge = ./thelounge;
|
||||||
trusted-nix-caches = ./trusted-nix-caches;
|
trusted-nix-caches = ./trusted-nix-caches;
|
||||||
user-password = ./user-password;
|
user-password = ./user-password;
|
||||||
|
vaultwarden = ./vaultwarden;
|
||||||
xfce = ./xfce;
|
xfce = ./xfce;
|
||||||
zerotier-static-peers = ./zerotier-static-peers;
|
zerotier-static-peers = ./zerotier-static-peers;
|
||||||
zt-tcp-relay = ./zt-tcp-relay;
|
zt-tcp-relay = ./zt-tcp-relay;
|
||||||
|
|||||||
@@ -6,26 +6,32 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.clan.matrix-synapse;
|
cfg = config.clan.matrix-synapse;
|
||||||
nginx-vhost = "matrix.${config.clan.matrix-synapse.domain}";
|
|
||||||
element-web =
|
element-web =
|
||||||
pkgs.runCommand "element-web-with-config" { nativeBuildInputs = [ pkgs.buildPackages.jq ]; }
|
pkgs.runCommand "element-web-with-config" { nativeBuildInputs = [ pkgs.buildPackages.jq ]; }
|
||||||
''
|
''
|
||||||
cp -r ${pkgs.element-web} $out
|
cp -r ${pkgs.element-web} $out
|
||||||
chmod -R u+w $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.app_domain}:443", "server_name": "${cfg.server_tld}" }' \
|
||||||
> $out/config.json < ${pkgs.element-web}/config.json
|
> $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.app_domain}.json
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
# FIXME: This was taken from upstream. Drop this when our patch is upstream
|
# FIXME: This was taken from upstream. Drop this when our patch is upstream
|
||||||
{
|
{
|
||||||
options.services.matrix-synapse.package = lib.mkOption { readOnly = false; };
|
options.services.matrix-synapse.package = lib.mkOption { readOnly = false; };
|
||||||
options.clan.matrix-synapse = {
|
options.clan.matrix-synapse = {
|
||||||
domain = lib.mkOption {
|
server_tld = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = "The domain name of the matrix server";
|
description = "The address that is suffixed after your username i.e @alice:example.com";
|
||||||
example = "example.com";
|
example = "example.com";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
app_domain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "The matrix server hostname also serves the element client";
|
||||||
|
example = "matrix.example.com";
|
||||||
|
};
|
||||||
|
|
||||||
users = lib.mkOption {
|
users = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrsOf (
|
type = lib.types.attrsOf (
|
||||||
@@ -61,14 +67,13 @@ in
|
|||||||
"matrix-synapse"
|
"matrix-synapse"
|
||||||
"enable"
|
"enable"
|
||||||
] "Importing the module will already enable the service.")
|
] "Importing the module will already enable the service.")
|
||||||
|
../nginx
|
||||||
../postgresql
|
|
||||||
];
|
];
|
||||||
config = {
|
config = {
|
||||||
services.matrix-synapse = {
|
services.matrix-synapse = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
server_name = cfg.domain;
|
server_name = cfg.server_tld;
|
||||||
database = {
|
database = {
|
||||||
args.user = "matrix-synapse";
|
args.user = "matrix-synapse";
|
||||||
args.database = "matrix-synapse";
|
args.database = "matrix-synapse";
|
||||||
@@ -169,18 +174,13 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
80
|
|
||||||
443
|
|
||||||
];
|
|
||||||
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
virtualHosts = {
|
virtualHosts = {
|
||||||
${cfg.domain} = {
|
"${cfg.server_tld}" = {
|
||||||
locations."= /.well-known/matrix/server".extraConfig = ''
|
locations."= /.well-known/matrix/server".extraConfig = ''
|
||||||
add_header Content-Type application/json;
|
add_header Content-Type application/json;
|
||||||
return 200 '${builtins.toJSON { "m.server" = "matrix.${cfg.domain}:443"; }}';
|
return 200 '${builtins.toJSON { "m.server" = "${cfg.app_domain}:443"; }}';
|
||||||
'';
|
'';
|
||||||
locations."= /.well-known/matrix/client".extraConfig = ''
|
locations."= /.well-known/matrix/client".extraConfig = ''
|
||||||
add_header Content-Type application/json;
|
add_header Content-Type application/json;
|
||||||
@@ -188,7 +188,7 @@ in
|
|||||||
return 200 '${
|
return 200 '${
|
||||||
builtins.toJSON {
|
builtins.toJSON {
|
||||||
"m.homeserver" = {
|
"m.homeserver" = {
|
||||||
"base_url" = "https://${nginx-vhost}";
|
"base_url" = "https://${cfg.app_domain}";
|
||||||
};
|
};
|
||||||
"m.identity_server" = {
|
"m.identity_server" = {
|
||||||
"base_url" = "https://vector.im";
|
"base_url" = "https://vector.im";
|
||||||
@@ -196,13 +196,15 @@ in
|
|||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
'';
|
'';
|
||||||
};
|
|
||||||
${nginx-vhost} = {
|
|
||||||
forceSSL = true;
|
forceSSL = true;
|
||||||
enableACME = true;
|
enableACME = true;
|
||||||
|
};
|
||||||
|
"${cfg.app_domain}" = {
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
locations."/".root = element-web;
|
||||||
locations."/_matrix".proxyPass = "http://localhost:8008";
|
locations."/_matrix".proxyPass = "http://localhost:8008";
|
||||||
locations."/_synapse".proxyPass = "http://localhost:8008";
|
locations."/_synapse".proxyPass = "http://localhost:8008";
|
||||||
locations."/".root = element-web;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
3
clanModules/nginx/README.md
Normal file
3
clanModules/nginx/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
description = "Good defaults for the nginx webserver"
|
||||||
|
---
|
||||||
70
clanModules/nginx/default.nix
Normal file
70
clanModules/nginx/default.nix
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
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
|
||||||
|
config.clan.core.facts.services."nginx-acme-email".public."nginx-acme-email".value;
|
||||||
|
|
||||||
|
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 = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
3
clanModules/vaultwarden/README.md
Normal file
3
clanModules/vaultwarden/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
description = "The server for the password manager bitwarden"
|
||||||
|
---
|
||||||
158
clanModules/vaultwarden/default.nix
Normal file
158
clanModules/vaultwarden/default.nix
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
cfg = config.clan.vaultwarden;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../postgresql
|
||||||
|
(lib.mkRemovedOptionModule [
|
||||||
|
"clan"
|
||||||
|
"vaultwarden"
|
||||||
|
"enable"
|
||||||
|
] "Importing the module will already enable the service.")
|
||||||
|
../nginx
|
||||||
|
];
|
||||||
|
|
||||||
|
options.clan.vaultwarden = {
|
||||||
|
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 = {
|
||||||
|
vaultwarden-admin = {
|
||||||
|
secret."vaultwarden-admin" = { };
|
||||||
|
secret."vaultwarden-admin-hash" = { };
|
||||||
|
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"/vaultwarden-admin
|
||||||
|
echo -n "$config" > "$secrets"/vaultwarden-admin-hash
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vaultwarden-smtp = {
|
||||||
|
secret."vaultwarden-smtp" = { };
|
||||||
|
generator.prompt = "${cfg.smtp.from} SMTP password";
|
||||||
|
generator.path = with pkgs; [ coreutils ];
|
||||||
|
generator.script = ''
|
||||||
|
config="
|
||||||
|
SMTP_PASSWORD=\"$prompt_value\"
|
||||||
|
"
|
||||||
|
echo -n "$config" > "$secrets"/vaultwarden-smtp
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services."vaultwarden" = {
|
||||||
|
serviceConfig = {
|
||||||
|
EnvironmentFile = [
|
||||||
|
config.clan.core.facts.services."vaultwarden-smtp".secret."vaultwarden-smtp".path
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.vaultwarden = {
|
||||||
|
enable = true;
|
||||||
|
dbBackend = "postgresql";
|
||||||
|
environmentFile =
|
||||||
|
config.clan.core.facts.services."vaultwarden-admin".secret."vaultwarden-admin-hash".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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -59,6 +59,8 @@ nav:
|
|||||||
- reference/clanModules/borgbackup.md
|
- reference/clanModules/borgbackup.md
|
||||||
- reference/clanModules/deltachat.md
|
- reference/clanModules/deltachat.md
|
||||||
- reference/clanModules/dyndns.md
|
- reference/clanModules/dyndns.md
|
||||||
|
- reference/clanModules/nginx.md
|
||||||
|
- reference/clanModules/vaultwarden.md
|
||||||
- reference/clanModules/ergochat.md
|
- reference/clanModules/ergochat.md
|
||||||
- reference/clanModules/garage.md
|
- reference/clanModules/garage.md
|
||||||
- reference/clanModules/golem-provider.md
|
- reference/clanModules/golem-provider.md
|
||||||
|
|||||||
Reference in New Issue
Block a user