add new server

This commit is contained in:
Grimmauld 2025-02-05 11:41:17 +01:00
parent e7a8f6c1f7
commit 94ba633f48
26 changed files with 1332 additions and 103 deletions

View file

@ -154,14 +154,13 @@
grimm-nixos-server-2 = customNixosSystem "x86_64-linux" {
modules = [
agenix.nixosModules.default
# agenix.nixosModules.default
# nixos-matrix-modules.nixosModules.default
# nixos-mailserver.nixosModules.default
nixos-mailserver.nixosModules.default
./configuration.nix
./specific/grimm-nixos-server-2/configuration.nix
# ./modules
./modules2
home-manager.nixosModules.home-manager
./hm
];

View file

@ -75,7 +75,10 @@ in
};
};
settings.log_config = ./matrix_synapse_log_config.yaml;
settings.enable_registration = false;
settings.enable_registration = true;
services.matrix-synapse.settings.enable_metrics = false;
settings.max_upload_size = "500M";
configureRedisLocally = true;
settings.redis.enabled = true;
@ -89,48 +92,6 @@ in
# "/var/lib/matrix-synapse/discord-registration.yaml"
];
};
# services.matrix-synapse-next = {
# enable = true;
#
# workers.federationSenders = 1;
# workers.federationReceivers = 1;
# workers.initialSyncers = 1;
# workers.normalSyncers = 1;
# workers.eventPersisters = 2;
# workers.useUserDirectoryWorker = true;
# mainLogConfig = ./matrix_synapse_log_config.yaml;
#
# enableNginx = true;
# enableSlidingSync = false;
#
# settings = {
# suppress_key_server_warning = true;
# server_name = domain;
# public_baseurl = "https://${domain}";
# enable_registration = true;
# registration_requires_token = true;
# registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
# # enable_registration_without_verification = true;
# # mainLogConfig = ./matrix_synapse_log_config.yaml;
#
# # registrations_require_3pid = [ "email" ];
#
# database = {
# name = "psycopg2";
# args = {
# host = "localhost";
# port = config.services.postgresql.settings.port;
# dbname = "synapse";
# user = "synapse";
# cp_min = 5;
# cp_max = 10;
# client_encoding = "auto";
# passfile = config.age.secrets.synapse_db_pass_prepared.path;
# };
# };
# };
# };
services.redis.servers."".enable = true;
age.secrets.synapse_db_pass = {
@ -194,61 +155,4 @@ in
locations."/_synapse/client".proxyPass = synapse_backend;
};
};
# services.nginx = {
# enable = true;
# virtualHosts."${domain}" = {
# forceSSL = true;
# enableACME = lib.mkForce false; # use the cert above, not some weird one that matrix-synapse module supplies
# useACMEHost = domain;
# locations."/.well-known/matrix/server" = {
# return = "200 '{\"m.server\":\"${vhosts.matrix_host.host}:443\"}'";
# extraConfig = ''
# default_type application/json;
# add_header Access-Control-Allow-Origin *;
# add_header Accept-Ranges bytes;'';
# };
# locations."/.well-known/matrix/client" = {
# return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${vhosts.matrix_host.host}\"}}'";
# extraConfig = ''
# add_header Access-Control-Allow-Origin *;
# default_type application/json;
# '';
# };
# locations."/_matrix" = {
# proxyPass = "http://$synapse_backend";
# extraConfig = ''
# add_header X-debug-backend $synapse_backend;
# add_header X-debug-group $synapse_uri_group;
# client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
# proxy_read_timeout 10m;
# '';
# };
# locations."/_synapse/client" = {
# proxyPass = "http://$synapse_backend";
# };
# locations."~ ^/_matrix/client/(r0|v3)/sync$" = {
# proxyPass = "http://$synapse_backend";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# locations."~ ^/_matrix/client/(api/v1|r0|v3)/initialSync$" = {
# proxyPass = "http://synapse_worker_initial_sync";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# locations."~ ^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$" = {
# proxyPass = "http://synapse_worker_initial_sync";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# # locations."/.well-known/matrix" = {
# proxyPass = "http://$synapse_backend";
# };
# };
# };
# networking.firewall.allowedTCPPorts = [ 8448 8008 ];
}

131
modules2/auth.nix Normal file
View file

@ -0,0 +1,131 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (config.serverConfig) vhosts;
inherit (config.networking) domain;
inherit (lib) remove concatStringsSep;
in
{
age.secrets.openldap_admin =
let
inherit (config.services.openldap) user group;
in
{
file = ../secrets/openldap_admin.age;
inherit group;
owner = user;
mode = "0444";
};
age.secrets.keycloak_db_pass = {
file = ../secrets/keycloak_db_pass.age;
group = "keycloak";
owner = "keycloak";
mode = "0444";
};
users.users.keycloak = {
isSystemUser = true;
group = "keycloak";
};
users.groups.keycloak = { };
services.postgresql =
let
inherit (config.services.keycloak.database) name username;
in
{
enable = true;
ensureDatabases = [ name ];
ensureUsers = [
{
name = username;
passFile = config.age.secrets.keycloak_db_pass.path;
ensureDBOwnership = true;
}
];
};
services.keycloak = {
enable = true;
database = {
type = "postgresql";
createLocally = false;
username = "keycloak";
passwordFile = config.age.secrets.keycloak_db_pass.path;
};
settings = {
hostname = vhosts.auth_host.host;
http-host = "127.0.0.1";
http-port = vhosts.auth_host.port;
proxy = "edge"; # passthrough";
};
};
services.openldap =
let
localDc = concatStringsSep "," (map (s: "dc=${s}") (remove [ ] (builtins.split "\\." domain)));
in
{
enable = true;
urlList = [
"ldap:///"
"ldapi:///"
];
# declarativeContents = {
# "${localDc}" = import ./ldapConf.nix { inherit localDc; };
# };
settings = {
attrs = {
olcLogLevel = "conns config";
};
children = {
"cn=schema".includes = [
"${pkgs.openldap}/etc/schema/core.ldif"
"${pkgs.openldap}/etc/schema/cosine.ldif"
"${pkgs.openldap}/etc/schema/inetorgperson.ldif"
];
"olcDatabase={1}mdb".attrs = {
objectClass = [
"olcDatabaseConfig"
"olcMdbConfig"
];
olcDatabase = "{1}mdb";
olcDbDirectory = "/var/lib/openldap/data";
olcSuffix = localDc;
olcRootDN = "cn=admin,${localDc}";
# olcRootPW.path = config.age.secrets.openldap_admin.path;
olcRootPW = "{SSHA}D1U1E6Xz07DGYLjke1YcCsVF6ddSLyLr";
olcAccess = [
# custom access rules for userPassword attributes
''
{0}to attrs=userPassword
by self write
by anonymous auth
by * none''
# allow read on anything else
''
{1}to *
by * read''
];
};
};
};
};
}

231
modules2/default.nix Normal file
View file

@ -0,0 +1,231 @@
{ lib, config, ... }:
let
inherit (config.networking) domain;
root_email = "contact@${domain}";
in
{
imports = [
./wireguard.nix
./matrix_legacy.nix
# ./puffer.nix
./gitea.nix
# ./grafana.nix
./nextcloud.nix
# ./prometheus.nix
./fail2ban.nix
./email.nix
./mastodon.nix
# ./nix_cache.nix
./hedgedoc.nix
];
options.serverConfig =
let
inherit (lib) mkOption types mkEnableOption;
in
{
ports = mkOption {
type = types.attrsOf (
types.submodule (
{ ... }:
{
options = {
port = mkOption {
type = types.int;
description = "port to define";
};
open = mkEnableOption "whether to open the port" // {
default = true;
};
};
}
)
);
default = { };
description = "ports associated with services";
};
vhosts = mkOption {
type = types.attrsOf (
types.submodule (
{ config, ... }:
let
type_lookup = {
proxy = {
locations."/".proxyPass = "http://127.0.0.1:${builtins.toString config.port}";
};
redirect = {
locations."/".return = "307 https://${domain}";
};
custom = { };
none = { };
};
in
{
options = {
port = mkOption {
type = types.int;
default = 80;
description = "port to redirect to this vhost";
};
host = mkOption {
type = types.nonEmptyStr;
description = "name if the vhost";
};
accessType = mkOption {
type = types.enum (lib.attrNames type_lookup);
default = "none";
description = "nginx template to use";
};
extraNginx = mkOption {
type = types.attrs;
default = type_lookup.${config.accessType};
description = "location definition for nginx";
};
};
}
)
);
default = { };
description = "vhosts associated with services";
};
};
config = {
networking.firewall.allowedTCPPorts = [
80
443
] ++ (lib.mapAttrsToList (n: v: v.port) (lib.filterAttrs (n: v: v.open) config.serverConfig.ports));
# ++ (lib.mapAttrsToList (n: v: v.port) (lib.filterAttrs (n: v: !v.disableWebAccess) config.serverConfig.vhosts));
services.nginx.virtualHosts =
{
"${domain}" = {
forceSSL = true;
enableACME = lib.mkForce false; # use the correct cert, not some weird one that matrix-synapse module supplies
useACMEHost = domain;
locations."/" = {
root = "/var/www/${domain}";
};
};
}
// (lib.concatMapAttrs (_: host: {
"${host.host}" = {
serverName = host.host;
forceSSL = true;
useACMEHost = domain;
enableACME = lib.mkForce false;
} // host.extraNginx;
}) (lib.filterAttrs (n: v: v.accessType != "none") config.serverConfig.vhosts));
serverConfig = {
ports = {
# puffer_sftp_port.port = 5657;
gitea_ssh_port.port = 2222;
# node_exporter = {
# port = 9002;
# open = false;
# };
# discord_matrix_bridge_port = {
# port = 9005;
# open = false;
# };
redis_nextcloud_port = {
port = 6379;
open = false;
};
# open_ldap_port = {
# port = 389;
# open = false;
# };
};
vhosts = {
# puffer_host = {
# port = 8080;
# host = "puffer.${domain}";
# accessType = "proxy";
# };
# ooye = {
# port = 6693;
# host = "ooye.${domain}";
# accessType = "proxy";
# };
hedgedoc_host = {
port = 8048;
host = "hedgedoc.${domain}";
accessType = "proxy";
};
# tlemap_host = {
# port = 8100;
# host = "tlemap.${domain}";
# accessType = "proxy";
# };
mail_host = {
host = "mail.${domain}";
accessType = "redirect";
};
gitea_host = {
host = "git.${domain}";
port = 8081;
accessType = "proxy";
};
matrix_host = {
# accessType = "redirect";
host = "matrix.${domain}";
# port = 8008;
};
prometheus_host = {
host = "prometheus.${domain}";
port = 9090;
accessType = "redirect";
};
grafana_host = {
host = "grafana.${domain}";
accessType = "proxy";
port = 8082;
};
nextcloud_host = rec {
host = "cloud.${domain}";
port = 8083;
accessType = "custom";
extraNginx.serverName = host;
};
mastodon_host = {
host = "mastodon.${domain}";
};
# nix_cache_host = {
# host = "nixcache.${domain}";
# port = 5000;
# accessType = "proxy";
# };
# auth_host = {
# host = "auth.${domain}";
# port = 38080;
# accessType = "proxy";
# };
};
};
security.acme = {
acceptTerms = true;
defaults.email = root_email;
certs."${domain}" = {
webroot = "/var/lib/acme/acme-challenge/";
extraDomainNames = lib.mapAttrsToList (n: v: v.host) config.serverConfig.vhosts;
};
};
services.nginx = {
# package = pkgs.nginxStable.override { openssl = pkgs.libressl; };
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
};
users.users.nginx.extraGroups = [ "acme" ];
};
}

View file

@ -0,0 +1,36 @@
{ config, pkgs, ... }:
let
inherit (config.serverConfig) ports;
in
{
age.secrets.matrix_discord_bridge_token.file = ../secrets/matrix_discord_bridge_token.age;
services.matrix-synapse-next.settings.app_service_config_files = [
"/var/lib/matrix-synapse/discord-registration.yaml"
];
services.matrix-appservice-discord = {
enable = false;
settings = {
auth = {
usePrivilegedIntents = true; # typing status and stuff
};
bridge = {
enableSelfServiceBridging = true;
domain = config.services.matrix-synapse.settings.server_name;
homeserverUrl = config.services.matrix-synapse.settings.public_baseurl;
disablePresence = true;
disableTypingNotifications = true;
};
inactiveAfterDays = 14;
# logging.console = "silly";
};
serviceDependencies = [ "matrix-synapse.target" ];
port = ports.discord_matrix_bridge_port.port;
localpart = "_discord_";
package = pkgs.matrix-appservice-discord;
environmentFile = config.age.secrets.matrix_discord_bridge_token.path;
};
environment.systemPackages = with pkgs; [ matrix-appservice-discord ];
}

34
modules2/email.nix Normal file
View file

@ -0,0 +1,34 @@
{ config, ... }:
let
inherit (config.serverConfig) vhosts;
inherit (config.networking) domain;
in
{
# services.dovecot2.sieve.extensions = [ "fileinto" ]; # sives break without this for some reason
mailserver = {
enable = true;
fqdn = vhosts.mail_host.host;
domains = [ domain ];
# A list of all login accounts. To create the password hashes, use
# nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt'
loginAccounts = {
"contact@${domain}" = {
hashedPasswordFile = ./mailpass/contact;
aliases = [ "kontakt@${domain}" ];
};
"admin@${domain}" = {
hashedPasswordFile = ./mailpass/admin;
};
"grimmauld@${domain}" = {
hashedPasswordFile = ./mailpass/grimmauld;
};
};
# Use Let's Encrypt certificates. Note that this needs to set up a stripped
# down nginx and opens port 80.
certificateScheme = "manual";
certificateFile = "/var/lib/acme/${domain}/fullchain.pem";
keyFile = "/var/lib/acme/${domain}/key.pem";
};
}

43
modules2/factorio.nix Normal file
View file

@ -0,0 +1,43 @@
{
pkgs,
config,
lib,
...
}:
{
networking.firewall.allowedTCPPorts = [
34197
34198
];
networking.firewall.allowedUDPPorts = [
34198
34197
];
services.prometheus.scrapeConfigs = [
{
job_name = "clusterio-trangar";
static_configs = [ { targets = [ "trang.ar:8080" ]; } ];
}
];
systemd.services.clusterio-trangar = {
description = "clusterio pulling its config from trang.ar";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig.Type = "simple";
# serviceConfig.PassEnvironment = "NIX_PATH";
#serviceConfig.User = "grimmauld";
#serviceConfig.Group = "users";
serviceConfig.WorkingDirectory = "/home/grimmauld/clusterio";
script = ''
export NIXPKGS_ALLOW_UNFREE=1
${lib.getExe' config.nix.package "nix-shell"} -I nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos /home/grimmauld/clusterio-nonfhs/shell.nix --run "cd /home/grimmauld/clusterio-nonfhs/install && nice -19 bash run-host.sh"
# /home/grimmauld/clusterio/shell.nix
'';
wantedBy = [ "multi-user.target" ]; # starts after login
enable = true;
};
}

22
modules2/fail2ban.nix Normal file
View file

@ -0,0 +1,22 @@
{ ... }:
{
services.fail2ban = {
enable = true;
maxretry = 5;
ignoreIP = [
# Whitelist some subnets
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
"matrix.org"
"app.element.io" # don't ratelimit matrix users
];
bantime = "1h"; # Ban IPs for 1h at first.
bantime-increment = {
enable = true; # Enable increment of bantime after each violation
multipliers = "1 2 4 8 16 32 64 128 256";
maxtime = "48h"; # Do not ban for more than 1 week
overalljails = true; # Calculate the bantime based on all the violations
};
};
}

40
modules2/gitea.nix Normal file
View file

@ -0,0 +1,40 @@
{ config, pkgs, ... }:
let
inherit (config.networking) domain;
inherit (config.serverConfig) ports vhosts;
in
{
services.forgejo = {
enable = true;
package = pkgs.forgejo;
database = {
user = "gitea";
path = "${config.services.forgejo.stateDir}/data/gitea.db";
name = "gitea";
};
dump.enable = true;
settings = {
service.DISABLE_REGISTRATION = true;
server = {
HTTP_PORT = vhosts.gitea_host.port;
ROOT_URL = "https://${vhosts.gitea_host.host}/";
DISABLE_SSH = false;
SSH_DOMAIN = domain;
START_SSH_SERVER = true;
BUILTIN_SSH_SERVER_USER = "git";
SSH_PORT = ports.gitea_ssh_port.port;
# SSH_LISTEN_HOST="::"; # fixme?
# SSH_AUTHORIZED_PRINCIPALS_ALLOW="username";
};
# log.LEVEL = "Debug";
"ssh.minimum_key_sizes".RSA = 2048;
"git.timeout".MIGRATE = 6000;
};
lfs.enable = true;
};
environment.systemPackages = with pkgs; [ gitea ];
}

29
modules2/grafana.nix Normal file
View file

@ -0,0 +1,29 @@
{ config, ... }:
let
inherit (config.serverConfig) ports vhosts;
inherit (config.networking) domain;
in
{
age.secrets.grafana_admin_pass = {
file = ../secrets/grafana_admin_pass.age;
owner = "grafana";
group = "grafana";
mode = "0600";
};
services.grafana = {
enable = true;
settings = {
security = {
admin_user = "admin";
admin_email = "admin@${domain}";
admin_password = "$__file{${config.age.secrets.grafana_admin_pass.path}}";
};
server = {
domain = vhosts.grafana_host.host;
root_url = "https://${vhosts.grafana_host.host}";
http_port = vhosts.grafana_host.port;
};
};
};
}

18
modules2/hedgedoc.nix Normal file
View file

@ -0,0 +1,18 @@
{ config, ... }:
let
inherit (config.serverConfig) vhosts;
in
{
services.hedgedoc = {
enable = true;
settings = {
domain = vhosts.hedgedoc_host.host;
inherit (vhosts.hedgedoc_host) port;
host = "127.0.0.1";
protocolUseSSL = true;
allowEmailRegister = false; # no registrations for now
allowAnonymousEdits = true; # anonymous can edit select files
allowAnonymous = false; # anonymous can't actually create notes
};
};
}

1
modules2/mailpass/admin Normal file
View file

@ -0,0 +1 @@
$2b$05$9E2phVa/06fZW3daV3CeYuLTCLcBBDY7xF5TOpeHdCBGU5yNemBgy

View file

@ -0,0 +1 @@
$2b$05$WsEwEXHa3kzDdMJdluirn.ExpK5BGJENEf3iH2AAjW6IFUPSpBWVa

View file

@ -0,0 +1 @@
$2b$05$nmY9QnYyOhhhXn3OOalxkeWWLZtlaxD2vGwr0f6gtHNUz5EfZXvsa

17
modules2/mastodon.nix Normal file
View file

@ -0,0 +1,17 @@
{ config, ... }:
let
inherit (config.serverConfig) vhosts;
inherit (config.networking) domain;
in
{
services.mastodon = {
enable = true;
localDomain = vhosts.mastodon_host.host;
streamingProcesses = 7;
configureNginx = true;
smtp = {
fromAddress = "noreply@${domain}";
};
extraConfig.SINGLE_USER_MODE = "true";
};
}

146
modules2/matrix.nix Normal file
View file

@ -0,0 +1,146 @@
{
lib,
config,
pkgs,
...
}:
let
inherit (config.networking) domain;
inherit (config.serverConfig) vhosts;
in
{
services.postgresql = {
enable = true;
ensureDatabases = [ "synapse" ];
ensureUsers = [
{
name = "synapse";
passFile = config.age.secrets.synapse_db_pass.path;
ensureDBOwnership = true;
}
];
};
services.matrix-synapse-next = {
enable = true;
workers.federationSenders = 1;
workers.federationReceivers = 1;
workers.initialSyncers = 1;
workers.normalSyncers = 1;
workers.eventPersisters = 1;
workers.useUserDirectoryWorker = true;
mainLogConfig = ./matrix_synapse_log_config.yaml;
enableNginx = true;
enableSlidingSync = false;
settings = {
suppress_key_server_warning = true;
server_name = domain;
public_baseurl = "https://${vhosts.matrix_host.host}";
enable_registration = true;
registration_requires_token = true;
registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
# enable_registration_without_verification = true;
# mainLogConfig = ./matrix_synapse_log_config.yaml;
# registrations_require_3pid = [ "email" ];
database = {
name = "psycopg2";
args = {
host = "localhost";
port = config.services.postgresql.settings.port;
dbname = "synapse";
user = "synapse";
cp_min = 5;
cp_max = 10;
client_encoding = "auto";
passfile = config.age.secrets.synapse_db_pass_prepared.path;
};
};
};
};
services.redis.servers."".enable = true;
age.secrets.synapse_db_pass = {
file = ../secrets/synapse_db_pass.age;
owner = "postgres";
group = "postgres";
};
age.secrets.synapse_db_pass_prepared = {
file = ../secrets/synapse_db_pass_prepared.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0600";
};
age.secrets.synapse_registration_shared_secret = {
file = ../secrets/synapse_registration_shared_secret.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0600";
};
environment.systemPackages = with pkgs; [
matrix-synapse-tools.synadm
matrix-synapse
];
services.nginx = {
enable = true;
virtualHosts."${domain}" = {
forceSSL = true;
enableACME = lib.mkForce false; # use the cert above, not some weird one that matrix-synapse module supplies
useACMEHost = domain;
locations."/.well-known/matrix/server" = {
return = "200 '{\"m.server\":\"${vhosts.matrix_host.host}:443\"}'";
extraConfig = ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
add_header Accept-Ranges bytes;'';
};
locations."/.well-known/matrix/client" = {
return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${vhosts.matrix_host.host}\"}}'";
extraConfig = ''
add_header Access-Control-Allow-Origin *;
default_type application/json;
'';
};
locations."/_matrix" = {
proxyPass = "http://$synapse_backend";
extraConfig = ''
add_header X-debug-backend $synapse_backend;
add_header X-debug-group $synapse_uri_group;
client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
proxy_read_timeout 10m;
'';
};
locations."~ ^/_matrix/client/(r0|v3)/sync$" = {
proxyPass = "http://$synapse_backend";
extraConfig = ''
proxy_read_timeout 1h;
'';
};
locations."~ ^/_matrix/client/(api/v1|r0|v3)/initialSync$" = {
proxyPass = "http://synapse_worker_initial_sync";
extraConfig = ''
proxy_read_timeout 1h;
'';
};
locations."~ ^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$" = {
proxyPass = "http://synapse_worker_initial_sync";
extraConfig = ''
proxy_read_timeout 1h;
'';
};
locations."/_synapse/client" = {
proxyPass = "http://$synapse_backend";
};
locations."/.well-known/matrix" = {
proxyPass = "http://$synapse_backend";
};
};
};
# networking.firewall.allowedTCPPorts = [ 8448 8008 ];
}

255
modules2/matrix_legacy.nix Normal file
View file

@ -0,0 +1,255 @@
{
lib,
config,
pkgs,
...
}:
let
inherit (config.networking) domain;
inherit (config.serverConfig) vhosts;
fqdn = vhosts.matrix_host.host;
base_url = "https://${fqdn}";
clientConfig."m.homeserver" = {
inherit base_url;
}; # = "https://${vhosts.matrix_host.host}";
serverConfig."m.server" = "${vhosts.matrix_host.host}:443";
mkWellKnown = data: ''
default_type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '${builtins.toJSON data}';
'';
synapse_backend = "http://[::1]:8008";
in
{
services.postgresql = {
enable = true;
ensureDatabases = [ "synapse" ];
ensureUsers = [
{
name = "synapse";
passFile = config.age.secrets.synapse_db_pass.path;
ensureDBOwnership = true;
}
];
};
services.matrix-synapse = {
enable = true;
settings.server_name = domain;
# The public base URL value must match the `base_url` value set in `clientConfig` above.
# The default value here is based on `server_name`, so if your `server_name` is different
# from the value of `fqdn` above, you will likely run into some mismatched domain names
# in client applications.
settings.public_baseurl = "https://${vhosts.matrix_host.host}";
settings.listeners = [
{
port = 8008;
bind_addresses = [ "::1" ];
type = "http";
tls = false;
x_forwarded = true;
resources = [
{
names = [
"client"
"federation"
];
compress = true;
}
];
}
];
settings.database = {
name = "psycopg2";
args = {
user = "synapse";
database = "synapse";
port = config.services.postgresql.settings.port;
cp_max = 10;
cp_min = 5;
client_encoding = "auto";
passfile = config.age.secrets.synapse_db_pass_prepared.path;
};
};
settings.log_config = ./matrix_synapse_log_config.yaml;
settings.enable_registration = true;
settings.registration_requires_token = true;
configureRedisLocally = true;
settings.redis.enabled = true;
settings.app_service_config_files = [
# The registration file is automatically generated after starting the
# appservice for the first time.
# cp /var/lib/mautrix-telegram/telegram-registration.yaml \
# /var/lib/matrix-synapse/
# chown matrix-synapse:matrix-synapse \
# /var/lib/matrix-synapse/telegram-registration.yaml
# "/var/lib/matrix-synapse/discord-registration.yaml"
];
};
# services.matrix-synapse-next = {
# enable = true;
#
# workers.federationSenders = 1;
# workers.federationReceivers = 1;
# workers.initialSyncers = 1;
# workers.normalSyncers = 1;
# workers.eventPersisters = 2;
# workers.useUserDirectoryWorker = true;
# mainLogConfig = ./matrix_synapse_log_config.yaml;
#
# enableNginx = true;
# enableSlidingSync = false;
#
# settings = {
# suppress_key_server_warning = true;
# server_name = domain;
# public_baseurl = "https://${domain}";
# enable_registration = true;
# registration_requires_token = true;
# registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
# # enable_registration_without_verification = true;
# # mainLogConfig = ./matrix_synapse_log_config.yaml;
#
# # registrations_require_3pid = [ "email" ];
#
# database = {
# name = "psycopg2";
# args = {
# host = "localhost";
# port = config.services.postgresql.settings.port;
# dbname = "synapse";
# user = "synapse";
# cp_min = 5;
# cp_max = 10;
# client_encoding = "auto";
# passfile = config.age.secrets.synapse_db_pass_prepared.path;
# };
# };
# };
# };
services.redis.servers."".enable = true;
age.secrets.synapse_db_pass = {
file = ../secrets/synapse_db_pass.age;
owner = "postgres";
group = "postgres";
};
age.secrets.synapse_db_pass_prepared = {
file = ../secrets/synapse_db_pass_prepared.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0600";
};
age.secrets.synapse_registration_shared_secret = {
file = ../secrets/synapse_registration_shared_secret.age;
owner = "matrix-synapse";
group = "matrix-synapse";
mode = "0600";
};
environment.systemPackages = with pkgs; [
matrix-synapse-tools.synadm
matrix-synapse
];
services.nginx = {
enable = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
virtualHosts."${domain}" = {
enableACME = true;
forceSSL = true;
# This section is not needed if the server_name of matrix-synapse is equal to
# the domain (i.e. example.org from @foo:example.org) and the federation port
# is 8448.
# Further reference can be found in the docs about delegation under
# https://element-hq.github.io/synapse/latest/delegate.html
locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
# This is usually needed for homeserver discovery (from e.g. other Matrix clients).
# Further reference can be found in the upstream docs at
# https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient
locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
};
virtualHosts."${fqdn}" = {
enableACME = true;
forceSSL = true;
locations."/_matrix" = {
proxyPass = synapse_backend;
#extraConfig = ''
# add_header X-debug-backend ${synapse_backend};
# add_header X-debug-group $synapse_uri_group;
# client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
# proxy_read_timeout 10m;
#'';
};
locations."/_synapse/client".proxyPass = synapse_backend;
};
};
# services.nginx = {
# enable = true;
# virtualHosts."${domain}" = {
# forceSSL = true;
# enableACME = lib.mkForce false; # use the cert above, not some weird one that matrix-synapse module supplies
# useACMEHost = domain;
# locations."/.well-known/matrix/server" = {
# return = "200 '{\"m.server\":\"${vhosts.matrix_host.host}:443\"}'";
# extraConfig = ''
# default_type application/json;
# add_header Access-Control-Allow-Origin *;
# add_header Accept-Ranges bytes;'';
# };
# locations."/.well-known/matrix/client" = {
# return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${vhosts.matrix_host.host}\"}}'";
# extraConfig = ''
# add_header Access-Control-Allow-Origin *;
# default_type application/json;
# '';
# };
# locations."/_matrix" = {
# proxyPass = "http://$synapse_backend";
# extraConfig = ''
# add_header X-debug-backend $synapse_backend;
# add_header X-debug-group $synapse_uri_group;
# client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
# proxy_read_timeout 10m;
# '';
# };
# locations."/_synapse/client" = {
# proxyPass = "http://$synapse_backend";
# };
# locations."~ ^/_matrix/client/(r0|v3)/sync$" = {
# proxyPass = "http://$synapse_backend";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# locations."~ ^/_matrix/client/(api/v1|r0|v3)/initialSync$" = {
# proxyPass = "http://synapse_worker_initial_sync";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# locations."~ ^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$" = {
# proxyPass = "http://synapse_worker_initial_sync";
# extraConfig = ''
# proxy_read_timeout 1h;
# '';
# };
# # locations."/.well-known/matrix" = {
# proxyPass = "http://$synapse_backend";
# };
# };
# };
# networking.firewall.allowedTCPPorts = [ 8448 8008 ];
}

View file

@ -0,0 +1,25 @@
version: 1
# In systemd's journal, loglevel is implicitly stored, so let's omit it
# from the message text.
formatters:
journal_fmt:
format: '%(name)s: [%(request)s] %(message)s'
filters:
context:
(): synapse.util.logcontext.LoggingContextFilter
request: ""
handlers:
journal:
class: systemd.journal.JournalHandler
formatter: journal_fmt
filters: [context]
SYSLOG_IDENTIFIER: synapse
root:
level: WARNING
handlers: [journal]
disable_existing_loggers: False

69
modules2/mjolnir.nix Normal file
View file

@ -0,0 +1,69 @@
{ ... }:
let
in
{
age.secrets = {
matrix_mjolnir_pass = {
file = ../secrets/matrix_mjolnir_pass.age;
owner = "mjolnir";
group = "mjolnir";
mode = "0600";
};
matrix_mjolnir_tle_pass = {
file = ../secrets/matrix_mjolnir_tle_pass.age;
owner = "mjolnir";
group = "mjolnir";
mode = "0777"; # not ideal, but containers are weird
};
};
# global mjolnir
services.mjolnir = {
enable = true;
homeserverUrl = config.services.matrix-synapse-next.settings.public_baseurl;
protectedRooms = [ "https://matrix.to/#/!zDkrFrfuMIKbqYFbFv:grimmauld.de" ];
managementRoom = "!kgfXXqEYHGgToIwhMP:grimmauld.de";
pantalaimon = {
enable = true;
username = "mjolnir";
options = {
homeserver = config.services.matrix-synapse-next.settings.public_baseurl;
};
passwordFile = config.age.secrets.matrix_mjolnir_pass.path;
};
};
services.logrotate.checkConfig = false; # needed or this explodes
containers.mjolnirtle =
let
baseurl = config.services.matrix-synapse-next.settings.public_baseurl;
pass_file = config.age.secrets.matrix_mjolnir_tle_pass.path;
in
{
privateNetwork = false; # don't want nat
autoStart = true;
bindMounts."${pass_file}".isReadOnly = true;
config =
{ config, ... }:
{
system.stateVersion = "unstable";
# tle mjolnir
services.logrotate.checkConfig = false;
services.mjolnir = {
enable = true;
homeserverUrl = baseurl;
protectedRooms = [ "https://matrix.to/#/!BgDBnHgMgilMMnPMyp:grimmauld.de" ];
managementRoom = "!NQedmlMeoQErGgAwxm:grimmauld.de";
pantalaimon = {
enable = true;
username = "mjolnir_tle";
options = {
homeserver = baseurl;
};
passwordFile = pass_file;
};
};
};
};
}

88
modules2/nextcloud.nix Normal file
View file

@ -0,0 +1,88 @@
{ pkgs, config, ... }:
let
inherit (config.serverConfig) ports vhosts;
in
{
services.postgresql = {
enable = true;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{
name = "nextcloud";
passFile = config.age.secrets.nextcloud_admin_pass.path;
ensureDBOwnership = true;
}
];
};
age.secrets = {
nextcloud_admin_pass = {
file = ../secrets/nextcloud_admin_pass.age;
owner = "nextcloud";
group = "nextcloud";
mode = "0600";
};
nextcloud_server_key = {
file = ../secrets/nextcloud_server_key.age;
owner = "nextcloud";
group = "nextcloud";
mode = "0600";
};
nextcloud_db_key = {
file = ../secrets/nextcloud_db_pass.age;
owner = "nextcloud";
group = "nextcloud";
mode = "0600";
};
};
services.redis.servers.nextcloud = {
enable = true;
bind = "::1";
port = ports.redis_nextcloud_port.port;
};
systemd.services.nextcloud-setup.serviceConfig.ExecStartPost =
pkgs.writeScript "nextcloud-redis.sh" ''
#!${pkgs.runtimeShell}
nextcloud-occ config:system:set redis 'host' --value '::1' --type string
nextcloud-occ config:system:set redis '${builtins.toString config.services.redis.servers.nextcloud.port}' --value 6379 --type integer
nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\Redis' --type string
nextcloud-occ config:system:set memcache.locking --value '\OC\Memcache\Redis' --type string
'';
services.nextcloud = {
enable = true;
https = true;
hostName = vhosts.nextcloud_host.host;
package = pkgs.nextcloud30;
caching.redis = true;
extraApps = {
inherit (config.services.nextcloud.package.packages.apps) calendar tasks;
};
config = {
adminpassFile = config.age.secrets.nextcloud_admin_pass.path;
dbuser = "nextcloud";
dbhost = "localhost:${builtins.toString config.services.postgresql.settings.port}";
dbtype = "pgsql";
dbpassFile = config.age.secrets.nextcloud_db_key.path;
};
settings = {
overwriteProtocol = "https";
# config_is_read_only = true;
defaultPhoneRegion = "DE";
filelocking.enabled = true;
sseCKeyFile = config.age.secrets.nextcloud_server_key;
redis = {
host = "localhost";
port = config.services.redis.servers.nextcloud.port;
timeout = 0.0;
};
};
phpOptions = {
"opcache.interned_strings_buffer" = "12";
};
};
}

11
modules2/nix_cache.nix Normal file
View file

@ -0,0 +1,11 @@
{ config, ... }:
let
inherit (config.serverConfig) vhosts;
in
{
services.harmonia = {
enable = true;
signKeyPaths = [ "/var/cache-priv-key.pem" ];
settings.bind = "[::]:${builtins.toString vhosts.nix_cache_host.port}";
};
}

View file

@ -0,0 +1,7 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [ ooye ];
services.matrix-synapse-next.settings.app_service_config_files = [ ./registration.yaml ];
}

47
modules2/prometheus.nix Normal file
View file

@ -0,0 +1,47 @@
{ config, lib, ... }:
let
inherit (config.serverConfig) ports vhosts;
in
{
services.prometheus = {
enable = true;
port = vhosts.prometheus_host.port;
globalConfig.scrape_interval = "15s";
scrapeConfigs = [
{
job_name = "chrysalis";
static_configs = [
{
targets =
let
inherit (lib)
filter
isAttrs
attrValues
filterAttrs
;
in
map (v: "127.0.0.1:${builtins.toString v.port}") (
filter (v: (isAttrs v) && v.enable) (
attrValues (filterAttrs (n: v: n != "minio" && n != "tor") config.services.prometheus.exporters)
)
);
}
];
}
];
exporters = {
# nginx.enable = true;
redis.enable = true;
domain.enable = true;
postgres.enable = true;
nginxlog.enable = true;
jitsi.enable = true;
node = {
enable = true;
enabledCollectors = [ "systemd" ];
port = ports.node_exporter.port;
};
};
};
}

30
modules2/puffer.nix Normal file
View file

@ -0,0 +1,30 @@
{ config, pkgs, ... }:
let
inherit (config.serverConfig) ports vhosts;
in
{
services.pufferpanel = {
enable = true;
environment = {
PUFFER_WEB_HOST = ":${builtins.toString vhosts.puffer_host.port}";
PUFFER_DAEMON_SFTP_HOST = ":${builtins.toString ports.puffer_sftp_port.port}";
};
extraGroups = [ "docker" ];
};
networking.firewall.allowedTCPPorts = [
25565
25566
25567
25568
7270
];
# virtualisation.podman.enable = true;
virtualisation.docker.enable = true;
environment.systemPackages = with pkgs; [
pufferpanel
(writeShellScriptBin "pufferpanel-nix" "pufferpanel --workDir /var/lib/pufferpanel $@")
];
}

42
modules2/wireguard.nix Normal file
View file

@ -0,0 +1,42 @@
{ pkgs, ... }:
{
# enable NAT
networking.nat.enable = true;
networking.nat.externalInterface = "eth0";
networking.nat.internalInterfaces = [ "wg0" ];
networking.firewall = {
allowedUDPPorts = [ 51820 ];
};
networking.wireguard.interfaces = {
# "wg0" is the network interface name. You can name the interface
# arbitrarily.}
wg0 = {
privateKeyFile = "/home/grimmauld/wireguard.priv";
# Determines the IP address and subnet of the server's end of the tunnel
# interface.
ips = [ "10.100.0.1/24" ];
# The port that WireGuard listens to. Must be accessible by the client.
listenPort = 51820;
# This allows the wireguard server to route your traffic to the internet and
# hence be like a VPN For this to work you have to set the dnsserver IP of
# your router (or dnsserver of choice) in your clients
postSetup = ''
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o ens18 -j MASQUERADE
'';
# This undoes the above command
postShutdown = ''
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o ens18 -j MASQUERADE
'';
generatePrivateKeyFile = true;
peers = [
{
publicKey = "2aANdnPYtf78iXfwNVAtYjIlE5k/yDWvbdXZ2jw0hXk=";
allowedIPs = [ "10.100.0.2/32" ];
}
];
};
};
environment.systemPackages = with pkgs; [ wireguard-tools ];
}

View file

@ -0,0 +1,2 @@
{