feat: add unbound control
This commit is contained in:
parent
d2d9b6cd4c
commit
5cf48868b0
|
@ -1,20 +1,55 @@
|
||||||
{
|
{
|
||||||
|
flake,
|
||||||
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
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" = {
|
age.secrets."mail@b12f.io-password" = {
|
||||||
file = "${flake.self}/secrets/mail@b12f.io-password.age";
|
file = "${flake.self}/secrets/mail@b12f.io-password.age";
|
||||||
mode = "400";
|
mode = "400";
|
||||||
# owner = "maddy";
|
owner = "maddy";
|
||||||
};
|
};
|
||||||
|
|
||||||
services.caddy.virtualHosts = {
|
services.caddy = {
|
||||||
"mail.b12f.io" = {
|
globalConfig = ''
|
||||||
extraConfig = ''
|
events {
|
||||||
|
on cert_obtained exec ${restartMaddyOnCertRenewal}/bin/restart-maddy-on-cert-renewal {event.data.name}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
|
||||||
|
virtualHosts = {
|
||||||
|
"mail.b12f.io".extraConfig = ''
|
||||||
respond "404 Not Found"
|
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;
|
openFirewall = true;
|
||||||
|
|
||||||
|
hostname = "mail.b12f.io";
|
||||||
|
|
||||||
primaryDomain = "b12f.io";
|
primaryDomain = "b12f.io";
|
||||||
|
|
||||||
ensureAccounts = [
|
ensureAccounts = [
|
||||||
|
@ -32,16 +69,39 @@
|
||||||
ensureCredentials = {
|
ensureCredentials = {
|
||||||
# Do not use this in production. This will make passwords world-readable
|
# Do not use this in production. This will make passwords world-readable
|
||||||
# in the Nix store
|
# 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 = {
|
tls = {
|
||||||
certificates = [
|
certificates = [
|
||||||
{
|
{
|
||||||
keyPath = "";
|
keyPath = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.b12f.io/mail.b12f.io.key";
|
||||||
certPath = "";
|
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" ];
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# This variable can be set from a file if you append it with _FILE
|
# 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).
|
# Imagine Firefly III can be reached at "http://172.16.0.2:8082" (internal Docker network or something).
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
networking.firewall.allowedUDPPorts = [ 67 547 ];
|
networking.firewall.allowedUDPPorts = [ 67 547 ];
|
||||||
networking.firewall.extraInputRules = ''
|
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 = {
|
services.kea.dhcp4 = {
|
||||||
|
|
|
@ -34,9 +34,17 @@ in {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
firefly.b12f.io {
|
firefly.b12f.io {
|
||||||
reverse_proxy 127.0.0.1:8080
|
reverse_proxy 127.0.0.1:8080
|
||||||
|
|
||||||
|
basicauth * {
|
||||||
|
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
firefly-importer.b12f.io {
|
firefly-importer.b12f.io {
|
||||||
reverse_proxy 127.0.0.1:8081
|
reverse_proxy 127.0.0.1:8081
|
||||||
|
|
||||||
|
basicauth * {
|
||||||
|
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
];
|
];
|
||||||
ipv6.addresses = [
|
ipv6.addresses = [
|
||||||
{ address = "2a02:908:5b1:e3c0:2::"; prefixLength = 128; }
|
{ 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; }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ in {
|
||||||
paperless.b12f.io {
|
paperless.b12f.io {
|
||||||
request_header Host localhost:${builtins.toString config.services.paperless.port}
|
request_header Host localhost:${builtins.toString config.services.paperless.port}
|
||||||
reverse_proxy 127.0.0.1:${builtins.toString config.services.paperless.port}
|
reverse_proxy 127.0.0.1:${builtins.toString config.services.paperless.port}
|
||||||
|
|
||||||
|
basicauth * {
|
||||||
|
b12f $2a$05$/xM7USOzLczswXmiacO6UOdg1YNPIw/KJMbMVerEkpsCtNUFwte4a
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
@ -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.allowedUDPPorts = [ 53 ];
|
||||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||||
|
|
||||||
|
@ -10,16 +40,25 @@
|
||||||
"\"${pkgs.adlist.unbound-adblockStevenBlack}\""
|
"\"${pkgs.adlist.unbound-adblockStevenBlack}\""
|
||||||
];
|
];
|
||||||
interface = [
|
interface = [
|
||||||
"0.0.0.0"
|
"127.0.0.1"
|
||||||
"::0"
|
"::1"
|
||||||
|
|
||||||
|
"192.168.178.2"
|
||||||
|
"2a02:908:5b1:e3c0:2::"
|
||||||
|
|
||||||
|
"10.0.1.2"
|
||||||
|
"fd00:b12f:acab:1312:acab:2::"
|
||||||
];
|
];
|
||||||
access-control = [
|
access-control = [
|
||||||
|
"127.0.0.1/32 allow"
|
||||||
|
|
||||||
# Allow from local network
|
# Allow from local network
|
||||||
"192.168.178.0/24 allow"
|
"192.168.178.0/24 allow"
|
||||||
|
"2a02:908:5b1:e3c0::/64 allow"
|
||||||
|
|
||||||
# Allow from wireguard
|
# Allow from wireguard
|
||||||
"10.0.1.0/24 allow"
|
"10.0.1.0/24 allow"
|
||||||
"fd00:b12f:acab:1312:acab::/48 allow"
|
"fd00:b12f:acab:1312::/64 allow"
|
||||||
];
|
];
|
||||||
local-zone = [
|
local-zone = [
|
||||||
"\"b12f.io\" static"
|
"\"b12f.io\" static"
|
||||||
|
@ -60,21 +99,29 @@
|
||||||
"\"fritz.box. 10800 IN A 192.168.178.1\""
|
"\"fritz.box. 10800 IN A 192.168.178.1\""
|
||||||
"\"fritz.box. 10800 IN AAAA fd00::3ea6:2fff:fe57:30b0\""
|
"\"fritz.box. 10800 IN AAAA fd00::3ea6:2fff:fe57:30b0\""
|
||||||
];
|
];
|
||||||
|
|
||||||
|
tls-cert-bundle = "/etc/ssl/certs/ca-certificates.crt";
|
||||||
};
|
};
|
||||||
forward-zone = [
|
forward-zone = [
|
||||||
{
|
{
|
||||||
name = ".";
|
name = ".";
|
||||||
forward-addr = [
|
forward-addr = [
|
||||||
"193.110.81.0" #dns0.eu
|
"193.110.81.0#dns0.eu"
|
||||||
"2a0f:fc80::" #dns0.eu
|
"2a0f:fc80::#dns0.eu"
|
||||||
"185.253.5.0" #dns0.eu
|
"185.253.5.0#dns0.eu"
|
||||||
"2a0f:fc81::" #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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
67
pkgs/caddy/default.nix
Normal file
67
pkgs/caddy/default.nix
Normal file
|
@ -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 ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ with prev; {
|
||||||
# keep sources this first
|
# keep sources this first
|
||||||
sources = callPackage (import ./_sources/generated.nix) {};
|
sources = callPackage (import ./_sources/generated.nix) {};
|
||||||
# then, call packages with `final.callPackage`
|
# then, call packages with `final.callPackage`
|
||||||
|
# caddy = callPackage (import ./caddy) {};
|
||||||
concourse = import ./concourse.nix final;
|
concourse = import ./concourse.nix final;
|
||||||
import-gtk-settings = writeShellScriptBin "import-gtk-settings" (import ./import-gtk-settings.nix final);
|
import-gtk-settings = writeShellScriptBin "import-gtk-settings" (import ./import-gtk-settings.nix final);
|
||||||
lgcl = writeShellScriptBin "lgcl" (import ./lgcl.nix final);
|
lgcl = writeShellScriptBin "lgcl" (import ./lgcl.nix final);
|
||||||
|
|
BIN
secrets/b12f.io-dkim-private-rsa.age
Normal file
BIN
secrets/b12f.io-dkim-private-rsa.age
Normal file
Binary file not shown.
|
@ -70,4 +70,11 @@ in {
|
||||||
"invoiceplane-db-secrets.env.age".publicKeys = pieKeys ++ baseKeys;
|
"invoiceplane-db-secrets.env.age".publicKeys = pieKeys ++ baseKeys;
|
||||||
|
|
||||||
"mail@b12f.io-password.age".publicKeys = frikandelKeys ++ 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;
|
||||||
}
|
}
|
||||||
|
|
BIN
secrets/unbound_control.key.age
Normal file
BIN
secrets/unbound_control.key.age
Normal file
Binary file not shown.
BIN
secrets/unbound_control.pem.age
Normal file
BIN
secrets/unbound_control.pem.age
Normal file
Binary file not shown.
BIN
secrets/unbound_server.key.age
Normal file
BIN
secrets/unbound_server.key.age
Normal file
Binary file not shown.
BIN
secrets/unbound_server.pem.age
Normal file
BIN
secrets/unbound_server.pem.age
Normal file
Binary file not shown.
|
@ -1,3 +1,14 @@
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform-backend-git -l git terraform plan
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
terraform-backend-git -l git terraform apply
|
||||||
|
```
|
||||||
|
|
||||||
|
# FAQ
|
||||||
|
|
||||||
Problem:
|
Problem:
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,14 @@ resource "hostingde_record" "b12f-autodiscover" {
|
||||||
# ttl = 300
|
# 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" {
|
resource "hostingde_record" "b12f-spf" {
|
||||||
zone_id = hostingde_zone.b12f.id
|
zone_id = hostingde_zone.b12f.id
|
||||||
name = "b12f.io"
|
name = "b12f.io"
|
||||||
|
@ -100,6 +108,14 @@ resource "hostingde_record" "b12f-spf" {
|
||||||
ttl = 300
|
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" {
|
resource "hostingde_record" "b12f-droppie-AAAA" {
|
||||||
zone_id = hostingde_zone.b12f.id
|
zone_id = hostingde_zone.b12f.id
|
||||||
name = "droppie.b12f.io"
|
name = "droppie.b12f.io"
|
||||||
|
|
Loading…
Reference in a new issue