diff --git a/hosts/frikandel/email.nix b/hosts/frikandel/email.nix index 19e509b..c52b667 100644 --- a/hosts/frikandel/email.nix +++ b/hosts/frikandel/email.nix @@ -1,20 +1,55 @@ { + flake, + config, pkgs, lib, - flake, ... -}: { +}: let + restartMaddyOnCertRenewal = pkgs.writeShellScriptBin "restart-maddy-on-cert-renewal" '' + if [ "$1" == "mail.b12f.io"]; then + ${pkgs.systemd}/bin/systemctl restart maddy.service; + fi + ''; +in { + age.secrets."b12f.io-dkim-private-rsa" = { + file = "${flake.self}/secrets/b12f.io-dkim-private-rsa.age"; + mode = "400"; + owner = "rspamd"; + }; + age.secrets."mail@b12f.io-password" = { file = "${flake.self}/secrets/mail@b12f.io-password.age"; mode = "400"; - # owner = "maddy"; + owner = "maddy"; }; - services.caddy.virtualHosts = { - "mail.b12f.io" = { - extraConfig = '' + services.caddy = { + globalConfig = '' + events { + on cert_obtained exec ${restartMaddyOnCertRenewal}/bin/restart-maddy-on-cert-renewal {event.data.name} + } + ''; + + virtualHosts = { + "mail.b12f.io".extraConfig = '' respond "404 Not Found" ''; + + "mta-sts.b12f.io".extraConfig = '' + encode gzip + file_server + root * ${ + pkgs.runCommand "testdir" {} '' + mkdir -p "$out/.well-known" + echo " + version: STSv1 + mode: enforce + max_age: 604800 + mx: mail.b12f.io + " > "$out/.well-known/mta-sts.txt" + '' + } + ''; }; }; @@ -23,6 +58,8 @@ openFirewall = true; + hostname = "mail.b12f.io"; + primaryDomain = "b12f.io"; ensureAccounts = [ @@ -32,16 +69,39 @@ ensureCredentials = { # Do not use this in production. This will make passwords world-readable # in the Nix store - "mail@b12f.io".passwordFile = "${pkgs.writeText "postmaster" "test"}"; + "mail@b12f.io".passwordFile = config.age.secrets."mail@b12f.io-password".path; }; tls = { certificates = [ { - keyPath = ""; - certPath = ""; + keyPath = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.b12f.io/mail.b12f.io.key"; + certPath = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.b12f.io/mail.b12f.io.crt"; } ]; }; + + config = (builtins.replaceStrings ["msgpipeline local_routing {"] [''msgpipeline local_routing { + check { + rspamd { + api_path http://localhost:11334 + } + }''] config.services.maddy.config.default) ++ '' + modify { + domains b12f.io + selector default + key_path ${config.age.secrets."b12f.io-dkim-private-rsa".path} + } + ''; + }; + + services.rspamd = { + enable = true; + locals."dkim_signing.conf".text = '' + enabled = false; + ''; + }; + + systemd.services.rspamd.serviceConfig.SupplementaryGroups = [ "maddy" ]; } diff --git a/hosts/pie/.env.firefly-importer b/hosts/pie/.env.firefly-importer index f7250bb..53e82b1 100644 --- a/hosts/pie/.env.firefly-importer +++ b/hosts/pie/.env.firefly-importer @@ -10,7 +10,7 @@ # # This variable can be set from a file if you append it with _FILE # -FIREFLY_III_URL=https://firefly.b12f.io +FIREFLY_III_URL=http://firefly:8080 # # Imagine Firefly III can be reached at "http://172.16.0.2:8082" (internal Docker network or something). diff --git a/hosts/pie/dhcpd.nix b/hosts/pie/dhcpd.nix index d9c3350..e09dca9 100644 --- a/hosts/pie/dhcpd.nix +++ b/hosts/pie/dhcpd.nix @@ -2,7 +2,7 @@ { networking.firewall.allowedUDPPorts = [ 67 547 ]; networking.firewall.extraInputRules = '' - ip6 daddr ff02::1:2/128 udp dport 547 accept comment "DHCPv6 client" + ip6 daddr ff02::1:2/128 udp dport 547 accept comment "DHCPv6 server" ''; services.kea.dhcp4 = { diff --git a/hosts/pie/firefly.nix b/hosts/pie/firefly.nix index 923405a..11bfe9a 100644 --- a/hosts/pie/firefly.nix +++ b/hosts/pie/firefly.nix @@ -34,9 +34,17 @@ in { extraConfig = '' firefly.b12f.io { reverse_proxy 127.0.0.1:8080 + + basicauth * { + b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a + } } firefly-importer.b12f.io { reverse_proxy 127.0.0.1:8081 + + basicauth * { + b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a + } } ''; }; diff --git a/hosts/pie/networking.nix b/hosts/pie/networking.nix index 9eae49e..04bbc6a 100644 --- a/hosts/pie/networking.nix +++ b/hosts/pie/networking.nix @@ -20,7 +20,7 @@ ]; ipv6.addresses = [ { address = "2a02:908:5b1:e3c0:2::"; prefixLength = 128; } - { address = "fe80::b12f:acab:1312:acab"; prefixLength = 128; } + { address = "fe80:b12f:acab:1312:acab:2::"; prefixLength = 128; } ]; }; diff --git a/hosts/pie/paperless.nix b/hosts/pie/paperless.nix index 52eb804..24de374 100644 --- a/hosts/pie/paperless.nix +++ b/hosts/pie/paperless.nix @@ -53,6 +53,10 @@ in { paperless.b12f.io { request_header Host localhost:${builtins.toString config.services.paperless.port} reverse_proxy 127.0.0.1:${builtins.toString config.services.paperless.port} + + basicauth * { + b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a + } } ''; }; diff --git a/hosts/pie/unbound.nix b/hosts/pie/unbound.nix index dba6948..4ae5762 100644 --- a/hosts/pie/unbound.nix +++ b/hosts/pie/unbound.nix @@ -1,4 +1,34 @@ -{ pkgs, lib, ... }: { +{ + flake, + config, + pkgs, + lib, + ... +}: { + age.secrets."unbound_control.key" = { + file = "${flake.self}/secrets/unbound_control.key.age"; + mode = "400"; + owner = "unbound"; + }; + + age.secrets."unbound_control.pem" = { + file = "${flake.self}/secrets/unbound_control.pem.age"; + mode = "400"; + owner = "unbound"; + }; + + age.secrets."unbound_server.key" = { + file = "${flake.self}/secrets/unbound_server.key.age"; + mode = "400"; + owner = "unbound"; + }; + + age.secrets."unbound_server.pem" = { + file = "${flake.self}/secrets/unbound_server.pem.age"; + mode = "400"; + owner = "unbound"; + }; + networking.firewall.allowedUDPPorts = [ 53 ]; networking.firewall.allowedTCPPorts = [ 53 ]; @@ -10,16 +40,25 @@ "\"${pkgs.adlist.unbound-adblockStevenBlack}\"" ]; interface = [ - "0.0.0.0" - "::0" + "127.0.0.1" + "::1" + + "192.168.178.2" + "2a02:908:5b1:e3c0:2::" + + "10.0.1.2" + "fd00:b12f:acab:1312:acab:2::" ]; access-control = [ + "127.0.0.1/32 allow" + # Allow from local network "192.168.178.0/24 allow" + "2a02:908:5b1:e3c0::/64 allow" # Allow from wireguard "10.0.1.0/24 allow" - "fd00:b12f:acab:1312:acab::/48 allow" + "fd00:b12f:acab:1312::/64 allow" ]; local-zone = [ "\"b12f.io\" static" @@ -60,21 +99,29 @@ "\"fritz.box. 10800 IN A 192.168.178.1\"" "\"fritz.box. 10800 IN AAAA fd00::3ea6:2fff:fe57:30b0\"" ]; + + tls-cert-bundle = "/etc/ssl/certs/ca-certificates.crt"; }; forward-zone = [ { name = "."; forward-addr = [ - "193.110.81.0" #dns0.eu - "2a0f:fc80::" #dns0.eu - "185.253.5.0" #dns0.eu - "2a0f:fc81::" #dns0.eu + "193.110.81.0#dns0.eu" + "2a0f:fc80::#dns0.eu" + "185.253.5.0#dns0.eu" + "2a0f:fc81::#dns0.eu" ]; - forward-tls-upstream = "yes"; + # forward-tls-upstream = "yes"; } ]; - remote-control.control-enable = true; + remote-control = { + control-enable = true; + control-key-file = config.age.secrets."unbound_control.key".path; + server-cert-file = config.age.secrets."unbound_server.pem".path; + server-key-file = config.age.secrets."unbound_server.key".path; + control-cert-file = config.age.secrets."unbound_control.pem".path; + }; }; }; diff --git a/pkgs/caddy/default.nix b/pkgs/caddy/default.nix new file mode 100644 index 0000000..1afb822 --- /dev/null +++ b/pkgs/caddy/default.nix @@ -0,0 +1,67 @@ +{ + lib, + buildGoModule, + fetchFromGitHub, + vendorSha256 ? "" +}: +with lib; +let + plugins = [ + "github.com/mholt/caddy-events-exec" + ]; + + imports = flip concatMapStrings plugins (pkg: "\t\t\t_ \"${pkg}\"\n"); + + main = '' + package main + + import ( + caddycmd "github.com/caddyserver/caddy/v2/cmd" + + _ "github.com/caddyserver/caddy/v2/modules/standard" + ${imports} + ) + + func main() { + caddycmd.Main() + } + ''; + +in buildGoModule rec { + pname = "caddy"; + version = "2.6.4"; + + subPackages = [ "cmd/caddy" ]; + + src = fetchFromGitHub { + owner = "caddyserver"; + repo = pname; + # https://github.com/NixOS/nixpkgs/blob/nixos-21.11/pkgs/servers/caddy/default.nix + rev = "v${version}"; + sha256 = "sha256-xNCxzoNpXkj8WF9+kYJfO18ux8/OhxygkGjA49+Q4vY="; + }; + + inherit vendorSha256; + + overrideModAttrs = (_: { + preBuild = "echo '${main}' > cmd/caddy/main.go"; + postInstall = "cp go.sum go.mod $out/ && ls $out/"; + }); + + postPatch = '' + echo '${main}' > cmd/caddy/main.go + cat cmd/caddy/main.go + ''; + + postConfigure = '' + cp vendor/go.sum ./ + cp vendor/go.mod ./ + ''; + + meta = with lib; { + homepage = https://caddyserver.com; + description = "Fast, cross-platform HTTP/2 web server with automatic HTTPS"; + license = licenses.asl20; + maintainers = with maintainers; [ rushmorem fpletz zimbatm ]; + }; +} diff --git a/pkgs/default.nix b/pkgs/default.nix index c703ffd..b10dc94 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -3,6 +3,7 @@ with prev; { # keep sources this first sources = callPackage (import ./_sources/generated.nix) {}; # then, call packages with `final.callPackage` + # caddy = callPackage (import ./caddy) {}; concourse = import ./concourse.nix final; import-gtk-settings = writeShellScriptBin "import-gtk-settings" (import ./import-gtk-settings.nix final); lgcl = writeShellScriptBin "lgcl" (import ./lgcl.nix final); diff --git a/secrets/b12f.io-dkim-private-rsa.age b/secrets/b12f.io-dkim-private-rsa.age new file mode 100644 index 0000000..7f2d190 Binary files /dev/null and b/secrets/b12f.io-dkim-private-rsa.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 1bfd8b7..ef851c8 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -70,4 +70,11 @@ in { "invoiceplane-db-secrets.env.age".publicKeys = pieKeys ++ baseKeys; "mail@b12f.io-password.age".publicKeys = frikandelKeys ++ baseKeys; + + "b12f.io-dkim-private-rsa.age".publicKeys = frikandelKeys ++ baseKeys; + + "unbound_control.key.age".publicKeys = pieKeys ++ baseKeys; + "unbound_control.pem.age".publicKeys = pieKeys ++ baseKeys; + "unbound_server.key.age".publicKeys = pieKeys ++ baseKeys; + "unbound_server.pem.age".publicKeys = pieKeys ++ baseKeys; } diff --git a/secrets/unbound_control.key.age b/secrets/unbound_control.key.age new file mode 100644 index 0000000..d1ed8c6 Binary files /dev/null and b/secrets/unbound_control.key.age differ diff --git a/secrets/unbound_control.pem.age b/secrets/unbound_control.pem.age new file mode 100644 index 0000000..8a7f85b Binary files /dev/null and b/secrets/unbound_control.pem.age differ diff --git a/secrets/unbound_server.key.age b/secrets/unbound_server.key.age new file mode 100644 index 0000000..b94a984 Binary files /dev/null and b/secrets/unbound_server.key.age differ diff --git a/secrets/unbound_server.pem.age b/secrets/unbound_server.pem.age new file mode 100644 index 0000000..c407af6 Binary files /dev/null and b/secrets/unbound_server.pem.age differ diff --git a/terraform/README.md b/terraform/README.md index d0827e8..f7e1f21 100644 --- a/terraform/README.md +++ b/terraform/README.md @@ -1,3 +1,14 @@ +# Usage + +``` +terraform-backend-git -l git terraform plan +``` + +``` +terraform-backend-git -l git terraform apply +``` + +# FAQ Problem: diff --git a/terraform/b12f.io.tf b/terraform/b12f.io.tf index 656962e..f652966 100644 --- a/terraform/b12f.io.tf +++ b/terraform/b12f.io.tf @@ -92,6 +92,14 @@ resource "hostingde_record" "b12f-autodiscover" { # ttl = 300 # } +resource "hostingde_record" "b12f-mta-sts" { + zone_id = hostingde_zone.b12f.id + name = "mta-sts.b12f.io" + type = "CNAME" + content = "frikandel.b12f.io" + ttl = 300 +} + resource "hostingde_record" "b12f-spf" { zone_id = hostingde_zone.b12f.id name = "b12f.io" @@ -100,6 +108,14 @@ resource "hostingde_record" "b12f-spf" { ttl = 300 } +resource "hostingde_record" "b12f-dkim" { + zone_id = hostingde_zone.b12f.id + name = "default._domainkey.b12f.io" + type = "TXT" + content = "\"v=DKIM1; k=rsa;\" \"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyla9hW3TvoXvZQxwzaJ4SZ9ict1HU3E6+FWlwNIgE6tIpTCyRJtiSIUDqB8TLTIBoxIs+QQBXZi+QUi3Agu6OSY2RiV0EwO8+oOOqOD9pERftc/aqe51cXuv4kPqwvpXEBwrXFWVM+VxivEubUJ7eKkFyXJpelv0LslXv/MmYbUyed6dF+reOGZCsvnbiRv74qdxbAL/25j62E8Wr\" \"nxzJwhUtx/JhdBOjsHBvuw9hy6rZsVJL9eXayWyGRV6qmsLRzsRSBs+mDrgmKk4dugADd11+A03ics3i8hplRoWDkqnNKz1qy4f5TsV6v9283IANrAzRfHwX8EvNiFsBz+ZCQIDAQAB\"" + ttl = 300 +} + resource "hostingde_record" "b12f-droppie-AAAA" { zone_id = hostingde_zone.b12f.id name = "droppie.b12f.io"