diff --git a/flake.lock b/flake.lock index 8cee96c..5f21279 100644 --- a/flake.lock +++ b/flake.lock @@ -85,7 +85,8 @@ "root": { "inputs": { "agenix": "agenix", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "thelenlucas": "thelenlucas" } }, "systems": { @@ -102,6 +103,27 @@ "repo": "default", "type": "github" } + }, + "thelenlucas": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1758437915, + "narHash": "sha256-Pov34Iw1P9kZwBQcNYt5Sur0ewBBt2EcY+M6eO+NpcY=", + "owner": "thelenlucas", + "repo": "thelenlucas.github.io", + "rev": "e5e7c6f05c6bad70861e1b0ea7e41ebe607fc6f7", + "type": "github" + }, + "original": { + "owner": "thelenlucas", + "ref": "main", + "repo": "thelenlucas.github.io", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 70cd66b..5d51fb2 100644 --- a/flake.nix +++ b/flake.nix @@ -3,13 +3,20 @@ inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; + inputs.thelenlucas = { + url = "github:thelenlucas/thelenlucas.github.io/main"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + inputs.agenix = { url = "github:ryantm/agenix"; inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = { self, nixpkgs, agenix }: { + outputs = { self, nixpkgs, thelenlucas, agenix }@inputs: { nixosConfigurations.homelab = nixpkgs.lib.nixosSystem { + specialArgs = { inherit inputs; }; + modules = [ agenix.nixosModules.default ./system.nix @@ -22,9 +29,11 @@ ./networking/adblock.nix ./networking/vpn-host.nix ./services/jellyfin.nix + ./services/site.nix { environment.systemPackages = [ agenix.packages.x86_64-linux.default ]; age.secrets.tailscale.file = ./tailscale.age; + age.secrets.aws.file = ./secrets/aws.age; } ]; }; diff --git a/secrets.nix b/secrets.nix index fb0196c..50464f5 100644 --- a/secrets.nix +++ b/secrets.nix @@ -4,5 +4,8 @@ let machine1 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINptuT84VNef3qdFdkqj5kbJtnzoenWcOwcWbdOqQxld root@labtop"; users = [ user1 machine1 ]; -in { "tailscale.age".publicKeys = users; } +in { + "tailscale.age".publicKeys = users; + "secrets/aws.age".publicKeys = users; +} diff --git a/secrets/aws.age b/secrets/aws.age new file mode 100644 index 0000000..8912cbe Binary files /dev/null and b/secrets/aws.age differ diff --git a/services/site.nix b/services/site.nix new file mode 100644 index 0000000..ff5fb00 --- /dev/null +++ b/services/site.nix @@ -0,0 +1,86 @@ +{ config, pkgs, inputs, ... }: +let + domain = "per-aspera.space"; + updateRoute53 = pkgs.writeShellScript "update-route53" '' + #!/usr/bin/env bash + set -euo pipefail + + HOSTED_ZONE_ID="Z09728753LLLNSYFXIBIM" # Get from Route 53 console + DOMAIN=${domain} + + # Get current public IP + CURRENT_IP=$(${pkgs.curl}/bin/curl -s https://ifconfig.me) + + # Validate IP format + if ! echo "$CURRENT_IP" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'; then + echo "[$(date)] ERROR: Invalid IP format: $CURRENT_IP" >&2 + exit 1 + fi + + # Get current DNS record + DNS_IP=$(${pkgs.dig}/bin/dig +short "$DOMAIN" @8.8.8.8 | tail -n1) + + if [ "$CURRENT_IP" != "$DNS_IP" ]; then + echo "[$(date)] IP changed: $DNS_IP -> $CURRENT_IP" + + ${pkgs.awscli2}/bin/aws route53 change-resource-record-sets \ + --hosted-zone-id "$HOSTED_ZONE_ID" \ + --change-batch "{ + \"Changes\": [{ + \"Action\": \"UPSERT\", + \"ResourceRecordSet\": { + \"Name\": \"$DOMAIN\", + \"Type\": \"A\", + \"TTL\": 300, + \"ResourceRecords\": [{\"Value\": \"$CURRENT_IP\"}] + } + }] + }" + + echo "[$(date)] DNS updated successfully to $CURRENT_IP" + else + echo "[$(date)] IP unchanged: $CURRENT_IP" + fi + ''; +in { + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + services.nginx = { + enable = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + + virtualHosts."${domain}" = { + forceSSL = false; + enableACME = false; + + root = "${inputs.thelenlucas.packages.${pkgs.system}.default}"; + }; + }; + + environment.systemPackages = [ pkgs.awscli2 ]; + systemd.services.route53-ddns = { + description = "Update Route 53 with current IP periodically"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + serviceConfig = { + Type = "oneshot"; + ExecStart = updateRoute53; + }; + }; + + systemd.timers.route53-ddns = { + description = "Route 53 DDNS Update Timer"; + wantedBy = [ "timers.target" ]; + + timerConfig = { + OnBootSec = "1min"; + OnUnitActiveSec = "5min"; + Persistent = true; + }; + }; +}