diff --git a/.sops.yaml b/.sops.yaml index 25b1f02..ffc2093 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,9 +1,11 @@ keys: - &sv1 age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug + - &sv2 age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 - &dk1 age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t creation_rules: - path_regex: library/secrets/.*.yaml key_groups: - age: - *sv1 + - *sv2 - *dk1 diff --git a/applications/default.nix b/applications/default.nix index 0e3bb3e..1f2b734 100644 --- a/applications/default.nix +++ b/applications/default.nix @@ -1,4 +1,5 @@ {pkgs}: { write-iso = pkgs.callPackage ./write-iso.nix {}; install-remote = pkgs.callPackage ./install-remote.nix {}; + update-remote = pkgs.callPackage ./update-remote.nix {}; } diff --git a/applications/update-remote.nix b/applications/update-remote.nix new file mode 100644 index 0000000..95a8298 --- /dev/null +++ b/applications/update-remote.nix @@ -0,0 +1,4 @@ +{remote-updater}: { + type = "app"; + program = "${remote-updater}/bin/remote-updater"; +} diff --git a/configurations/default.nix b/configurations/default.nix index e6d7ff9..7166149 100644 --- a/configurations/default.nix +++ b/configurations/default.nix @@ -1,5 +1,6 @@ {lib}: { sv1 = lib.callFragment ./sv1.nix {}; + sv2 = lib.callFragment ./sv2.nix {}; dk1 = lib.callFragment ./dk1.nix {}; dk1-iso = lib.callFragment ./dk1-iso.nix {}; } diff --git a/configurations/sv2.nix b/configurations/sv2.nix new file mode 100644 index 0000000..e7dd829 --- /dev/null +++ b/configurations/sv2.nix @@ -0,0 +1,9 @@ +{ + nixosSystem, + nixosSystems, + nixosModules, +}: +nixosSystem { + system = nixosSystems.x86_64-linux; + modules = [nixosModules.sv2]; +} diff --git a/library/secrets/ddclient.yaml b/library/secrets/ddclient.yaml new file mode 100644 index 0000000..7406229 --- /dev/null +++ b/library/secrets/ddclient.yaml @@ -0,0 +1,39 @@ +dylanblades-net-password: ENC[AES256_GCM,data:g2NI/9vdP9BBiOnMragYPe9LaIzUGQFhj4uchNoQzm4=,iv:exvcNphgi2z+Bxp+VQlhAGcYPKZ2LU0TEQSK8Qqpr0g=,tag:puns2dsEEyfx0ohjRFI7fg==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzYyt3RWJ2elRTOHBTb1Vq + b1ZzanZMd1RLRGlENTBQQUV5SmhLc3kwMXkwCitESUJTRGdLTFNlbUl6OGtnS0NR + ZSs4aUVnRWtuRGQ2bkJ1M010ejZkTEkKLS0tIDFxVmEvdU1ndENFY3gwVUNRNlJL + S3pjQjVkNnkzTTlGTGVGSFZpQXpxQ28KCgJLQ5cLHZSotlyM3zAssXbpbKKRSkTq + ZGbXOxnN9dw5CbPj1Qz3o6ajU7xweFEqNOybpnZQmA+QPzCc1b5B2A== + -----END AGE ENCRYPTED FILE----- + - recipient: age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByTll3NHdMcCtVYmlUZTZJ + UmdiZ21KMFRUZ3FsclYwU0RKbTY0SzR1a1VjCk5LV0lyakl5eDdud0Q4eHptTGNw + ZFcxUURtQmdOZlJwSENDaFdlYzVLQmMKLS0tIHNFeElVQmZGaXRuTHMrWXJEbnVj + VWFOcGh1MktNMytKNmhSc3RSdEZoRTAK4PWekDDsCnC6CaCRomM5sZntmEWCfUGZ + xdqL+T5Eq3tbcThpJjs2J1kLZ/6AkN0AhDg7dCJJ+dwxfUiZWQvamQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtaDhXLzVyMGhESldqNnlj + N3VkMnpLOUZrWTkybDlROGRNRk51elRHMUZFCkpENFduOTgwR3pZSS9jMmw1Z2tr + YVp5d3F6dHBPcG9GU2phRGxETXRwQmsKLS0tIG1VRmFwQXBvVTI0UkI5YTF6bkZz + dE9iRXhHUmc2ZUQralp4VGJ4dVlSdlUKYtBWPas2JYF5WzFgymsgy+DP7JvgcNvQ + q6uuRw8JG6+1+tCUOmpubcZ7YrMsnn2uP0Qh8Lwg9GyOnQgDe4smCg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-05-11T20:09:09Z" + mac: ENC[AES256_GCM,data:HC7wONi5gsLbb5EQ+mPHqnzt6v9zODVeiKxJ/odeKq+V+/AxVRt+wQ6FaxlqUpid91G1YEGWjG4qgpG8vhdTi9G5q+l5S8sD9TGzYbIE1imkoadzdOEoyRUVRtjhmjHT8Rjmd+A91x7KObqL9JCgAALvEi5nV6GZhY77bYrSZzY=,iv:l7HKxy3gvFko4GEGjTju4eaLHhzoUlQ2hcSi1gD/V7Q=,tag:q3jZwAHxJLznsteByxomdA==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/library/secrets/default.nix b/library/secrets/default.nix index af7129d..a6986fd 100644 --- a/library/secrets/default.nix +++ b/library/secrets/default.nix @@ -2,4 +2,6 @@ sb1 = ./sb1.yaml; network-manager = ./network-manager.yaml; users = ./users.yaml; + ddclient = ./ddclient.yaml; + gitea = ./gitea.yaml; } diff --git a/library/secrets/gitea.yaml b/library/secrets/gitea.yaml new file mode 100644 index 0000000..31f77f6 --- /dev/null +++ b/library/secrets/gitea.yaml @@ -0,0 +1,39 @@ +gitea-admin-password: ENC[AES256_GCM,data:AK+x3JblSAnD/BYVvu/jEg==,iv:aa+J/2NKTcdR0rfLpso61787hK5jRdEmT3CMMWRSo5g=,tag:SpqyaB6jppQEJgbcqBft1A==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVenBTTW83SUtqOHRiYkYz + VGRvU2VJL0E5WjBJdHlGcHZXcW0zbnpBQWl3CmxldkJBZFViSWpoaHhNWjRISHpC + Qm9kMmt2WjkyK0hDcW91U09FM0NIczgKLS0tIDk3MzFDTDVMcGRhaXFOclE2RHRv + d040T3dwTkFrbHBQSHc4TEV3bTY5SzQKqScv10lBS5P4FEa4/eGSx8zVPazkZErq + 5hFxn7I4ZCvJPundaoMaOLMI3vCrfwv9DCtGddcGPDZM2i99zKMPww== + -----END AGE ENCRYPTED FILE----- + - recipient: age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqVjkwanh3RnNla1VhdmVz + ZnJ4cHRYSEVJT0ViWldzQnVhMm8ycVpQY3k0ClNrWjVadlQxYzg0OFcwaDN5K1BR + TmRuVDA5Ykp6Tk53OUR3dGZFRitqZ2cKLS0tIGN2c1lYelptakFwUXdtTTNZL1Ni + VnVzS21NSnRiT0p3RHFrN1k5UzYvcHcKHNpIpuW7pmFmqkFTrQIejlciYak9qbTe + aNyTVRLaBqUdQS8BkkltfneKnIgAGytLjLM63YkIV137Pl+ATq22UQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3U1VkWFB6b00yd056VzJx + a0pvU0xkTnRwN1BLMmxXUU9Sd3IvTlF2WGdrCjh2M2o0eHdiR3ZJVGp1dFJLbjVU + WjJPczRuSnRnOW5TOTZ0VXBHZVloS1UKLS0tIDh0RUQ3N2grY0w5QU5BZS9XRnhV + a2FJbk4vaWhmQnRUVzFBOGtwNkg3L2sKu5Yha2rAdFXmLbdUZcXwFYfaMk8KwaI7 + 2xlNBxyHF/9X/jSebhgS8f7lXgk1Qt981Nve6Wj7CShWQmYdIj5oWA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-05-16T20:07:27Z" + mac: ENC[AES256_GCM,data:Tpj9skaayjpd6WTav8i8ezKVwIRDLk7CY72xoZgsEdT25jgkUCR6TWi0lGcFu0hOWNSNrlbMrFoSucfHdi3qcOk9q/jipexy5OcD2edTOmiCe8PkUnx/+uddHSnJ6gwbvi9RRmx8RRDE7TgasQpex16dp6OoHuO6M01nIgVWdEA=,iv:7FmXzbY4ztbHPcapqAyMypNW3AuGkcp4pRKq89SfPLc=,tag:/BJEffonTy2W92S2FRJZtQ==,type:str] + pgp: [] + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/library/secrets/network-manager.yaml b/library/secrets/network-manager.yaml index 2a4a581..93cb18f 100644 --- a/library/secrets/network-manager.yaml +++ b/library/secrets/network-manager.yaml @@ -9,20 +9,29 @@ sops: - recipient: age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByRDNtR1huOVJ6clNycERp - M0R0SnM2RUVCVXFFWWUrdnZzVHVIS1luZkEwCkUrVHpjTWlPdmZJRXQ2M2xGdzBn - OTVlcDRFdzZsUlRFVE1Vd1VFKy81R00KLS0tIFRSNHowK3E0UGZlYzk1RW5HR2tV - bWNYUG16QTZ1b3RHWThPcm5vdUpGenMKs7xWFe70u3ochn51t7uGITG/oHRDC4v5 - LJIl5LBauwkJO3ddZqPnc57ci2lXukM8Z4EKi3QwYiJ6dxxtizTAng== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0NzlXZ1RFTnIwb3pFR01l + aWcwdTZZdy9KbFBNbU55RisxQnNCcFVqaGd3Cm9HT25ZWHErN0tZY3h1L3NqbldP + SWtsdURCaEQ0bWV1Y3RPdkV6ZzNQOEUKLS0tIFJXNDkraitMYjNaNnQ1S1QzMDJI + QVVsWGpxbkd5cWxqemdsZzQ4aFZ1OEUK2arjSOcjPUXKpfyAYUKYGSpvXcMy/O43 + i3HNZldZaFrXgjr9PvXBjKJMCKZ86Ps7hZIT/YSCmEydQ2WyAdbYjA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBubG5VZkM1M2srVU1iZU81 + Zm9ZaXFMTW43RFFMY0RPTVQxTGsvamRWQVZVCmNqeHA2WjR4YmJES0lGYjlVMDgr + aDMybW15dExNMEphRENkMEF6Ym1YbFkKLS0tIG1ES0hFVzVOVWVwdlBRTFNtTkdQ + UTFkNTExQ3F0c29tR2pHbCsxMVhwY3MKx+Rv72gAJn+I03UAJgTdBsIi36KLAQvB + YIOCv7fuLygeStT9dJ2RFdGr/DG8qHZREbHCXmDBfJNXAnJSeXZYGA== -----END AGE ENCRYPTED FILE----- - recipient: age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHbG9VZDBvM3k2Z0pFMTNO - ZHQ2UUtMWnJhVGY2M256L2lEbVpLUFM4R0V3ClhCNUV1b0ZEQkhaRklMenpyRzJq - Ym95Y21BUHpacXhFcnhwY2FwMUMzQ2MKLS0tIDRuY2FnbVEzQ295R3JqUnk0NjVC - enEyWkRVT014Vk1FTktmVU5kbjVaUTAKJKIIMjBDLJxXv6y9nIzirH5vaqkQyZ6a - pF45ayqxXOAdonrnn0hbyxW8NcKp0Jjy0ehTd6AfAnNCrxPomPbflw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1K1Bld0N3a2k4anczcXBs + UjlxTXhmMU9lOTMvWGcvYnpjUU1XMm9McUFvCkc2Rng5b3ZsNzh5T0haSm9oYzRO + c0tGajFNdFQ3RjlrUFoxMG1QZmdzUjQKLS0tIDlya2J1R1VzUUtMckdkZktzR2ds + SEJkSnRMOEZhdURVa0pneHhjSEY5SkUKulLGTiJZxbNpZokoewj6vYOGS+WKahOi + yzuhKjUQYuA+TChoRHf+mei7OFHBnSUYnGuY7UoCBt+zN8x4pUt8Ow== -----END AGE ENCRYPTED FILE----- lastmodified: "2025-04-27T13:55:15Z" mac: ENC[AES256_GCM,data:sV9QVvQTeHAqPVluN+RHyUXI9zmMw3P6ok1VQ+XHnOcJb4GSWkUdOmWT4XcAMWUSPKEIbexei97rfj46BMT+2VbJS414buoOxvKSx17UVEdFwlXGVIv3jvmyrfp3jd66gSYzznJe8wBakbdKWCHb5kLnF4tqGpdgKprAxwaYnlU=,iv:wEk4qVEF20OZzdjRCRjMzZgipI76hIew39GF/dknKr4=,tag:jJU5JBHsElMxgIgANDcuJg==,type:str] diff --git a/library/secrets/sb1.yaml b/library/secrets/sb1.yaml index 5b39d52..d8fc6a1 100644 --- a/library/secrets/sb1.yaml +++ b/library/secrets/sb1.yaml @@ -9,20 +9,29 @@ sops: - recipient: age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwZWllVjN5TE1YUENueFFo - NVZDbXc5cEFBZ25PaVVRYWtGN3ZuMDI3cVhnCmRSM0g3SzU3dWZueGF2dGZYa01z - OFFuMVFIbFdRUkFGaDcyWThnME56cW8KLS0tIFkxanBHUEdOOEJ1cXppSmhDUUdC - czExSmg1YWo4YlZQM0plSG5vNnpsR28KQ8v96L/EcZmyBFnKjhJPsgN6miKdWHGt - 61KwpMn8g89+f+QdFfji4NkJfteeLsnHMG+JKzoetVB05Xp+cDwfmg== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoTFNobU9hZ3BUUlB0eExZ + WE9KMjljRVpmVVZzMmlSaHZBbm5tMFhIdlNBCkJWeTZyOFoyWVJoQUZzRXlaekFS + dXhiMDVhTExOOG9oS0wvdXVDbmxxVmcKLS0tIEJnRWs2bVQ5MTMzenpncFNJNHZw + bHlCQ0FRbDZUTWs2ZkxXWGNJWkVuM0EK69xEaK2gF6PHqzv0keZCOIHjyhopbZK7 + rvW5EcXPBXiZu67uTfnggsPp02HuZJ2zRCaL7dEHR1QulNjd5TuMKw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5TE9mMkgwQU9jKzdtTk4r + TGR6WktMUVAxS0d0eFNjMEthWm5Ucm9tSDBFCjVzU3g5Y0FSV3kwVGVZMU1XcFhi + TkZ5cGNjaG95QzYzZjVaUjB1L2o4RlUKLS0tIEZucUk1RnNuL1Zpa0tRZ2p2L2Jw + VFFWaFpLbHdZcGdMcU5GekRZSmtmMHcK6dAqNbSbicDSbv2Eq7w6A1idZx+vqmap + PML+E/cKKx899V5ZpZenzUkID+WoiLT5IJaEE2x9IrqKqZ/gnfBhxA== -----END AGE ENCRYPTED FILE----- - recipient: age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkQ2d2ZVlpTG5NTnZ0RHYx - WDVyMlkvVHdhNCtPSFluSHVQSW4yM1dhdmc0CktUazdwK1J1ME1CZERnZlRDM25p - bFczQ2hUYWY5YVZ0TTU3R2FLSHk4RkEKLS0tIGJBVkEwcDk4MjdJL3FMVnVXd0ZO - YS9pM3VKcTlTSVArK1B3ZHZnRzhvQW8KfdvpHYMWHkTaprrB1WgRIBHzQnaWeKmp - Rx6xKwOeTaIS4g62Lv9M9uHJzaVD2v22Q53MNeHOPS+47D7XBrstrA== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwL2hwSm03VlFGUE1iZ1Vx + Y1c1anc1d0ZYelhrSVpjcXovclpLeWxJdkZjCi9uaEVWWXVibDl5SDk4MGFwdi9R + eWJqeHlqd1dIUldkYzgxQ2t3RkRpSUEKLS0tIGtXajdxNDF1S0dyYzVHWDlVT1Bj + VkxySnlHMVluVk9TRURmVlNwR1lndzgK5Zje8OrG8RCtnAcT6LcpvMBei4V15OFJ + DHfFPkt5/d1YxXh3kxUw0eXHkQY/8GsTE0ybB3uezie0bEeFBSHYYg== -----END AGE ENCRYPTED FILE----- lastmodified: "2025-01-01T22:35:24Z" mac: ENC[AES256_GCM,data:PH0lfE79d1ZuE0YyMZuWhpZNu1OHh+9JMNbr66RJoRRPpLa134Y6mQE+PzZXOZ0PR2mT+VOrkNhNRhzEhr79oScM0d3ahBfKVY8VcNpvP34Llb9PQWPAZpQ5moa9o6g850bLrXl3XolLPEMpZg4BVa5EzFjo9BXNbuSY/zoW2x0=,iv:my+mb+qbjDs3iHdmaEptylgHbNu7a6zwHx2NEhlwi1Q=,tag:YfEYhl4QOulNbKALLB8ylg==,type:str] diff --git a/library/secrets/users.yaml b/library/secrets/users.yaml index 11d0db8..687969f 100644 --- a/library/secrets/users.yaml +++ b/library/secrets/users.yaml @@ -9,20 +9,29 @@ sops: - recipient: age1zr5m64rzl8r5pk5cnwcfycc8ze09lx4xqa6s0cpkf24gwwxxpy2sltfsug enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBveHVjN2EwYjgrc2FLRVpL - cVBUNStRRkI2RnpBb3YzZUx6dnpJUHhiamwwCkJ1L3lubWZ3Y0YyWXNQWmJkMjhL - TkxTejRWUWIzajBNcFBqSnJBQ1BFL2cKLS0tIEl0TllEcStwTWF0NngxWVM1cUdI - M2E5TG56S3FMaFVhUG5JQmw2SWpKQjAKNmddLTfypjo3wU84jOsCQULX5cmUunWt - WM712sCFeJShWTA47zBg9um4+dWhY+QungDiuJO2+zoj6UMuE31vew== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvT2gxTENibzlwQzVmcng4 + MS9aVzMxUDhKbkZQZlYyTEx6c0VJVWtXSDFJCk1VSVNrbWJnbHVNMzk4MGxuTlZq + OFl0ekRIL3Fwa2ZsUUwzdnRWUGQ2YnMKLS0tIEZKdjMzeWswOTBDTnZxNVU2aER0 + Zi9ROEtEYzVIOWxMUDl0M1M3Y2lnNTQK1Bu4xf+GFvpEJx2wadgtx/AJ65tzc6Jh + a7kY0Ih6TeVc7jvTy07ahU9I5SwwHMmQqz3RMG+QYl6zyMVQGahJ0w== + -----END AGE ENCRYPTED FILE----- + - recipient: age1zyl84qp93ykfx9h7egcrt8m4uczcwg2zk40s6l5g7svfnsvs2ddsazzs74 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwbllibWFMbkY5ZFg1dUFY + cEk5L1JBWko1bFV2RnhYYmY1NThGN2FNN3pBCnFoOEN6VDhoemFBajBPQWFjZjQ1 + WjJOajdUaGtTdVlNMXljWFVSUTY1dEUKLS0tIHdxaE5CUW0rbHc4ck85b1BrdFNp + R25yV1pZcWVSRURWZ1lxSXVqUkNiVDgKlc0dz/3335Rd2uhkQP4HVParz6DFHLx9 + GBsFE6ytqL1V9XZwQdekSYwkN4+m4KMt01MzN9y3s9flbPH5UjFUIQ== -----END AGE ENCRYPTED FILE----- - recipient: age14x7k4stulqyp849x3uksprk2w3vjyn6pjlvgrp6up3tem6g6xucqvms68t enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5cUFWeDJ2L1lWazE1eFZC - MEZSQmRiNDhuY0VvWStMUkUrQ0Z0V1BrYVdZCitFTDB4d2ZWVE5lLzhMbWFVSFZ3 - RkdxTzlYQkRyclFFclhnRXdqa1o3Z0kKLS0tIEFmNUFTWkl4K3dtTWhJK2ptWXpJ - NUdwczNJNDVEQkk5cnl4Mmh3UGMra1EKFEIbff+6kGo67KCd1Dj+dRaqlfM5Rmi5 - MiYibYIb5Ff47HG/uEA/u5nt/DHE8yUGeBldbJoqE92arA18st8dgg== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNZnI5clRNbms0ZExrT3l6 + NXJSZW1zZUkrQzFZZUFrSzVSWVh0Nm9rTFVvCmtxcG83emFlU2tPcXl3bDVBbW1n + bGhMeFNHaWliV3VESktvODVlVGM2QUkKLS0tIFZmZjQxM0x1VTZPN3k5WS9CQzU3 + NjM1VGF2Mm84djQxMGZhTjRqejNDMWsKIFT+Mn3xquK8q7XCyy6/p8MbUDCWpMfM + PcAGhpj3m57vG+UDrL+1MTONr1E6+vhKIiKhxi2ZQ6kBnU2qVLpa8Q== -----END AGE ENCRYPTED FILE----- lastmodified: "2025-04-27T13:58:51Z" mac: ENC[AES256_GCM,data:uMCeMLYJrfAHQ037NZKmXTuPuZnSU1GOCFMsVE/xjGBkZnXJ4yYh3Fec3ncyuD0HWHgEeFGh4lRi3YNu6nkiK2R/mCrIrm4A3Ry0k0yGjam6Q8dfigaV9RkmMf50bV+JA6j03G5pxfyrBq5OTSWohYSmsvOTJXRKvIJalxfn+f0=,iv:AUcoar5Ls3qLtcg6WkHjElYefwsHN2GNKIMinvF0bps=,tag:qDCpTXRMsjS8880csWRTpw==,type:str] diff --git a/modules/default.nix b/modules/default.nix index bbc334a..0f30830 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,5 +1,30 @@ { - sv1 = import ./sv1.nix; - dk1 = import ./dk1.nix; - dk1-iso = import ./dk1-iso.nix; + secrets = import ./secrets.nix; + networking = import ./networking.nix; + locale = import ./locale.nix; + users = import ./users.nix; + overlays = import ./overlays.nix; + nix = import ./nix.nix; + version = import ./version.nix; + + ssh = import ./ssh.nix; + storage-box = import ./storage-box.nix; + + sv1 = import ./sv1/legacy.nix; + + sv2 = import ./sv2/install.nix; + sv2-disk = import ./sv2/disk.nix; + sv2-hardware = import ./sv2/hardware.nix; + sv2-services-my-site = import ./sv2/services/my-site.nix; + sv2-services-gitea = import ./sv2/services/gitea.nix; + sv2-services-jellyfin = import ./sv2/services/jellyfin.nix; + + dk1 = import ./dk1/install.nix; + dk1-iso = import ./dk1/iso.nix; + dk1-disk = import ./dk1/disk.nix; + dk1-hardware = import ./dk1/hardware.nix; + dk1-services-ddclient = import ./dk1/services/ddclient.nix; + dk1-services-my-site = import ./dk1/services/my-site.nix; + dk1-services-gitea = import ./dk1/services/gitea.nix; + dk1-services-jellyfin = import ./dk1/services/jellyfin.nix; } diff --git a/modules/dk1-iso.nix b/modules/dk1-iso.nix deleted file mode 100644 index fbd8b73..0000000 --- a/modules/dk1-iso.nix +++ /dev/null @@ -1,133 +0,0 @@ -{ - lib, - config, - pkgs, - modulesPath, - ... -}: { - imports = with lib.nixosModules; [ - (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") - sops - ]; - - sops = { - gnupg.sshKeyPaths = []; - age = { - sshKeyPaths = []; - keyFile = "/iso/key"; - }; - secrets = { - root-password = { - sopsFile = lib.secrets.users; - neededForUsers = true; - }; - user-password = { - sopsFile = lib.secrets.users; - neededForUsers = true; - }; - home-ssid.sopsFile = lib.secrets.network-manager; - home-psk.sopsFile = lib.secrets.network-manager; - }; - templates.network-manager.content = '' - home_ssid="${config.sops.placeholder.home-ssid}" - home_psk="${config.sops.placeholder.home-psk}" - ''; - }; - - boot.extraModulePackages = with config.boot.kernelPackages; [ - rtl88xxau-aircrack - ]; - - networking = { - hostName = "dk1-iso"; - wireless.enable = false; - networkmanager = { - enable = true; - ensureProfiles = { - profiles.home = { - connection = { - id = "home"; - type = "wifi"; - }; - ipv4 = { - method = "manual"; - address1 = "192.168.0.200/24"; - gateway = "192.168.0.1"; - dns = "192.168.0.1"; - }; - wifi = { - ssid = "$home_ssid"; - mode = "infrastructure"; - }; - wifi-security = { - auth-alg = "open"; - key-mgmt = "wpa-psk"; - psk = "$home_psk"; - }; - }; - environmentFiles = [config.sops.templates.network-manager.path]; - }; - }; - }; - - time.timeZone = "Europe/London"; - i18n.defaultLocale = "en_GB.UTF-8"; - console.keyMap = "uk"; - - users = { - mutableUsers = false; - users = { - root = { - isSystemUser = true; - hashedPassword = null; - hashedPasswordFile = config.sops.secrets.root-password.path; - openssh.authorizedKeys.keys = with lib.sshKeys; [ - lp1.user - lp2.user - ]; - }; - user = { - isNormalUser = true; - extraGroups = ["wheel"]; - hashedPassword = null; - hashedPasswordFile = config.sops.secrets.user-password.path; - openssh.authorizedKeys.keys = with lib.sshKeys; [ - lp1.user - lp2.user - ]; - }; - nixos = { - hashedPassword = null; - hashedPasswordFile = config.sops.secrets.user-password.path; - }; - }; - }; - - services = { - openssh = { - enable = true; - settings.PermitRootLogin = lib.mkForce "without-password"; - }; - getty = { - helpLine = lib.mkForce ""; - autologinUser = lib.mkForce null; - }; - }; - - nixpkgs.overlays = [lib.overlays.pkgs]; - environment.systemPackages = with pkgs; [ - git - my-vim - nixos-anywhere - ]; - - nix.settings = { - trusted-users = ["root"]; - experimental-features = [ - "nix-command" - "flakes" - ]; - }; - - system.stateVersion = "24.11"; -} diff --git a/modules/dk1.nix b/modules/dk1/disk.nix similarity index 53% rename from modules/dk1.nix rename to modules/dk1/disk.nix index aef97d3..6e3e5b4 100644 --- a/modules/dk1.nix +++ b/modules/dk1/disk.nix @@ -1,9 +1,4 @@ -{ - lib, - config, - pkgs, - ... -}: { +{lib, ...}: { imports = with lib.nixosModules; [disko]; disko.devices.disk.NixOS = { @@ -37,6 +32,7 @@ }; }; }; + boot = { loader = { grub = { @@ -49,46 +45,5 @@ efiSysMountPoint = "/efi"; }; }; - extraModulePackages = with config.boot.kernelPackages; [rtl88xxau-aircrack]; }; - - networking = { - hostName = "dk1"; - networkmanager.enable = true; - }; - - time.timeZone = "Europe/London"; - i18n.defaultLocale = "en_GB.UTF-8"; - console.keyMap = "uk"; - - users = { - mutableUsers = false; - users = { - root = { - isSystemUser = true; - password = "root"; - }; - user = { - isNormalUser = true; - extraGroups = ["wheel"]; - password = "user"; - }; - }; - }; - - nixpkgs.overlays = [lib.overlays.pkgs]; - environment.systemPackages = with pkgs; [ - git - my-vim - ]; - - nix.settings = { - trusted-users = ["root"]; - experimental-features = [ - "nix-command" - "flakes" - ]; - }; - - system.stateVersion = "24.11"; } diff --git a/modules/dk1/hardware.nix b/modules/dk1/hardware.nix new file mode 100644 index 0000000..d845aa3 --- /dev/null +++ b/modules/dk1/hardware.nix @@ -0,0 +1,6 @@ +{config, ...}: { + boot.extraModulePackages = with config.boot.kernelPackages; [ + rtl88xxau-aircrack + ]; + console.keyMap = "uk"; +} diff --git a/modules/dk1/install.nix b/modules/dk1/install.nix new file mode 100644 index 0000000..3b1af3e --- /dev/null +++ b/modules/dk1/install.nix @@ -0,0 +1,36 @@ +{ + lib, + pkgs, + ... +}: { + imports = with lib.nixosModules; [ + secrets + networking + locale + users + overlays + nix + version + + ssh + + dk1-disk + dk1-hardware + dk1-services-ddclient + dk1-services-gitea + dk1-services-jellyfin + ]; + + sops.age.keyFile = "/var/lib/sops-nix/key.age"; + + networking = { + hostName = "dk1"; + networkmanager.ensureProfiles.profiles.home.ipv4 + .address1 = "192.168.0.200/24"; + }; + + environment.systemPackages = with pkgs; [ + git + my-vim + ]; +} diff --git a/modules/dk1/iso.nix b/modules/dk1/iso.nix new file mode 100644 index 0000000..6495b59 --- /dev/null +++ b/modules/dk1/iso.nix @@ -0,0 +1,44 @@ +{ + lib, + config, + modulesPath, + ... +}: { + imports = with lib.nixosModules; [ + (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") + + secrets + networking + locale + users + overlays + nix + version + + ssh + + dk1-hardware + ]; + + sops.age.keyFile = "/iso/key"; + + networking = { + hostName = "dk1-iso"; + wireless.enable = false; + networkmanager.ensureProfiles.profiles.home.ipv4 + .address1 = "192.168.0.200/24"; + }; + + users.users.nixos = { + hashedPassword = null; + hashedPasswordFile = config.sops.secrets.user-password.path; + }; + + services = { + openssh.settings.PermitRootLogin = lib.mkForce "without-password"; + getty = { + helpLine = lib.mkForce ""; + autologinUser = lib.mkForce null; + }; + }; +} diff --git a/modules/dk1/services/ddclient.nix b/modules/dk1/services/ddclient.nix new file mode 100644 index 0000000..cb3b142 --- /dev/null +++ b/modules/dk1/services/ddclient.nix @@ -0,0 +1,25 @@ +{ + lib, + config, + ... +}: let + rootDomain = "dylanblades.net"; + passwordFile = config.sops.secrets.dylanblades-net-password.path; +in { + imports = with lib.nixosModules; [secrets]; + + sops.secrets.dylanblades-net-password.sopsFile = lib.secrets.ddclient; + + services.ddclient = { + enable = true; + usev4 = "webv4, webv4=dynamicdns.park-your-domain.com/getip"; + protocol = "namecheap"; + server = "dynamicdns.park-your-domain.com"; + username = rootDomain; + inherit passwordFile; + domains = [ + "*" + "@" + ]; + }; +} diff --git a/modules/dk1/services/gitea.nix b/modules/dk1/services/gitea.nix new file mode 100644 index 0000000..24cd5a5 --- /dev/null +++ b/modules/dk1/services/gitea.nix @@ -0,0 +1,101 @@ +{ + lib, + config, + ... +}: let + rootDomain = "dylanblades.net"; + hostDomain = rootDomain; + + adminUsername = "Bladesy"; + adminEmail = "gitea@dylanblades.net"; +in { + imports = with lib.nixosModules; [secrets]; + + sops.secrets.gitea-admin-password = { + sopsFile = lib.secrets.gitea; + owner = config.users.users.gitea.name; + group = config.users.users.gitea.group; + }; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + certs.${hostDomain}.extraDomainNames = ["gitea.${rootDomain}"]; + }; + + # Workaround for useWizard. + systemd.services.gitea.postStart = let + exe = lib.getExe config.services.gitea.package; + adminPasswordFile = config.sops.secrets.gitea-admin-password.path; + in '' + [ "$(${exe} admin user list --admin | wc -l)" -eq 1 ] \ + && ${exe} admin user create \ + --admin \ + --username Bladesy \ + --email gitea@dylanblades.net \ + --password "$(cat ${adminPasswordFile})" \ + && echo "admin created" \ + || echo "admin already present" + ''; + + services = { + gitea = { + enable = true; + /* + Option useWizard does not work. + useWizard = true; + */ + appName = "Gitea"; + settings = { + service.DISABLE_REGISTRATION = true; + server = { + DOMAIN = "gitea.${rootDomain}"; + ROOT_URL = "https://gitea.${rootDomain}/"; + }; + ui.DEFAULT_THEME = "gitea-dark"; + }; + }; + nginx = { + enable = true; + virtualHosts = { + ${hostDomain}.enableACME = true; + "gitea.${rootDomain}" = { + forceSSL = true; + useACMEHost = hostDomain; + locations."/" = { + proxyPass = "http://localhost:3000"; + extraConfig = '' + client_max_body_size 512M; + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + ''; + }; + }; + }; + }; + }; + + /* + Required for an ephemeral system. + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + { + directory = "/var/lib/gitea"; + user = "gitea"; + group = "gitea"; + mode = "u=rwx,g=rx,o="; + } + ]; + }; + */ +} diff --git a/modules/dk1/services/jellyfin.nix b/modules/dk1/services/jellyfin.nix new file mode 100644 index 0000000..6ac82a4 --- /dev/null +++ b/modules/dk1/services/jellyfin.nix @@ -0,0 +1,74 @@ +let + rootDomain = "dylanblades.net"; + hostDomain = rootDomain; +in { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + certs.${hostDomain}.extraDomainNames = ["jellyfin.${rootDomain}"]; + }; + + services = { + jellyfin.enable = true; + nginx = { + enable = true; + virtualHosts = { + ${hostDomain}.enableACME = true; + "jellyfin.${rootDomain}" = { + forceSSL = true; + useACMEHost = hostDomain; + locations = { + "/" = { + proxyPass = "http://localhost:8096"; + extraConfig = '' + client_max_body_size 20M; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Protocol $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_buffering off; + ''; + }; + "/socket" = { + proxyPass = "http://localhost:8096"; + extraConfig = '' + client_max_body_size 20M; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Protocol $scheme; + proxy_set_header X-Forwarded-Host $http_host; + ''; + }; + }; + }; + }; + }; + }; + + /* + Required for an ephemeral system. + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + { + directory = "/var/lib/jellyfin"; + user = "jellyfin"; + group = "jellyfin"; + mode = "u=rwx,g=rx,o="; + } + ]; + }; + */ +} diff --git a/modules/dk1/services/my-site.nix b/modules/dk1/services/my-site.nix new file mode 100644 index 0000000..fab0a2d --- /dev/null +++ b/modules/dk1/services/my-site.nix @@ -0,0 +1,31 @@ +{pkgs, ...}: let + rootDomain = "dylanblades.net"; + hostDomain = rootDomain; +in { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + /* + Should have logic about extra certs here for the case where rootDomain and + hostDomain are not the same. + */ + }; + + services.nginx = { + enable = true; + /* + Should really be using hostDomain here for ACME, and rootDomain for my-site. + This is not robust and should be changed. + */ + virtualHosts.${rootDomain} = { + forceSSL = true; + enableACME = true; + root = pkgs.my-site; + }; + }; +} diff --git a/modules/locale.nix b/modules/locale.nix new file mode 100644 index 0000000..85eafd9 --- /dev/null +++ b/modules/locale.nix @@ -0,0 +1,4 @@ +{ + time.timeZone = "Europe/London"; + i18n.defaultLocale = "en_GB.UTF-8"; +} diff --git a/modules/networking.nix b/modules/networking.nix new file mode 100644 index 0000000..974f76a --- /dev/null +++ b/modules/networking.nix @@ -0,0 +1,47 @@ +{ + lib, + config, + ... +}: { + imports = with lib.nixosModules; [secrets]; + + sops = { + secrets = { + home-ssid.sopsFile = lib.secrets.network-manager; + home-psk.sopsFile = lib.secrets.network-manager; + }; + templates.network-manager.content = '' + home_ssid="${config.sops.placeholder.home-ssid}" + home_psk="${config.sops.placeholder.home-psk}" + ''; + }; + + networking = { + networkmanager = { + enable = true; + ensureProfiles = { + profiles.home = { + connection = { + id = "home"; + type = "wifi"; + }; + ipv4 = { + method = "manual"; + gateway = "192.168.0.1"; + dns = "192.168.0.1"; + }; + wifi = { + ssid = "$home_ssid"; + mode = "infrastructure"; + }; + wifi-security = { + auth-alg = "open"; + key-mgmt = "wpa-psk"; + psk = "$home_psk"; + }; + }; + environmentFiles = [config.sops.templates.network-manager.path]; + }; + }; + }; +} diff --git a/modules/nix.nix b/modules/nix.nix new file mode 100644 index 0000000..8e131bc --- /dev/null +++ b/modules/nix.nix @@ -0,0 +1,9 @@ +{ + nix.settings = { + trusted-users = ["root"]; + experimental-features = [ + "nix-command" + "flakes" + ]; + }; +} diff --git a/modules/overlays.nix b/modules/overlays.nix new file mode 100644 index 0000000..106f744 --- /dev/null +++ b/modules/overlays.nix @@ -0,0 +1,3 @@ +{lib, ...}: { + nixpkgs.overlays = [lib.overlays.pkgs]; +} diff --git a/modules/secrets.nix b/modules/secrets.nix new file mode 100644 index 0000000..b6c64d6 --- /dev/null +++ b/modules/secrets.nix @@ -0,0 +1,8 @@ +{lib, ...}: { + imports = with lib.nixosModules; [sops]; + + sops = { + gnupg.sshKeyPaths = []; + age.sshKeyPaths = []; + }; +} diff --git a/modules/ssh.nix b/modules/ssh.nix new file mode 100644 index 0000000..4ecd1d1 --- /dev/null +++ b/modules/ssh.nix @@ -0,0 +1,6 @@ +{ + services.openssh = { + enable = true; + settings.PermitRootLogin = "without-password"; + }; +} diff --git a/modules/storage-box.nix b/modules/storage-box.nix new file mode 100644 index 0000000..5456862 --- /dev/null +++ b/modules/storage-box.nix @@ -0,0 +1,34 @@ +{ + lib, + config, + pkgs, + ... +}: { + imports = with lib.nixosModules; [secrets]; + + sops = { + secrets = { + sb1-username.sopsFile = lib.secrets.sb1; + sb1-password.sopsFile = lib.secrets.sb1; + }; + templates.sb1-credentials.content = '' + username=${config.sops.placeholder.sb1-username} + password=${config.sops.placeholder.sb1-password} + ''; + }; + + fileSystems."/mnt/sb1" = { + device = "//u424050.your-storagebox.de/backup"; + fsType = "cifs"; + options = [ + "x-systemd.automount" + "noauto" + "x-systemd.idle-timeout=60" + "x-systemd.device-timeout=5s" + "x-systemd.mount-timeout=5s" + "credentials=${config.sops.templates.sb1-credentials.path}" + ]; + }; + + environment.systemPackages = with pkgs; [cifs-utils]; +} diff --git a/modules/sv1.nix b/modules/sv1/legacy.nix similarity index 100% rename from modules/sv1.nix rename to modules/sv1/legacy.nix diff --git a/modules/sv2/disk.nix b/modules/sv2/disk.nix new file mode 100644 index 0000000..83e0f0d --- /dev/null +++ b/modules/sv2/disk.nix @@ -0,0 +1,138 @@ +{lib, ...}: { + imports = with lib.nixosModules; [ + disko + impermanence + ]; + + disko.devices.disk.NixOS = { + device = "/dev/sda"; + type = "disk"; + content = { + type = "gpt"; + partitions = { + BSP = { + type = "EF02"; + size = "1M"; + }; + Crypt = { + size = "100%"; + content = { + type = "luks"; + name = "crypt"; + extraFormatArgs = ["--type luks1"]; + content = { + type = "btrfs"; + postCreateHook = '' + btrfs="$(mktemp -d)" + mount -o subvol=/ /dev/mapper/crypt "$btrfs" + btrfs subvolume snapshot -r "$btrfs/root" "$btrfs/blank" + umount "$btrfs" + rm -rf "$btrfs" + boot="$(mktemp -d)" + mount -o subvol=/boot /dev/mapper/crypt "$boot" + dd if=/dev/urandom "of=$boot/luks.bin" bs=1024 count=4 + cryptsetup luksAddKey \ + /dev/disk/by-partlabel/disk-NixOS-Crypt \ + "$boot/luks.bin" + umount "$boot" + rm -rf "$boot" + ''; + subvolumes = { + "/root" = { + mountpoint = "/"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/boot" = { + mountpoint = "/boot"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/home" = { + mountpoint = "/home"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/persist" = { + mountpoint = "/persist"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/log" = { + mountpoint = "/var/log"; + mountOptions = [ + "compress=zstd" + "noatime" + ]; + }; + "/swap" = { + mountpoint = "/.swap"; + swap.swapfile.size = "4G"; + }; + }; + }; + }; + }; + }; + }; + }; + fileSystems = { + "/persist".neededForBoot = true; + "/var/log".neededForBoot = true; + }; + + boot = { + loader = { + grub = { + enable = true; + enableCryptodisk = true; + }; + }; + initrd = { + secrets."/luks.bin" = "/boot/luks.bin"; + luks.devices.crypt = { + device = "/dev/disk/by-partlabel/disk-NixOS-Crypt"; + keyFile = "/luks.bin"; + }; + postDeviceCommands = lib.mkBefore '' + btrfs="$(mktemp -d)" + mount -o subvol=/ /dev/mapper/crypt "$btrfs" + trap "umount $btrfs_root; rm -rf $btrfs" EXIT + btrfs subvolume list -o "$btrfs/root" \ + | cut -f9 -d' ' \ + | while read subvolume; do \ + btrfs subvolume delete "$btrfs/$subvolume" + done \ + && btrfs subvolume delete "$btrfs/root" + btrfs subvolume snapshot "$btrfs/blank" "$btrfs/root" + ''; + }; + }; + + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + { + directory = "/var/lib/nixos"; + user = "root"; + group = "root"; + mode = "u=rwx,g=rx,o=rx"; + } + ]; + }; +} diff --git a/modules/sv2/hardware.nix b/modules/sv2/hardware.nix new file mode 100644 index 0000000..f6056cb --- /dev/null +++ b/modules/sv2/hardware.nix @@ -0,0 +1,25 @@ +{ + boot.initrd = { + availableKernelModules = [ + "virtio_net" + "virtio_pci" + "virtio_mmio" + "virtio_blk" + "virtio_scsi" + "9p" + "9pnet_virtio" + "ahci" + "xhci_pci" + "virtio_pci" + "virtio_scsi" + "sd_mod" + "sr_mod" + ]; + kernelModules = [ + "virtio_balloon" + "virtio_console" + "virtio_rng" + "virtio_gpu" + ]; + }; +} diff --git a/modules/sv2/install.nix b/modules/sv2/install.nix new file mode 100644 index 0000000..b0da23c --- /dev/null +++ b/modules/sv2/install.nix @@ -0,0 +1,35 @@ +{ + lib, + pkgs, + ... +}: { + imports = with lib.nixosModules; [ + secrets + locale + users + overlays + nix + version + + ssh + storage-box + + sv2-disk + sv2-hardware + sv2-services-my-site + sv2-services-gitea + sv2-services-jellyfin + ]; + + sops.age.keyFile = "/persist/key.age"; + + networking = { + hostName = "sv2"; + networkmanager.enable = true; + }; + + environment.systemPackages = with pkgs; [ + git + my-vim + ]; +} diff --git a/modules/sv2/services/gitea.nix b/modules/sv2/services/gitea.nix new file mode 100644 index 0000000..d498274 --- /dev/null +++ b/modules/sv2/services/gitea.nix @@ -0,0 +1,98 @@ +{ + lib, + config, + ... +}: let + rootDomain = "gumpling.net"; + hostDomain = rootDomain; + + adminUsername = "Bladesy"; + adminEmail = "gitea@dylanblades.net"; +in { + imports = with lib.nixosModules; [secrets]; + + sops.secrets.gitea-admin-password = { + sopsFile = lib.secrets.gitea; + owner = config.users.users.gitea.name; + group = config.users.users.gitea.group; + }; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + certs.${hostDomain}.extraDomainNames = ["gitea.${rootDomain}"]; + }; + + # Workaround for useWizard. + systemd.services.gitea.postStart = let + exe = lib.getExe config.services.gitea.package; + adminPasswordFile = config.sops.secrets.gitea-admin-password.path; + in '' + [ "$(${exe} admin user list --admin | wc -l)" -eq 1 ] \ + && ${exe} admin user create \ + --admin \ + --username Bladesy \ + --email gitea@dylanblades.net \ + --password "$(cat ${adminPasswordFile})" \ + && echo "admin created" \ + || echo "admin already present" + ''; + + services = { + gitea = { + enable = true; + /* + Option useWizard does not work. + useWizard = true; + */ + appName = "Gitea"; + settings = { + service.DISABLE_REGISTRATION = true; + server = { + DOMAIN = "gitea.${rootDomain}"; + ROOT_URL = "https://gitea.${rootDomain}/"; + }; + ui.DEFAULT_THEME = "gitea-dark"; + }; + }; + nginx = { + enable = true; + virtualHosts = { + ${hostDomain}.enableACME = true; + "gitea.${rootDomain}" = { + forceSSL = true; + useACMEHost = hostDomain; + locations."/" = { + proxyPass = "http://localhost:3000"; + extraConfig = '' + client_max_body_size 512M; + proxy_set_header Connection $http_connection; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + ''; + }; + }; + }; + }; + }; + + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + { + directory = "/var/lib/gitea"; + user = "gitea"; + group = "gitea"; + mode = "u=rwx,g=rx,o="; + } + ]; + }; +} diff --git a/modules/sv2/services/jellyfin.nix b/modules/sv2/services/jellyfin.nix new file mode 100644 index 0000000..ce61ac3 --- /dev/null +++ b/modules/sv2/services/jellyfin.nix @@ -0,0 +1,71 @@ +let + rootDomain = "gumpling.net"; + hostDomain = rootDomain; +in { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + certs.${hostDomain}.extraDomainNames = ["jellyfin.${rootDomain}"]; + }; + + services = { + jellyfin.enable = true; + nginx = { + enable = true; + virtualHosts = { + ${hostDomain}.enableACME = true; + "jellyfin.${rootDomain}" = { + forceSSL = true; + useACMEHost = hostDomain; + locations = { + "/" = { + proxyPass = "http://localhost:8096"; + extraConfig = '' + client_max_body_size 20M; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Protocol $scheme; + proxy_set_header X-Forwarded-Host $http_host; + proxy_buffering off; + ''; + }; + "/socket" = { + proxyPass = "http://localhost:8096"; + extraConfig = '' + client_max_body_size 20M; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Protocol $scheme; + proxy_set_header X-Forwarded-Host $http_host; + ''; + }; + }; + }; + }; + }; + }; + + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + { + directory = "/var/lib/jellyfin"; + user = "jellyfin"; + group = "jellyfin"; + mode = "u=rwx,g=rx,o="; + } + ]; + }; +} diff --git a/modules/sv2/services/my-site.nix b/modules/sv2/services/my-site.nix new file mode 100644 index 0000000..1e49b15 --- /dev/null +++ b/modules/sv2/services/my-site.nix @@ -0,0 +1,31 @@ +{pkgs, ...}: let + rootDomain = "gumpling.net"; + hostDomain = rootDomain; +in { + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "acme.evict519@simplelogin.com"; + /* + Should have logic about extra certs here for the case where rootDomain and + hostDomain are not the same. + */ + }; + + services.nginx = { + enable = true; + /* + Should really be using hostDomain here for ACME, and rootDomain for my-site. + This is not robust and should be changed. + */ + virtualHosts.${rootDomain} = { + forceSSL = true; + enableACME = true; + root = pkgs.my-site; + }; + }; +} diff --git a/modules/users.nix b/modules/users.nix new file mode 100644 index 0000000..7a4156a --- /dev/null +++ b/modules/users.nix @@ -0,0 +1,43 @@ +{ + lib, + config, + ... +}: { + imports = with lib.nixosModules; [secrets]; + + sops.secrets = { + root-password = { + sopsFile = lib.secrets.users; + neededForUsers = true; + }; + user-password = { + sopsFile = lib.secrets.users; + neededForUsers = true; + }; + }; + + users = { + mutableUsers = false; + users = { + root = { + isSystemUser = true; + hashedPassword = null; + hashedPasswordFile = config.sops.secrets.root-password.path; + openssh.authorizedKeys.keys = with lib.sshKeys; [ + lp1.user + lp2.user + ]; + }; + user = { + isNormalUser = true; + extraGroups = ["wheel"]; + hashedPassword = null; + hashedPasswordFile = config.sops.secrets.user-password.path; + openssh.authorizedKeys.keys = with lib.sshKeys; [ + lp1.user + lp2.user + ]; + }; + }; + }; +} diff --git a/modules/version.nix b/modules/version.nix new file mode 100644 index 0000000..a05de83 --- /dev/null +++ b/modules/version.nix @@ -0,0 +1,3 @@ +{ + system.stateVersion = "24.11"; +} diff --git a/packages/default.nix b/packages/default.nix index d1ddc20..4523606 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -4,4 +4,5 @@ iso-writer = pkgs.callPackage ./iso-writer {}; dk1-iso = pkgs.callPackage ./dk1-iso {}; remote-installer = pkgs.callPackage ./remote-installer {}; + remote-updater = pkgs.callPackage ./remote-updater {}; } diff --git a/packages/iso-writer/src/iso-writer.sh b/packages/iso-writer/src/iso-writer.sh index 0d6f545..2d4b1f4 100644 --- a/packages/iso-writer/src/iso-writer.sh +++ b/packages/iso-writer/src/iso-writer.sh @@ -48,10 +48,10 @@ root_id="0" && exit [ -z "$key" ] \ && target="$source" -[ -n "$key" -a -z "$target" ] \ - && temporary_directory="$(mktemp -d)" \ - && target="$temporary_directory/target.iso" \ - && trap "rm -rf \"$target\"" SIGTERM +[ -n "$key" -a -z "$target" ] \ + && temporary_directory="$(mktemp -d)" \ + && target="$temporary_directory/target.iso" \ + && trap "rm -rf \"$temporary_directory\"" SIGTERM [ -n "$key" ] \ && xorriso \ diff --git a/packages/remote-installer/src/remote-installer.sh b/packages/remote-installer/src/remote-installer.sh index 294bc2e..6d77401 100644 --- a/packages/remote-installer/src/remote-installer.sh +++ b/packages/remote-installer/src/remote-installer.sh @@ -27,6 +27,10 @@ done [ -n "$help" ] \ && printf "Usage: remote-installer" \ && printf " [--help]" \ + && printf " [--flake_address]" \ + && printf " --host_name" \ + && printf " [--key]" \ + && printf " --host_address" \ && printf "\n" \ && printf "Install a NixOS configuration remotely." \ && printf "\n" \ @@ -44,7 +48,19 @@ done && printf "host_address not provided.\n" \ && exit -nixos-anywhere \ - --disko-mode disko \ - --flake "$flake_address#$host_name" \ - --target-host "root@$host_address" +[ -n "$key" ] \ + && temporary_directory="$(mktemp -d)" \ + && key_directory="$temporary_directory/var/lib/sops-nix" \ + && mkdir -p "$key_directory" \ + && cp "$key" "$key_directory/key.age" \ + && trap "rm -rf \"$temporary_directory\"" SIGTERM \ + && nixos-anywhere \ + --disko-mode disko \ + --flake "$flake_address#$host_name" \ + --extra-files "$temporary_directory" \ + --target-host "root@$host_address" +[ -z "$key" ] \ + && nixos-anywhere \ + --disko-mode disko \ + --flake "$flake_address#$host_name" \ + --target-host "root@$host_address" diff --git a/packages/remote-updater/default.nix b/packages/remote-updater/default.nix new file mode 100644 index 0000000..85ee46e --- /dev/null +++ b/packages/remote-updater/default.nix @@ -0,0 +1,30 @@ +{ + lib, + stdenvNoCC, + makeWrapper, + coreutils, + nixos-rebuild, + openssh, +}: let + inherit (lib) makeBinPath; + runtimeInputs = [ + coreutils + nixos-rebuild + openssh + ]; +in + stdenvNoCC.mkDerivation { + name = "remote-updater"; + src = ./src; + nativeBuildInputs = [makeWrapper]; + buildInputs = runtimeInputs; + installPhase = '' + mkdir -p $out/bin + cp $src/remote-updater.sh $out/bin/remote-updater + chmod +x $out/bin/remote-updater + ''; + postFixup = '' + wrapProgram $out/bin/remote-updater \ + --set PATH ${makeBinPath runtimeInputs} + ''; + } diff --git a/packages/remote-updater/src/remote-updater.sh b/packages/remote-updater/src/remote-updater.sh new file mode 100644 index 0000000..f2313ae --- /dev/null +++ b/packages/remote-updater/src/remote-updater.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +read -a arguments <<< "$@" +number_of_arguments="${#arguments[@]}" +arguments_last_index="$(expr $number_of_arguments - 1)" +for argument_index in $(seq 0 "$arguments_last_index") +do + argument="${arguments[argument_index]}" + next_argument_index="$(expr $argument_index + 1)" + next_argument="${arguments[next_argument_index]}" + case "$argument" in + --*) + name="${argument/--/}" + [ "$argument_index" -eq "$arguments_last_index" \ + -o "${next_argument:0:2}" = "--" ] \ + && declare "$name=$name" + ;; + *) + value="$argument" + [ -n "$name" ] \ + && declare "$name=$value" + name="" + ;; + esac +done + +[ -n "$help" ] \ + && printf "Usage: remote-updater" \ + && printf " [--help]" \ + && printf " [--flake_address]" \ + && printf " --host_name" \ + && printf " --host_address" \ + && printf "\n" \ + && printf "Update a NixOS configuration remotely." \ + && printf "\n" \ + && exit + +[ -z "$flake_address" ] \ + && protocol="git+https" \ + && gitea="gitea.dylanblades.com" \ + && repository="Bladesy/nixos-config" \ + && flake_address="$protocol://$gitea/$repository" +[ -z "$host_name" ] \ + && printf "host_name not provided.\n" \ + && exit +[ -z "$host_address" ] \ + && printf "host_address not provided.\n" \ + && exit + +nixos-rebuild \ + --flake "$flake_address#$host_name" \ + --target-host "root@$host_address" \ + switch