From 32ca1456a292048bedff116cfee3eeb277b9bc2c Mon Sep 17 00:00:00 2001 From: Hermes-Neo Date: Sun, 28 Jun 2026 19:04:34 +0100 Subject: [PATCH] fix: recreate docker-host.nix with raw content (was double-base64'd) --- modules/common/docker-host.nix | 122 +++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 modules/common/docker-host.nix diff --git a/modules/common/docker-host.nix b/modules/common/docker-host.nix new file mode 100644 index 0000000..a270d19 --- /dev/null +++ b/modules/common/docker-host.nix @@ -0,0 +1,122 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.docker-host-incus; + containerName = "docker-host"; +in +{ + options.services.docker-host-incus = { + enable = mkEnableOption "Incus Docker host container"; + + image = mkOption { + type = types.str; + default = "images:ubuntu/24.04"; + description = "Incus image to use for the Docker host container"; + }; + + network = mkOption { + type = types.str; + default = "internalbr0"; + description = "Incus bridge network to attach the container to"; + }; + + ip = mkOption { + type = types.str; + default = "10.0.0.2"; + description = "Static IP for the Docker host container"; + }; + + gateway = mkOption { + type = types.str; + default = "10.0.0.1"; + description = "Gateway for the container network"; + }; + + dns = mkOption { + type = types.str; + default = "1.1.1.1"; + description = "DNS server for the container"; + }; + + exposeDockerTcp = mkOption { + type = types.bool; + default = false; + description = "Expose Docker TCP API on port 2375 (internal bridge only)"; + }; + }; + + config = mkIf cfg.enable { + # Ensure incus + jq are available on the host + environment.systemPackages = with pkgs; [ incus-lts jq ]; + + # ── Systemd oneshot that creates/starts the Docker host container ── + systemd.services.incus-docker-host = { + description = "Incus Docker Host Container (${containerName})"; + after = [ "incus.service" ]; + requires = [ "incus.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = with pkgs; [ incus-lts jq ]; + + script = '' + set -euo pipefail + + create_container() { + echo "Creating ${containerName} from ${cfg.image}..." + + incus init "${cfg.image}" "${containerName}" \ + --config security.privileged=true \ + --config boot.autostart=true + + # Attach to the internal bridge + incus config device add "${containerName}" eth0 nic \ + nictype=bridged \ + parent="${cfg.network}" + + # Inject cloud-init to install Docker + incus config set "${containerName}" user.user-data - <<'CLOUD_EOF' +#cloud-config +package_update: true +packages: + - docker.io + - docker-compose-v2 + - curl +runcmd: + - systemctl enable docker.service + - systemctl start docker.service + - sleep 2 + - docker info || echo "Docker not ready yet, will start on boot" +CLOUD_EOF + + # Set a static lease + ${optionalString (cfg.ip != "auto") '' + incus config device set "${containerName}" eth0 ipv4.address "${cfg.ip}" + ''} + + incus start "${containerName}" + echo "✓ ${containerName} created and started" + } + + # ── Main logic ── + if ! incus list --format json 2>/dev/null | jq -e '.[] | select(.name == "${containerName}")' >/dev/null 2>&1; then + create_container + else + STATUS=$(incus list --format json 2>/dev/null | jq -r '.[] | select(.name == "${containerName}") | .status') + if [ "$STATUS" != "Running" ]; then + echo "${containerName} is $STATUS — starting..." + incus start "${containerName}" + else + echo "${containerName} already running" + fi + fi + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + }; +}