diff --git a/flake.nix b/flake.nix index 92da8ac..1b3c544 100644 --- a/flake.nix +++ b/flake.nix @@ -25,7 +25,7 @@ nixosConfigurations = { distrust = lib.nixosSystem { system = "x86_64-linux"; - modules = [./system ./services nixos-mailserver.nixosModules.default agenix.nixosModules.default]; + modules = [./system ./services ./helpers/services.nix nixos-mailserver.nixosModules.default agenix.nixosModules.default]; }; }; }; diff --git a/helpers/services.nix b/helpers/services.nix new file mode 100644 index 0000000..a1e4f5a --- /dev/null +++ b/helpers/services.nix @@ -0,0 +1,79 @@ +{ + config, + lib, + ... +}: let + cfg = config.distrust.services; +in { + options = { + distrust = { + services = lib.mkOption { + description = "Services configuration map"; + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + url = lib.mkOption { + description = "Clearnet URL"; + type = lib.types.str; + }; + onion = lib.mkOption { + description = "Onion service settings"; + type = lib.types.submodule { + options = { + url = lib.mkOption { + description = ".onion URL"; + type = lib.types.str; + }; + secretKey = lib.mkOption { + description = "Path to onion secret key file"; + type = lib.types.path; + }; + }; + }; + default = {}; + }; + virtualHostConfig = lib.mkOption { + description = "Caddy virtual host config"; + type = lib.types.str; + }; + }; + } + ); + default = {}; + }; + }; + }; + + config = { + services.tor.relay.onionServices = + builtins.foldl' + (acc: key: + acc + // { + "${key}" = { + map = [80]; + inherit (cfg.${key}.onion) secretKey; + }; + }) + {} + (builtins.attrNames cfg); + + services.caddy = { + enable = true; + virtualHosts = builtins.foldl' (acc: key: let + site = cfg.${key}; + vhostKey = "${site.url} ${site.onion.url}"; + extraCfg = '' + ${site.virtualHostConfig or ""} + header Onion-Location ${site.onion.url} + ''; + in + acc + // { + "${vhostKey}" = { + extraConfig = extraCfg; + }; + }) {} (builtins.attrNames cfg); + }; + }; +} diff --git a/helpers/tor-hostname.nix b/helpers/tor-hostname.nix new file mode 100644 index 0000000..7ef179e --- /dev/null +++ b/helpers/tor-hostname.nix @@ -0,0 +1,84 @@ +{pkgs ? import {}}: +pkgs.python3Packages.buildPythonApplication rec { + pname = "tor-hostname"; + version = "1.0.0"; + + format = "other"; + + propagatedBuildInputs = with pkgs.python3Packages; [ + pynacl + cryptography + ]; + + dontUnpack = true; + + installPhase = '' + mkdir -p $out/bin + cat > $out/bin/tor-hostname <<'EOF' + #!/usr/bin/env python3 + """Convert Tor v3 secret key to .onion hostname""" + + import hashlib + import base64 + import sys + + def onion_address_from_public_key(public_key): + """Generate .onion address from ed25519 public key""" + version = b'\x03' + checksum = hashlib.sha3_256(b'.onion checksum' + public_key + version).digest()[:2] + onion_address = base64.b32encode(public_key + checksum + version).decode().lower() + return f"{onion_address}.onion" + + def read_tor_secret_key(filepath): + """Read Tor hs_ed25519_secret_key file""" + with open(filepath, 'rb') as f: + content = f.read() + + header = b'== ed25519v1-secret: type0 ==\x00\x00\x00' + + if not content.startswith(header): + raise ValueError("Invalid Tor secret key file format") + + expanded_key = content[32:96] + return expanded_key + + def derive_public_from_expanded_secret(expanded_key): + """Derive ed25519 public key from 64-byte expanded secret key""" + from nacl.bindings import crypto_scalarmult_ed25519_base_noclamp + + secret_scalar = expanded_key[:32] + public_key = crypto_scalarmult_ed25519_base_noclamp(secret_scalar) + return public_key + + def main(): + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + secret_key_path = sys.argv[1] + + try: + expanded_key = read_tor_secret_key(secret_key_path) + public_key = derive_public_from_expanded_secret(expanded_key) + hostname = onion_address_from_public_key(public_key) + print(hostname) + except FileNotFoundError: + print(f"Error: File not found: {secret_key_path}") + sys.exit(1) + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + if __name__ == '__main__': + main() + EOF + + chmod +x $out/bin/tor-hostname + ''; + + meta = with pkgs.lib; { + description = "Convert Tor v3 secret key to .onion hostname"; + license = licenses.mit; + platforms = platforms.unix; + }; +} diff --git a/secrets/bind_pw b/secrets/bind_pw index d3c4258..125388f 100644 Binary files a/secrets/bind_pw and b/secrets/bind_pw differ diff --git a/secrets/hidden_service/akkoma b/secrets/hidden_service/akkoma new file mode 100644 index 0000000..ce1fd1a Binary files /dev/null and b/secrets/hidden_service/akkoma differ diff --git a/secrets/hidden_service/forgejo b/secrets/hidden_service/forgejo new file mode 100644 index 0000000..40fa20f --- /dev/null +++ b/secrets/hidden_service/forgejo @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 OPPxWw EI6x+qUDXzqxQSlCYUbP+7QPZMnjXpltYZtqKGTC0mA +CRKukPnjX7UkoUhvbRqp9R7okrCXSdFOKQ6NqOJOQPM +-> ssh-ed25519 aO1l/A yYtKmIaqYqE1GtbpZ57LSOvIk3ShAKRxwLhF28+kX04 +G3LaXN/I2MQsibGKQFhaN9fozZc3WTDfduVNpSs8c6c +--- l669kOCRaI4AYjSfEnh3ipLsLClXVtsZ7XeCVtYe76A +S'`Gh6mխ 8&#r%@w`o"BXegNfPd!C@ ssh-ed25519 OPPxWw uTCw+F+4qeg9cwzmqutlo73TKh+3gHLlKiNnGtH0pBg +/z43V3RLple7a9DQryhGlIuyr4zEkb1VeiP5a/Wj1uE +-> ssh-ed25519 aO1l/A 6taX73uwY+2dvd4urZsYuzdz+nCeT1esrgwVK061/Hc +hijoJqXSWN2yWwm8wJAzn0rxYFVKboov6auJMWJiQoE +--- on7Z0/l1J9q8zvDBrcLV4vDvfuSpEIuuAAOaMCywwF8 +khԐLJ8rs1/}9gSΏ-zU/$lHYtq`C25U tK >dqqpnyx"4D~"ڃeLAqzW %V}kS. \ No newline at end of file diff --git a/secrets/hidden_service/microbin b/secrets/hidden_service/microbin new file mode 100644 index 0000000..026272e --- /dev/null +++ b/secrets/hidden_service/microbin @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 OPPxWw iecDZG4hirn38+rgldEWI2+8/8rq71uWNT+SHlfAiDY +qx6clYF4hxRBJYYu0KKB7hRfPZwCbHcQpjLL941Z83c +-> ssh-ed25519 aO1l/A l5cKreKOle24HArdayk83bPWXfXsRJ+Ra+hQJ/wIbxg +so31JolmVJl3EFNBMY0+iFnt68e8IE21hPgywlgKEIA +--- hde73O1LCWGqO/2nrIg8SefxAzPp8ZY1lJFzEOCkNEs +9Q~={XCϧq$4Nlkh 5W5bQkjۺ2q/}B%+uw6 -0_;3nd\l> чC* \ No newline at end of file diff --git a/secrets/hidden_service/nextcloud b/secrets/hidden_service/nextcloud new file mode 100644 index 0000000..8da8eff Binary files /dev/null and b/secrets/hidden_service/nextcloud differ diff --git a/secrets/hidden_service/site b/secrets/hidden_service/site new file mode 100644 index 0000000..3128e86 Binary files /dev/null and b/secrets/hidden_service/site differ diff --git a/secrets/hidden_service/vaultwarden b/secrets/hidden_service/vaultwarden new file mode 100644 index 0000000..1118341 --- /dev/null +++ b/secrets/hidden_service/vaultwarden @@ -0,0 +1,7 @@ +age-encryption.org/v1 +-> ssh-ed25519 OPPxWw yYJgjjH8GaBc+bDIPHIyyG5tBqDjIe7P/9gNhnNcCGw +SomRbtpu4TqEa16yGBImEXWKNIUGNs5RIw1AT2YrEQg +-> ssh-ed25519 aO1l/A 1qypu4ZiyZTqEEVEo9Rj8BO3SlPgoPHzn5gMA8SaajU +zPPbrM6mWhhtAuU/3h8/ess31XjHf4kct9HRslv/pwM +--- rF+OjMZvtrB5BSHs89xn8i+UitXqqmmDf+UFliwOxgI +)ݏBZ׫JB1dφCFI'  &nb`i ^)@Qu͊0'f8g0gIAذ4} uY՛v,}jC5Ԯ \ No newline at end of file diff --git a/secrets/nextcloud-admin-pass b/secrets/nextcloud-admin-pass index 9a46ce1..8332c19 100644 Binary files a/secrets/nextcloud-admin-pass and b/secrets/nextcloud-admin-pass differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index a97a6d2..4b0adfa 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -10,4 +10,12 @@ in { "bind_pw".publicKeys = all; "nextcloud-admin-pass".publicKeys = all; "vaultwarden.env".publicKeys = all; + + "hidden_service/akkoma".publicKeys = all; + "hidden_service/forgejo".publicKeys = all; + "hidden_service/lldap".publicKeys = all; + "hidden_service/microbin".publicKeys = all; + "hidden_service/nextcloud".publicKeys = all; + "hidden_service/site".publicKeys = all; + "hidden_service/vaultwarden".publicKeys = all; } diff --git a/secrets/vaultwarden.env b/secrets/vaultwarden.env index cab01a4..df5e539 100644 Binary files a/secrets/vaultwarden.env and b/secrets/vaultwarden.env differ diff --git a/services/akkoma.nix b/services/akkoma.nix index 20dc366..9e2860f 100644 --- a/services/akkoma.nix +++ b/services/akkoma.nix @@ -1,8 +1,13 @@ -{pkgs, ...}: let +{ + pkgs, + config, + ... +}: let fediPort = 8083; - onionUrl = "http://n5j5sq55iem2hzbgvkba5vwd5gx5qj2pkb7nxyginbtmnkah74rtulad.onion"; inherit ((pkgs.formats.elixirConf {}).lib) mkAtom; in { + age.secrets."hidden_service/akkoma".file = ../secrets/hidden_service/akkoma; + services = { akkoma = { enable = true; @@ -35,14 +40,16 @@ in { }; }; }; + }; - caddy.virtualHosts."https://social.distrust.network ${onionUrl}".extraConfig = '' + distrust.services."akkoma" = { + url = "https://social.distrust.network"; + onion = { + url = "http://n5j5sq55iem2hzbgvkba5vwd5gx5qj2pkb7nxyginbtmnkah74rtulad.onion"; + secretKey = config.age.secrets."hidden_service/akkoma".path; + }; + virtualHostConfig = '' reverse_proxy localhost:${toString fediPort} - header Onion-Loction ${onionUrl} ''; - - tor.relay.onionServices."akkoma".map = [ - 80 - ]; }; } diff --git a/services/caddy.nix b/services/caddy.nix index 4d60b47..6e387f9 100644 --- a/services/caddy.nix +++ b/services/caddy.nix @@ -1,7 +1,13 @@ { - services = { - caddy.enable = true; - tor.enable = true; + services.caddy = { + enable = true; + #globalConfig = '' + # pki { + # ca local { + # name "Distrust CA" + # } + # } + #''; }; networking.firewall.allowedTCPPorts = [80 443]; diff --git a/services/forgejo.nix b/services/forgejo.nix index 81480cc..6039d03 100644 --- a/services/forgejo.nix +++ b/services/forgejo.nix @@ -1,26 +1,29 @@ -let +{config, ...}: let forgejoPort = 8082; - onionUrl = "http://cr27k6asjs7skvjxs6smhqfam3wlvmft2f3iins44k6p6rmmfyolobqd.onion"; in { - services = { - forgejo = { - enable = true; - lfs.enable = false; - settings.server = { - DOMAIN = "git.distrust.network"; - HTTP_PORT = forgejoPort; - ROOT_URL = "https://git.distrust.network/"; - SSH_PORT = 292; - }; + age.secrets."hidden_service/forgejo" = { + file = ../secrets/hidden_service/forgejo; + }; + + services.forgejo = { + enable = true; + lfs.enable = false; + settings.server = { + DOMAIN = "git.distrust.network"; + HTTP_PORT = forgejoPort; + ROOT_URL = "https://git.distrust.network/"; + SSH_PORT = builtins.head config.services.openssh.ports; }; + }; - caddy.virtualHosts."https://git.distrust.network ${onionUrl}".extraConfig = '' + distrust.services."forgejo" = { + url = "https://git.distrust.network"; + onion = { + url = "http://cr27k6asjs7skvjxs6smhqfam3wlvmft2f3iins44k6p6rmmfyolobqd.onion"; + secretKey = config.age.secrets."hidden_service/forgejo".path; + }; + virtualHostConfig = '' reverse_proxy localhost:${toString forgejoPort} - header Onion-Location ${onionUrl} ''; - - tor.relay.onionServices."forgejo".map = [ - 80 - ]; }; } diff --git a/services/lldap.nix b/services/lldap.nix index 5069208..86b1ece 100644 --- a/services/lldap.nix +++ b/services/lldap.nix @@ -1,25 +1,28 @@ -let - onionUrl = "http://i3a47orggn2cebueja2jur66yjgyqd2y7kzthajar4ghuerbx2kzwqyd.onion"; +{config, ...}: let + lldapPort = 8089; in { - services = { - lldap = { - enable = true; - settings = { - http_url = "https://login.distrust.network"; - ldap_user_email = "root@distrust.network"; - ldap_user_dn = "root"; - ldap_base_dn = "dc=distrust,dc=network"; - ldap_user_pass = "VERY_SECURE"; - }; + age.secrets."hidden_service/lldap".file = ../secrets/hidden_service/lldap; + + services.lldap = { + enable = true; + settings = { + http_url = "https://login.distrust.network"; + http_port = lldapPort; + ldap_user_email = "root@distrust.network"; + ldap_user_dn = "root"; + ldap_base_dn = "dc=distrust,dc=network"; + ldap_user_pass = "VERY_SECURE"; }; + }; - caddy.virtualHosts."https://login.distrust.network ${onionUrl}".extraConfig = '' - reverse_proxy localhost:17170 - header Onion-Location ${onionUrl} + distrust.services."lldap" = { + url = "https://login.distrust.network"; + onion = { + url = "http://i3a47orggn2cebueja2jur66yjgyqd2y7kzthajar4ghuerbx2kzwqyd.onion"; + secretKey = config.age.secrets."hidden_service/lldap".path; + }; + virtualHostConfig = '' + reverse_proxy localhost:${toString lldapPort} ''; - - tor.relay.onionServices."lldap".map = [ - 80 - ]; }; } diff --git a/services/nextcloud.nix b/services/nextcloud.nix index 9930b22..1cf5d32 100644 --- a/services/nextcloud.nix +++ b/services/nextcloud.nix @@ -4,18 +4,21 @@ lib, ... }: let - onionDomain = "znfdxs4e3rqvzxtkksiidomupgm2x44wtrzyxtpomczto3xg5qxpcbqd.onion"; - onionUrl = "http://${onionDomain}"; + onionHostName = "znfdxs4e3rqvzxtkksiidomupgm2x44wtrzyxtpomczto3xg5qxpcbqd.onion"; in { - age.secrets."nextcloud-admin-pass".file = ../secrets/nextcloud-admin-pass; + age.secrets = { + "nextcloud-admin-pass".file = ../secrets/nextcloud-admin-pass; + "hidden_service/nextcloud".file = ../secrets/hidden_service/nextcloud; + }; users.groups.nextcloud.members = ["nextcloud" "caddy"]; + services = { nextcloud = { enable = true; hostName = "cloud.distrust.network"; settings = { - trusted_domains = [onionDomain]; + trusted_domains = [onionHostName]; trusted_proxies = ["127.0.0.1"]; maintenance_window_start = 1; }; @@ -38,7 +41,15 @@ in { "listen.owner" = "caddy"; "listen.group" = "caddy"; }; - caddy.virtualHosts."https://cloud.distrust.network ${onionUrl}".extraConfig = '' + }; + + distrust.services."nextcloud" = { + url = "https://cloud.distrust.network"; + onion = { + url = "http://${onionHostName}"; + secretKey = config.age.secrets."hidden_service/nextcloud".path; + }; + virtualHostConfig = '' # encode zstd gzip root * ${config.services.nginx.virtualHosts."cloud.distrust.network".root} @@ -64,7 +75,7 @@ in { X-Forwarded-For {remote_host} X-Forwarded-Proto {scheme} X-Forwarded-Host {host} - Onion-Loation ${onionUrl} + Onion-Loation http://${onionHostName} } @@ -98,9 +109,5 @@ in { file_server ''; - - tor.relay.onionServices."nextcloud".map = [ - 80 - ]; }; } diff --git a/services/paste.nix b/services/paste.nix index abf97f0..3d5a355 100644 --- a/services/paste.nix +++ b/services/paste.nix @@ -1,27 +1,28 @@ -let +{config, ...}: let pastePort = 8087; - onionUrl = "http://s4h5nfnwwhzku55opxlqouobioibx4htwygnp2l4fkp256lur5s53rad.onion"; in { - services = { - microbin = { - enable = true; - settings = { - MICROBIN_PORT = pastePort; - MICROBIN_ENABLE_BURN_AFTER = true; - MICROBIN_QR = true; - MICROBIN_NO_LISTING = true; - MICROBIN_HIGHLIGHTSYNTAX = true; - MICROBIN_PUBLIC_PATH = "https://paste.distrust.network/"; - }; + age.secrets."hidden_service/microbin".file = ../secrets/hidden_service/microbin; + + services.microbin = { + enable = true; + settings = { + MICROBIN_PORT = pastePort; + MICROBIN_ENABLE_BURN_AFTER = true; + MICROBIN_QR = true; + MICROBIN_NO_LISTING = true; + MICROBIN_HIGHLIGHTSYNTAX = true; + MICROBIN_PUBLIC_PATH = "https://paste.distrust.network/"; }; + }; - caddy.virtualHosts."https://paste.distrust.network ${onionUrl}".extraConfig = '' + distrust.services."microbin" = { + url = "https://paste.distrust.network"; + onion = { + url = "http://s4h5nfnwwhzku55opxlqouobioibx4htwygnp2l4fkp256lur5s53rad.onion"; + secretKey = config.age.secrets."hidden_service/microbin".path; + }; + virtualHostConfig = '' reverse_proxy localhost:${toString pastePort} - header Onion-Location ${onionUrl} ''; - - tor.relay.onionServices."microbin".map = [ - 80 - ]; }; } diff --git a/services/site.nix b/services/site.nix index 3459106..fe87ed1 100644 --- a/services/site.nix +++ b/services/site.nix @@ -1,15 +1,17 @@ -let - onionUrl = "http://distrustdtp5qgbk2firlzfkkmu5p6v6acuh2ox454zd2i3ujdqad5yd.onion"; -in { - services.caddy.virtualHosts = { - "https://distrust.network ${onionUrl}".extraConfig = '' - root * /etc/nixos/site - file_server - header Onion-Location ${onionUrl} - ''; +{config, ...}: { + age.secrets."hidden_service/site" = { + file = ../secrets/hidden_service/site; }; - services.tor.relay.onionServices."site".map = [ - 80 - ]; + distrust.services."site" = { + url = "https://distrust.network"; + onion = { + url = "http://distrustdtp5qgbk2firlzfkkmu5p6v6acuh2ox454zd2i3ujdqad5yd.onion"; + secretKey = config.age.secrets."hidden_service/site".path; + }; + virtualHostConfig = '' + root * /etc/nixos/site + file_server + ''; + }; } diff --git a/services/tor.nix b/services/tor.nix index 0795c08..af71524 100644 --- a/services/tor.nix +++ b/services/tor.nix @@ -10,6 +10,6 @@ ORPort = 9001; }; }; - - networking.firewall.allowedTCPPorts = [ 9001 ]; + + networking.firewall.allowedTCPPorts = [9001]; } diff --git a/services/vaultwarden.nix b/services/vaultwarden.nix index 07d647b..1a7a768 100644 --- a/services/vaultwarden.nix +++ b/services/vaultwarden.nix @@ -1,26 +1,28 @@ {config, ...}: let vaultPort = 8222; - onionUrl = "http://gfoqwlo4nmhcywzzyhfanhkf7hz64lkjayngfyrpbd7ohaucu3q4znqd.onion"; in { - age.secrets."vaultwarden.env".file = ../secrets/vaultwarden.env; + age.secrets = { + "vaultwarden.env".file = ../secrets/vaultwarden.env; + "hidden_service/vaultwarden".file = ../secrets/hidden_service/vaultwarden; + }; - services = { - vaultwarden = { - enable = true; - config = { - DOMAIN = "https://vault.distrust.network"; - ROCKET_PORT = vaultPort; - }; - environmentFile = config.age.secrets."vaultwarden.env".path; + services.vaultwarden = { + enable = true; + config = { + DOMAIN = "https://vault.distrust.network"; + ROCKET_PORT = vaultPort; }; + environmentFile = config.age.secrets."vaultwarden.env".path; + }; - caddy.virtualHosts."https://vault.distrust.network ${onionUrl}".extraConfig = '' + distrust.services."vaultwarden" = { + url = "https://vault.distrust.network"; + onion = { + url = "http://gfoqwlo4nmhcywzzyhfanhkf7hz64lkjayngfyrpbd7ohaucu3q4znqd.onion"; + secretKey = config.age.secrets."hidden_service/vaultwarden".path; + }; + virtualHostConfig = '' reverse_proxy localhost:${toString vaultPort} - header Onion-Location ${onionUrl} ''; - - tor.relay.onionServices."vaultwarden".map = [ - 80 - ]; }; } diff --git a/site/index.html b/site/index.html index 081df81..35ecb09 100644 --- a/site/index.html +++ b/site/index.html @@ -117,6 +117,7 @@ [hover]
  • Microbin (Paste) [tor] [clearnet]
  • +
  • Self-Serve Password Changes [tor] [clearnet]
  • We also host nodes for Bitcoin (BTC), Monero (XMR), an IPFS gateway, and a TOR relay to strengthen their respective networks. They are all available over clearnet and TOR using this main webpages IP diff --git a/system/configuration.nix b/system/configuration.nix index fdd6fe1..27a89c7 100644 --- a/system/configuration.nix +++ b/system/configuration.nix @@ -3,8 +3,9 @@ #!/bin/sh nixos-rebuild switch --flake /etc/nixos#distrust --impure ''; + tor-hostname = import ../helpers/tor-hostname.nix {inherit pkgs;}; in { - environment.systemPackages = with pkgs; [vim btop git alejandra statix deadnix] ++ [updateScript]; + environment.systemPackages = with pkgs; [vim btop git alejandra statix deadnix] ++ [updateScript tor-hostname]; nix.settings.experimental-features = ["nix-command" "flakes"];