feat[server]: also proxy roundcube

This commit is contained in:
Leon Schwarzäugl 2025-12-23 01:52:26 +01:00 committed by Leon Schwarzäugl
parent 1502faf345
commit b06c19c52b
24 changed files with 436 additions and 216 deletions

View file

@ -33,6 +33,8 @@
endme
git-replace
prstatus
swarsel-gens
swarsel-switch
];
};
}

View file

@ -127,6 +127,7 @@ in
additions = final: _: import "${self}/pkgs/config" {
inherit self config lib;
pkgs = final;
nixosConfig = config;
homeConfig = config.home-manager.users.${config.swarselsystems.mainUser};
};
in

View file

@ -0,0 +1,45 @@
{ self, pkgs, lib, config, globals, ... }:
let
inherit (config.repo.secrets.common) dnsProvider dnsBase dnsMail;
sopsFile = self + "/secrets/nginx/acme.json";
in
{
options.swarselmodules.server.acme = lib.mkEnableOption "enable acme on server";
config = lib.mkIf config.swarselmodules.server.acme {
environment.systemPackages = with pkgs; [
lego
];
sops = {
secrets = {
acme-creds = { format = "json"; key = ""; group = "acme"; inherit sopsFile; mode = "0660"; };
};
templates."certs.secret".content = ''
ACME_DNS_API_BASE = ${dnsBase}
ACME_DNS_STORAGE_PATH=${config.sops.secrets.acme-creds.path}
'';
};
users.groups.acme.members = lib.mkIf config.swarselmodules.server.nginx [ "nginx" ];
security.acme = {
acceptTerms = true;
defaults = {
inherit dnsProvider;
email = dnsMail;
environmentFile = "${config.sops.templates."certs.secret".path}";
reloadServices = [ "nginx" ];
dnsPropagationCheck = true;
};
certs."${globals.domains.main}" = {
domain = "*.${globals.domains.main}";
};
};
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
directories = [{ directory = "/var/lib/acme"; }];
};
};
}

View file

@ -1,9 +1,13 @@
{ lib, config, globals, dns, confLib, ... }:
let
inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceDomain serviceProxy proxyAddress4 proxyAddress6;
inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain serviceProxy proxyAddress4 proxyAddress6;
inherit (config.repo.secrets.local.mailserver) user1 alias1_1 alias1_2 alias1_3 alias1_4 user2 alias2_1 alias2_2 user3;
baseDomain = globals.domains.main;
roundcubeDomain = config.repo.secrets.common.services.domains.roundcube;
endpointAddress4 = globals.hosts.${config.node.name}.wanAddress4 or null;
endpointAddress6 = globals.hosts.${config.node.name}.wanAddress6 or null;
in
{
options = {
@ -12,12 +16,20 @@ in
config = lib.mkIf config.swarselmodules.server.${serviceName} {
nodes.stoicclub.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host endpointAddress4 endpointAddress6;
"${globals.services.roundcube.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
globals.services.${serviceName} = {
domain = serviceDomain;
inherit proxyAddress4 proxyAddress6;
globals.services = {
${serviceName} = {
domain = serviceDomain;
proxyAddress4 = endpointAddress4;
proxyAddress6 = endpointAddress6;
};
roundcube = {
domain = roundcubeDomain;
inherit proxyAddress4 proxyAddress6;
};
};
sops.secrets = {
@ -83,7 +95,7 @@ in
enable = true;
# this is the url of the vhost, not necessarily the same as the fqdn of
# the mailserver
hostName = serviceDomain;
hostName = roundcubeDomain;
extraConfig = ''
$config['imap_host'] = "ssl://${config.mailserver.fqdn}";
$config['smtp_host'] = "ssl://${config.mailserver.fqdn}";
@ -96,10 +108,11 @@ in
# the rest of the ports are managed by snm
networking.firewall.allowedTCPPorts = [ 80 servicePort ];
nodes.${serviceProxy}.services.nginx = {
services.nginx = {
virtualHosts = {
"${serviceDomain}" = {
enableACME = true;
"${roundcubeDomain}" = {
useACMEHost = globals.domains.main;
enableACME = false;
forceSSL = true;
acmeRoot = null;
locations = {
@ -112,5 +125,31 @@ in
};
};
nodes.${serviceProxy}.services.nginx = {
upstreams = {
${serviceName} = {
servers = {
"${serviceAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${roundcubeDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations = {
"/" = {
proxyPass = "https://${serviceName}";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
};
};
};
}

View file

@ -1,7 +1,5 @@
{ pkgs, lib, config, globals, ... }:
{ pkgs, lib, config, ... }:
let
inherit (config.repo.secrets.common) dnsProvider dnsBase dnsMail;
serviceUser = "nginx";
serviceGroup = serviceUser;
@ -81,40 +79,12 @@ in
};
};
config = lib.mkIf config.swarselmodules.server.nginx {
environment.systemPackages = with pkgs; [
lego
];
sops = lib.mkIf (config.node.name == config.swarselsystems.proxyHost) {
secrets = {
acme-creds = { format = "json"; key = ""; group = "acme"; sopsFile = config.node.secretsDir + "/acme.json"; mode = "0660"; };
};
templates."certs.secret".content = ''
ACME_DNS_API_BASE = ${dnsBase}
ACME_DNS_STORAGE_PATH=${config.sops.secrets.acme-creds.path}
'';
};
users.groups.acme.members = [ "nginx" ];
security.acme = lib.mkIf (config.node.name == config.swarselsystems.proxyHost) {
acceptTerms = true;
defaults = {
inherit dnsProvider;
email = dnsMail;
environmentFile = "${config.sops.templates."certs.secret".path}";
reloadServices = [ "nginx" ];
dnsPropagationCheck = true;
};
certs."${globals.domains.main}" = {
domain = "*.${globals.domains.main}";
};
};
swarselmodules.server.acme = lib.mkDefault true;
networking.firewall.allowedTCPPorts = [ 80 443 ];
environment.persistence."/persist" = lib.mkIf config.swarselsystems.isImpermanence {
directories = [{ directory = "/var/lib/acme"; }];
files = [ dhParamsPathBase ];
};

View file

@ -3,7 +3,7 @@ with dns.lib.combinators; {
SOA = {
nameServer = "soa";
adminEmail = "admin@${globals.domains.main}"; # this option is not parsed as domain (we cannot just write "admin")
serial = 2025120506; # update this on changes for secondary dns
serial = 2025122204; # update this on changes for secondary dns
};
useOrigin = false;
@ -13,7 +13,23 @@ with dns.lib.combinators; {
"srv"
] ++ globals.domains.externalDns;
CAA = letsEncrypt config.repo.secrets.common.dnsMail;
CAA = [
{
issuerCritical = false;
tag = "issue";
value = "letsencrypt.org";
}
{
issuerCritical = false;
tag = "issuewild";
value = "letsencrypt.org";
}
{
issuerCritical = false;
tag = "iodef";
value = "mailto:${config.repo.secrets.common.dnsMail}";
}
];
A = [ config.repo.secrets.local.dns.homepage-ip ];

View file

@ -14,6 +14,9 @@
swarsel-deploy
tmux
busybox
attic-client
swarsel-gens
swarsel-switch
];
};
}