diff options
Diffstat (limited to 'os/kay/modules')
-rw-r--r-- | os/kay/modules/acme.nix | 23 | ||||
-rw-r--r-- | os/kay/modules/cgit.nix | 33 | ||||
-rw-r--r-- | os/kay/modules/dendrite.nix | 108 | ||||
-rw-r--r-- | os/kay/modules/dns/5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone | 14 | ||||
-rw-r--r-- | os/kay/modules/dns/ddns.nix | 44 | ||||
-rw-r--r-- | os/kay/modules/dns/default.nix | 137 | ||||
-rw-r--r-- | os/kay/modules/dns/sinanmohd.com.zone | 46 | ||||
-rw-r--r-- | os/kay/modules/hurricane.nix | 115 | ||||
-rw-r--r-- | os/kay/modules/iperf3.nix | 10 | ||||
-rw-r--r-- | os/kay/modules/mail.nix | 110 | ||||
-rw-r--r-- | os/kay/modules/matrix-sliding-sync.nix | 18 | ||||
-rw-r--r-- | os/kay/modules/network.nix | 82 | ||||
-rw-r--r-- | os/kay/modules/router.nix | 43 | ||||
-rw-r--r-- | os/kay/modules/sftp.nix | 44 | ||||
-rw-r--r-- | os/kay/modules/sshfwd.nix | 29 | ||||
-rw-r--r-- | os/kay/modules/wireguard.nix | 57 | ||||
-rw-r--r-- | os/kay/modules/www.nix | 134 |
17 files changed, 1047 insertions, 0 deletions
diff --git a/os/kay/modules/acme.nix b/os/kay/modules/acme.nix new file mode 100644 index 0000000..f4ded0a --- /dev/null +++ b/os/kay/modules/acme.nix @@ -0,0 +1,23 @@ +{ config, pkgs, ... }: let + email = config.userdata.email; + domain = config.userdata.domain; + + environmentFile = + pkgs.writeText "acme-dns" "RFC2136_NAMESERVER='[2001:470:ee65::1]:53'"; +in { + security.acme = { + acceptTerms = true; + defaults.email = email; + + certs.${domain} = { + inherit domain; + extraDomainNames = [ "*.${domain}" ]; + + dnsProvider = "rfc2136"; + dnsPropagationCheck = false; # local DNS server + + inherit environmentFile; + group = config.services.nginx.group; + }; + }; +} diff --git a/os/kay/modules/cgit.nix b/os/kay/modules/cgit.nix new file mode 100644 index 0000000..f8fb25c --- /dev/null +++ b/os/kay/modules/cgit.nix @@ -0,0 +1,33 @@ +{ config, pkgs, ... }: + +let + domain = config.userdata.domain; + user = config.userdata.name; +in +{ + environment.systemPackages = with pkgs; [ + luajitPackages.luaossl + lua52Packages.luaossl + ]; + + services.cgit."git.${domain}" = { + enable = true; + nginx.virtualHost = "git.${domain}"; + scanPath = "/var/lib/git"; + settings = { + project-list = "/var/lib/git/project.list"; + remove-suffix = 1; + enable-commit-graph = 1; + root-title = "${user}'s git repository"; + root-desc = "how do i learn github anon"; + source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; + about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; + readme = ":README.md"; + footer = ""; + enable-blame = 1; + clone-url = "https://git.${domain}/$CGIT_REPO_URL"; + enable-log-filecount = 1; + enable-log-linecount = 1; + }; + }; +} diff --git a/os/kay/modules/dendrite.nix b/os/kay/modules/dendrite.nix new file mode 100644 index 0000000..8277e21 --- /dev/null +++ b/os/kay/modules/dendrite.nix @@ -0,0 +1,108 @@ +{ config, lib, pkgs, ... }: + +let + domain = config.userdata.domain; + database = { + connection_string = "postgres:///dendrite?host=/run/postgresql"; + max_open_conns = 90; + max_idle_conns = 5; + conn_max_lifetime = -1; + }; +in +{ + sops.secrets."matrix-${domain}/key" = {}; + + services = { + postgresql = { + enable = true; + package = with pkgs; postgresql_15; + settings = { + log_timezone = config.time.timeZone; + listen_addresses = lib.mkForce ""; + }; + ensureDatabases = [ "dendrite" ]; + ensureUsers = [{ + name = "dendrite"; + ensureDBOwnership = true; + }]; + authentication = lib.mkForce "local all all trust"; + }; + + dendrite = { + enable = true; + loadCredential = [ + "private_key:${config.sops.secrets."matrix-${domain}/key".path}" + ]; + + settings = { + sync_api.search = { + enable = true; + index_path = "/var/lib/dendrite/searchindex"; + }; + global = { + server_name = domain; + private_key = "$CREDENTIALS_DIRECTORY/private_key"; + trusted_third_party_id_servers = [ + "matrix.org" + "vector.im" + ]; + inherit database; + }; + logging = [{ + type = "std"; + level = "warn"; + }]; + mscs = { + inherit database; + mscs = [ "msc2836" ]; + }; + sync_api = { + inherit database; + real_ip_header = "X-Real-IP"; + }; + media_api = { + inherit database; + dynamic_thumbnails = true; + max_file_size_bytes = 12800000000; + }; + federation_api = { + inherit database; + send_max_retries = 8; + key_perspectives = [{ + server_name = "matrix.org"; + keys = [ + { + key_id = "ed25519:auto"; + public_key = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + { + key_id = "ed25519:a_RXGa"; + public_key = "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ"; + } + ]; + }]; + }; + + app_service_api = { + inherit database; + }; + room_server = { + inherit database; + }; + push_server = { + inherit database; + }; + relay_api = { + inherit database; + }; + key_server = { + inherit database; + }; + user_api = { + account_database = database; + device_database = database; + }; + }; + }; + }; +} diff --git a/os/kay/modules/dns/5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone b/os/kay/modules/dns/5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone new file mode 100644 index 0000000..69b3524 --- /dev/null +++ b/os/kay/modules/dns/5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone @@ -0,0 +1,14 @@ +$ORIGIN 5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa. +$TTL 2d + +@ IN SOA ns1.sinanmohd.com. sinan.sinanmohd.com. ( + 2024020400 ; serial + 2h ; refresh + 5m ; retry + 1d ; expire + 5m ) ; nx ttl + + IN NS ns1.sinanmohd.com. + +1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR ns1.sinanmohd.com. +7.3.3.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0 IN PTR mail.sinanmohd.com. diff --git a/os/kay/modules/dns/ddns.nix b/os/kay/modules/dns/ddns.nix new file mode 100644 index 0000000..e6e417a --- /dev/null +++ b/os/kay/modules/dns/ddns.nix @@ -0,0 +1,44 @@ +{ pkgs, ... }: { + services.pppd.script = { + "02-ddns-ipv4" = { + runtimeInputs = with pkgs; [ coreutils knot-dns ]; + type = "ip-up"; + + text = '' + cat <<- EOF | knsupdate + server 2001:470:ee65::1 + zone sinanmohd.com. + + update delete sinanmohd.com. A + update add sinanmohd.com. 180 A $4 + + update delete mail.sinanmohd.com. A + update add mail.sinanmohd.com. 180 A $4 + + send + EOF + ''; + }; + + "02-ddns-ipv6" = { + runtimeInputs = with pkgs; [ coreutils knot-dns iproute2 gnugrep ]; + type = "ipv6-up"; + + text = '' + while ! ipv6="$(ip -6 addr show dev "$1" scope global | grep -o '[0-9a-f:]*::1')"; do + sleep 0.2 + done + + cat <<- EOF | knsupdate + server 2001:470:ee65::1 + zone sinanmohd.com. + + update delete sinanmohd.com. AAAA + update add sinanmohd.com. 180 AAAA $ipv6 + + send + EOF + ''; + }; + }; +} diff --git a/os/kay/modules/dns/default.nix b/os/kay/modules/dns/default.nix new file mode 100644 index 0000000..1146cc3 --- /dev/null +++ b/os/kay/modules/dns/default.nix @@ -0,0 +1,137 @@ +{ config, pkgs, ... }: let + listen_addr = "2001:470:ee65::1"; + + acmeSOA = pkgs.writeText "acmeSOA" '' + $TTL 2d + + @ IN SOA ns1.sinanmohd.com. sinan.sinanmohd.com. ( + 2024020505 ; serial + 2h ; refresh + 5m ; retry + 1d ; expire + 5m ) ; nx ttl + + IN NS ns1.sinanmohd.com. + ''; +in { + imports = [ ./ddns.nix ]; + + networking.firewall = { + allowedTCPPorts = [ 53 ]; + allowedUDPPorts = [ 53 ]; + }; + + sops.secrets.dns = { + owner = config.systemd.services.knot.serviceConfig.User; + group = config.systemd.services.knot.serviceConfig.Group; + }; + + services.knot = { + enable = true; + keyFiles = [ config.sops.secrets.dns.path ]; + + settings = { + server.listen = listen_addr; + + remote = [ + { + id = "ns1.he.net"; + address = [ "2001:470:100::2" "216.218.130.2" ]; + via = "2001:470:ee65::1"; + } + { + id = "m.gtld-servers.net"; + address = [ "2001:501:b1f9::30" "192.55.83.30" ]; + } + ]; + + submission = [{ + id = "gtld-servers.net"; + parent = "m.gtld-servers.net"; + }]; + + policy = [{ + id = "gtld-servers.net"; + algorithm = "ecdsap384sha384"; + ksk-lifetime = "365d"; + ksk-submission = "gtld-servers.net"; + }]; + + # generate TSIG key with keymgr -t name + acl = [ + { + id = "ns1.he.net"; + key = "ns1.he.net"; + address = [ "2001:470:600::2" "216.218.133.2" ]; + action = "transfer"; + } + { + id = "localhost"; + address = [ listen_addr ]; + update-type = [ "A" "AAAA" ]; + action = "update"; + } + { + id = "acme"; + address = [ listen_addr ]; + update-type = [ "TXT" ]; + action = "update"; + } + ]; + + mod-rrl = [{ + id = "default"; + rate-limit = 200; + slip = 2; + }]; + + template = [ + { + id = "default"; + semantic-checks = "on"; + global-module = "mod-rrl/default"; + } + { + id = "master"; + semantic-checks = "on"; + + dnssec-signing = "on"; + dnssec-policy = "gtld-servers.net"; + + notify = [ "ns1.he.net" ]; + acl = [ "ns1.he.net" "localhost" ]; + + zonefile-sync = "-1"; + zonefile-load = "difference"; + } + { + id = "acme"; + semantic-checks = "on"; + acl = [ "acme" ]; + + zonefile-sync = "-1"; + zonefile-load = "difference"; + journal-content = "changes"; + } + ]; + + zone = [ + { + domain = "sinanmohd.com"; + file = ./sinanmohd.com.zone; + template = "master"; + } + { + domain = "_acme-challenge.sinanmohd.com"; + file = acmeSOA; + template = "acme"; + } + { + domain = "5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa"; + file = ./5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone; + } + ]; + }; + }; + +} diff --git a/os/kay/modules/dns/sinanmohd.com.zone b/os/kay/modules/dns/sinanmohd.com.zone new file mode 100644 index 0000000..0409efc --- /dev/null +++ b/os/kay/modules/dns/sinanmohd.com.zone @@ -0,0 +1,46 @@ +$ORIGIN sinanmohd.com. +$TTL 2d + +@ IN SOA ns1 hostmaster ( + 2024022700 ; serial + 2h ; refresh + 5m ; retry + 1d ; expire + 5m ) ; nx ttl + + IN NS ns1 + IN NS ns2.he.net. + IN NS ns3.he.net. + IN NS ns4.he.net. + IN NS ns5.he.net. + + 30 IN A 127.0.0.1 + 30 IN AAAA ::1 + + IN MX 10 mail + + IN TXT "v=spf1 mx -all" +_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:reports@sinanmohd.com; ruf=mailto:reports@sinanmohd.com; adkim=s; aspf=s" + +ed25519._domainkey IN TXT "v=DKIM1; k=ed25519; p=EHk924AruF9Y0Xaf009rpRl+yGusjmjT1Zeho67BnDU=" +rsa._domainkey IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4HEqO63fSC0cUnJt9vAQBssTkPfT4QefmAK/1BtAIRIOdGakf7PI7p3A1ETgwfYxuHj7BUSzUtESsHMThbhB1Wko79+AR+5ZBDBmD8CE0dOnZfzeG8xIaGfYkaL4gana6YZWiBT2oi/CimJfc22wacF01SufOs4R8cDpy4BZIgDD/zfF4bFTORQ0vMSJQJkp1zdQelERDU5CEezgxgVYgoSmdEpgkhc23PJSyj4Z7hA69N0amsb3cVVrfVXcYvSqTK3S2vLLA89ws4CUjCCpUW40gVIP8QP6CqTL76936Oo7OVWgmV3Sn3wa8FMN6IATY+fbMlrdOMsPY5PauJyEoQIDAQAB" + +ns1 IN AAAA 2001:470:ee65::1 + +mail 30 IN A 127.0.0.1 +mail IN AAAA 2001:470:ee65::1337 +smtp IN CNAME @ +imap IN CNAME @ +mta-sts IN CNAME @ + +_mta-sts IN TXT "v=STSv1; id=2024022500" +_smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:reports@sinanmohd.com" + +www IN CNAME @ +git IN CNAME @ +bin IN CNAME @ +static IN CNAME @ + +lia IN A 65.0.3.127 + +_acme-challenge IN NS ns1 diff --git a/os/kay/modules/hurricane.nix b/os/kay/modules/hurricane.nix new file mode 100644 index 0000000..9e22bf5 --- /dev/null +++ b/os/kay/modules/hurricane.nix @@ -0,0 +1,115 @@ +{ config, pkgs, lib, ... }: + +let + iface = "hurricane"; + remote = "216.218.221.42"; + + clinet = "2001:470:35:72a::2"; + server = "2001:470:35:72a::1"; + + prefix64 = "2001:470:36:72a::/64"; + prefix48 = "2001:470:ee65::/48"; + + makeAddr = prefix: host: let + split = lib.strings.splitString "/" prefix; + in { + address = "${lib.head split}${host}"; + prefixLength = lib.toInt (lib.last split); + }; +in +{ + networking = { + sits.${iface} = { + inherit remote; + ttl = 225; + }; + interfaces.${iface} = { + mtu = 1440; # 1460(ppp0) - 20 + ipv6.addresses = [ + { + address = clinet; + prefixLength = 64; + } + + (makeAddr prefix64 "1") + (makeAddr prefix48 "1") + (makeAddr prefix48 "1337") + ]; + }; + + iproute2 = { + enable = true; + rttablesExtraConfig = "200 hurricane"; + }; + + firewall.extraCommands = + "iptables -A INPUT --proto 41 --source ${remote} --jump ACCEPT"; + }; + + sops.secrets = { + "hurricane/username" = {}; + "hurricane/update_key" = {}; + "hurricane/tunnel_id" = {}; + }; + + systemd.services."network-route-${iface}" = { + description = "Routing configuration of ${iface}"; + wantedBy = [ + "network-setup.service" + "network.target" + ]; + before = [ "network-setup.service" ]; + bindsTo = [ "network-addresses-hurricane.service" ]; + after = [ "network-pre.target" "network-addresses-hurricane.service" ]; + # restart rather than stop+start this unit to prevent the + # network from dying during switch-to-configuration. + stopIfChanged = false; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + path = [ pkgs.iproute2 ]; + script = '' + echo -n "adding route" + + ip -6 rule add from ${clinet}/64 table hurricane || exit 1 + ip -6 rule add from ${prefix64} table hurricane || exit 1 + ip -6 rule add from ${prefix48} table hurricane || exit 1 + + ip -6 route add default via ${server} dev hurricane table hurricane || exit 1 + ''; + preStop = '' + echo -n "deleting route" + + ip -6 route del default via ${server} dev hurricane table hurricane || exit 1 + + ip -6 rule del from ${prefix48} table hurricane || exit 1 + ip -6 rule del from ${prefix64} table hurricane || exit 1 + ip -6 rule del from ${clinet}/64 table hurricane || exit 1 + ''; + }; + + + services.pppd.script."01-${iface}" = { + runtimeInputs = with pkgs; [ curl coreutils iproute2 iputils ]; + text = '' + wan_ip="$4" + username="$(cat ${config.sops.secrets."hurricane/username".path})" + update_key="$(cat ${config.sops.secrets."hurricane/update_key".path})" + tunnel_id="$(cat ${config.sops.secrets."hurricane/tunnel_id".path})" + + auth_url="https://$username:$update_key@ipv4.tunnelbroker.net/nic/update?hostname=$tunnel_id" + until curl --silent "$auth_url"; do + sleep 1 + done + + while [ ! -e /sys/class/net/${iface} ]; do + sleep 1 # make sure ${iface} is up + done + + ip tunnel change ${iface} local "$wan_ip" mode sit + ''; + }; +} diff --git a/os/kay/modules/iperf3.nix b/os/kay/modules/iperf3.nix new file mode 100644 index 0000000..901a93d --- /dev/null +++ b/os/kay/modules/iperf3.nix @@ -0,0 +1,10 @@ +{ ... }: + +{ + services.iperf3 = { + enable = true; + + bind = "10.0.0.1"; + openFirewall = true; + }; +} diff --git a/os/kay/modules/mail.nix b/os/kay/modules/mail.nix new file mode 100644 index 0000000..79e4019 --- /dev/null +++ b/os/kay/modules/mail.nix @@ -0,0 +1,110 @@ +{ config, ... }: let + ipv6 = "2001:470:ee65::1337"; + domain = config.userdata.domain; + + username = config.userdata.name; + secret = "$argon2i$v=19$m=4096,t=3,p=1$SWV5aWU3YWUgZWFTNm9oc28gTGFvdDdlRG8ga2FTaWVjaDYgYWV0aDFHb28$O/sDv7oy9wUxFjvKoxB5o8ZnPvjYJo9DjX0C/AZQFF0"; + email = [ + "${username}@${domain}" + "official@${domain}" + + "postmaster@${domain}" + "hostmaster@${domain}" + ]; + + credentials_directory = "/run/credentials/stalwart-mail.service"; +in { + networking.firewall.allowedTCPPorts = [ + 25 # smto + 465 # submission + 587 # submissions + 993 # imap ssl + 4190 # managesieve + ]; + + security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service"; + sops.secrets = { + "mail.${domain}/dkim_rsa" = {}; + "mail.${domain}/dkim_ed25519" = {}; + }; + + services.stalwart-mail = { + enable = true; + loadCredential = [ + "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}" + "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}" + + "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem" + "key:${config.security.acme.certs.${domain}.directory}/key.pem" + ]; + + settings = { + macros = { + host = "mail.${domain}"; + default_domain = domain; + default_directory = "in-memory"; + default_store = "sqlite"; + }; + + queue.outbound = { + ip-strategy = "ipv6_then_ipv4"; + source-ip.v6 = "['${ipv6}']"; + tls.starttls = "optional"; + }; + server.listener = { + smtp.bind = [ "[${ipv6}]:25" "0.0.0.0:25" ]; + jmap.bind = [ "[::]:8034" ]; + }; + + signature = { + rsa = { + private-key = "file://${credentials_directory}/dkim_rsa"; + selector = "rsa"; + set-body-length = true; + }; + ed25519 = { + public-key = "EHk924AruF9Y0Xaf009rpRl+yGusjmjT1Zeho67BnDU="; + private-key = "file://${credentials_directory}/dkim_ed25519"; + domain = "%{DEFAULT_DOMAIN}%"; + selector = "ed25519"; + headers = [ "From" "To" "Date" "Subject" "Message-ID" ]; + algorithm = "ed25519-sha256"; + canonicalization = "relaxed/relaxed"; + set-body-length = true; + report = true; + }; + }; + + certificate."default" = { + cert = "file://${credentials_directory}/cert"; + private-key = "file://${credentials_directory}/key"; + }; + + storage.blob = "fs"; + store = { + fs.disable = false; + sqlite.disable = false; + }; + + directory."in-memory" = { + type = "memory"; + options.subaddressing = true; + + principals = [ + { + inherit email; + inherit secret; + name = username; + type = "admin"; + } + { # for mta-sts & dmarc reports + email = "reports${domain}"; + inherit secret; + name = "reports"; + type = "individual"; + } + ]; + }; + }; + }; +} diff --git a/os/kay/modules/matrix-sliding-sync.nix b/os/kay/modules/matrix-sliding-sync.nix new file mode 100644 index 0000000..ebdc34d --- /dev/null +++ b/os/kay/modules/matrix-sliding-sync.nix @@ -0,0 +1,18 @@ +{ config, ... }: + +let + domain = config.userdata.domain; +in +{ + sops.secrets."matrix-${domain}/sliding_sync" = {}; + + services.matrix-sliding-sync = { + enable = true; + environmentFile = config.sops.secrets."matrix-${domain}/sliding_sync".path; + + settings = { + SYNCV3_LOG_LEVEL = "warn"; + SYNCV3_SERVER = "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; + }; + }; +} diff --git a/os/kay/modules/network.nix b/os/kay/modules/network.nix new file mode 100644 index 0000000..929fb1b --- /dev/null +++ b/os/kay/modules/network.nix @@ -0,0 +1,82 @@ +{ config, ... }: + +let + inetVlan = 722; + voipVlan = 1849; + wanInterface = "enp4s0"; + nameServer = "1.0.0.1"; +in +{ + imports = [ + ./router.nix + ./hurricane.nix + ]; + + sops.secrets = { + "ppp/chap-secrets" = {}; + "ppp/pap-secrets" = {}; + "ppp/username" = {}; + }; + + networking = let + voipVlanIface = "voip"; + in { + vlans = { + wan = { + id = inetVlan; + interface = wanInterface; + }; + ${voipVlanIface} = { + id = voipVlan; + interface = wanInterface; + }; + }; + + interfaces.${voipVlanIface}.useDHCP = true; + dhcpcd.extraConfig = '' + interface ${voipVlanIface} + ipv4only + nogateway + ''; + }; + + services = { + dnsmasq = { + enable = true; + settings = { + server = [ nameServer ]; + bind-interfaces = true; + }; + }; + + pppd = { + enable = true; + + config = '' + plugin pppoe.so + debug + + nic-wan + defaultroute + ipv6 ::1, + noauth + + persist + lcp-echo-adaptive + lcp-echo-interval 1 + lcp-echo-failure 5 + ''; + + peers.bsnl = { + enable = true; + autostart = true; + configFile = config.sops.secrets."ppp/username".path; + }; + + secret = { + chap = config.sops.secrets."ppp/chap-secrets".path; + pap = config.sops.secrets."ppp/pap-secrets".path; + }; + }; + }; +} diff --git a/os/kay/modules/router.nix b/os/kay/modules/router.nix new file mode 100644 index 0000000..2254c3b --- /dev/null +++ b/os/kay/modules/router.nix @@ -0,0 +1,43 @@ +{ ... }: + +let + lanInterface = "enp0s20u1"; + wanInterface = "ppp0"; + subnet = "10.0.0.0"; + prefix = 24; + host = "10.0.0.1"; + leaseRangeStart = "10.0.0.100"; + leaseRangeEnd = "10.0.0.254"; +in +{ + imports = [ + ./wireguard.nix + ./iperf3.nix + ]; + + networking = { + nat = { + enable = true; + externalInterface = wanInterface; + internalInterfaces = [ lanInterface ]; + }; + interfaces."${lanInterface}" = { + ipv4.addresses = [{ + address = host; + prefixLength = prefix; + }]; + }; + firewall = { + allowedUDPPorts = [ 53 67 ]; + allowedTCPPorts = [ 53 ]; + extraCommands = '' + iptables -t nat -I POSTROUTING 1 -s ${subnet}/${toString prefix} -o ${wanInterface} -j MASQUERADE + ''; + }; + }; + + services.dnsmasq.settings = { + dhcp-range = [ "${leaseRangeStart},${leaseRangeEnd}" ]; + interface = [ lanInterface ]; + }; +} diff --git a/os/kay/modules/sftp.nix b/os/kay/modules/sftp.nix new file mode 100644 index 0000000..bbe055e --- /dev/null +++ b/os/kay/modules/sftp.nix @@ -0,0 +1,44 @@ +{ config, ... }: + +let + storage = "/hdd/users"; + user = config.userdata.name; + pubKeys = config.users.users.${user}.openssh.authorizedKeys.keys; +in +{ + users = { + groups."sftp".members = []; + + users."sftp" = { + group = "sftp"; + shell = "/run/current-system/sw/bin/nologin"; + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFmA1dyV+o9gfoxlbVG0Y+dn3lVqdFs5fMqfxyNc5/Lr sftp@cez" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDCbgjAfyDNtLNyOS+sfLirYtfEAkGqV54LOwabpWkvf sftp@veu" + ] ++ pubKeys; + }; + + users."nazer" = { + group = "sftp"; + shell = "/run/current-system/sw/bin/nologin"; + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV09w9Ovk9wk4Bhn/06iOn+Ss8lK3AmQAl8+lXHRycu nazu@pc" + ]; + }; + }; + + services.openssh.extraConfig = '' + Match Group sftp + # chroot dir should be owned by root + # and sub dirs by %u + ChrootDirectory ${storage}/%u + ForceCommand internal-sftp + + PermitTunnel no + AllowAgentForwarding no + AllowTcpForwarding no + X11Forwarding no + ''; +} diff --git a/os/kay/modules/sshfwd.nix b/os/kay/modules/sshfwd.nix new file mode 100644 index 0000000..d70b893 --- /dev/null +++ b/os/kay/modules/sshfwd.nix @@ -0,0 +1,29 @@ +{ ... }: let + group = "sshfwd"; +in { + networking.firewall.allowedTCPPorts = [ 2222 ]; + + users = { + groups.${group}.members = []; + + users."lia" = { + inherit group; + isSystemUser = true; + + openssh.authorizedKeys.keys + = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe7fJlh9L+9JSq0+hK7jNZjszmZqNXwzqcZ+zx0yJyU lia" ]; + }; + }; + + services.openssh.extraConfig = '' + Match Group ${group} + ForceCommand echo 'this account is only usable for remote forwarding' + PermitTunnel no + AllowAgentForwarding no + X11Forwarding no + + AllowTcpForwarding remote + GatewayPorts clientspecified + PermitListen *:2222 + ''; +} diff --git a/os/kay/modules/wireguard.nix b/os/kay/modules/wireguard.nix new file mode 100644 index 0000000..578a86a --- /dev/null +++ b/os/kay/modules/wireguard.nix @@ -0,0 +1,57 @@ +{ config, ... }: + +let + wgInterface = "wg"; + wanInterface = "ppp0"; + subnet = "10.0.1.0"; + prefix = 24; + port = 51820; +in +{ + sops.secrets."misc/wireguard" = {}; + + networking = { + nat = { + enable = true; + externalInterface = wanInterface; + internalInterfaces = [ wgInterface ]; + }; + firewall = { + allowedUDPPorts = [ port ]; + extraCommands = '' + iptables -t nat -I POSTROUTING 1 -s ${subnet}/${toString prefix} -o ${wanInterface} -j MASQUERADE + ''; + }; + + wireguard.interfaces.${wgInterface} = { + ips = [ "10.0.1.1/${toString prefix}" ]; + listenPort = port; + mtu = 1380; # 1460 (ppp0) - 80 + privateKeyFile = config.sops.secrets."misc/wireguard".path; + + peers = [ + { # cez + publicKey = "IcMpAs/D0u8O/AcDBPC7pFUYSeFQXQpTqHpGOeVpjS8="; + allowedIPs = [ "10.0.1.2/32" ]; + } + { # veu + publicKey = "bJ9aqGYD2Jh4MtWIL7q3XxVHFuUdwGJwO8p7H3nNPj8="; + allowedIPs = [ "10.0.1.3/32" ]; + } + { # dad + publicKey = "q70IyOS2IpubIRWqo5sL3SeEjtUy2V/PT8yqVExiHTQ="; + allowedIPs = [ "10.0.1.4/32" ]; + } + { # shambai + publicKey = "YYDlp/bNKkqFHAhdgaZ2SSEMnIjKTqPTK7Ju6O9/1gY="; + allowedIPs = [ "10.0.1.5/32" ]; + } + ]; + }; + }; + + services.dnsmasq.settings = { + no-dhcp-interface = wgInterface; + interface = [ wgInterface ]; + }; +} diff --git a/os/kay/modules/www.nix b/os/kay/modules/www.nix new file mode 100644 index 0000000..3891bf6 --- /dev/null +++ b/os/kay/modules/www.nix @@ -0,0 +1,134 @@ +{ config, pkgs, lib, ... }: + +let + domain = config.userdata.domain; + fscusat = "fscusat.org"; + mark = "themark.ing"; + storage = "/hdd/users/sftp/shr"; +in +{ + imports = [ + ./dendrite.nix + ./matrix-sliding-sync.nix + ./cgit.nix + ]; + + security.acme.certs.${domain}.postRun = "systemctl reload nginx.service"; + networking.firewall = { + allowedTCPPorts = [ 80 443 ]; + allowedUDPPorts = [ 443 ]; + }; + + services.nginx = { + enable = true; + package = pkgs.nginxQuic; + enableQuicBPF = true; + + recommendedTlsSettings = true; + recommendedZstdSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + recommendedBrotliSettings = true; + eventsConfig = "worker_connections 1024;"; + + virtualHosts = let + defaultOpts = { + quic = true; + http3 = true; + forceSSL = true; + useACMEHost = domain; + }; + in { + "${domain}" = defaultOpts // { + default = true; + globalRedirect = "www.${domain}"; + + extraConfig = '' + client_max_body_size ${toString + config.services.dendrite.settings.media_api.max_file_size_bytes + }; + ''; + + locations = { + "/.well-known/matrix/server".return = '' + 200 '{ "m.server": "${domain}:443" }' + ''; + + "/.well-known/matrix/client".return = '' + 200 '${builtins.toJSON { + "m.homeserver".base_url = "https://${domain}"; + "org.matrix.msc3575.proxy".url = "https://${domain}"; + }}' + ''; + + "/_matrix".proxyPass = "http://127.0.0.1:${toString + config.services.dendrite.httpPort + }"; + + "/_matrix/client/unstable/org.matrix.msc3575/sync".proxyPass = + "http://${config.services.matrix-sliding-sync.settings.SYNCV3_BINDADDR}"; + }; + }; + + "www.${domain}" = defaultOpts // { + root = "/var/www/${domain}"; + }; + + "git.${domain}" = defaultOpts; + + "bin.${domain}" = defaultOpts // { + root = "${storage}/bin"; + locations."= /".return = "307 https://www.${domain}"; + }; + + "static.${domain}" = defaultOpts // { + root = "${storage}/static"; + locations."= /".return = "301 https://www.${domain}"; + }; + + "${fscusat}" = defaultOpts // { + useACMEHost = null; + enableACME = true; + + globalRedirect = "www.${fscusat}"; + }; + "www.${fscusat}" = defaultOpts // { + useACMEHost = null; + enableACME = true; + + locations."/" = { + return = "200 '<h1>under construction</h1>'"; + extraConfig = "add_header Content-Type text/html;"; + }; + }; + + "${mark}" = defaultOpts // { + useACMEHost = null; + enableACME = true; + + globalRedirect = "www.${mark}"; + }; + "www.${mark}" = defaultOpts // { + useACMEHost = null; + enableACME = true; + + locations."/" = { + return = "200 '<h1>under construction, see you soon</h1>'"; + extraConfig = "add_header Content-Type text/html;"; + }; + }; + + "mta-sts.${domain}" = defaultOpts // { + locations."= /.well-known/mta-sts.txt".return = ''200 "${ + lib.strings.concatStringsSep "\\n" [ + "version: STSv1" + "mode: enforce" + "mx: mail.${domain}" + "max_age: 86400" + ] + }"''; + }; + }; + }; +} |