Finish migration to NixOS modules

This commit is contained in:
Paul-Henri Froidmont 2024-03-26 23:37:53 +01:00
parent aef5eabce5
commit d944e36197
Signed by: phfroidmont
GPG key ID: BE948AFD7E7873BE
21 changed files with 1071 additions and 1151 deletions

View file

@ -1,20 +1,14 @@
{ config, lib, ... }: { config, lib, ... }:
with lib; let cfg = config.custom.services.binary-cache;
let in {
cfg = config.custom.services.binary-cache;
in
{
options.custom.services.binary-cache = { options.custom.services.binary-cache = {
enable = mkEnableOption "binary-cache"; enable = lib.mkEnableOption "binary-cache";
secretKeyFile = mkOption { secretKeyFile = lib.mkOption { type = lib.types.path; };
type = types.path;
};
}; };
config = lib.mkIf cfg.enable {
config = mkIf cfg.enable {
services.nix-serve = { services.nix-serve = {
enable = true; enable = true;
port = 1500; port = 1500;
@ -29,7 +23,9 @@ in
forceSSL = true; forceSSL = true;
locations."/".extraConfig = '' locations."/".extraConfig = ''
proxy_pass http://localhost:${toString config.services.nix-serve.port}; proxy_pass http://localhost:${
toString config.services.nix-serve.port
};
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

View file

@ -1,5 +1,4 @@
{ config, pkgs, ... }: { config, pkgs, ... }: {
{
imports = [ imports = [
./backup-job.nix ./backup-job.nix
./monit.nix ./monit.nix
@ -7,5 +6,19 @@
./openssh.nix ./openssh.nix
./murmur.nix ./murmur.nix
./mastodon.nix ./mastodon.nix
./nginx.nix
./jellyfin.nix
./stb.nix
./monero.nix
./torrents.nix
./jitsi.nix
./binary-cache.nix
./grafana.nix
./monitoring-exporters.nix
./synapse.nix
./nextcloud.nix
./roundcube.nix
./dokuwiki.nix
./postgresql.nix
]; ];
} }

View file

@ -1,5 +1,4 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib;
let let
cfg = config.custom.services.dokuwiki; cfg = config.custom.services.dokuwiki;
@ -47,11 +46,11 @@ let
in { in {
options.custom.services.dokuwiki = { options.custom.services.dokuwiki = {
enable = mkEnableOption "dokuwiki"; enable = lib.mkEnableOption "dokuwiki";
secretKeyFile = mkOption { type = types.path; }; secretKeyFile = lib.mkOption { type = lib.types.path; };
}; };
config = mkIf cfg.enable config = lib.mkIf cfg.enable
(lib.mkMerge [ (configureWiki "anderia") (configureWiki "arkadia") ]); (lib.mkMerge [ (configureWiki "anderia") (configureWiki "arkadia") ]);
} }

View file

@ -1,187 +1,183 @@
{ config, ... }: { config, lib, ... }:
{ let cfg = config.custom.services.grafana;
in {
options.custom.services.grafana = { enable = lib.mkEnableOption "grafana"; };
sops.secrets = { config = lib.mkIf cfg.enable {
grafanaAdminPassword = { sops.secrets = {
owner = config.users.users.grafana.name; grafanaAdminPassword = {
key = "grafana/admin_password"; owner = config.users.users.grafana.name;
}; key = "grafana/admin_password";
};
services.grafana = {
enable = true;
dataDir = "/nix/var/data/grafana";
settings = {
server = {
domain = "grafana.${config.networking.domain}";
}; };
security.admin_password = "$__file{${config.sops.secrets.grafanaAdminPassword.path}}";
}; };
provision = {
services.grafana = {
enable = true; enable = true;
datasources.settings = { dataDir = "/nix/var/data/grafana";
datasources = [ settings = {
{ server = { domain = "grafana.${config.networking.domain}"; };
name = "Prometheus"; security.admin_password =
type = "prometheus"; "$__file{${config.sops.secrets.grafanaAdminPassword.path}}";
url = "http://127.0.0.1:${toString config.services.prometheus.port}";
isDefault = true;
}
{
name = "Loki";
type = "loki";
access = "proxy";
url = "http://127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}";
}
];
}; };
dashboards.settings.providers = [ provision = {
{ enable = true;
datasources.settings = {
datasources = [
{
name = "Prometheus";
type = "prometheus";
url =
"http://127.0.0.1:${toString config.services.prometheus.port}";
isDefault = true;
}
{
name = "Loki";
type = "loki";
access = "proxy";
url = "http://127.0.0.1:${
toString
config.services.loki.configuration.server.http_listen_port
}";
}
];
};
dashboards.settings.providers = [{
name = "Config"; name = "Config";
options.path = ./dashboards; options.path = ./dashboards;
}];
};
};
services.nginx = {
virtualHosts = {
"${config.services.grafana.settings.server.domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${
toString config.services.grafana.settings.server.http_port
}";
proxyWebsockets = true;
};
};
};
};
services.prometheus = {
enable = true;
scrapeConfigs = [
{
job_name = "node";
static_configs = [{
targets = [
"10.0.2.3:${
toString config.services.prometheus.exporters.node.port
}"
"10.0.1.1:${
toString config.services.prometheus.exporters.node.port
}"
"10.0.1.11:${
toString config.services.prometheus.exporters.node.port
}"
];
}];
}
{
job_name = "synapse";
scrape_interval = "15s";
metrics_path = "/_synapse/metrics";
static_configs = [{ targets = [ "10.0.1.1:9000" ]; }];
}
{
job_name = "dmarc";
scrape_interval = "15s";
static_configs = [{
targets = [
"10.0.2.3:${
toString config.services.prometheus.exporters.dmarc.port
}"
];
}];
} }
]; ];
}; };
};
services.nginx = { services.loki = {
virtualHosts = { enable = true;
"${config.services.grafana.settings.server.domain}" = {
enableACME = true; dataDir = "/nix/var/data/loki";
forceSSL = true;
locations."/" = { configuration = {
proxyPass = "http://127.0.0.1:${toString config.services.grafana.settings.server.http_port}"; server.http_listen_port = 3100;
proxyWebsockets = true; auth_enabled = false;
};
};
};
};
services.prometheus = { ingester = {
enable = true; lifecycler = {
address = "127.0.0.1";
scrapeConfigs = [ ring = {
{ kvstore = { store = "inmemory"; };
job_name = "node"; replication_factor = 1;
static_configs = [{
targets = [
"10.0.2.3:${toString config.services.prometheus.exporters.node.port}"
"10.0.1.1:${toString config.services.prometheus.exporters.node.port}"
"10.0.1.11:${toString config.services.prometheus.exporters.node.port}"
];
}];
}
{
job_name = "synapse";
scrape_interval = "15s";
metrics_path = "/_synapse/metrics";
static_configs = [{
targets = [
"10.0.1.1:9000"
];
}];
}
{
job_name = "dmarc";
scrape_interval = "15s";
static_configs = [{
targets = [
"10.0.2.3:${toString config.services.prometheus.exporters.dmarc.port}"
];
}];
}
];
};
services.loki = {
enable = true;
dataDir = "/nix/var/data/loki";
configuration = {
server.http_listen_port = 3100;
auth_enabled = false;
ingester = {
lifecycler = {
address = "127.0.0.1";
ring = {
kvstore = {
store = "inmemory";
}; };
replication_factor = 1; };
chunk_idle_period = "1h";
max_chunk_age = "1h";
chunk_target_size = 999999;
chunk_retain_period = "30s";
max_transfer_retries = 0;
};
limits_config = { ingestion_rate_mb = 16; };
schema_config = {
configs = [{
from = "2022-09-15";
store = "boltdb-shipper";
object_store = "filesystem";
schema = "v11";
index = {
prefix = "index_";
period = "24h";
};
}];
};
storage_config = {
boltdb_shipper = {
active_index_directory =
"${config.services.loki.dataDir}/boltdb-index";
cache_location = "${config.services.loki.dataDir}/boltdb-cache";
cache_ttl = "24h";
shared_store = "filesystem";
};
filesystem = {
directory = "${config.services.loki.dataDir}/chunks";
}; };
}; };
chunk_idle_period = "1h";
max_chunk_age = "1h";
chunk_target_size = 999999;
chunk_retain_period = "30s";
max_transfer_retries = 0;
};
limits_config = { limits_config = {
ingestion_rate_mb = 16; reject_old_samples = true;
}; reject_old_samples_max_age = "168h";
};
schema_config = { chunk_store_config = { max_look_back_period = "0s"; };
configs = [{
from = "2022-09-15";
store = "boltdb-shipper";
object_store = "filesystem";
schema = "v11";
index = {
prefix = "index_";
period = "24h";
};
}];
};
storage_config = { table_manager = {
boltdb_shipper = { retention_deletes_enabled = false;
active_index_directory = "${config.services.loki.dataDir}/boltdb-index"; retention_period = "0s";
cache_location = "${config.services.loki.dataDir}/boltdb-cache"; };
cache_ttl = "24h";
compactor = {
working_directory = "${config.services.loki.dataDir}";
shared_store = "filesystem"; shared_store = "filesystem";
compactor_ring = { kvstore = { store = "inmemory"; }; };
}; };
filesystem = { analytics = { reporting_enabled = false; };
directory = "${config.services.loki.dataDir}/chunks";
};
};
limits_config = {
reject_old_samples = true;
reject_old_samples_max_age = "168h";
};
chunk_store_config = {
max_look_back_period = "0s";
};
table_manager = {
retention_deletes_enabled = false;
retention_period = "0s";
};
compactor = {
working_directory = "${config.services.loki.dataDir}";
shared_store = "filesystem";
compactor_ring = {
kvstore = {
store = "inmemory";
};
};
};
analytics = {
reporting_enabled = false;
}; };
}; };
}; };
} }

View file

@ -1,38 +1,43 @@
{ config, lib, pkgs, ... }: { config, lib, ... }:
{ let cfg = config.custom.services.jellyfin;
services.jellyfin = { in {
enable = true; options.custom.services.jellyfin = {
enable = lib.mkEnableOption "jellyfin";
}; };
systemd.services.jellyfin.serviceConfig.ExecStart = config = lib.mkIf cfg.enable {
lib.mkOverride 10 "${config.services.jellyfin.package}/bin/jellyfin --datadir '/nix/var/data/jellyfin' --cachedir '/var/cache/jellyfin'"; services.jellyfin = { enable = true; };
services.nginx.virtualHosts."jellyfin.${config.networking.domain}" = { systemd.services.jellyfin.serviceConfig.ExecStart = lib.mkOverride 10
enableACME = true; "${config.services.jellyfin.package}/bin/jellyfin --datadir '/nix/var/data/jellyfin' --cachedir '/var/cache/jellyfin'";
forceSSL = true;
locations."= /".extraConfig = '' services.nginx.virtualHosts."jellyfin.${config.networking.domain}" = {
return 302 https://$host/web/; enableACME = true;
''; forceSSL = true;
locations."/" = { locations."= /".extraConfig = ''
proxyPass = "http://127.0.0.1:8096"; return 302 https://$host/web/;
extraConfig = ''
proxy_buffering off;
''; '';
};
locations."= /web/" = { locations."/" = {
proxyPass = "http://127.0.0.1:8096/web/index.html"; proxyPass = "http://127.0.0.1:8096";
}; extraConfig = ''
proxy_buffering off;
'';
};
locations."/socket" = { locations."= /web/" = {
proxyPass = "http://127.0.0.1:8096"; proxyPass = "http://127.0.0.1:8096/web/index.html";
extraConfig = '' };
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; locations."/socket" = {
proxy_set_header Connection "upgrade"; proxyPass = "http://127.0.0.1:8096";
''; extraConfig = ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
'';
};
}; };
}; };
} }

View file

@ -1,8 +1,14 @@
{ pkgs, lib, config, ... }: { { pkgs, config, lib, ... }:
services.jitsi-meet = { let cfg = config.custom.services.jitsi;
enable = true; in {
hostName = "jitsi.froidmont.org"; options.custom.services.jitsi = { enable = lib.mkEnableOption "jitsi"; };
interfaceConfig = { RECENT_LIST_ENABLED = false; };
config = lib.mkIf cfg.enable {
services.jitsi-meet = {
enable = true;
hostName = "jitsi.froidmont.org";
interfaceConfig = { RECENT_LIST_ENABLED = false; };
};
services.jitsi-videobridge.openFirewall = true;
}; };
services.jitsi-videobridge.openFirewall = true;
} }

View file

@ -1,182 +0,0 @@
{ config, lib, pkgs, ... }: {
sops.secrets = {
paultrialPassword = { key = "email/accounts_passwords/paultrial"; };
eliosPassword = { key = "email/accounts_passwords/elios"; };
mariePassword = { key = "email/accounts_passwords/marie"; };
alicePassword = { key = "email/accounts_passwords/alice"; };
monitPassword = { key = "email/accounts_passwords/monit"; };
noreplyBanditlairPassword = {
key = "email/accounts_passwords/noreply_banditlair";
};
noreplyFroidmontPassword = {
key = "email/accounts_passwords/noreply_froidmont";
};
};
mailserver = {
enable = true;
fqdn = "mail.banditlair.com";
domains = [ "banditlair.com" "froidmont.org" "falbo.fr" ];
localDnsResolver = false;
enableManageSieve = true;
mailDirectory = "/nix/var/data/vmail";
sieveDirectory = "/nix/var/data/sieve";
lmtpSaveToDetailMailbox = "no";
policydSPFExtraConfig = ''
Domain_Whitelist = skynet.be
'';
loginAccounts = {
"paultrial@banditlair.com" = {
# nix run nixpkgs.apacheHttpd -c htpasswd -nbB "" "super secret password" | cut -d: -f2 > /hashed/password/file/location
hashedPasswordFile = config.sops.secrets.paultrialPassword.path;
aliases = [ "contact@froidmont.org" "account@banditlair.com" ];
};
"marie-alice@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.mariePassword.path;
aliases = [
"osteopathie@froidmont.org"
"communication@froidmont.org"
"crelan.communication@froidmont.org"
"kerger.communication@froidmont.org"
"3arcs.communication@froidmont.org"
"7days.communication@froidmont.org"
"ulb.communication@froidmont.org"
"baijot.communication@froidmont.org"
"alltrails.communication@froidmont.org"
"alltricks.communication@froidmont.org"
"amazon.communication@froidmont.org"
"athletv.communication@froidmont.org"
"bebecenter.communication@froidmont.org"
"canyon.communication@froidmont.org"
"cbc.communication@froidmont.org"
"coursulb.communication@froidmont.org"
"decathlon.communication@froidmont.org"
"degiro.communication@froidmont.org"
"delogne.communication@froidmont.org"
"diagnosteo.communication@froidmont.org"
"haptis.communication@froidmont.org"
"fortis.communication@froidmont.org"
"fox.communication@froidmont.org"
"vandenborre.communication@froidmont.org"
"swissquote.communication@froidmont.org"
"belso.communication@froidmont.org"
"hibike.communication@froidmont.org"
"giromedical.communication@froidmont.org"
"gymna.communication@froidmont.org"
"hotmail.communication@froidmont.org"
"hubo.communication@froidmont.org"
"infopixel.communication@froidmont.org"
"jysk.communication@froidmont.org"
"kerger.communication@froidmont.org"
"ldlc.communication@froidmont.org"
"location.communication@froidmont.org"
"mainslibres.communication@froidmont.org"
"vistaprint.communication@froidmont.org"
"solidaris.communication@froidmont.org"
"coulon.communication@froidmont.org"
"vlan.communication@froidmont.org"
"hotel.communication@froidmont.org"
"medipost.communication@froidmont.org"
"proximus.communication@froidmont.org"
"marie.communication@froidmont.org"
"tuxedo.communication@froidmont.org"
"corine.wallaux.communication@froidmont.org"
"maziers.communication@froidmont.org"
"miliboo.communication@froidmont.org"
"nike.communication@froidmont.org"
"partena.communication@froidmont.org"
"payconiq.communication@froidmont.org"
"plumart.communication@froidmont.org"
"probikeshop.communication@froidmont.org"
"ring.communication@froidmont.org"
"teams.communication@froidmont.org"
"trail.communication@froidmont.org"
"wikiloc.communication@froidmont.org"
"udemy.communication@froidmont.org"
];
};
"alice@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.alicePassword.path;
};
"elios@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.eliosPassword.path;
aliases = [
"webshit@banditlair.com"
"outlook-pascal@banditlair.com"
"nexusmods.webshit@banditlair.com"
"pizza.webshit@banditlair.com"
"fnac.webshit@banditlair.com"
"paypal.webshit@banditlair.com"
"zooplus.webshit@banditlair.com"
"event.webshit@banditlair.com"
"reservation.webshit@banditlair.com"
"netflix.webshit@banditlair.com"
"jvc.webshit@banditlair.com"
"kickstarter.webshit@banditlair.com"
"vpn.webshit@banditlair.com"
"VOO.WEBSHIT@banditlair.com"
"proximus.webshit@banditlair.com"
"post.webshit@banditlair.com"
"ikea.webshit@banditlair.com"
"microsoft.webshit@banditlair.com"
"zerotier.webshit@banditlair.com"
"athome.webshit@banditlair.com"
"nordvpn.webshit@banditlair.com"
"sncf.webshit@banditlair.com"
"paradox.webshit@banditlair.com"
"oracle.webshit@banditlair.com"
"kinepolis.webshit@banditlair.com"
"leboncoin.webshit@banditlair.com"
"wondercraft.webshit@banditlair.com"
"petitvapoteur.webshit@banditlair.com"
"ryanair.webshit@banditlair.com"
"europapark.webshit@banditlair.com"
"Tricount.webshit@banditlair.com"
"huawei.webshit@banditlair.com"
"facebook.webshit@banditlair.com"
"roll20.webshit@banditlair.com"
"drivethrurpg.webshit@banditlair.com"
"chrono24.webshit@banditlair.com"
"emby.webshit@banditlair.com"
"amazon.webshit@banditlair.com"
"steam.webshit@banditlair.com"
"tinder.webshit@banditlair.com"
];
};
"monit@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.monitPassword.path;
sendOnly = true;
};
"noreply@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.noreplyBanditlairPassword.path;
sendOnly = true;
};
"noreply@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.noreplyFroidmontPassword.path;
sendOnly = true;
};
};
extraVirtualAliases = {
"info@banditlair.com" = "paultrial@banditlair.com";
"postmaster@banditlair.com" = "paultrial@banditlair.com";
"abuse@banditlair.com" = "paultrial@banditlair.com";
"info@froidmont.org" = "paultrial@banditlair.com";
"postmaster@froidmont.org" = "paultrial@banditlair.com";
"abuse@froidmont.org" = "paultrial@banditlair.com";
"info@falbo.fr" = "paultrial@banditlair.com";
"postmaster@falbo.fr" = "paultrial@banditlair.com";
"abuse@falbo.fr" = "paultrial@banditlair.com";
#Catch all
"@banditlair.com" = "paultrial@banditlair.com";
"@froidmont.org" = "paultrial@banditlair.com";
"@falbo.fr" = "elios@banditlair.com";
};
certificateScheme = "acme-nginx";
};
}

View file

@ -1,21 +1,24 @@
{ config, lib, pkgs, ... }: { config, lib, ... }:
{ let cfg = config.custom.services.monero;
in {
options.custom.services.monero = { enable = lib.mkEnableOption "monero"; };
services.monero = { config = lib.mkIf cfg.enable {
enable = true; services.monero = {
rpc.restricted = true; enable = true;
}; rpc.restricted = true;
};
services.nginx.virtualHosts."monero.${config.networking.domain}" = { services.nginx.virtualHosts."monero.${config.networking.domain}" = {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:18081"; proxyPass = "http://127.0.0.1:18081";
extraConfig = '' extraConfig = ''
proxy_http_version 1.1; proxy_http_version 1.1;
''; '';
};
}; };
}; };
} }

View file

@ -1,61 +1,61 @@
{ config, lib, ... }: { config, lib, ... }:
{ let cfg = config.custom.services.monitoring-exporters;
services.prometheus = { in {
exporters = { options.custom.services.monitoring-exporters = {
node = { enable = lib.mkEnableOption "monitoring-exporters";
enable = true;
enabledCollectors = [ "systemd" "processes" ];
};
};
}; };
services.promtail = { config = lib.mkIf cfg.enable {
enable = true; services.prometheus = {
configuration = { exporters = {
server = { node = {
http_listen_port = 3101; enable = true;
grpc_listen_port = 0; enabledCollectors = [ "systemd" "processes" ];
};
}; };
clients = [{ };
url = "http://10.0.2.3:3100/loki/api/v1/push";
}]; services.promtail = {
scrape_configs = [ enable = true;
{ configuration = {
job_name = "journal"; server = {
journal = { http_listen_port = 3101;
max_age = "12h"; grpc_listen_port = 0;
labels = { };
job = "systemd-journal"; clients = [{ url = "http://10.0.2.3:3100/loki/api/v1/push"; }];
host = "${config.networking.hostName}"; scrape_configs = [
{
job_name = "journal";
journal = {
max_age = "12h";
labels = {
job = "systemd-journal";
host = "${config.networking.hostName}";
};
}; };
}; relabel_configs = [{
relabel_configs = [{ source_labels = [ "__journal__systemd_unit" ];
source_labels = [ "__journal__systemd_unit" ]; target_label = "unit";
target_label = "unit"; }];
}]; }
} (lib.mkIf config.services.nginx.enable {
(lib.mkIf config.services.nginx.enable { job_name = "nginx";
job_name = "nginx"; static_configs = [{
static_configs = [
{
targets = [ "localhost" ]; targets = [ "localhost" ];
labels = { labels = {
job = "nginx"; job = "nginx";
host = "${config.networking.hostName}"; host = "${config.networking.hostName}";
__path__ = "/var/log/nginx/*.log"; __path__ = "/var/log/nginx/*.log";
}; };
} }];
]; })
}) ];
]; };
};
systemd.services.promtail.serviceConfig = {
ReadOnlyPaths = lib.mkIf config.services.nginx.enable "/var/log/nginx";
SupplementaryGroups = lib.mkIf config.services.nginx.enable [ "nginx" ];
}; };
}; };
systemd.services.promtail.serviceConfig = {
ReadOnlyPaths = lib.mkIf config.services.nginx.enable "/var/log/nginx";
SupplementaryGroups = lib.mkIf config.services.nginx.enable [ "nginx" ];
};
} }

View file

@ -1,15 +1,9 @@
{ config, lib, ... }: { config, lib, ... }:
with lib; let cfg = config.custom.services.murmur;
let in {
cfg = config.custom.services.murmur; options.custom.services.murmur = { enable = lib.mkEnableOption "murmur"; };
in
{
options.custom.services.murmur = {
enable = mkEnableOption "murmur";
};
config = lib.mkIf cfg.enable {
config = mkIf cfg.enable {
sops.secrets.murmurEnvFile = { sops.secrets.murmurEnvFile = {
owner = config.systemd.services.murmur.serviceConfig.User; owner = config.systemd.services.murmur.serviceConfig.User;
key = "murmur.env"; key = "murmur.env";

View file

@ -1,5 +1,6 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
let let
cfg = config.custom.services.nextcloud;
uidFile = pkgs.writeText "uidfile" '' uidFile = pkgs.writeText "uidfile" ''
nextcloud:993 nextcloud:993
''; '';
@ -7,85 +8,92 @@ let
nextcloud:991 nextcloud:991
''; '';
in { in {
sops.secrets = { options.custom.services.nextcloud = {
sshfsKey = { key = "sshfs_keys/private"; }; enable = lib.mkEnableOption "nextcloud";
nextcloudDbPassword = {
owner = config.users.users.nextcloud.name;
key = "nextcloud/db_password";
restartUnits = [ "nextcloud-setup.service" ];
};
nextcloudAdminPassword = {
owner = config.users.users.nextcloud.name;
key = "nextcloud/admin_password";
restartUnits = [ "nextcloud-setup.service" ];
};
}; };
environment.systemPackages = with pkgs; [ sshfs ]; config = lib.mkIf cfg.enable {
sops.secrets = {
systemd.services.nextcloud-data-sshfs = { sshfsKey = { key = "sshfs_keys/private"; };
wantedBy = [ "multi-user.target" "nextcloud-setup.service" ]; nextcloudDbPassword = {
before = [ "phpfpm-nextcloud.service" ]; owner = config.users.users.nextcloud.name;
restartIfChanged = false; key = "nextcloud/db_password";
serviceConfig = { restartUnits = [ "nextcloud-setup.service" ];
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/nextcloud/data"; };
ExecStart = let nextcloudAdminPassword = {
options = builtins.concatStringsSep "," [ owner = config.users.users.nextcloud.name;
"identityfile=${config.sops.secrets.sshfsKey.path}" key = "nextcloud/admin_password";
"ServerAliveInterval=15" restartUnits = [ "nextcloud-setup.service" ];
"idmap=file" };
"uidfile=${uidFile}"
"gidfile=${gidFile}"
"allow_other"
"default_permissions"
"nomap=ignore"
];
in "${pkgs.sshfs}/bin/mount.fuse.sshfs www-data@10.0.2.3:/nix/var/data/nextcloud/data "
+ "/var/lib/nextcloud/data -o ${options}";
ExecStopPost = "-${pkgs.fuse}/bin/fusermount -u /var/lib/nextcloud/data";
KillMode = "process";
};
};
services.nginx.virtualHosts."${config.services.nextcloud.hostName}" = {
enableACME = true;
forceSSL = true;
};
services.nextcloud = {
enable = true;
package = pkgs.nextcloud28;
hostName = "cloud.${config.networking.domain}";
https = true;
maxUploadSize = "1G";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "10.0.1.11";
dbname = "nextcloud";
dbpassFile = "${config.sops.secrets.nextcloudDbPassword.path}";
adminpassFile = "${config.sops.secrets.nextcloudAdminPassword.path}";
adminuser = "root";
overwriteProtocol = "https";
defaultPhoneRegion = "BE";
}; };
extraOptions = { maintenance_window_start = 1; }; environment.systemPackages = with pkgs; [ sshfs ];
phpOptions = { systemd.services.nextcloud-data-sshfs = {
short_open_tag = "Off"; wantedBy = [ "multi-user.target" "nextcloud-setup.service" ];
expose_php = "Off"; before = [ "phpfpm-nextcloud.service" ];
error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT"; restartIfChanged = false;
display_errors = "stderr"; serviceConfig = {
"opcache.enable_cli" = "1"; ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/nextcloud/data";
"opcache.interned_strings_buffer" = "12"; ExecStart = let
"opcache.max_accelerated_files" = "10000"; options = builtins.concatStringsSep "," [
"opcache.memory_consumption" = "128"; "identityfile=${config.sops.secrets.sshfsKey.path}"
"opcache.revalidate_freq" = "1"; "ServerAliveInterval=15"
"opcache.fast_shutdown" = "1"; "idmap=file"
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt"; "uidfile=${uidFile}"
catch_workers_output = "yes"; "gidfile=${gidFile}"
"allow_other"
"default_permissions"
"nomap=ignore"
];
in "${pkgs.sshfs}/bin/mount.fuse.sshfs www-data@10.0.2.3:/nix/var/data/nextcloud/data "
+ "/var/lib/nextcloud/data -o ${options}";
ExecStopPost =
"-${pkgs.fuse}/bin/fusermount -u /var/lib/nextcloud/data";
KillMode = "process";
};
};
services.nginx.virtualHosts."${config.services.nextcloud.hostName}" = {
enableACME = true;
forceSSL = true;
};
services.nextcloud = {
enable = true;
package = pkgs.nextcloud28;
hostName = "cloud.${config.networking.domain}";
https = true;
maxUploadSize = "1G";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "10.0.1.11";
dbname = "nextcloud";
dbpassFile = "${config.sops.secrets.nextcloudDbPassword.path}";
adminpassFile = "${config.sops.secrets.nextcloudAdminPassword.path}";
adminuser = "root";
overwriteProtocol = "https";
defaultPhoneRegion = "BE";
};
extraOptions = { maintenance_window_start = 1; };
phpOptions = {
short_open_tag = "Off";
expose_php = "Off";
error_reporting = "E_ALL & ~E_DEPRECATED & ~E_STRICT";
display_errors = "stderr";
"opcache.enable_cli" = "1";
"opcache.interned_strings_buffer" = "12";
"opcache.max_accelerated_files" = "10000";
"opcache.memory_consumption" = "128";
"opcache.revalidate_freq" = "1";
"opcache.fast_shutdown" = "1";
"openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt";
catch_workers_output = "yes";
};
}; };
}; };
} }

View file

@ -1,15 +1,20 @@
{ pkgs, lib, config, ... }: { config, lib, ... }:
{ let cfg = config.custom.services.nginx;
security.acme.defaults.email = "letsencrypt.account@banditlair.com"; in {
security.acme.defaults.webroot = "/var/lib/acme/acme-challenge"; options.custom.services.nginx = { enable = lib.mkEnableOption "nginx"; };
security.acme.acceptTerms = true;
services.nginx = { config = lib.mkIf cfg.enable {
enable = true; security.acme.defaults.email = "letsencrypt.account@banditlair.com";
security.acme.defaults.webroot = "/var/lib/acme/acme-challenge";
security.acme.acceptTerms = true;
recommendedTlsSettings = true; services.nginx = {
recommendedOptimisation = true; enable = true;
recommendedGzipSettings = true;
recommendedProxySettings = true; recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedProxySettings = true;
};
}; };
} }

View file

@ -1,87 +1,94 @@
{ config, lib, pkgs, ... }: { { config, lib, pkgs, ... }:
let cfg = config.custom.services.postgresql;
services.postgresql = { in {
enable = true; options.custom.services.postgresql = {
package = pkgs.postgresql_15; enable = lib.mkEnableOption "postgresql";
enableTCPIP = true;
identMap = ''
root_as_others root postgres
root_as_others root synapse
root_as_others root nextcloud
root_as_others root roundcube
root_as_others root mastodon
'';
authentication = ''
local all postgres peer
local all all peer map=root_as_others
host all all 10.0.1.0/24 md5
'';
}; };
sops.secrets = { config = lib.mkIf cfg.enable {
synapseDbPassword = { services.postgresql = {
owner = config.services.postgresql.superUser; enable = true;
key = "synapse/db_password"; package = pkgs.postgresql_15;
restartUnits = [ "postgresql-setup.service" ]; enableTCPIP = true;
identMap = ''
root_as_others root postgres
root_as_others root synapse
root_as_others root nextcloud
root_as_others root roundcube
root_as_others root mastodon
'';
authentication = ''
local all postgres peer
local all all peer map=root_as_others
host all all 10.0.1.0/24 md5
'';
}; };
nextcloudDbPassword = {
owner = config.services.postgresql.superUser; sops.secrets = {
key = "nextcloud/db_password"; synapseDbPassword = {
restartUnits = [ "postgresql-setup.service" ]; owner = config.services.postgresql.superUser;
key = "synapse/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
nextcloudDbPassword = {
owner = config.services.postgresql.superUser;
key = "nextcloud/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
roundcubeDbPassword = {
owner = config.services.postgresql.superUser;
key = "roundcube/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
mastodonDbPassword = {
owner = config.services.postgresql.superUser;
key = "mastodon/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
}; };
roundcubeDbPassword = {
owner = config.services.postgresql.superUser;
key = "roundcube/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
mastodonDbPassword = {
owner = config.services.postgresql.superUser;
key = "mastodon/db_password";
restartUnits = [ "postgresql-setup.service" ];
};
};
systemd.services.postgresql-setup = let pgsql = config.services.postgresql; systemd.services.postgresql-setup = let pgsql = config.services.postgresql;
in { in {
after = [ "postgresql.service" ]; after = [ "postgresql.service" ];
bindsTo = [ "postgresql.service" ]; bindsTo = [ "postgresql.service" ];
wantedBy = [ "postgresql.service" ]; wantedBy = [ "postgresql.service" ];
path = [ pgsql.package pkgs.util-linux ]; path = [ pgsql.package pkgs.util-linux ];
script = '' script = ''
set -u set -u
PSQL() { PSQL() {
psql --port=${toString pgsql.port} "$@" psql --port=${toString pgsql.port} "$@"
} }
PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'synapse'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "synapse"' PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'synapse'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "synapse"'
PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'nextcloud'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "nextcloud"' PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'nextcloud'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "nextcloud"'
PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'roundcube'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "roundcube"' PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'roundcube'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "roundcube"'
PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'mastodon'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "mastodon"' PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname = 'mastodon'" | grep -q 1 || PSQL -tAc 'CREATE ROLE "mastodon"'
PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'synapse'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "synapse" OWNER "synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"' PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'synapse'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "synapse" OWNER "synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"'
PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'nextcloud'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "nextcloud" OWNER "nextcloud"' PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'nextcloud'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "nextcloud" OWNER "nextcloud"'
PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'roundcube'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "roundcube" OWNER "roundcube"' PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'roundcube'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "roundcube" OWNER "roundcube"'
PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'mastodon'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "mastodon" OWNER "mastodon"' PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'mastodon'" | grep -q 1 || PSQL -tAc 'CREATE DATABASE "mastodon" OWNER "mastodon"'
PSQL -tAc "ALTER ROLE synapse LOGIN" PSQL -tAc "ALTER ROLE synapse LOGIN"
PSQL -tAc "ALTER ROLE nextcloud LOGIN" PSQL -tAc "ALTER ROLE nextcloud LOGIN"
PSQL -tAc "ALTER ROLE roundcube LOGIN" PSQL -tAc "ALTER ROLE roundcube LOGIN"
PSQL -tAc "ALTER ROLE mastodon LOGIN" PSQL -tAc "ALTER ROLE mastodon LOGIN"
synapse_password="$(<'${config.sops.secrets.synapseDbPassword.path}')" synapse_password="$(<'${config.sops.secrets.synapseDbPassword.path}')"
PSQL -tAc "ALTER ROLE synapse WITH PASSWORD '$synapse_password'" PSQL -tAc "ALTER ROLE synapse WITH PASSWORD '$synapse_password'"
nextcloud_password="$(<'${config.sops.secrets.nextcloudDbPassword.path}')" nextcloud_password="$(<'${config.sops.secrets.nextcloudDbPassword.path}')"
PSQL -tAc "ALTER ROLE nextcloud WITH PASSWORD '$nextcloud_password'" PSQL -tAc "ALTER ROLE nextcloud WITH PASSWORD '$nextcloud_password'"
roundcube_password="$(<'${config.sops.secrets.roundcubeDbPassword.path}')" roundcube_password="$(<'${config.sops.secrets.roundcubeDbPassword.path}')"
PSQL -tAc "ALTER ROLE roundcube WITH PASSWORD '$roundcube_password'" PSQL -tAc "ALTER ROLE roundcube WITH PASSWORD '$roundcube_password'"
mastodon_password="$(<'${config.sops.secrets.mastodonDbPassword.path}')" mastodon_password="$(<'${config.sops.secrets.mastodonDbPassword.path}')"
PSQL -tAc "ALTER ROLE mastodon WITH PASSWORD '$mastodon_password'" PSQL -tAc "ALTER ROLE mastodon WITH PASSWORD '$mastodon_password'"
''; '';
serviceConfig = { serviceConfig = {
User = pgsql.superUser; User = pgsql.superUser;
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
};
}; };
}; };
} }

View file

@ -1,42 +1,47 @@
{ pkgs, lib, config, ... }: { pkgs, lib, config, ... }:
{ let cfg = config.custom.services.roundcube;
in {
sops.secrets = { options.custom.services.roundcube = {
pgPassFile = { enable = lib.mkEnableOption "roundcube";
owner = "nginx";
key = "roundcube/pg_pass_file";
};
dbPassword = {
owner = "nginx";
key = "roundcube/db_password";
};
}; };
services.roundcube = { config = lib.mkIf cfg.enable {
enable = true; sops.secrets = {
plugins = [ "managesieve" ]; pgPassFile = {
dicts = with pkgs.aspellDicts; [ en fr de ]; owner = "nginx";
hostName = "webmail.banditlair.com"; key = "roundcube/pg_pass_file";
database = { };
host = "10.0.1.11"; dbPassword = {
username = "roundcube"; owner = "nginx";
dbname = "roundcube"; key = "roundcube/db_password";
passwordFile = config.sops.secrets.pgPassFile.path; };
}; };
services.roundcube = {
enable = true;
plugins = [ "managesieve" ];
dicts = with pkgs.aspellDicts; [ en fr de ];
hostName = "webmail.banditlair.com";
database = {
host = "10.0.1.11";
username = "roundcube";
dbname = "roundcube";
passwordFile = config.sops.secrets.pgPassFile.path;
};
extraConfig = '' extraConfig = ''
# This override is required as a workaround for the nixpkgs config because we need a plain password instead of a pgpass file # This override is required as a workaround for the nixpkgs config because we need a plain password instead of a pgpass file
$password = file_get_contents('${config.sops.secrets.dbPassword.path}'); $password = file_get_contents('${config.sops.secrets.dbPassword.path}');
$config['db_dsnw'] = 'pgsql://roundcube:' . $password . '@10.0.1.11/roundcube'; $config['db_dsnw'] = 'pgsql://roundcube:' . $password . '@10.0.1.11/roundcube';
$config['default_host'] = 'ssl://mail.banditlair.com:993'; $config['default_host'] = 'ssl://mail.banditlair.com:993';
$config['smtp_server'] = 'ssl://%h'; $config['smtp_server'] = 'ssl://%h';
$config['smtp_user'] = '%u'; $config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p'; $config['smtp_pass'] = '%p';
$config['identities_level'] = 0; $config['identities_level'] = 0;
$config['managesieve_host'] = 'tls://%h'; $config['managesieve_host'] = 'tls://%h';
$config['managesieve_auth_type'] = 'PLAIN'; $config['managesieve_auth_type'] = 'PLAIN';
''; '';
};
}; };
} }

View file

@ -1,5 +1,6 @@
{ config, lib, pkgs, ... }: { pkgs, config, lib, ... }:
let let
cfg = config.custom.services.stb;
uploadWordpressConfig = pkgs.writeText "upload.ini" '' uploadWordpressConfig = pkgs.writeText "upload.ini" ''
file_uploads = On file_uploads = On
memory_limit = 64M memory_limit = 64M
@ -7,62 +8,62 @@ let
post_max_size = 64M post_max_size = 64M
max_execution_time = 600 max_execution_time = 600
''; '';
in in {
{ options.custom.services.stb = { enable = lib.mkEnableOption "stb"; };
systemd.services.init-stb-network = {
description = "Create the network bridge stb-br for wordpress.";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig.Type = "oneshot"; config = lib.mkIf cfg.enable {
script = systemd.services.init-stb-network = {
let dockercli = "${config.virtualisation.docker.package}/bin/docker"; description = "Create the network bridge stb-br for wordpress.";
in after = [ "network.target" ];
'' wantedBy = [ "multi-user.target" ];
# Put a true at the end to prevent getting non-zero return code, which will
# crash the whole service.
check=$(${dockercli} network ls | grep "stb-br" || true)
if [ -z "$check" ]; then
${dockercli} network create stb-br
else
echo "stb-br already exists in docker"
fi
'';
};
virtualisation.oci-containers.containers = { serviceConfig.Type = "oneshot";
"stb-mariadb" = { script =
image = "mariadb:10.7"; let dockercli = "${config.virtualisation.docker.package}/bin/docker";
environment = { in ''
"MYSQL_ROOT_PASSWORD" = "root"; # Put a true at the end to prevent getting non-zero return code, which will
"MYSQL_USER" = "stb"; # crash the whole service.
"MYSQL_PASSWORD" = "stb"; check=$(${dockercli} network ls | grep "stb-br" || true)
"MYSQL_DATABASE" = "stb"; if [ -z "$check" ]; then
${dockercli} network create stb-br
else
echo "stb-br already exists in docker"
fi
'';
};
virtualisation.oci-containers.containers = {
"stb-mariadb" = {
image = "mariadb:10.7";
environment = {
"MYSQL_ROOT_PASSWORD" = "root";
"MYSQL_USER" = "stb";
"MYSQL_PASSWORD" = "stb";
"MYSQL_DATABASE" = "stb";
};
volumes = [ "/var/lib/mariadb/stb:/var/lib/mysql" ];
extraOptions = [ "--network=stb-br" ];
autoStart = true;
};
"stb-wordpress" = {
image = "wordpress:5.8-php7.4-apache";
volumes = [
"/nix/var/data/stb-wordpress:/var/www/html"
"${uploadWordpressConfig}:/usr/local/etc/php/conf.d/uploads.ini"
];
ports = [ "127.0.0.1:8180:80" ];
extraOptions = [ "--network=stb-br" ];
autoStart = true;
}; };
volumes = [ "/var/lib/mariadb/stb:/var/lib/mysql" ];
extraOptions = [ "--network=stb-br" ];
autoStart = true;
}; };
"stb-wordpress" = { services.nginx.virtualHosts."www.societe-de-tir-bertrix.com" = {
image = "wordpress:5.8-php7.4-apache"; serverAliases = [ "societe-de-tir-bertrix.com" ];
volumes = [ forceSSL = true;
"/nix/var/data/stb-wordpress:/var/www/html" enableACME = true;
"${uploadWordpressConfig}:/usr/local/etc/php/conf.d/uploads.ini"
];
ports = [ "127.0.0.1:8180:80" ];
extraOptions = [ "--network=stb-br" ];
autoStart = true;
};
};
services.nginx.virtualHosts."www.societe-de-tir-bertrix.com" = { locations."/" = { proxyPass = "http://127.0.0.1:8180"; };
serverAliases = [ "societe-de-tir-bertrix.com" ];
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:8180";
}; };
}; };
} }

View file

@ -1,10 +1,10 @@
{ pkgs, lib, config, ... }: { pkgs, config, lib, ... }:
let let
fqdn = cfg = config.custom.services.synapse;
let fqdn = let
join = hostName: domain: hostName + lib.optionalString (domain != null) ".${domain}"; join = hostName: domain:
in hostName + lib.optionalString (domain != null) ".${domain}";
join "matrix" config.networking.domain; in join "matrix" config.networking.domain;
synapseDbConfig = pkgs.writeText "synapse-db-config.yaml" '' synapseDbConfig = pkgs.writeText "synapse-db-config.yaml" ''
database: database:
name: psycopg2 name: psycopg2
@ -24,214 +24,211 @@ let
macaroon_secret_key: "MACAROON_SECRET_KEY" macaroon_secret_key: "MACAROON_SECRET_KEY"
turn_shared_secret: "TURN_SHARED_SECRET" turn_shared_secret: "TURN_SHARED_SECRET"
''; '';
in in {
{ options.custom.services.synapse = { enable = lib.mkEnableOption "synapse"; };
services.nginx = {
virtualHosts = {
# This host section can be placed on a different host than the rest,
# i.e. to delegate from the host being accessible as ${config.networking.domain}
# to another host actually running the Matrix homeserver.
"${config.networking.domain}" = {
enableACME = true;
forceSSL = true;
# acmeFallbackHost = "storage1.banditlair.com";
locations."= /.well-known/matrix/server".extraConfig = config = lib.mkIf cfg.enable {
let services.nginx = {
virtualHosts = {
# This host section can be placed on a different host than the rest,
# i.e. to delegate from the host being accessible as ${config.networking.domain}
# to another host actually running the Matrix homeserver.
"${config.networking.domain}" = {
enableACME = true;
forceSSL = true;
# acmeFallbackHost = "storage1.banditlair.com";
locations."= /.well-known/matrix/server".extraConfig = let
# use 443 instead of the default 8448 port to unite # use 443 instead of the default 8448 port to unite
# the client-server and server-server port for simplicity # the client-server and server-server port for simplicity
server = { "m.server" = "${fqdn}:443"; }; server = { "m.server" = "${fqdn}:443"; };
in in ''
''
add_header Content-Type application/json; add_header Content-Type application/json;
return 200 '${builtins.toJSON server}'; return 200 '${builtins.toJSON server}';
''; '';
locations."= /.well-known/matrix/client".extraConfig = locations."= /.well-known/matrix/client".extraConfig = let
let
client = { client = {
"m.homeserver" = { "base_url" = "https://${fqdn}"; }; "m.homeserver" = { "base_url" = "https://${fqdn}"; };
"m.identity_server" = { "base_url" = "https://vector.im"; }; "m.identity_server" = { "base_url" = "https://vector.im"; };
}; };
# ACAO required to allow element-web on any URL to request this json file # ACAO required to allow element-web on any URL to request this json file
in in ''
''
add_header Content-Type application/json; add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Origin *;
return 200 '${builtins.toJSON client}'; return 200 '${builtins.toJSON client}';
''; '';
}; };
# Reverse proxy for Matrix client-server and server-server communication # Reverse proxy for Matrix client-server and server-server communication
${fqdn} = { ${fqdn} = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
# Or do a redirect instead of the 404, or whatever is appropriate for you. # Or do a redirect instead of the 404, or whatever is appropriate for you.
# But do not put a Matrix Web client here! See the Element web section below. # But do not put a Matrix Web client here! See the Element web section below.
locations."/".extraConfig = '' locations."/".extraConfig = ''
return 404; return 404;
''; '';
# forward all Matrix API calls to the synapse Matrix homeserver # forward all Matrix API calls to the synapse Matrix homeserver
locations."~ ^(/_matrix|/health)" = { locations."~ ^(/_matrix|/health)" = {
proxyPass = "http://[::1]:8008"; # without a trailing / proxyPass = "http://[::1]:8008"; # without a trailing /
};
}; };
}; };
}; };
};
sops.secrets = { sops.secrets = {
synapseDbPassword = { synapseDbPassword = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User; owner = config.systemd.services.matrix-synapse.serviceConfig.User;
key = "synapse/db_password"; key = "synapse/db_password";
restartUnits = [ "matrix-synapse-setup" ]; restartUnits = [ "matrix-synapse-setup" ];
};
noreplySmtpPassword = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
key = "email/accounts_passwords/noreply_banditlair_clear";
};
macaroonSecretKey = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
key = "synapse/macaroon_secret_key";
restartUnits = [ "matrix-synapse-setup" ];
};
turnSharedSecret = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
group = "turnserver";
mode = "0440";
key = "synapse/turn_shared_secret";
restartUnits = [ "matrix-synapse-setup" "coturn" ];
};
}; };
noreplySmtpPassword = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User; systemd.services.matrix-synapse-setup = {
key = "email/accounts_passwords/noreply_banditlair_clear"; before = [ "matrix-synapse.service" ];
script = ''
set -euo pipefail
install -m 600 ${synapseDbConfig} /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'SYNAPSE_DB_PASSWORD' '${config.sops.secrets.synapseDbPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'SMTP_PASSWORD' '${config.sops.secrets.noreplySmtpPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'MACAROON_SECRET_KEY' '${config.sops.secrets.noreplySmtpPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'TURN_SHARED_SECRET' '${config.sops.secrets.turnSharedSecret.path}' /run/synapse/synapse-db-config.yaml
'';
serviceConfig = {
User = config.systemd.services.matrix-synapse.serviceConfig.User;
Group = config.systemd.services.matrix-synapse.serviceConfig.Group;
Type = "oneshot";
RemainAfterExit = true;
RuntimeDirectory = "synapse";
};
}; };
macaroonSecretKey = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User; systemd.services.matrix-synapse = {
key = "synapse/macaroon_secret_key"; after = [ "matrix-synapse-setup.service" "network.target" ];
restartUnits = [ "matrix-synapse-setup" ]; bindsTo = [ "matrix-synapse-setup.service" ];
}; };
turnSharedSecret = {
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
group = "turnserver";
mode = "0440";
key = "synapse/turn_shared_secret";
restartUnits = [ "matrix-synapse-setup" "coturn" ];
};
};
systemd.services.matrix-synapse-setup = { services.matrix-synapse = with config.services.coturn; {
before = [ "matrix-synapse.service" ]; enable = true;
settings = {
server_name = config.networking.domain;
script = '' enable_metrics = true;
set -euo pipefail
install -m 600 ${synapseDbConfig} /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'SYNAPSE_DB_PASSWORD' '${config.sops.secrets.synapseDbPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'SMTP_PASSWORD' '${config.sops.secrets.noreplySmtpPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'MACAROON_SECRET_KEY' '${config.sops.secrets.noreplySmtpPassword.path}' /run/synapse/synapse-db-config.yaml
${pkgs.replace-secret}/bin/replace-secret 'TURN_SHARED_SECRET' '${config.sops.secrets.turnSharedSecret.path}' /run/synapse/synapse-db-config.yaml
'';
serviceConfig = { listeners = [
User = config.systemd.services.matrix-synapse.serviceConfig.User; {
Group = config.systemd.services.matrix-synapse.serviceConfig.Group; port = 8008;
Type = "oneshot"; bind_addresses = [ "::1" "127.0.0.1" ];
RemainAfterExit = true; type = "http";
RuntimeDirectory = "synapse"; tls = false;
}; x_forwarded = true;
}; resources = [{
systemd.services.matrix-synapse = {
after = [ "matrix-synapse-setup.service" "network.target" ];
bindsTo = [ "matrix-synapse-setup.service" ];
};
services.matrix-synapse = with config.services.coturn; {
enable = true;
settings = {
server_name = config.networking.domain;
enable_metrics = true;
listeners = [
{
port = 8008;
bind_addresses = [ "::1" "127.0.0.1" ];
type = "http";
tls = false;
x_forwarded = true;
resources = [
{
names = [ "client" "federation" ]; names = [ "client" "federation" ];
compress = false; compress = false;
} }];
]; }
} {
{ port = 9000;
port = 9000; bind_addresses = [ "0.0.0.0" ];
bind_addresses = [ "0.0.0.0" ]; type = "metrics";
type = "metrics"; tls = false;
tls = false; resources = [ ];
resources = [ ]; }
} ];
];
database = { database = {
name = "psycopg2"; name = "psycopg2";
args = { args = {
host = "fake"; # This section is overriden by "extraConfigFiles" host = "fake"; # This section is overriden by "extraConfigFiles"
};
}; };
turn_uris = [
"turn:${realm}:3478?transport=udp"
"turn:${realm}:3478?transport=tcp"
];
turn_user_lifetime = "1h";
}; };
dataDir = "/nix/var/data/matrix-synapse";
turn_uris = [ "turn:${realm}:3478?transport=udp" "turn:${realm}:3478?transport=tcp" ]; extraConfigFiles = [ "/run/synapse/synapse-db-config.yaml" ];
turn_user_lifetime = "1h";
}; };
dataDir = "/nix/var/data/matrix-synapse";
extraConfigFiles = [ "/run/synapse/synapse-db-config.yaml" ];
};
services.coturn = rec { services.coturn = rec {
enable = true; enable = true;
no-cli = true; no-cli = true;
no-tcp-relay = true; no-tcp-relay = true;
min-port = 49000; min-port = 49000;
max-port = 50000; max-port = 50000;
use-auth-secret = true; use-auth-secret = true;
static-auth-secret-file = config.sops.secrets.turnSharedSecret.path; static-auth-secret-file = config.sops.secrets.turnSharedSecret.path;
realm = "turn.${config.networking.domain}"; realm = "turn.${config.networking.domain}";
cert = "${config.security.acme.certs.${realm}.directory}/full.pem"; cert = "${config.security.acme.certs.${realm}.directory}/full.pem";
pkey = "${config.security.acme.certs.${realm}.directory}/key.pem"; pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
extraConfig = '' extraConfig = ''
# for debugging # for debugging
verbose verbose
# ban private IP ranges # ban private IP ranges
no-multicast-peers no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255 denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255 denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255 denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255 denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255 denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255 denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255 denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255 denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255 denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255 denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255 denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255 denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255 denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1 denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255 denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
''; '';
}; };
networking.firewall = networking.firewall = let
let
range = with config.services.coturn; [{ range = with config.services.coturn; [{
from = min-port; from = min-port;
to = max-port; to = max-port;
}]; }];
in in {
{
allowedUDPPortRanges = range; allowedUDPPortRanges = range;
allowedUDPPorts = [ 3478 ]; allowedUDPPorts = [ 3478 ];
allowedTCPPortRanges = range; allowedTCPPortRanges = range;
allowedTCPPorts = [ 3478 ]; allowedTCPPorts = [ 3478 ];
}; };
security.acme.certs.${config.services.coturn.realm} = {
security.acme.certs.${config.services.coturn.realm} = { postRun = "systemctl restart coturn.service";
postRun = "systemctl restart coturn.service"; group = "turnserver";
group = "turnserver"; };
}; };
} }

View file

@ -1,227 +1,234 @@
{ config, lib, pkgs, ... }: { { config, lib, pkgs, ... }:
let cfg = config.custom.services.torrents;
sops.secrets = { in {
vpnCredentials = { key = "openvpn/credentials"; }; options.custom.services.torrents = {
transmissionRpcCredentials = { key = "transmission/rpc_config.json"; }; enable = lib.mkEnableOption "torrents";
}; };
containers.torrents = { config = lib.mkIf cfg.enable {
ephemeral = true; sops.secrets = {
autoStart = true; vpnCredentials = { key = "openvpn/credentials"; };
enableTun = true; transmissionRpcCredentials = { key = "transmission/rpc_config.json"; };
privateNetwork = true;
hostAddress = "192.168.1.1";
localAddress = "192.168.1.2";
bindMounts = {
"${config.sops.secrets.vpnCredentials.path}" = {
hostPath = config.sops.secrets.vpnCredentials.path;
};
"${config.sops.secrets.transmissionRpcCredentials.path}" = {
hostPath = config.sops.secrets.transmissionRpcCredentials.path;
};
"/nix/var/data/media" = {
hostPath = "/nix/var/data/media";
isReadOnly = false;
};
"/nix/var/data/jackett" = {
hostPath = "/nix/var/data/jackett";
isReadOnly = false;
};
"/nix/var/data/sonarr" = {
hostPath = "/nix/var/data/sonarr";
isReadOnly = false;
};
"/nix/var/data/radarr" = {
hostPath = "/nix/var/data/radarr";
isReadOnly = false;
};
"/nix/var/data/lidarr" = {
hostPath = "/nix/var/data/lidarr";
isReadOnly = false;
};
"/nix/var/data/transmission" = {
hostPath = "/nix/var/data/transmission";
isReadOnly = false;
};
}; };
config = { containers.torrents = {
time.timeZone = "Europe/Amsterdam"; ephemeral = true;
users.users.www-data = { autoStart = true;
uid = 993; enableTun = true;
isSystemUser = true;
group = config.users.groups.www-data.name;
};
users.groups.www-data = { gid = 991; };
services.openvpn.servers.client = {
updateResolvConf = true;
config = ''
client
dev tun
resolv-retry infinite
nobind
persist-key
persist-tun
verb 3
remote-cert-tls server
ping 10
ping-restart 60
sndbuf 524288
rcvbuf 524288
cipher AES-256-CBC
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA
proto udp
<ca>
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
</ca>
tun-ipv6
script-security 2
fast-io
remote-random
remote de-fra-101.mullvad.net 1194
remote de-fra-201.mullvad.net 1194
remote de-fra-009.mullvad.net 1194
remote de-fra-002.mullvad.net 1194
remote de-fra-202.mullvad.net 1194
remote de-fra-005.mullvad.net 1194
remote de-fra-203.mullvad.net 1194
remote de-fra-003.mullvad.net 1194
remote de-fra-004.mullvad.net 1194
remote de-fra-008.mullvad.net 1194
remote de-fra-006.mullvad.net 1194
remote de-fra-007.mullvad.net 1194
remote de-fra-102.mullvad.net 1194
auth-user-pass ${config.sops.secrets.vpnCredentials.path}
'';
};
services.transmission = { privateNetwork = true;
enable = true; hostAddress = "192.168.1.1";
openRPCPort = true; localAddress = "192.168.1.2";
user = config.users.users.www-data.name;
group = config.users.groups.www-data.name; bindMounts = {
credentialsFile = config.sops.secrets.transmissionRpcCredentials.path; "${config.sops.secrets.vpnCredentials.path}" = {
home = "/nix/var/data/transmission"; hostPath = config.sops.secrets.vpnCredentials.path;
settings = { };
rpc-bind-address = "0.0.0.0"; "${config.sops.secrets.transmissionRpcCredentials.path}" = {
rpc-whitelist = "127.0.0.1,192.168.1.1"; hostPath = config.sops.secrets.transmissionRpcCredentials.path;
rpc-authentication-required = true; };
rpc-host-whitelist-enabled = false; "/nix/var/data/media" = {
incomplete-dir = "/nix/var/data/transmission/.incomplete"; hostPath = "/nix/var/data/media";
watch-dir = "/nix/var/data/transmission/watchdir"; isReadOnly = false;
download-dir = "/nix/var/data/transmission/downloads"; };
"/nix/var/data/jackett" = {
hostPath = "/nix/var/data/jackett";
isReadOnly = false;
};
"/nix/var/data/sonarr" = {
hostPath = "/nix/var/data/sonarr";
isReadOnly = false;
};
"/nix/var/data/radarr" = {
hostPath = "/nix/var/data/radarr";
isReadOnly = false;
};
"/nix/var/data/lidarr" = {
hostPath = "/nix/var/data/lidarr";
isReadOnly = false;
};
"/nix/var/data/transmission" = {
hostPath = "/nix/var/data/transmission";
isReadOnly = false;
}; };
}; };
systemd.services.transmission.serviceConfig.BindReadOnlyPaths =
lib.mkForce [
builtins.storeDir
"/etc"
]; # https://github.com/NixOS/nixpkgs/issues/258793
services.jackett = { config = {
enable = true; time.timeZone = "Europe/Amsterdam";
openFirewall = true; users.users.www-data = {
user = config.users.users.www-data.name; uid = 993;
group = config.users.groups.www-data.name; isSystemUser = true;
dataDir = "/nix/var/data/jackett"; group = config.users.groups.www-data.name;
}; };
services.sonarr = { users.groups.www-data = { gid = 991; };
enable = true; services.openvpn.servers.client = {
openFirewall = true; updateResolvConf = true;
user = config.users.users.www-data.name; config = ''
group = config.users.groups.www-data.name; client
dataDir = "/nix/var/data/sonarr"; dev tun
}; resolv-retry infinite
services.radarr = { nobind
enable = true; persist-key
openFirewall = true; persist-tun
user = config.users.users.www-data.name; verb 3
group = config.users.groups.www-data.name; remote-cert-tls server
dataDir = "/nix/var/data/radarr"; ping 10
}; ping-restart 60
services.lidarr = { sndbuf 524288
enable = true; rcvbuf 524288
openFirewall = true; cipher AES-256-CBC
user = config.users.users.www-data.name; tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA
group = config.users.groups.www-data.name; proto udp
dataDir = "/nix/var/data/lidarr"; <ca>
}; -----BEGIN CERTIFICATE-----
MIIGIzCCBAugAwIBAgIJAK6BqXN9GHI0MA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
VQQGEwJTRTERMA8GA1UECAwIR290YWxhbmQxEzARBgNVBAcMCkdvdGhlbmJ1cmcx
FDASBgNVBAoMC0FtYWdpY29tIEFCMRAwDgYDVQQLDAdNdWxsdmFkMRswGQYDVQQD
DBJNdWxsdmFkIFJvb3QgQ0EgdjIxIzAhBgkqhkiG9w0BCQEWFHNlY3VyaXR5QG11
bGx2YWQubmV0MB4XDTE4MTEwMjExMTYxMVoXDTI4MTAzMDExMTYxMVowgZ8xCzAJ
BgNVBAYTAlNFMREwDwYDVQQIDAhHb3RhbGFuZDETMBEGA1UEBwwKR290aGVuYnVy
ZzEUMBIGA1UECgwLQW1hZ2ljb20gQUIxEDAOBgNVBAsMB011bGx2YWQxGzAZBgNV
BAMMEk11bGx2YWQgUm9vdCBDQSB2MjEjMCEGCSqGSIb3DQEJARYUc2VjdXJpdHlA
bXVsbHZhZC5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCifDn7
5E/Zdx1qsy31rMEzuvbTXqZVZp4bjWbmcyyXqvnayRUHHoovG+lzc+HDL3HJV+kj
xKpCMkEVWwjY159lJbQbm8kkYntBBREdzRRjjJpTb6haf/NXeOtQJ9aVlCc4dM66
bEmyAoXkzXVZTQJ8h2FE55KVxHi5Sdy4XC5zm0wPa4DPDokNp1qm3A9Xicq3Hsfl
LbMZRCAGuI+Jek6caHqiKjTHtujn6Gfxv2WsZ7SjerUAk+mvBo2sfKmB7octxG7y
AOFFg7YsWL0AxddBWqgq5R/1WDJ9d1Cwun9WGRRQ1TLvzF1yABUerjjKrk89RCzY
ISwsKcgJPscaDqZgO6RIruY/xjuTtrnZSv+FXs+Woxf87P+QgQd76LC0MstTnys+
AfTMuMPOLy9fMfEzs3LP0Nz6v5yjhX8ff7+3UUI3IcMxCvyxdTPClY5IvFdW7CCm
mLNzakmx5GCItBWg/EIg1K1SG0jU9F8vlNZUqLKz42hWy/xB5C4QYQQ9ILdu4ara
PnrXnmd1D1QKVwKQ1DpWhNbpBDfE776/4xXD/tGM5O0TImp1NXul8wYsDi8g+e0p
xNgY3Pahnj1yfG75Yw82spZanUH0QSNoMVMWnmV2hXGsWqypRq0pH8mPeLzeKa82
gzsAZsouRD1k8wFlYA4z9HQFxqfcntTqXuwQcQIDAQABo2AwXjAdBgNVHQ4EFgQU
faEyaBpGNzsqttiSMETq+X/GJ0YwHwYDVR0jBBgwFoAUfaEyaBpGNzsqttiSMETq
+X/GJ0YwCwYDVR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggIBADH5izxu4V8Javal8EA4DxZxIHUsWCg5cuopB28PsyJYpyKipsBoI8+R
XqbtrLLue4WQfNPZHLXlKi+A3GTrLdlnenYzXVipPd+n3vRZyofaB3Jtb03nirVW
Ga8FG21Xy/f4rPqwcW54lxrnnh0SA0hwuZ+b2yAWESBXPxrzVQdTWCqoFI6/aRnN
8RyZn0LqRYoW7WDtKpLmfyvshBmmu4PCYSh/SYiFHgR9fsWzVcxdySDsmX8wXowu
Ffp8V9sFhD4TsebAaplaICOuLUgj+Yin5QzgB0F9Ci3Zh6oWwl64SL/OxxQLpzMW
zr0lrWsQrS3PgC4+6JC4IpTXX5eUqfSvHPtbRKK0yLnd9hYgvZUBvvZvUFR/3/fW
+mpBHbZJBu9+/1uux46M4rJ2FeaJUf9PhYCPuUj63yu0Grn0DreVKK1SkD5V6qXN
0TmoxYyguhfsIPCpI1VsdaSWuNjJ+a/HIlKIU8vKp5iN/+6ZTPAg9Q7s3Ji+vfx/
AhFtQyTpIYNszVzNZyobvkiMUlK+eUKGlHVQp73y6MmGIlbBbyzpEoedNU4uFu57
mw4fYGHqYZmYqFaiNQv4tVrGkg6p+Ypyu1zOfIHF7eqlAOu/SyRTvZkt9VtSVEOV
H7nDIGdrCC9U/g1Lqk8Td00Oj8xesyKzsG214Xd8m7/7GmJ7nXe5
-----END CERTIFICATE-----
</ca>
tun-ipv6
script-security 2
fast-io
remote-random
remote de-fra-101.mullvad.net 1194
remote de-fra-201.mullvad.net 1194
remote de-fra-009.mullvad.net 1194
remote de-fra-002.mullvad.net 1194
remote de-fra-202.mullvad.net 1194
remote de-fra-005.mullvad.net 1194
remote de-fra-203.mullvad.net 1194
remote de-fra-003.mullvad.net 1194
remote de-fra-004.mullvad.net 1194
remote de-fra-008.mullvad.net 1194
remote de-fra-006.mullvad.net 1194
remote de-fra-007.mullvad.net 1194
remote de-fra-102.mullvad.net 1194
auth-user-pass ${config.sops.secrets.vpnCredentials.path}
'';
};
system.stateVersion = "21.11"; services.transmission = {
}; enable = true;
}; openRPCPort = true;
user = config.users.users.www-data.name;
group = config.users.groups.www-data.name;
credentialsFile = config.sops.secrets.transmissionRpcCredentials.path;
home = "/nix/var/data/transmission";
settings = {
rpc-bind-address = "0.0.0.0";
rpc-whitelist = "127.0.0.1,192.168.1.1";
rpc-authentication-required = true;
rpc-host-whitelist-enabled = false;
incomplete-dir = "/nix/var/data/transmission/.incomplete";
watch-dir = "/nix/var/data/transmission/watchdir";
download-dir = "/nix/var/data/transmission/downloads";
};
};
systemd.services.transmission.serviceConfig.BindReadOnlyPaths =
lib.mkForce [
builtins.storeDir
"/etc"
]; # https://github.com/NixOS/nixpkgs/issues/258793
virtualisation.oci-containers.containers.flaresolverr = { services.jackett = {
image = "ghcr.io/flaresolverr/flaresolverr:v3.3.11"; enable = true;
environment = { openFirewall = true;
"LOG_LEVEL" = "debug"; user = config.users.users.www-data.name;
"CAPTCHA_SOLVER" = "hcaptcha-solver"; group = config.users.groups.www-data.name;
}; dataDir = "/nix/var/data/jackett";
ports = [ "192.168.1.1:8191:8191" ]; };
autoStart = true; services.sonarr = {
}; enable = true;
openFirewall = true;
user = config.users.users.www-data.name;
group = config.users.groups.www-data.name;
dataDir = "/nix/var/data/sonarr";
};
services.radarr = {
enable = true;
openFirewall = true;
user = config.users.users.www-data.name;
group = config.users.groups.www-data.name;
dataDir = "/nix/var/data/radarr";
};
services.lidarr = {
enable = true;
openFirewall = true;
user = config.users.users.www-data.name;
group = config.users.groups.www-data.name;
dataDir = "/nix/var/data/lidarr";
};
services.nginx.virtualHosts = { system.stateVersion = "21.11";
"transmission.${config.networking.domain}" = { };
forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://192.168.1.2:9091"; };
}; };
"jackett.${config.networking.domain}" = {
forceSSL = true; virtualisation.oci-containers.containers.flaresolverr = {
enableACME = true; image = "ghcr.io/flaresolverr/flaresolverr:v3.3.11";
locations."/" = { proxyPass = "http://192.168.1.2:9117"; }; environment = {
"LOG_LEVEL" = "debug";
"CAPTCHA_SOLVER" = "hcaptcha-solver";
};
ports = [ "192.168.1.1:8191:8191" ];
autoStart = true;
}; };
"sonarr.${config.networking.domain}" = {
forceSSL = true; services.nginx.virtualHosts = {
enableACME = true; "transmission.${config.networking.domain}" = {
locations."/" = { proxyPass = "http://192.168.1.2:8989"; }; forceSSL = true;
}; enableACME = true;
"radarr.${config.networking.domain}" = { locations."/" = { proxyPass = "http://192.168.1.2:9091"; };
forceSSL = true; };
enableACME = true; "jackett.${config.networking.domain}" = {
locations."/" = { proxyPass = "http://192.168.1.2:7878"; }; forceSSL = true;
}; enableACME = true;
"lidarr.${config.networking.domain}" = { locations."/" = { proxyPass = "http://192.168.1.2:9117"; };
forceSSL = true; };
enableACME = true; "sonarr.${config.networking.domain}" = {
locations."/" = { proxyPass = "http://192.168.1.2:8686"; }; forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://192.168.1.2:8989"; };
};
"radarr.${config.networking.domain}" = {
forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://192.168.1.2:7878"; };
};
"lidarr.${config.networking.domain}" = {
forceSSL = true;
enableACME = true;
locations."/" = { proxyPass = "http://192.168.1.2:8686"; };
};
}; };
}; };
} }

View file

@ -1,8 +0,0 @@
{ config, lib, pkgs, ... }:
{
services.nginx.virtualHosts."osteopathie.froidmont.org" = {
enableACME = true;
forceSSL = true;
root = "/nix/var/data/website-marie";
};
}

View file

@ -1,16 +1,5 @@
{ config, lib, pkgs, ... }: { { config, lib, pkgs, ... }: {
imports = [ imports = [ ../environment.nix ../hardware/hcloud.nix ../modules ];
../environment.nix
../hardware/hcloud.nix
../modules
../modules/nginx.nix
../modules/synapse.nix
../modules/nextcloud.nix
../modules/dokuwiki.nix
../modules/website-marie.nix
../modules/roundcube.nix
../modules/monitoring-exporters.nix
];
sops.secrets = { sops.secrets = {
borgSshKey = { borgSshKey = {
@ -20,6 +9,7 @@
}; };
custom = { custom = {
services.backup-job = { services.backup-job = {
enable = true; enable = true;
repoName = "bk1"; repoName = "bk1";
@ -63,13 +53,15 @@
''; '';
}; };
services.nginx.enable = true;
services.dokuwiki.enable = true; services.dokuwiki.enable = true;
services.openssh.enable = true; services.openssh.enable = true;
services.murmur.enable = true; services.murmur.enable = true;
services.mastodon.enable = false; services.mastodon.enable = false;
services.synapse.enable = true;
services.nextcloud.enable = true;
services.roundcube.enable = true;
services.monitoring-exporters.enable = true;
}; };
services.uptime-kuma = { services.uptime-kuma = {
@ -77,34 +69,42 @@
settings = { PORT = "3001"; }; settings = { PORT = "3001"; };
}; };
services.nginx.virtualHosts."uptime.froidmont.org" = { services.nginx.virtualHosts = {
serverAliases = [ "status.${config.networking.domain}" ]; "osteopathie.froidmont.org" = {
forceSSL = true; enableACME = true;
enableACME = true; forceSSL = true;
root = "/nix/var/data/website-marie";
locations."/" = {
proxyPass =
"http://127.0.0.1:${config.services.uptime-kuma.settings.PORT}";
proxyWebsockets = true;
}; };
};
services.nginx.virtualHosts."www.fautlfer.com" = { "uptime.froidmont.org" = {
enableACME = true; serverAliases = [ "status.${config.networking.domain}" ];
forceSSL = true; forceSSL = true;
enableACME = true;
locations."= /".extraConfig = '' locations."/" = {
return 302 https://blogz.zaclys.com/faut-l-fer/; proxyPass =
''; "http://127.0.0.1:${config.services.uptime-kuma.settings.PORT}";
}; proxyWebsockets = true;
};
};
services.nginx.virtualHosts."fautlfer.com" = { "www.fautlfer.com" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations."= /".extraConfig = '' locations."= /".extraConfig = ''
return 302 https://blogz.zaclys.com/faut-l-fer/; return 302 https://blogz.zaclys.com/faut-l-fer/;
''; '';
};
"fautlfer.com" = {
enableACME = true;
forceSSL = true;
locations."= /".extraConfig = ''
return 302 https://blogz.zaclys.com/faut-l-fer/;
'';
};
}; };
networking.firewall.allowedTCPPorts = [ 80 443 64738 ]; networking.firewall.allowedTCPPorts = [ 80 443 64738 ];

View file

@ -1,11 +1,5 @@
{ config, lib, pkgs, ... }: { { config, lib, pkgs, ... }: {
imports = [ imports = [ ../environment.nix ../hardware/hcloud.nix ../modules ];
../environment.nix
../hardware/hcloud.nix
../modules
../modules/postgresql.nix
../modules/monitoring-exporters.nix
];
networking.firewall.interfaces."eth1".allowedTCPPorts = [ networking.firewall.interfaces."eth1".allowedTCPPorts = [
config.services.prometheus.exporters.node.port config.services.prometheus.exporters.node.port
@ -35,6 +29,8 @@
}; };
services.openssh.enable = true; services.openssh.enable = true;
services.postgresql.enable = true;
services.monitoring-exporters.enable = true;
}; };
} }

View file

@ -3,17 +3,6 @@
../environment.nix ../environment.nix
../hardware/hetzner-dedicated-storage1.nix ../hardware/hetzner-dedicated-storage1.nix
../modules ../modules
../modules/openssh.nix
../modules/mailserver.nix
../modules/nginx.nix
../modules/jellyfin.nix
../modules/stb.nix
../modules/monero.nix
../modules/torrents.nix
../modules/jitsi.nix
../modules/binary-cache.nix
../modules/grafana.nix
../modules/monitoring-exporters.nix
]; ];
sops.secrets = { sops.secrets = {
@ -23,6 +12,17 @@
}; };
nixCacheKey = { key = "nix/cache_secret_key"; }; nixCacheKey = { key = "nix/cache_secret_key"; };
dmarcExporterPassword = { key = "dmarc_exporter/password"; }; dmarcExporterPassword = { key = "dmarc_exporter/password"; };
paultrialPassword = { key = "email/accounts_passwords/paultrial"; };
eliosPassword = { key = "email/accounts_passwords/elios"; };
mariePassword = { key = "email/accounts_passwords/marie"; };
alicePassword = { key = "email/accounts_passwords/alice"; };
monitPassword = { key = "email/accounts_passwords/monit"; };
noreplyBanditlairPassword = {
key = "email/accounts_passwords/noreply_banditlair";
};
noreplyFroidmontPassword = {
key = "email/accounts_passwords/noreply_froidmont";
};
}; };
custom = { custom = {
@ -95,8 +95,80 @@
''; '';
}; };
services.nginx.enable = true;
services.gitlab-runner.enable = true; services.gitlab-runner.enable = true;
services.openssh.enable = true; services.openssh.enable = true;
services.jellyfin.enable = true;
services.stb.enable = true;
services.monero.enable = true;
services.torrents.enable = true;
services.jitsi.enable = true;
services.grafana.enable = true;
services.monitoring-exporters.enable = true;
};
mailserver = {
enable = true;
fqdn = "mail.banditlair.com";
domains = [ "banditlair.com" "froidmont.org" "falbo.fr" ];
localDnsResolver = false;
enableManageSieve = true;
mailDirectory = "/nix/var/data/vmail";
sieveDirectory = "/nix/var/data/sieve";
lmtpSaveToDetailMailbox = "no";
policydSPFExtraConfig = ''
Domain_Whitelist = skynet.be
'';
loginAccounts = {
"paultrial@banditlair.com" = {
# nix run nixpkgs.apacheHttpd -c htpasswd -nbB "" "super secret password" | cut -d: -f2 > /hashed/password/file/location
hashedPasswordFile = config.sops.secrets.paultrialPassword.path;
aliases = [ "contact@froidmont.org" "account@banditlair.com" ];
};
"marie-alice@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.mariePassword.path;
aliases = [ "osteopathie@froidmont.org" "communication@froidmont.org" ];
};
"alice@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.alicePassword.path;
};
"elios@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.eliosPassword.path;
aliases = [ "webshit@banditlair.com" "outlook-pascal@banditlair.com" ];
};
"monit@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.monitPassword.path;
sendOnly = true;
};
"noreply@banditlair.com" = {
hashedPasswordFile = config.sops.secrets.noreplyBanditlairPassword.path;
sendOnly = true;
};
"noreply@froidmont.org" = {
hashedPasswordFile = config.sops.secrets.noreplyFroidmontPassword.path;
sendOnly = true;
};
};
extraVirtualAliases = {
"info@banditlair.com" = "paultrial@banditlair.com";
"postmaster@banditlair.com" = "paultrial@banditlair.com";
"abuse@banditlair.com" = "paultrial@banditlair.com";
"info@froidmont.org" = "paultrial@banditlair.com";
"postmaster@froidmont.org" = "paultrial@banditlair.com";
"abuse@froidmont.org" = "paultrial@banditlair.com";
"info@falbo.fr" = "paultrial@banditlair.com";
"postmaster@falbo.fr" = "paultrial@banditlair.com";
"abuse@falbo.fr" = "paultrial@banditlair.com";
#Catch all
"@banditlair.com" = "paultrial@banditlair.com";
"@froidmont.org" = "paultrial@banditlair.com";
"@falbo.fr" = "elios@banditlair.com";
};
certificateScheme = "acme-nginx";
}; };
services.prometheus.exporters.dmarc = { services.prometheus.exporters.dmarc = {