Tangled infrastructure definitions in Nix

nixify appview

Signed-off-by: Anirudh Oppiliappan <anirudh@tangled.org>

anirudh.fi e838ef67 2195a8f6

verified
+4 -4
flake.lock
··· 337 337 "sqlite-lib-src": "sqlite-lib-src" 338 338 }, 339 339 "locked": { 340 - "lastModified": 1758898964, 341 - "narHash": "sha256-UFCO4KN7EzT058WcJtjiQiIaoKwSP2ddkhPK74S8zug=", 340 + "lastModified": 1762506184, 341 + "narHash": "sha256-4NqqrAHQXMUasM5Vw7BUUgjvXA1xrfYkhaKu6YNxFpo=", 342 342 "ref": "refs/heads/master", 343 - "rev": "7ddfed41ed0e2241dbb2edb9b0f69fce7e40f820", 344 - "revCount": 1450, 343 + "rev": "30d281f77d830b1c45104a44c9e7e5eafb52b354", 344 + "revCount": 1611, 345 345 "type": "git", 346 346 "url": "https://tangled.org/@tangled.org/core" 347 347 },
+30
flake.nix
··· 29 29 }; 30 30 nixosConfigurations.pds = nixpkgs.lib.nixosSystem { 31 31 system = "x86_64-linux"; 32 + specialArgs = { 33 + commonArgs = import ./common/ssh.nix; 34 + }; 32 35 modules = [ 33 36 disko.nixosModules.disko 34 37 ./hosts/pds/configuration.nix 38 + ]; 39 + }; 40 + nixosConfigurations.appview = nixpkgs.lib.nixosSystem { 41 + system = "x86_64-linux"; 42 + specialArgs = { 43 + commonArgs = import ./common/ssh.nix; 44 + }; 45 + modules = [ 46 + disko.nixosModules.disko 47 + ./hosts/appview/configuration.nix 35 48 ]; 36 49 }; 37 50 ··· 50 63 environment.systemPackages = [ 51 64 pkgs.curl 52 65 ]; 66 + }; 67 + appview = { pkgs, ... }: { 68 + deployment = { 69 + targetHost = "alpha.tangled.sh"; 70 + targetPort = 22; 71 + targetUser = "tangler"; 72 + buildOnTarget = true; 73 + }; 74 + nixpkgs.system = "x86_64-linux"; 75 + imports = [ 76 + disko.nixosModules.disko 77 + tangled.nixosModules.appview 78 + ./hosts/appview/configuration.nix 79 + ./hosts/appview/services/appview.nix 80 + ./hosts/appview/services/nginx-alpha.nix 81 + ]; 82 + time.timeZone = "Europe/Helsinki"; 53 83 }; 54 84 pds = { pkgs, ... }: { 55 85 deployment = {
+57
hosts/appview/configuration.nix
··· 1 + { modulesPath 2 + , lib 3 + , pkgs 4 + , ... 5 + } @ args: 6 + { 7 + imports = [ 8 + (modulesPath + "/installer/scan/not-detected.nix") 9 + (modulesPath + "/profiles/qemu-guest.nix") 10 + ./disk-config.nix 11 + ]; 12 + boot.loader.grub = { 13 + # no need to set devices, disko will add all devices that have a EF02 partition to the list already 14 + # devices = [ ]; 15 + efiSupport = true; 16 + efiInstallAsRemovable = true; 17 + }; 18 + 19 + networking.hostName = "appview-arn"; 20 + services = { 21 + openssh.enable = true; 22 + }; 23 + 24 + 25 + nix = { 26 + extraOptions = '' 27 + experimental-features = nix-command flakes ca-derivations 28 + warn-dirty = false 29 + keep-outputs = false 30 + ''; 31 + }; 32 + 33 + environment.systemPackages = map lib.lowPrio [ 34 + pkgs.curl 35 + pkgs.gitMinimal 36 + ]; 37 + 38 + users.users.tangler = { 39 + extraGroups = [ "networkmanager" "wheel" ]; 40 + openssh.authorizedKeys.keys = args.commonArgs.sshKeys; 41 + isNormalUser = true; 42 + }; 43 + 44 + security.sudo.extraRules = [ 45 + { 46 + users = [ "tangler" ]; 47 + commands = [ 48 + { 49 + command = "ALL"; 50 + options = [ "NOPASSWD" ]; 51 + } 52 + ]; 53 + } 54 + ]; 55 + 56 + system.stateVersion = "25.05"; 57 + }
+56
hosts/appview/disk-config.nix
··· 1 + # Example to create a bios compatible gpt partition 2 + { lib, ... }: 3 + { 4 + disko.devices = { 5 + disk.disk1 = { 6 + device = lib.mkDefault "/dev/vda"; 7 + type = "disk"; 8 + content = { 9 + type = "gpt"; 10 + partitions = { 11 + boot = { 12 + name = "boot"; 13 + size = "1M"; 14 + type = "EF02"; 15 + }; 16 + esp = { 17 + name = "ESP"; 18 + size = "500M"; 19 + type = "EF00"; 20 + content = { 21 + type = "filesystem"; 22 + format = "vfat"; 23 + mountpoint = "/boot"; 24 + }; 25 + }; 26 + root = { 27 + name = "root"; 28 + size = "100%"; 29 + content = { 30 + type = "lvm_pv"; 31 + vg = "pool"; 32 + }; 33 + }; 34 + }; 35 + }; 36 + }; 37 + lvm_vg = { 38 + pool = { 39 + type = "lvm_vg"; 40 + lvs = { 41 + root = { 42 + size = "100%FREE"; 43 + content = { 44 + type = "filesystem"; 45 + format = "ext4"; 46 + mountpoint = "/"; 47 + mountOptions = [ 48 + "defaults" 49 + ]; 50 + }; 51 + }; 52 + }; 53 + }; 54 + }; 55 + }; 56 + }
+11
hosts/appview/services/appview.nix
··· 1 + { modulesPath 2 + , lib 3 + , pkgs 4 + , ... 5 + } @ args: 6 + { 7 + services.tangled.appview = { 8 + enable = true; 9 + environmentFile = "/etc/secrets/appview.env"; 10 + }; 11 + }
+53
hosts/appview/services/nginx-alpha.nix
··· 1 + { config, pkgs, ... }: 2 + { 3 + services.nginx = { 4 + enable = true; 5 + recommendedTlsSettings = true; 6 + recommendedOptimisation = true; 7 + recommendedGzipSettings = true; 8 + 9 + # Fix proxy headers hash warnings 10 + appendHttpConfig = '' 11 + proxy_headers_hash_max_size 1024; 12 + proxy_headers_hash_bucket_size 128; 13 + ''; 14 + 15 + virtualHosts = { 16 + # AppView service on alpha.tangled.sh 17 + "alpha.tangled.sh" = { 18 + forceSSL = true; 19 + enableACME = true; 20 + 21 + locations."/" = { 22 + proxyPass = "http://127.0.0.1:3000"; 23 + extraConfig = '' 24 + proxy_http_version 1.1; 25 + proxy_set_header Host $host; 26 + proxy_set_header X-Real-IP $remote_addr; 27 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 + proxy_set_header X-Forwarded-Proto $scheme; 29 + client_max_body_size 100M; 30 + ''; 31 + }; 32 + 33 + # WebSocket support for /logs endpoint 34 + locations."~ /logs$" = { 35 + proxyPass = "http://127.0.0.1:3000"; 36 + proxyWebsockets = true; 37 + extraConfig = '' 38 + proxy_read_timeout 86400; 39 + ''; 40 + }; 41 + }; 42 + }; 43 + }; 44 + 45 + # Open firewall ports 46 + networking.firewall.allowedTCPPorts = [ 80 443 ]; 47 + 48 + # ACME configuration for Let's Encrypt 49 + security.acme = { 50 + acceptTerms = true; 51 + defaults.email = "team@tangled.org"; 52 + }; 53 + }
+93
hosts/appview/services/nginx.nix
··· 1 + { config, pkgs, ... }: 2 + { 3 + services.nginx = { 4 + enable = true; 5 + recommendedProxySettings = true; 6 + recommendedTlsSettings = true; 7 + recommendedOptimisation = true; 8 + recommendedGzipSettings = true; 9 + 10 + virtualHosts = { 11 + # Redirect tangled.sh → tangled.org 12 + "tangled.sh" = { 13 + serverAliases = [ "www.tangled.sh" ]; 14 + locations."/" = { 15 + return = "301 https://tangled.org$request_uri"; 16 + }; 17 + forceSSL = true; 18 + enableACME = true; 19 + }; 20 + 21 + # Redirect strings.tangled.sh → tangled.org/strings/* 22 + "strings.tangled.sh" = { 23 + locations."/" = { 24 + return = "301 https://tangled.org/strings$request_uri"; 25 + }; 26 + forceSSL = true; 27 + enableACME = true; 28 + }; 29 + 30 + # Redirect strings.tangled.org → tangled.org/strings/* 31 + "strings.tangled.org" = { 32 + locations."/" = { 33 + return = "301 https://tangled.org/strings$request_uri"; 34 + }; 35 + forceSSL = true; 36 + enableACME = true; 37 + }; 38 + 39 + # Main app on tangled.org 40 + "tangled.org" = { 41 + serverAliases = [ "www.tangled.org" ]; 42 + 43 + forceSSL = true; 44 + enableACME = true; 45 + 46 + extraConfig = '' 47 + # Redirect www → bare domain 48 + if ($host = www.tangled.org) { 49 + return 301 https://tangled.org$request_uri; 50 + } 51 + 52 + client_max_body_size 100M; 53 + ''; 54 + 55 + locations."~ ^/@tangled\\.sh(/.*)?$" = { 56 + return = "301 https://tangled.org/@tangled.org$1$is_args$args"; 57 + }; 58 + 59 + locations."~ ^/tangled\\.sh(/.*)?$" = { 60 + return = "301 https://tangled.org/tangled.org$1$is_args$args"; 61 + }; 62 + 63 + locations."~ /logs$" = { 64 + proxyPass = "http://127.0.0.1:3000"; 65 + proxyWebsockets = true; 66 + extraConfig = '' 67 + proxy_read_timeout 86400; 68 + ''; 69 + }; 70 + 71 + locations."/" = { 72 + proxyPass = "http://127.0.0.1:3000"; 73 + extraConfig = '' 74 + proxy_set_header Host $host; 75 + proxy_set_header X-Real-IP $remote_addr; 76 + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 77 + proxy_set_header X-Forwarded-Proto $scheme; 78 + include ${config.services.nginx.package}/conf/mime.types; 79 + ''; 80 + }; 81 + }; 82 + }; 83 + }; 84 + 85 + # Open firewall ports 86 + networking.firewall.allowedTCPPorts = [ 80 443 ]; 87 + 88 + # ACME configuration for Let's Encrypt 89 + security.acme = { 90 + acceptTerms = true; 91 + defaults.email = "team@tangled.org"; 92 + }; 93 + }
+1 -1
hosts/nixery/configuration.nix
··· 19 19 networking.hostName = "nixery"; 20 20 services = { 21 21 openssh.enable = true; 22 - tangled-spindle = { 22 + tangled.spindle = { 23 23 enable = true; 24 24 server = { 25 25 owner = "did:plc:wshs7t2adsemcrrd4snkeqli"; # @tangled.sh