diff --git a/hosts/franz/arion/default.nix b/hosts/franz/arion/default.nix index 84bec20..8f3a00d 100644 --- a/hosts/franz/arion/default.nix +++ b/hosts/franz/arion/default.nix @@ -19,6 +19,7 @@ ./signal ./feed ./matrix + ./headscale ]; environment.systemPackages = with pkgs; [arion]; diff --git a/hosts/franz/arion/headscale/arion-compose.nix b/hosts/franz/arion/headscale/arion-compose.nix new file mode 100644 index 0000000..1b5f898 --- /dev/null +++ b/hosts/franz/arion/headscale/arion-compose.nix @@ -0,0 +1,48 @@ +{pkgs, ...}: { + project.name = "headscale"; + + networks.dmz = { + name = "dmz"; + external = true; + }; + + services = { + headscale.service = { + image = "headscale/headscale:0.22.3-debug"; + container_name = "headscale"; + restart = "always"; + command = "headscale serve"; + labels = { + "traefik.enable" = "true"; + "traefik.http.services.headscale-external.loadbalancer.server.port" = "8080"; + "traefik.http.routers.headscale.entrypoints" = "websecure-external"; + "traefik.http.routers.headscale.rule" = "Host(`headscale.ghoscht.com`)"; + "traefik.http.routers.headscale.tls" = "true"; + "traefik.http.routers.headscale.tls.certresolver" = "letsencrypt"; + }; + volumes = [ + "/storage/dataset/docker/headscale/headscale_config:/etc/headscale" + "/storage/dataset/docker/headscale/headscale_data:/var/lib/headscale" + ]; + networks = [ + "dmz" + ]; + }; + headscale-ui.service = { + image = "ghcr.io/gurucomputing/headscale-ui:2024.02.24-beta1"; + container_name = "headscale-ui"; + restart = "always"; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.headscale-ui.entrypoints" = "websecure"; + "traefik.http.routers.headscale-ui.rule" = "PathPrefix(`/web`)&&Host(`headscale.ghoscht.com`)"; + "traefik.http.services.headscale-ui.loadbalancer.server.port" = "80"; + "traefik.http.routers.headscale-ui.tls" = "true"; + "traefik.http.routers.headscale-ui.tls.certresolver" = "letsencrypt"; + }; + networks = [ + "dmz" + ]; + }; + }; +} diff --git a/hosts/franz/arion/headscale/arion-pkgs.nix b/hosts/franz/arion/headscale/arion-pkgs.nix new file mode 100644 index 0000000..69aad13 --- /dev/null +++ b/hosts/franz/arion/headscale/arion-pkgs.nix @@ -0,0 +1,6 @@ +# Instead of pinning Nixpkgs, we can opt to use the one in NIX_PATH +import { + # We specify the architecture explicitly. Use a Linux remote builder when + # calling arion from other platforms. + system = "x86_64-linux"; +} diff --git a/hosts/franz/arion/headscale/default.nix b/hosts/franz/arion/headscale/default.nix new file mode 100644 index 0000000..d1be53e --- /dev/null +++ b/hosts/franz/arion/headscale/default.nix @@ -0,0 +1,13 @@ +{config, ...}: let + vars = import ../../../../vars.nix; +in { + # Tailscale client for exit node/routes + services.tailscale.enable = true; + services.tailscale.useRoutingFeatures = "server"; + + virtualisation.arion = { + projects.headscale.settings = { + imports = [./arion-compose.nix]; + }; + }; +} diff --git a/hosts/franz/arion/infrastructure/arion-compose.nix b/hosts/franz/arion/infrastructure/arion-compose.nix index abe29fa..89b9c4f 100644 --- a/hosts/franz/arion/infrastructure/arion-compose.nix +++ b/hosts/franz/arion/infrastructure/arion-compose.nix @@ -19,7 +19,9 @@ useHostStore = true; ports = [ "80:80" + "81:81" "443:443" + "444:444" "8421:8080" ]; labels = { @@ -91,5 +93,18 @@ "dmz" ]; }; + dyndns.service = { + image = "ghcr.io/cromefire/fritzbox-cloudflare-dyndns:1.2.1"; + container_name = "dyndns"; + restart = "always"; + ports = ["8888:8080"]; + dns = ["1.1.1.1"]; + environment = { + CLOUDFLARE_ZONES_IPV4 = "ghoscht.com"; + }; + env_file = [ + "/home/ghoscht/.docker/infrastructure/dyndns.env" + ]; + }; }; } diff --git a/hosts/franz/arion/infrastructure/default.nix b/hosts/franz/arion/infrastructure/default.nix index 3d97c94..fe9f15b 100644 --- a/hosts/franz/arion/infrastructure/default.nix +++ b/hosts/franz/arion/infrastructure/default.nix @@ -21,6 +21,10 @@ in { owner = vars.user; }; + sops.secrets."dyndns/cloudflare_api_key" = { + owner = vars.user; + }; + sops.templates."cloudflared.env" = { path = "/home/${vars.user}/.docker/infrastructure/cloudflared.env"; owner = vars.user; @@ -40,6 +44,15 @@ in { ''; }; + sops.templates."dyndns.env" = { + path = "/home/${vars.user}/.docker/infrastructure/dyndns.env"; + owner = vars.user; + mode = "0775"; + content = '' + CLOUDFLARE_API_TOKEN="${config.sops.placeholder."dyndns/cloudflare_api_key"}" + ''; + }; + sops.templates."traefik.toml" = { path = "/home/${vars.user}/.docker/infrastructure/traefik_data/traefik.toml"; owner = vars.user; @@ -48,8 +61,12 @@ in { [entryPoints] [entryPoints.web] address = ":80" + [entryPoints.web-external] + address = ":81" [entryPoints.websecure] address = ":443" + [entryPoints.websecure-external] + address = ":444" [api] dashboard = true insecure = true @@ -66,8 +83,8 @@ in { [providers.docker] watch = true - network = "web" - exposedByDefault = false + network = "dmz" + exposedByDefault = false # overriden by traefik.enable=true ''; }; } diff --git a/secrets/franz.yaml b/secrets/franz.yaml index e1f9b9f..3d8554a 100644 --- a/secrets/franz.yaml +++ b/secrets/franz.yaml @@ -35,6 +35,8 @@ matrix: postgres_database: ENC[AES256_GCM,data:9O0vYjbTuQ==,iv:L5QCwhFSjPW0OiUMjCQo6BcLktUXJcqTsTXEi5JdaWo=,tag:LUPRSZl0pza5WOWI8RrAmw==,type:str] postgres_user: ENC[AES256_GCM,data:S9ksmTOAbBg=,iv:q/6Oo9JhiSAqQq3ZKa0dbQGtfYAuD0oeiDLR4YwV0nk=,tag:RIc/1UVs88Jg8+4zGnW6vQ==,type:str] postgres_password: ENC[AES256_GCM,data:sKlU4HKDDNERv4LZK9/M2+kvnNht1uxQ7+pQSIZWPkk=,iv:fD98XPUMjo+eZOmE/cVOh5TFkmTY/KDCjfZcf5fSWOg=,tag:B5zsxgjvs7+czDWcCst/eg==,type:str] +dyndns: + cloudflare_api_key: ENC[AES256_GCM,data:O8biURYpw+joKm5A+7E9ARKlFRcnwFaqrbLPHevOXvYTFED1NdMSGQ==,iv:Vm1DreqdaFd1owN7zci242gzpGEZqE57Yn9XAzVxXoQ=,tag:KdQtVvZCypAYIghtuM5kjw==,type:str] sops: kms: [] gcp_kms: [] @@ -50,8 +52,8 @@ sops: VUUxcEhvYi8zeXlCUUViUTl0eWdhcU0KXOfbnDc+zc8lnBcyEAV5EiJSjcSU6AgI EfeRw8qVqwChrYn1agslcNnDbE0WQsOCBuA6cE4V3kRofp9HU949ig== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-04-13T14:40:45Z" - mac: ENC[AES256_GCM,data:KnlhlaJkO0WMjXn9xqSTViciHL1Hvb9nlb40H5jB0AF6QzcZbteLZRCRfX1VGgsoGoqRprkNEAIZfirnRHxIId8rnLJezV/+e0R5+py8UkOOIAPxrnTyIJ2ThCsAxvfV2JTGo3TwM8PdzxH/zbhVpSaea4Or2+Y3pipZB+qtq74=,iv:lSWzwg9pdqeJzbuxZHIS1upfkFHklFQCfhzE4nqnPl4=,tag:iYx6xkhomksHkpz78WCw3w==,type:str] + lastmodified: "2024-05-01T14:35:26Z" + mac: ENC[AES256_GCM,data:w7CK7SSvG3/vgpSwW3F3n/FRpm797pYcYs6sy46qBZffpyi4lSS0e1bnqqIcHxBWP8EWXHJwXIA+eyzpdH9UhUbJ/B7ZSaK0rQC6rp9CIIw5+R1js3ccV/ByOjgzz/fhTWGiYp15sm5d/CjZGq99+kME4LOWkkmE/UTevivFbn8=,iv:VzHl8Vn4D7bHe3LY+GjBHKYmiYIRSkThsl1aky/B7AM=,tag:K+8sQ9AMzADuBHulFauB+g==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.8.1