summaryrefslogtreecommitdiff
path: root/os/kay/modules
diff options
context:
space:
mode:
Diffstat (limited to 'os/kay/modules')
-rw-r--r--os/kay/modules/acme.nix23
-rw-r--r--os/kay/modules/cgit.nix33
-rw-r--r--os/kay/modules/dendrite.nix108
-rw-r--r--os/kay/modules/dns/5.6.e.e.0.7.4.0.1.0.0.2.ip6.arpa.zone14
-rw-r--r--os/kay/modules/dns/ddns.nix44
-rw-r--r--os/kay/modules/dns/default.nix137
-rw-r--r--os/kay/modules/dns/sinanmohd.com.zone46
-rw-r--r--os/kay/modules/hurricane.nix115
-rw-r--r--os/kay/modules/iperf3.nix10
-rw-r--r--os/kay/modules/mail.nix110
-rw-r--r--os/kay/modules/matrix-sliding-sync.nix18
-rw-r--r--os/kay/modules/network.nix82
-rw-r--r--os/kay/modules/router.nix43
-rw-r--r--os/kay/modules/sftp.nix44
-rw-r--r--os/kay/modules/sshfwd.nix29
-rw-r--r--os/kay/modules/wireguard.nix57
-rw-r--r--os/kay/modules/www.nix134
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"
+ ]
+ }"'';
+ };
+ };
+ };
+}