From 5536e74de0ddb860263194559c108550425bc2a6 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sat, 21 Mar 2026 19:05:50 +0900 Subject: [PATCH 1/8] Add custom Lima templates and link via ~/.lima/_templates Create a custom Lima template `homeless-docker.yaml` derived from the standard `docker` template. This avoids mounting the host's `~` directory, which is not overridable via `default.yaml`. * pkgs/local/lima-custom-templates: add a package to generate custom templates * home-manager/lima-host.nix: link the custom templates recursively to ~/.lima/_templates/ * .github/workflows/lima-guest.yml: update CI to use the new template * README.md: update setup instructions Assisted-by: Gemini CLI --- .github/workflows/lima-guest.yml | 26 +++++--- README.md | 10 ++-- home-manager/lima-host.nix | 5 ++ pkgs/local/lima-custom-templates/package.nix | 62 ++++++++++++++++++++ 4 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 pkgs/local/lima-custom-templates/package.nix diff --git a/.github/workflows/lima-guest.yml b/.github/workflows/lima-guest.yml index 34b3b9a98..c3c8d7985 100644 --- a/.github/workflows/lima-guest.yml +++ b/.github/workflows/lima-guest.yml @@ -33,6 +33,8 @@ jobs: with: persist-credentials: false + - uses: ./.github/actions/setup-nix + - uses: lima-vm/lima-actions/setup@55627e31b78637bf254a8b2a14da8ea7d12564e5 # v1 id: lima-setup with: @@ -48,10 +50,16 @@ jobs: restore-keys: | lima-${{ steps.lima-setup.outputs.version }}- - - name: Create Lima Instance from standard template + - name: Generate homeless-docker template + run: | + mkdir -p ~/.lima/_templates + nix build .#lima-custom-templates + cp result/share/lima/templates/homeless-docker.yaml ~/.lima/_templates/ + + - name: Create Lima Instance from custom template run: | - limactl delete -f docker-nix || true - limactl create --yes --name=docker-nix template:docker + limactl delete -f homeless-docker-nix || true + limactl create --yes --name=homeless-docker-nix template:homeless-docker test-provisioning: needs: prepare-image @@ -76,25 +84,25 @@ jobs: restore-keys: | lima-${{ steps.lima-setup.outputs.version }}- - - name: Start docker-nix - run: limactl start --name=docker-nix --tty=false + - name: Start homeless-docker-nix + run: limactl start --name=homeless-docker-nix --tty=false - name: Install and configure Nix in Guest env: REV: ${{ github.head_ref || github.ref_name }} run: | # Use the same pipe-based command as in README, passing the current branch. - curl -fsSL "https://raw.githubusercontent.com/kachick/dotfiles/${REV}/scripts/install-nix.bash" | limactl shell docker-nix bash -s -- "${REV}" + curl -fsSL "https://raw.githubusercontent.com/kachick/dotfiles/${REV}/scripts/install-nix.bash" | limactl shell homeless-docker-nix bash -s -- "${REV}" - name: Verify Nix installation in Guest - run: limactl shell docker-nix nix --version + run: limactl shell homeless-docker-nix nix --version - name: Show Binary Cache effectiveness in Guest env: REV: ${{ github.head_ref || github.ref_name }} run: | FLAKE_URI="github:kachick/dotfiles/${REV}" - limactl shell docker-nix nix run --accept-flake-config "${FLAKE_URI}#la" -- --version + limactl shell homeless-docker-nix nix run --accept-flake-config "${FLAKE_URI}#la" -- --version - name: Show Docker works in Guest - run: limactl shell docker-nix docker run --rm hello-world + run: limactl shell homeless-docker-nix docker run --rm hello-world diff --git a/README.md b/README.md index a7fb20c8c..389099108 100644 --- a/README.md +++ b/README.md @@ -194,29 +194,29 @@ However I should keep the minimum environment for now. ## Lima -1. Start a standard Docker guest with Lima: +1. Start a custom Docker guest with Lima: ```bash - limactl start --name=docker-nix template:docker + limactl start --name=homeless-docker-nix template:homeless-docker ``` 1. Install and configure Nix in the guest: ```bash REV=main; \ - curl -fsSL "https://raw.githubusercontent.com/kachick/dotfiles/$REV/scripts/install-nix.bash" | limactl shell docker-nix bash -s -- "$REV" + curl -fsSL "https://raw.githubusercontent.com/kachick/dotfiles/$REV/scripts/install-nix.bash" | limactl shell homeless-docker-nix bash -s -- "$REV" ``` 1. Apply home-manager: ```bash - limactl shell docker-nix nix run --accept-flake-config "github:kachick/dotfiles#home-manager" -- switch -b backup --flake "github:kachick/dotfiles#user@lima" + limactl shell homeless-docker-nix nix run --accept-flake-config "github:kachick/dotfiles#home-manager" -- switch -b backup --flake "github:kachick/dotfiles#user@lima" ``` 1. Run containers: ```bash - limactl shell docker-nix docker run --rm hello-world + limactl shell homeless-docker-nix docker run --rm hello-world ``` ## How to setup secrets diff --git a/home-manager/lima-host.nix b/home-manager/lima-host.nix index 7649cfc8c..f403e9e82 100644 --- a/home-manager/lima-host.nix +++ b/home-manager/lima-host.nix @@ -27,6 +27,11 @@ in # See https://github.com/lima-vm/lima/blob/v1.0.1/templates/default.yaml#L536-L574 for detail file.".lima/_config/default.yaml".source = ../config/lima/_config/default.yaml; + file.".lima/_templates" = { + source = "${pkgs.local.lima-custom-templates}/share/lima/templates"; + recursive = true; + }; + shellAliases = { "lc" = "limactl"; }; diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix new file mode 100644 index 000000000..d7f1c9c37 --- /dev/null +++ b/pkgs/local/lima-custom-templates/package.nix @@ -0,0 +1,62 @@ +{ + lib, + stdenvNoCC, + yq-go, + pkgs, +}: + +let + lima = pkgs.local.lima; +in +stdenvNoCC.mkDerivation { + pname = "lima-custom-templates"; + version = lima.version; + + dontUnpack = true; + + nativeBuildInputs = [ yq-go ]; + + buildPhase = '' + runHook preBuild + + yq 'del(.base[] | select(. == "template:_default/mounts"))' ${lima}/share/lima/templates/docker.yaml > homeless-docker.yaml + + runHook postBuild + ''; + + doCheck = true; + + checkPhase = '' + runHook preCheck + + # Verify that the deletion actually happened by comparing the logical structure. + # If the structure is exactly the same, the 'del' command silently failed (e.g. target string changed). + if [ "$(yq -o=json -I=0 '.' ${lima}/share/lima/templates/docker.yaml)" = "$(yq -o=json -I=0 '.' homeless-docker.yaml)" ]; then + echo "Error: The template was not modified. The target string might not exist anymore." >&2 + exit 1 + fi + + runHook postCheck + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out/share/lima/templates + cp homeless-docker.yaml $out/share/lima/templates/ + + runHook postInstall + ''; + + meta = { + description = "Custom Lima templates with the default home mount removed"; + longDescription = '' + Most standard Lima templates (except for a few like k3s) inherit `template:_default/mounts`, which cannot be excluded via `default.yaml`. + To improve security, this package creates templates with those mounts removed by default. + While Lima 2.0+ supports avoiding default mounts via CLI flags like `--mount-only`, it is safer to have them disabled by default in the template. + Revisit once https://github.com/lima-vm/lima/discussions/4372 is resolved. + ''; + inherit (lima.meta) platforms; + maintainers = with lib.maintainers; [ kachick ]; + }; +} From bab436c95941b1beea45bf5728533d3e29f432aa Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sat, 21 Mar 2026 19:28:39 +0900 Subject: [PATCH 2/8] Add custom Lima templates and link via ~/.lima/_templates Create a custom Lima template `homeless-docker.yaml` derived from the standard `docker` template. This avoids mounting the host's `~` directory, which is not overridable via `default.yaml`. * pkgs/local/lima-custom-templates: add a package to generate custom templates * home-manager/lima-host.nix: link the custom templates recursively to ~/.lima/_templates/ * .github/workflows/lima-guest.yml: update CI to build templates via Nix and rename the instance * README.md: update setup instructions Assisted-by: Gemini CLI --- .github/workflows/lima-guest.yml | 8 +++++--- pkgs/local/lima-custom-templates/package.nix | 15 ++++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.github/workflows/lima-guest.yml b/.github/workflows/lima-guest.yml index c3c8d7985..64bfbcf34 100644 --- a/.github/workflows/lima-guest.yml +++ b/.github/workflows/lima-guest.yml @@ -50,11 +50,13 @@ jobs: restore-keys: | lima-${{ steps.lima-setup.outputs.version }}- - - name: Generate homeless-docker template + - name: Generate homeless templates run: | - mkdir -p ~/.lima/_templates nix build .#lima-custom-templates - cp result/share/lima/templates/homeless-docker.yaml ~/.lima/_templates/ + # Remove potential read-only symlink from cache + rm -rf ~/.lima/_templates + mkdir -p ~/.lima/_templates + cp result/share/lima/templates/homeless-*.yaml ~/.lima/_templates/ - name: Create Lima Instance from custom template run: | diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix index d7f1c9c37..61e795871 100644 --- a/pkgs/local/lima-custom-templates/package.nix +++ b/pkgs/local/lima-custom-templates/package.nix @@ -2,6 +2,7 @@ lib, stdenvNoCC, yq-go, + gnugrep, pkgs, }: @@ -14,12 +15,17 @@ stdenvNoCC.mkDerivation { dontUnpack = true; - nativeBuildInputs = [ yq-go ]; + nativeBuildInputs = [ yq-go gnugrep ]; buildPhase = '' runHook preBuild - yq 'del(.base[] | select(. == "template:_default/mounts"))' ${lima}/share/lima/templates/docker.yaml > homeless-docker.yaml + for template_path in ${lima}/share/lima/templates/*.yaml; do + template_name=$(basename "$template_path") + if yq '.base[] | select(. == "template:_default/mounts")' "$template_path" | grep -q .; then + yq 'del(.base[] | select(. == "template:_default/mounts"))' "$template_path" > "homeless-$template_name" + fi + done runHook postBuild ''; @@ -29,8 +35,7 @@ stdenvNoCC.mkDerivation { checkPhase = '' runHook preCheck - # Verify that the deletion actually happened by comparing the logical structure. - # If the structure is exactly the same, the 'del' command silently failed (e.g. target string changed). + # Verify that the deletion actually happened for a representative template. if [ "$(yq -o=json -I=0 '.' ${lima}/share/lima/templates/docker.yaml)" = "$(yq -o=json -I=0 '.' homeless-docker.yaml)" ]; then echo "Error: The template was not modified. The target string might not exist anymore." >&2 exit 1 @@ -43,7 +48,7 @@ stdenvNoCC.mkDerivation { runHook preInstall mkdir -p $out/share/lima/templates - cp homeless-docker.yaml $out/share/lima/templates/ + cp homeless-*.yaml $out/share/lima/templates/ runHook postInstall ''; From f3f05ad4a98daf7c09f7e1bef4d41f8355b92203 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sat, 21 Mar 2026 21:02:23 +0900 Subject: [PATCH 3/8] Adjust meta.longDescription --- pkgs/local/lima-custom-templates/package.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix index 61e795871..f7fca7188 100644 --- a/pkgs/local/lima-custom-templates/package.nix +++ b/pkgs/local/lima-custom-templates/package.nix @@ -15,7 +15,10 @@ stdenvNoCC.mkDerivation { dontUnpack = true; - nativeBuildInputs = [ yq-go gnugrep ]; + nativeBuildInputs = [ + yq-go + gnugrep + ]; buildPhase = '' runHook preBuild @@ -58,7 +61,7 @@ stdenvNoCC.mkDerivation { longDescription = '' Most standard Lima templates (except for a few like k3s) inherit `template:_default/mounts`, which cannot be excluded via `default.yaml`. To improve security, this package creates templates with those mounts removed by default. - While Lima 2.0+ supports avoiding default mounts via CLI flags like `--mount-only`, it is safer to have them disabled by default in the template. + While Lima 2.1+ supports avoiding default mounts via CLI flags like `--mount-only`, `--mount-none` it is safer to have them disabled by default in the template. Revisit once https://github.com/lima-vm/lima/discussions/4372 is resolved. ''; inherit (lima.meta) platforms; From 833a7c826a4874fa0450c46ea3dd922f2a3b8795 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sun, 22 Mar 2026 10:54:41 +0900 Subject: [PATCH 4/8] Fix mountPoint of lima config --- config/lima/_config/default.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/lima/_config/default.yaml b/config/lima/_config/default.yaml index efd137e1e..7bcbd1f46 100644 --- a/config/lima/_config/default.yaml +++ b/config/lima/_config/default.yaml @@ -3,7 +3,9 @@ mounts: # TODO: Disable default mounting host home to keep secure even if it is not writable # - location: '~' # Just comment out still respects template default. And setting mountPoint as false handles the false as string... - location: '~/repos' # See git.nix in this repo - mountPoint: '{{.Home}}/repos' # Keep same behavior for ghq and the wrapped scripts + # Don't hardcode it as '{{.Home}}/repos' to consider different username usecase of host and guests. + # Also consider and tests ghq and the wrapped scripts(cdrepo). + # mountPoint: '{{.Home}}/repos' writable: true # For developing purpose, writable should be reasonable. And my system does not directly include these files # https://github.com/lima-vm/lima/issues/1015#issuecomment-4092839880 From 4754f1f95578510784b1298a7c0736d416b63d55 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sun, 22 Mar 2026 11:01:24 +0900 Subject: [PATCH 5/8] Refine technical English in comments * config/lima/_config/default.yaml: Clarify the intent of matching absolute paths to ensure 'limactl shell' can synchronize directories. * pkgs/local/lima-custom-templates: Improve readability of CLI flags description in meta.longDescription. Assisted-by: Gemini CLI --- config/lima/_config/default.yaml | 5 +++-- pkgs/local/lima-custom-templates/package.nix | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/lima/_config/default.yaml b/config/lima/_config/default.yaml index 7bcbd1f46..a2862bb0f 100644 --- a/config/lima/_config/default.yaml +++ b/config/lima/_config/default.yaml @@ -3,8 +3,9 @@ mounts: # TODO: Disable default mounting host home to keep secure even if it is not writable # - location: '~' # Just comment out still respects template default. And setting mountPoint as false handles the false as string... - location: '~/repos' # See git.nix in this repo - # Don't hardcode it as '{{.Home}}/repos' to consider different username usecase of host and guests. - # Also consider and tests ghq and the wrapped scripts(cdrepo). + # Avoid hardcoding '{{.Home}}/repos' to ensure 'limactl shell' can + # synchronize the working directory by matching the host's absolute path. + # Also, consider and test compatibility with ghq and wrapped scripts (e.g., cdrepo). # mountPoint: '{{.Home}}/repos' writable: true # For developing purpose, writable should be reasonable. And my system does not directly include these files diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix index f7fca7188..f9deca1d0 100644 --- a/pkgs/local/lima-custom-templates/package.nix +++ b/pkgs/local/lima-custom-templates/package.nix @@ -61,7 +61,7 @@ stdenvNoCC.mkDerivation { longDescription = '' Most standard Lima templates (except for a few like k3s) inherit `template:_default/mounts`, which cannot be excluded via `default.yaml`. To improve security, this package creates templates with those mounts removed by default. - While Lima 2.1+ supports avoiding default mounts via CLI flags like `--mount-only`, `--mount-none` it is safer to have them disabled by default in the template. + While Lima 2.1+ supports avoiding default mounts via CLI flags such as `--mount-only` or `--mount-none`, it is safer to have them disabled by default in the template. Revisit once https://github.com/lima-vm/lima/discussions/4372 is resolved. ''; inherit (lima.meta) platforms; From a0cf69ddc1081d6f7d1bba347444b62e47932452 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sun, 22 Mar 2026 11:39:20 +0900 Subject: [PATCH 6/8] Exclude default.yaml from homeless template generation Lima's default.yaml has a special configuration intended for global defaults rather than a standalone template, so generating a 'homeless' version of it might not behave as expected. Assisted-by: Gemini CLI --- pkgs/local/lima-custom-templates/package.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix index f9deca1d0..02f8a8f08 100644 --- a/pkgs/local/lima-custom-templates/package.nix +++ b/pkgs/local/lima-custom-templates/package.nix @@ -25,6 +25,10 @@ stdenvNoCC.mkDerivation { for template_path in ${lima}/share/lima/templates/*.yaml; do template_name=$(basename "$template_path") + # Skip default.yaml as it has a special configuration and isn't intended to be a standalone homeless template. + if [ "$template_name" = "default.yaml" ]; then + continue + fi if yq '.base[] | select(. == "template:_default/mounts")' "$template_path" | grep -q .; then yq 'del(.base[] | select(. == "template:_default/mounts"))' "$template_path" > "homeless-$template_name" fi From 392c08e4c9d669008cd95bf39ae72cb690857f87 Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sun, 22 Mar 2026 11:47:52 +0900 Subject: [PATCH 7/8] Add installCheckPhase to validate custom Lima templates Use `limactl validate` in `installCheckPhase` to ensure all generated homeless templates are valid YAML and follow Lima's schema. This uses `writableTmpDirAsHomeHook` to provide a temporary HOME directory for `limactl`. Assisted-by: Gemini CLI --- pkgs/local/lima-custom-templates/package.nix | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/pkgs/local/lima-custom-templates/package.nix b/pkgs/local/lima-custom-templates/package.nix index 02f8a8f08..47767dc2e 100644 --- a/pkgs/local/lima-custom-templates/package.nix +++ b/pkgs/local/lima-custom-templates/package.nix @@ -3,6 +3,7 @@ stdenvNoCC, yq-go, gnugrep, + writableTmpDirAsHomeHook, pkgs, }: @@ -16,6 +17,10 @@ stdenvNoCC.mkDerivation { dontUnpack = true; nativeBuildInputs = [ + # Use yq-go instead of `limactl template yq` because the latter fills in + # default values and resolves external references before evaluation, + # which would result in large, static YAML files rather than templates + # that inherit from bases. yq-go gnugrep ]; @@ -60,6 +65,28 @@ stdenvNoCC.mkDerivation { runHook postInstall ''; + doInstallCheck = true; + + nativeInstallCheckInputs = [ + lima + # Workaround for: "panic: $HOME is not defined" in limactl + writableTmpDirAsHomeHook + ]; + + installCheckPhase = '' + runHook preInstallCheck + + for template in $out/share/lima/templates/*.yaml; do + limactl validate "$template" + done + + runHook postInstallCheck + ''; + + preInstallCheck = '' + export USER=nix + ''; + meta = { description = "Custom Lima templates with the default home mount removed"; longDescription = '' From d0c01da66032a41aedc503608500780b22c431ab Mon Sep 17 00:00:00 2001 From: Kenichi Kamiya Date: Sun, 22 Mar 2026 12:04:35 +0900 Subject: [PATCH 8/8] lima-guest: symlink host repos to guest home Automatically create a symlink from `~/repos` in the guest home to the mounted host `repos` directory. This restores compatibility with tools like `ghq` and `cdrepo` while still allowing `limactl shell` to synchronize the working directory using absolute host paths. Assisted-by: Gemini CLI --- home-manager/lima-guest.nix | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/home-manager/lima-guest.nix b/home-manager/lima-guest.nix index a968b8cc6..ab467b6b4 100644 --- a/home-manager/lima-guest.nix +++ b/home-manager/lima-guest.nix @@ -1,6 +1,20 @@ -{ config, ... }: +{ config, lib, ... }: { # https://github.com/lima-vm/lima/blame/0d058b0eaa2d1bafc867298503a9239e89c202a8/templates/default.yaml#L295-L296 home.homeDirectory = "/home/${config.home.username}.linux"; + + # Restore access from the guest home to the host-path mounts. + # This allows 'limactl shell' to sync CWD (via absolute host paths) while keeping + # compatibility with tools expecting '~/repos' such as ghq and cdrepo. + home.activation.setupHostReposSymlink = lib.hm.dag.entryAfter [ "writeBoundary" ] '' + for d in /home/*; do + # 1. Skip if it's the current guest home (e.g., /home/user.linux) + # 2. Check if 'repos' directory exists inside it (the host mount point) + if [ "$d" != "$HOME" ] && [ -d "$d/repos" ]; then + $DRY_RUN_CMD ln -sfn "$d/repos" "$HOME/repos" + break + fi + done + ''; }