This commit is contained in:
Henry Hiles 2025-07-21 20:28:06 -04:00
commit cb4b7e370d
No known key found for this signature in database
8 changed files with 366 additions and 23 deletions

View file

@ -1,12 +1,19 @@
{pkgs, ...}: {
{
pkgs,
lib,
...
}: {
networking.firewall.allowedTCPPorts = [443];
services.caddy = {
enable = true;
email = "henry@henryhiles.com";
services = {
nginx.enable = lib.mkForce false;
caddy = {
enable = true;
email = "hen" + "ry@he" + "nryhi" + "les.c" + "om";
package = pkgs.caddy.withPlugins {
plugins = ["github.com/ggicci/caddy-jwt@v1.1.0"];
hash = "sha256-sdhX/dAQ7lIxBo/ZW6XYX8SRuacLO9HobtIVKD/cw0o=";
package = pkgs.caddy.withPlugins {
plugins = ["github.com/ggicci/caddy-jwt@v1.1.0"];
hash = "sha256-sdhX/dAQ7lIxBo/ZW6XYX8SRuacLO9HobtIVKD/cw0o=";
};
};
};
}

View file

@ -0,0 +1,47 @@
{
lib,
config,
...
}: {
services = let
domain = lib.head config.mailserver.domains;
fqdn = config.mailserver.fqdn;
in {
caddy.virtualHosts = {
"autoconfig.${domain}" = {
serverAliases = ["autodiscover.${domain}"];
extraConfig = let
proxy = "reverse_proxy 127.0.0.1:${toString config.services.automx2.port}";
in ''
route {
handle_path /initdb* {
@not_local not remote_ip 127.0.0.1
abort @not_local
${proxy}
}
${proxy}
}
'';
};
};
automx2 = {
enable = true;
inherit domain;
settings = {
provider = "Federated Nexus";
domains = [domain];
servers = [
{
type = "imap";
name = fqdn;
}
{
type = "smtp";
name = fqdn;
}
];
};
};
};
}

View file

@ -0,0 +1,37 @@
{
config,
inputs,
...
}: let
domain = "federated.nexus";
fqdn = "mail.${domain}";
certDir = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${fqdn}";
in {
imports = [inputs.mailserver.nixosModule];
mailserver = {
enable = true;
stateVersion = 3;
inherit fqdn;
domains = [domain];
localDnsResolver = false;
certificateScheme = "manual";
certificateFile = "${certDir}/${fqdn}.crt";
keyFile = "${certDir}/${fqdn}.key";
oauth2 = let
auth = "https://auth.federated.nexus";
in {
enable = true;
introspection = {
url = "${auth}/introspect";
mode = "post";
};
oidc.configuration_url = "${auth}/.well-known/openid-configuration";
};
};
services.dovecot2.group = config.services.caddy.group;
}

View file

@ -0,0 +1,122 @@
{
lib,
pkgs,
config,
...
}: {
nixpkgs.overlays = [
(final: prev: {
sogo = prev.sogo.overrideAttrs (old: {
buildInputs = old.buildInputs ++ [prev.postgresql.lib];
NIX_LDFLAGS = (old.NIX_LDFLAGS or "") + " -lpq";
});
})
];
services = let
domain = "mail.federated.nexus";
in {
memcached = {
enable = true;
user = "sogo";
enableUnixSocket = true;
extraOptions = [
"-a"
"0600"
];
};
postgresql = {
enable = true;
enableTCPIP = true;
ensureDatabases = ["sogo"];
ensureUsers = [
{
name = "sogo";
ensureDBOwnership = true;
}
];
};
sogo = {
enable = true;
timezone = config.time.timeZone;
extraConfig = let
db = "postgresql://sogo@127.0.0.1/sogo";
in ''
SOGoMailDomain = "federated.nexus";
SOGoMemcachedHost = "/run/memcached/memcached.sock";
SOGoAuthenticationType = "openid";
SOGoOpenIdConfigUrl = "https://auth.federated.nexus/.well-known/openid-configuration";
SOGoOpenIdClient = "Federated Nexus Auth";
SOGoOpenIdClientSecret = "";
SOGoOpenIdScope = "";
SOGoOpenIdTokenCheckInterval = 600;
SOGoSMTPServer = "smtp://localhost";
SOGoSMTPAuthenticationType = "xoauth2";
SOGoIMAPServer = "imap://localhost";
NGImap4AuthMechanism = "xoauth2";
SOGoPageTitle = "Federated Nexus Mail";
SOGoZipPath = "${lib.getExe pkgs.zip}";
OCSSessionsFolderURL = "${db}/sogo_sessions_folder";
OCSFolderInfoURL = "${db}/sogo_folder_info";
OCSOpenIdURL = "${db}/sogo_openid";
MySQL4Encoding = "utf8mb4";
'';
};
caddy.virtualHosts."${domain}".extraConfig = ''
# Redirect root to /SOGo
@root path /
redir @root https://{host}/SOGo
# Redirect /principals/ to /SOGo/dav
@principals path /principals/*
redir @principals https://{host}/SOGo/dav
# Static assets for SOGo
handle_path /SOGo.woa/WebServerResources/* {
root * ${pkgs.sogo}/lib/GNUstep/SOGo/WebServerResources/
file_server
}
handle_path /SOGo/WebServerResources/* {
root * ${pkgs.sogo}/lib/GNUstep/SOGo/
file_server
}
# Regex match: ControlPanel products
@resources1 path_regexp resources1 ^/SOGo/so/ControlPanel/Products/([^/]*)/Resources/(.*)$
handle @resources1 {
root * ${pkgs.sogo}/lib/GNUstep/SOGo/{http.regexp.resources1.1}.SOGo/Resources/
rewrite * /{http.regexp.resources1.2}
file_server
}
# Regex match: ControlPanel UI resources
@resources2 path_regexp resources2 ^/SOGo/so/ControlPanel/Products/([^/]*)UI/Resources/(.*\.(jpg|png|gif|css|js))$
handle @resources2 {
root * ${pkgs.sogo}/lib/GNUstep/SOGo/{http.regexp.resources2.1}UI.SOGo/Resources/
rewrite * /{http.regexp.resources2.2}
file_server
}
# SOGo app proxy
handle_path /SOGo* {
reverse_proxy 127.0.0.1:20000 {
header_up x-webobjects-server-protocol HTTP/1.0
header_up x-webobjects-remote-host 127.0.0.1
header_up x-webobjects-server-port {server_port}
header_up x-webobjects-server-name {host}
header_up x-webobjects-server-url {scheme}://{host}
}
}
'';
};
}