25 files changed,
160 insertions(+),
256 deletions(-)
Author:
Oleksandr Smirnov
olexsmir@gmail.com
Committed at:
2026-03-02 13:44:49 +0200
Parent:
9068778
jump to
M
nix/flake.lock
··· 257 257 }, 258 258 "nixpkgs": { 259 259 "locked": { 260 - "lastModified": 1771903837, 261 - "narHash": "sha256-sdaqdnsQCv3iifzxwB22tUwN/fSHoN7j2myFW5EIkGk=", 260 + "lastModified": 1772047000, 261 + "narHash": "sha256-7DaQVv4R97cii/Qdfy4tmDZMB2xxtyIvNGSwXBBhSmo=", 262 262 "owner": "NixOS", 263 263 "repo": "nixpkgs", 264 - "rev": "e764fc9a405871f1f6ca3d1394fb422e0a0c3951", 264 + "rev": "1267bb4920d0fc06ea916734c11b0bf004bbe17e", 265 265 "type": "github" 266 266 }, 267 267 "original": { ··· 346 346 "rev": "12ef7f8f63ee4a14a552ebed603802c79e4d72f8", 347 347 "revCount": 1678, 348 348 "type": "git", 349 - "url": "https://tangled.org/@tangled.org/core" 349 + "url": "https://tangled.org/tangled.org/core" 350 350 }, 351 351 "original": { 352 352 "ref": "refs/tags/v1.11.0-alpha", 353 353 "type": "git", 354 - "url": "https://tangled.org/@tangled.org/core" 354 + "url": "https://tangled.org/tangled.org/core" 355 355 } 356 356 } 357 357 },
M
nix/flake.nix
··· 1 1 { 2 - description = "my nix"; 3 2 inputs = { 4 3 nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; 5 - agenix = { 6 - url = "github:ryantm/agenix"; 7 - inputs.nixpkgs.follows = "nixpkgs"; 8 - }; 9 - disko = { 10 - url = "github:nix-community/disko"; 11 - inputs.nixpkgs.follows = "nixpkgs"; 12 - }; 13 - tangled = { 14 - url = "git+https://tangled.org/@tangled.org/core?ref=refs/tags/v1.11.0-alpha"; 15 - inputs.nixpkgs.follows = "nixpkgs"; 16 - }; 17 - mugit = { 18 - url = "github:olexsmir/mugit"; 19 - inputs.nixpkgs.follows = "nixpkgs"; 4 + 5 + agenix.url = "github:ryantm/agenix"; 6 + agenix.inputs.nixpkgs.follows = "nixpkgs"; 7 + 8 + disko.url = "github:nix-community/disko"; 9 + disko.inputs.nixpkgs.follows = "nixpkgs"; 10 + 11 + tangled.url = "git+https://tangled.org/tangled.org/core?ref=refs/tags/v1.11.0-alpha"; 12 + tangled.inputs.nixpkgs.follows = "nixpkgs"; 13 + 14 + mugit.url = "github:olexsmir/mugit"; 15 + mugit.inputs.nixpkgs.follows = "nixpkgs"; 16 + }; 17 + outputs = { nixpkgs, agenix, disko, ... } @ inputs: { 18 + nixosConfigurations."thought" = nixpkgs.lib.nixosSystem { 19 + modules = [ 20 + ./hosts/thought 21 + agenix.nixosModules.default 22 + disko.nixosModules.disko 23 + inputs.tangled.nixosModules.knot 24 + inputs.tangled.nixosModules.spindle 25 + inputs.mugit.nixosModules.default 26 + { nixpkgs.hostPlatform = "x86_64-linux"; } 27 + ]; 20 28 }; 21 29 }; 22 - 23 - outputs = 24 - { 25 - nixpkgs, 26 - agenix, 27 - disko, 28 - tangled, 29 - mugit, 30 - ... 31 - }: 32 - { 33 - nixosConfigurations."thought" = nixpkgs.lib.nixosSystem { 34 - system = "x86_64-linux"; 35 - modules = [ 36 - ./hosts/thought 37 - agenix.nixosModules.default 38 - disko.nixosModules.disko 39 - tangled.nixosModules.knot 40 - tangled.nixosModules.spindle 41 - mugit.nixosModules.default 42 - ]; 43 - }; 44 - }; 45 30 }
M
nix/hosts/thought/configuration.nix
··· 1 -{ pkgs, ... }: 2 -{ 1 +{ ... }: { 3 2 imports = [ 4 3 ./disko-config.nix 5 4 ./hardware-configuration.nix ··· 7 6 8 7 system.stateVersion = "25.11"; 9 8 10 - swapDevices = [ 11 - { 12 - device = "/swapfile"; 13 - size = 2048; # MB 14 - } 15 - ]; 16 - 17 9 boot.loader.grub = { 18 10 efiSupport = true; 19 11 efiInstallAsRemovable = true; 20 12 }; 21 13 14 + swapDevices = [ { 15 + device = "/swapfile"; 16 + size = 2048; # MB 17 + } ]; 18 + 22 19 time.timeZone = "Europe/Kyiv"; 23 20 i18n.defaultLocale = "en_US.UTF-8"; 24 - 25 21 networking = { 26 - hostName = "vps"; 27 - interfaces = { }; 22 + hostName = "thought"; 28 23 firewall = { 29 24 enable = true; 30 - allowedTCPPorts = [ 31 - 80 32 - 443 33 - 2222 34 - ]; 25 + allowedTCPPorts = [ 80 443 2222 ]; 35 26 }; 36 27 }; 37 - 38 - age.identityPaths = [ "/keys.txt" ]; 39 28 40 29 services = { 41 30 caddy.enable = true; ··· 48 37 }; 49 38 }; 50 39 }; 51 - 52 - nix = { 53 - gc = { 54 - automatic = true; 55 - dates = "weekly"; 56 - options = "--delete-older-than 30d"; 57 - }; 58 - settings = { 59 - auto-optimise-store = true; 60 - experimental-features = [ 61 - "nix-command" 62 - "flakes" 63 - ]; 64 - }; 65 - }; 66 - 67 - environment.systemPackages = with pkgs; [ 68 - neovim 69 - git 70 - htop 71 - ]; 72 40 }
M
nix/hosts/thought/default.nix
··· 1 -{ ... }: 2 -{ 1 +{ ... }: { 3 2 imports = [ 4 3 ./digitalocean.nix 5 4 ./configuration.nix 6 5 ./hardware-configuration.nix 7 6 8 - ../../users/q.nix 9 - 10 - ../../modules/freshrss.nix 11 - ../../modules/moviefeed.nix 12 - ../../modules/mugit.nix 13 - ../../modules/wireguard.nix 14 - ../../modules/shortener.nix 15 - ../../modules/vikunja.nix 7 + ../../modules/common.nix 8 + ../../modules/users/q.nix 9 + ../../modules/services/freshrss.nix 10 + ../../modules/services/mugit.nix 11 + ../../modules/services/wireguard.nix 12 + ../../modules/services/moviefeed.nix 16 13 ]; 17 14 }
A
nix/modules/common.nix
··· 1 +{ pkgs, ... }: { 2 + age.identityPaths = [ "/keys.txt" ]; 3 + 4 + nix = { 5 + gc = { 6 + automatic = true; 7 + dates = "weekly"; 8 + options = "--delete-older-than 30d"; 9 + }; 10 + optimise.automatic = true; 11 + settings = { 12 + auto-optimise-store = true; 13 + trusted-users = [ "root" "olex" "q" ]; 14 + experimental-features = [ "nix-command" "flakes" ]; 15 + }; 16 + }; 17 + 18 + environment.systemPackages = with pkgs; [ 19 + git 20 + htop 21 + neovim 22 + ]; 23 +}
M
nix/modules/moviefeed.nix
→ nix/modules/services/moviefeed.nix
··· 1 1 { pkgs, ... }: 2 2 let 3 3 configFile = "/home/q/moviedfeed.yml"; 4 - version = "1875224"; 5 4 moviefeed = pkgs.buildGoModule { 6 5 pname = "moviefeed"; 7 - inherit version; 6 + version = "lol"; 8 7 vendorHash = "sha256-FWkYhhX/cZhF+ctgbYPhPRYcQZSLIL3zoaxqrbWZCcU="; 9 8 src = pkgs.fetchFromGitHub { 10 9 owner = "olexsmir"; 11 10 repo = "moviefeed"; 12 - rev = version; 11 + rev = "1875224"; 13 12 hash = "sha256-rmFLFbVQ4P2LdezM6ZGS+DI9NY4VMpXrp1p1QjB9FO0="; 14 13 }; 15 14 }; 16 -in 17 -{ 15 +in { 18 16 services.caddy.virtualHosts."moviefeed.olexsmir.xyz".extraConfig = '' 19 17 reverse_proxy localhost:8000 20 18 '';
M
nix/modules/mugit.nix
→ nix/modules/services/mugit.nix
··· 1 1 { config, ... }: 2 -{ 2 +let mkSec = file: { inherit file; owner = "mugit"; group = "mugit"; }; 3 +in { 4 + age.secrets.github-token = mkSec ../../secrets/github-token.age; 5 + age.secrets.mugit-host = mkSec ../../secrets/mugit-host.age; 6 + 3 7 services.caddy.virtualHosts."git.olexsmir.xyz".extraConfig = '' 4 8 reverse_proxy localhost:8008 5 9 ''; 6 10 7 - age.secrets.github_token = { 8 - file = ../secrets/github_token.age; 9 - owner = "mugit"; 10 - group = "mugit"; 11 - }; 12 - 13 - age.secrets.mugit_host = { 14 - file = ../secrets/mugit_host.age; 15 - owner = "mugit"; 16 - group = "mugit"; 17 - }; 18 - 19 11 services.mugit = { 20 12 enable = true; 21 13 exposeCli = true; ··· 31 23 ssh = { 32 24 enable = true; 33 25 port = 22; 34 - host_key = config.age.secrets.mugit_host.path; 26 + host_key = config.age.secrets.mugit-host.path; 35 27 keys = [ 36 28 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLLJdkVYKZgsayw+sHanKPKZbI0RMS2CakqBCEi5Trz" 37 29 "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMPQ0Qz0DFB+rGrD8ScUqbUTZ1/O8FHrOBF5bIAGQgMj" ··· 40 32 mirror = { 41 33 enable = true; 42 34 interval = "6h"; 43 - github_token = "$file:" + config.age.secrets.github_token.path; 35 + github_token = "$file:" + config.age.secrets.github-token.path; 44 36 }; 45 37 }; 46 38 };
A
nix/modules/services/wireguard.nix
··· 1 +{ config, pkgs, ... }: 2 +let 3 + peers = [ 4 + { name = "laptop"; key = "cF0abpqZiMrofQUgFHS4D+FuXq3ZoCPBQUlr6WuvBwM="; ip = "10.100.0.2"; } 5 + { name = "phone"; key = "GodHMXUBh/0aEyz+XBJID7pm/Hi8xnZv6YzkQbl/Uwc="; ip = "10.100.0.3"; } 6 + ]; 7 +in { 8 + age.secrets.wg-key.file = ../../secrets/wg-key.age; 9 + 10 + boot.kernel.sysctl."net.ipv4.ip_forward" = 1; 11 + networking = { 12 + nat = { 13 + enable = true; 14 + externalInterface = "ens3"; 15 + internalInterfaces = [ "wg0" ]; 16 + }; 17 + firewall.allowedUDPPorts = [ 51820 ]; 18 + wireguard.interfaces."wg0" = { 19 + ips = [ "10.100.0.1/24" ]; 20 + listenPort = 51820; 21 + privateKeyFile = config.age.secrets.wg-key.path; 22 + postSetup = ''${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE''; 23 + postShutdown = ''${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE''; 24 + peers = map(p: { 25 + publicKey = p.key; 26 + allowedIPs = [ "${p.ip}/32" ]; 27 + }) peers; 28 + }; 29 + }; 30 +}
D
nix/modules/soju.nix
··· 1 -{ ... }: 2 -let 3 - domain = "irc.olexsmir.xyz"; 4 -in 5 -{ 6 - networking.firewall.allowedTCPPorts = [ 6697 ]; 7 - services.caddy = { 8 - virtualHosts.${domain}.extraConfig = '' 9 - respond "irc bouncer" 10 - ''; 11 - globalConfig = '' 12 - layer4 { 13 - :6697 { 14 - route { 15 - tls { 16 - connection_policy { 17 - alpn http/1.1 http/1.0 irc 18 - default_sni ${domain} 19 - } 20 - } 21 - proxy { 22 - proxy_protocol v2 23 - upstream localhost:6667 24 - } 25 - } 26 - } 27 - } 28 - ''; 29 - }; 30 - 31 - services.soju = { 32 - enable = true; 33 - hostName = domain; 34 - listen = [ "irc+insecure://localhost:6667" ]; 35 - acceptProxyIP = [ "localhost" ]; 36 - }; 37 -}
A
nix/modules/users/q.nix
··· 1 +{ config, ... }: 2 +let 3 + ssh-keys = [ 4 + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLLJdkVYKZgsayw+sHanKPKZbI0RMS2CakqBCEi5Trz" # laptop 5 + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINeXccmMQ9jfLG2Z8CITaZZ+pUgYVNVYDFtmdkBHd3xk" # phone 6 + ]; 7 +in 8 +{ 9 + age.secrets.q-password.file = ../../secrets/q-pass.age; 10 + 11 + users.users.q = { 12 + isNormalUser = true; 13 + extraGroups = [ "wheel" ]; 14 + hashedPasswordFile = config.age.secrets.q-password.path; 15 + openssh.authorizedKeys.keys = ssh-keys; 16 + }; 17 +}
D
nix/modules/vikunja.nix
··· 1 -{ ... }: 2 -{ 3 - services.caddy.virtualHosts."vikunja.olexsmir.xyz".extraConfig = '' 4 - reverse_proxy localhost:3456 5 - ''; 6 - 7 - services.vikunja = { 8 - enable = true; 9 - frontendScheme = "https"; 10 - frontendHostname = "vikunja.olexsmir.xyz"; 11 - settings = { 12 - service = { 13 - enableregistration = true; 14 - }; 15 - }; 16 - }; 17 -}
D
nix/modules/wireguard.nix
··· 1 -{ config, pkgs, ... }: 2 -{ 3 - 4 - boot.kernel.sysctl."net.ipv4.ip_forward" = 1; 5 - 6 - networking.nat = { 7 - enable = true; 8 - externalInterface = "ens3"; 9 - internalInterfaces = [ "wg0" ]; 10 - }; 11 - 12 - age.secrets.wg-private-key.file = ../secrets/wg-private-key.age; 13 - 14 - networking.firewall.allowedUDPPorts = [ 51820 ]; 15 - networking.wireguard.interfaces.wg0 = { 16 - ips = [ "10.100.0.1/24" ]; 17 - listenPort = 51820; 18 - privateKeyFile = config.age.secrets.wg-private-key.path; 19 - 20 - postSetup = ''${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE''; 21 - postShutdown = ''${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o ens3 -j MASQUERADE''; 22 - 23 - peers = [ 24 - { 25 - publicKey = "cF0abpqZiMrofQUgFHS4D+FuXq3ZoCPBQUlr6WuvBwM="; # laptop 26 - allowedIPs = [ "10.100.0.2/32" ]; 27 - } 28 - { 29 - publicKey = "GodHMXUBh/0aEyz+XBJID7pm/Hi8xnZv6YzkQbl/Uwc="; # phone 30 - allowedIPs = [ "10.100.0.3/32" ]; 31 - } 32 - ]; 33 - }; 34 -}
M
nix/secrets/freshrss-olex.age
··· 1 -age-encryption.org/v1 2 --> ssh-ed25519 jgjvUw dIOnVUmbf9R0pl92JrlTDWa/htZQEUUPdTbNCKTa+S4 3 -R4unw/VGqtrNG/otzW3HjvgMtZK+RT7tqs6dZkLh3pc 4 --> X25519 E3+gKkjH6LkkYhnwE+9QbPiSYOEF3GJhbVXy2+mCDTM 5 -IcwPmVZ8IOLhzJNUeMicC0cPmDym0TjFb7P8MHBwDNI 6 ---- JF/k9Wyj6kIEX7F1SjkqiFlv8UFngZ4lJvVwWQ8425c 7 -mr8M}2; -D~vMa9"T 8 -:ڔV9 1 +-----BEGIN AGE ENCRYPTED FILE----- 2 +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1WjVHL21uZGpHSDluMGVE 3 +UWovMlQzb2l2TFhjK2ZUbWxtbGhySzkvVWtnCnVCWVllSHVsZURkRTZlMkpaWWs3 4 +MGFWWFVDazBWRVJtOWw4WEVKRWUreFkKLT4gc3NoLWVkMjU1MTkgamdqdlV3IEtB 5 +OEwxSENFSmdBZWNnZ1E2NmhXUE94OHprYzhveVV3REdrcGM4eGpnaWsKdEJkbElU 6 +cjBPREd4OHo5a0tzTVhBaGsySVVUZm5uZ0pvenNYNE9URmdCSQotLS0gYWlmQStJ 7 +blNKMThLUTROWS9ybStlbnh1dzg2RVd1c3c3YjZMeUxJdWV1QQogiJjGLMGCGslk 8 +wErR1S5x3bK8hPUwasyvA+3ZrgDkIwuQTCKhsd9ZbQ== 9 +-----END AGE ENCRYPTED FILE-----
A
nix/secrets/q-pass.age
··· 1 +-----BEGIN AGE ENCRYPTED FILE----- 2 +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmVXY5SDIyYkNmRVVrNWti 3 +bFNiaU9XL3AzL0o0UUNJUStKTC9lWldaVmpZCjRrNDloV2RiR2prWXNjZ09PMGJE 4 +cnBJWGZDR0N0RVN3M0U5SndSQkRFcjAKLT4gc3NoLWVkMjU1MTkgamdqdlV3IHdr 5 +WnJua0xQdUozYndzY0cxS3FLTHo3R2xiZHBhWnYyWXZuako5ZEd0RUEKd3VlSnRq 6 +ZmhVRlQ0NGI4ZXVieTdCNzBmdVhOWWVYa1FoSTdXVkNUZ3pSRQotLS0geTNkL1JQ 7 +aUg4RkxrOGNBM3dJVWZXVVoycWVMKzFEVWFwZVRxV2EwNWp6WQrTE6r0BDtTNhdN 8 +Gs0+LJc5l/L3MuhrAvbW9PIJo/AMxR6Sbkyg 9 +-----END AGE ENCRYPTED FILE-----
D
nix/secrets/q-password.age
··· 1 -age-encryption.org/v1 2 --> ssh-ed25519 jgjvUw Yy4VmBRoL5acIbY+GMmg5qW9iTp9U/XZSvx12r3SzRU 3 -rNNYDN0ikwrSJf8kKi0uLczMY39rg0Xi3MSvR9fAzYU 4 --> X25519 t9640/amrr9kdgjY9ALE0n6yoaqMGTCjjk0OxPmHwwM 5 -x6nm6fXvrrRngMJVY8oGh8QJU0K5TBkl7S+v5E3k8iw 6 ---- kM18cW1nk37CnZlFmdS0XAuCt6gHzazZ83X9iNuzb5w 7 -XOb^Ye]yG-dM
M
nix/secrets/secrets.nix
··· 1 1 let 2 2 laptop = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLLJdkVYKZgsayw+sHanKPKZbI0RMS2CakqBCEi5Trz"; 3 3 infra = "age1k4e6mm0whyjzfaqlhahu2pst4vxvzul53xs3ff0tk8uty459zgzqk3965k"; 4 - allKeys = [ 5 - laptop 6 - infra 7 - ]; 4 + allKeys = [ laptop infra ]; 8 5 in 9 6 { 10 - "q-password.age".publicKeys = allKeys; 7 + "q-pass.age".publicKeys = allKeys; 11 8 "freshrss-olex.age".publicKeys = allKeys; 12 - "wg-private-key.age".publicKeys = allKeys; 13 - "github_token.age".publicKeys = allKeys; 14 - "mugit_host.age".publicKeys = allKeys; 9 + "wg-key.age".publicKeys = allKeys; 10 + "github-token.age".publicKeys = allKeys; 11 + "mugit-host.age".publicKeys = allKeys; 15 12 }
A
nix/secrets/wg-key.age
··· 1 +-----BEGIN AGE ENCRYPTED FILE----- 2 +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwNkc5c08wWHVhWjFob2dS 3 +VllkeDFJQ1NqS2lvUlJOdGlFeTM2NlVUYlVvCklGUVVsRVk1K2ZVaUYrdGoycUdm 4 +bDRxZlFnZDBLWHNJdUkvS0RnMHVDVjgKLT4gc3NoLWVkMjU1MTkgamdqdlV3IEpP 5 +T3RhNURDc0xvTC9OY3IwM0FCUk00d041RlcxeFdObXJod2J5bThiQTQKUzdTTWtZ 6 +bXdhOUk1MndoNUlzaVltcFlTVlJLMmppSTlwVnRGT3lLejZPVQotLS0gSHA5clBR 7 +YjZIRHcyUXJMVTZZUkRWTjQwdjcyeGtzT2JvWkZ4R0F3ODJuZwpFyHRBsfuOeXFT 8 +1zD3BpztIgzpNZQtH74T9ZbQmNSTbZ5z1GjmLU20QxNkNnw/IWwjzuXTSiWJ0sIc 9 +iTVF53i1xPS7aIyPnHeclysIxw== 10 +-----END AGE ENCRYPTED FILE-----
D
nix/users/_sshkeys.nix
··· 1 -[ 2 - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPLLJdkVYKZgsayw+sHanKPKZbI0RMS2CakqBCEi5Trz" # laptop 3 - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINeXccmMQ9jfLG2Z8CITaZZ+pUgYVNVYDFtmdkBHd3xk u0_a930@localhost" # phone 4 -]
D
nix/users/q.nix
··· 1 -{ config, ... }: 2 -{ 3 - age.secrets.q-password.file = ../secrets/q-password.age; 4 - 5 - users.users.q = { 6 - isNormalUser = true; 7 - extraGroups = [ 8 - "wheel" 9 - "headscale" 10 - ]; 11 - hashedPasswordFile = config.age.secrets.q-password.path; 12 - openssh.authorizedKeys.keys = import ./_sshkeys.nix; 13 - }; 14 -}