Compare commits

...

54 Commits

Author SHA1 Message Date
ce9475e001 Mount docker from persistence 2026-06-21 21:13:21 +00:00
a37e25329a Improve jailed-agy
Add python, ruby, go, custom paths.
2026-06-19 13:37:00 +00:00
3975092d67 nix flake update 2026-06-19 12:03:08 +00:00
a2c2b2a2e5 Fix unfree and PATH for jailed-agy 2026-06-12 13:35:31 +00:00
0c0c94e4bf Extract jailed-agy into reusable module 2026-06-11 19:27:46 +00:00
a659a07637 Move ssh config into nix 2026-06-09 19:19:27 +00:00
60531ed270 Auto-create undodir if it doesn't exist
This is required for undo to work across restarts
2026-06-09 18:57:16 +00:00
e6e62a375c Remove master overlay
agy is now available in unstable
2026-06-09 18:08:07 +00:00
58ade9d886 Finish migrating from ag to rg 2026-06-09 17:38:48 +00:00
eb2bdc2d33 nix flake update 2026-06-09 10:20:05 +00:00
c4fb365814 Remove ag (dropped from nix) 2026-06-08 18:42:01 +00:00
b4383e0d19 Use system browser in iTerm2 2026-06-07 20:23:32 +02:00
e57b3e6937 Avoid warning about darwin-x86_64 expiring 2026-06-05 06:21:39 +00:00
0938c76f1b Extract "artem" into a variable 2026-06-05 06:21:05 +00:00
2e02f82ae2 Leave symlink to latest nix-deploy'ed version
This will keep gc root on the linked derivation and prevent
nix-collect-garbage from removing it.
2026-05-26 17:02:09 +00:00
2c380eaf10 Move mcp server settings to antigravity-cli 2026-05-25 08:59:19 +00:00
76061f4919 gemini-cli -> antigravity-cli 2026-05-25 08:20:48 +00:00
159daf0630 Move from legacyPackages to proper import 2026-05-25 08:17:19 +00:00
82419c57ad Move allowUnfree to all of homes
Eventually for antigravity-cli
2026-05-25 08:10:12 +00:00
6df89b4b06 Allow access to KVM 2026-05-25 07:52:24 +00:00
3fabad4344 nix flake update 2026-05-23 17:58:29 +00:00
616a81d29d nix flake update
```
Version changes:
[U.]  #1  gemini-cli   0.40.1 -> 0.41.2
[U.]  #2  libgit2      1.9.2-lib -> 1.9.3-lib
[U.]  #3  nodejs       22.22.2 -> 22.22.3
[U.]  #4  nodejs-slim  22.22.2, 22.22.2-corepack, 22.22.2-npm -> 22.22.3, 22.22.3-corepack, 22.22.3-npm
[U.]  #5  vscode       1.116.0 -> 1.119.0
```
2026-05-17 16:31:54 +02:00
5a1da34702 iTerm scrollback 1k -> 1M 2026-05-17 16:14:35 +02:00
8b813e6345 Periodic nix-collect-garbage on darwin 2026-05-17 11:06:48 +02:00
080cd5b1cc Fix undefined variable when deployed in NixOS 2026-05-15 19:55:18 +00:00
28a2a91d93 Remove redundant variable 2026-05-15 15:39:00 +00:00
f878110e49 Move common into imports
This follows the same pattern as modules
2026-05-15 15:36:11 +00:00
a57b0f2fef Sprinkle a bit of standard library in home config 2026-05-15 15:25:52 +00:00
0160a8aa80 Add nvd (version diff) 2026-05-15 15:15:27 +00:00
3b688fd5a2 Mark all known signers as allowed 2026-05-15 13:31:40 +00:00
0ee7266b3d Populate allowedSignersFile 2026-05-15 13:05:41 +00:00
ecb0dc092e Migrate .gitconfig to home-manager 2026-05-15 12:55:42 +00:00
97248c0da3 Use identities from fw_nix 2026-05-15 12:24:03 +00:00
7819928be2 Hint for where to look up system setting values 2026-05-14 19:25:32 +02:00
6e1631d77b Describe layout 2026-05-14 15:38:40 +02:00
ac28afc5eb Update signing key 2026-05-14 15:22:08 +02:00
ac3712aec5 Correct path to test legacy presence 2026-05-14 15:20:23 +02:00
a453390013 Clarify "migrated" .zshrc 2026-05-14 15:19:41 +02:00
00049f5255 Make homeDirectory setting a default
Some hosts may have different home path
2026-05-14 15:17:23 +02:00
6f260619a7 Add git signingkey and name/email to personal file 2026-05-14 14:38:06 +02:00
031eab1b27 Clarify FIDO2 key limitations 2026-05-14 14:04:34 +02:00
231a769de5 Update fw_nix to pick up new cache paths 2026-05-13 20:53:04 +00:00
6df6976cd2 nix flake update 2026-05-11 19:14:38 +00:00
9f5e9b00e8 Enable mosh on linux-headless 2026-05-11 19:10:04 +00:00
7b85d3b585 Give gemini esphome 2026-05-11 19:09:52 +00:00
ce75ee4024 Show timezone next to timestamp in tmux 2026-05-08 15:41:02 +00:00
94800586f6 Add MIT license 2026-05-04 09:27:04 +00:00
efbcd546f9 TODO for better integration between zsh and iTerm2 2026-05-03 16:20:53 +02:00
f75a9f1ccb Finish migrating to tmux
fix environment variable being reset to most recent value in new panels
2026-05-01 19:49:21 +00:00
e38f96eedb Move linux-lxc away from linux-headless
Not every linux-headless is LXC; e.g. venus
2026-04-30 13:12:34 +02:00
d7be1664ae nix flake update 2026-04-29 20:48:39 +00:00
24055ddfe7 Extract linux bits into a new module 2026-04-29 22:44:15 +02:00
7bde25ebec Avoid affinity warnings for ag 2026-04-29 19:57:14 +00:00
930d951625 Migrate from GNU screen to tmux 2026-04-29 19:56:58 +00:00
24 changed files with 638 additions and 422 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ result
# nix pre-commit autogenerated by devShell
/.pre-commit-config.yaml
# agy sessions
.antigravitycli

7
LICENSE.txt Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2026 dotdoom
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -28,6 +28,18 @@ nix run \
--flake .#artem@deimos
```
## Layout
- `migrated`: files which are assets for home-manager, but can still be used to
stow
- `legacy`: files to be placed under `$HOME` which are still under stow
- `hosts/*/{darwin,nixos,home}.nix`: personal machine nix configs
- `modules/{darwin,nixos,home}/*.nix`: exported nix configs
TODO: rename `migrated` to `assets` and create `exported` which would be the
exact mirror of nix-built configuration, but without nix (for machines where nix
can not be installed). That `exported` will then be used by stow.
## Security
Risks taken (disclaimer):
@@ -68,7 +80,9 @@ Risks taken (disclaimer):
Instead of PIV, we use FIDO2 slots on Yubikey to generate resident (i.e.
stored solely on Yubikey itself) SSH keys using modern OpenSSH client built-in
FIDO2 support. This doesn't need an agent or a background daemon.
FIDO2 support. This doesn't need an agent or a background daemon. The lack of
agent however means that these keys can not be forwarded to remote host for
further SSH, Git signing or push.
To generate a new key:
@@ -103,8 +117,9 @@ Host deimos
### Commit signing
Use SSH keys (from Apple SE and Yubikey) to sign commits. Make sure to generate
a different set of keys for signing than the one you use for authentication. Add
`-O application=ssh:git-signature` to mark the key for signing (personal
a different set of keys for signing than the one you use for authentication, to
decouple authentication from authorization and reduce key leakage blast radius.
Add `-O application=ssh:git-signature` to mark the key for signing (personal
convention).
### AGE encryption

75
flake.lock generated
View File

@@ -3,16 +3,16 @@
"brew-src": {
"flake": false,
"locked": {
"lastModified": 1774235677,
"narHash": "sha256-0ryNYmzDAeRlrzPTAgmzGH/Cgc8iv/LBN6jWGUANvIk=",
"lastModified": 1781226006,
"narHash": "sha256-w4ZTuOnhYiDxjaynrMTASzp802QblBWmo3wpB8wVN4Y=",
"owner": "Homebrew",
"repo": "brew",
"rev": "894a3d23ac0c8aaf561b9874b528b9cb2e839201",
"rev": "109191be4988470b51a60a5ef1998520aa24c01b",
"type": "github"
},
"original": {
"owner": "Homebrew",
"ref": "5.1.1",
"ref": "6.0.1",
"repo": "brew",
"type": "github"
}
@@ -24,11 +24,11 @@
]
},
"locked": {
"lastModified": 1775037210,
"narHash": "sha256-KM2WYj6EA7M/FVZVCl3rqWY+TFV5QzSyyGE2gQxeODU=",
"lastModified": 1781761792,
"narHash": "sha256-rCPytmKNjctLloB6UgK5CRrHSwV4b0ygxtJLPPp8R14=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "06648f4902343228ce2de79f291dd5a58ee12146",
"rev": "a1fa429e945becaf60468600daf649be4ba0350c",
"type": "github"
},
"original": {
@@ -96,11 +96,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1776096920,
"narHash": "sha256-8ZyTKMgyms+4Gcp1Zy3qMDXLxvO3FUDJUukxUYnlbLU=",
"lastModified": 1781866110,
"narHash": "sha256-eysWGLqD/9ZshEAg1bj1O8QpJZ6UoDEpjWzBJaR6ono=",
"ref": "refs/heads/main",
"rev": "caafea45ba50ab9cdaefaf049ecd862b690124bb",
"revCount": 19,
"rev": "7fdd373d58137cdcddd8ba6f00ee06186affe5a5",
"revCount": 36,
"type": "git",
"url": "https://github.com/futureware-tech/nix.git"
},
@@ -119,11 +119,11 @@
]
},
"locked": {
"lastModified": 1774104215,
"narHash": "sha256-EAtviqz0sEAxdHS4crqu7JGR5oI3BwaqG0mw7CmXkO8=",
"lastModified": 1778507602,
"narHash": "sha256-kTwur1wV+01SdqskVMSo6JMEpg71ps3HpbFY2GsflKs=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "f799ae951fde0627157f40aec28dec27b22076d0",
"rev": "61ab0e80d9c7ab14c256b5b453d8b3fb0189ba0a",
"type": "github"
},
"original": {
@@ -141,11 +141,11 @@
]
},
"locked": {
"lastModified": 1775585728,
"narHash": "sha256-8Psjt+TWvE4thRKktJsXfR6PA/fWWsZ04DVaY6PUhr4=",
"lastModified": 1781733627,
"narHash": "sha256-U3yTuGBnmXvXoQI3qkpfEDsn9RovQPAjN7ndRco+3u0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "580633fa3fe5fc0379905986543fd7495481913d",
"rev": "3bbec39bc90eadfa031e6f3b77272f3f60803e39",
"type": "github"
},
"original": {
@@ -204,11 +204,11 @@
]
},
"locked": {
"lastModified": 1776046499,
"narHash": "sha256-Wzc4nn07/0RL21ypPHRzNDQZcjhIC8LaYo7QJQjM5T4=",
"lastModified": 1781844424,
"narHash": "sha256-sWBr0D6eu6UhmtM87NOd4oOYilIclFXGDd/s7tVvO10=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "287f84846c1eb3b72c986f5f6bebcff0bd67440d",
"rev": "c804fab681f03ec772390af4421bcc9bce80c1d9",
"type": "github"
},
"original": {
@@ -219,11 +219,11 @@
},
"jail-nix": {
"locked": {
"lastModified": 1772137954,
"narHash": "sha256-h4MGNbOo7L3RHi4uNFmsg5g17/DHXEfnv/xiG6BrNFQ=",
"lastModified": 1776230864,
"narHash": "sha256-YsEjjdOsGEzTeD+iT7ONh071BqWAOQWpzYVei3okAXE=",
"owner": "~alexdavid",
"repo": "jail.nix",
"rev": "42b355c38ca63dab4904acc5c0d95f17954a8c9b",
"rev": "404e7da9da5ab9aa643666682b2ba1312fa5fbe8",
"type": "sourcehut"
},
"original": {
@@ -237,11 +237,11 @@
"brew-src": "brew-src"
},
"locked": {
"lastModified": 1774720267,
"narHash": "sha256-YYftFe8jyfpQI649yfr0E+dqEXE2jznZNcYvy/lKV1U=",
"lastModified": 1781389246,
"narHash": "sha256-ORqLAo/hoJdsZC7UPAuEHev6S0+XIqKEC7vjo5prz1k=",
"owner": "zhaofengli",
"repo": "nix-homebrew",
"rev": "a7760a3a83f7609f742861afb5732210fdc437ed",
"rev": "de7953a08ed4bb9245be043e468561c17b89130d",
"type": "github"
},
"original": {
@@ -252,11 +252,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1775710090,
"narHash": "sha256-ar3rofg+awPB8QXDaFJhJ2jJhu+KqN/PRCXeyuXR76E=",
"lastModified": 1781577229,
"narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "4c1018dae018162ec878d42fec712642d214fdfa",
"rev": "567a49d1913ce81ac6e9582e3553dd90a955875f",
"type": "github"
},
"original": {
@@ -266,22 +266,6 @@
"type": "github"
}
},
"nixpkgs-screen": {
"locked": {
"lastModified": 1737753705,
"narHash": "sha256-fQeXAeNQrsEUH3fd6RTjN/W+8flJiAFHo7Eya2RT87M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e518d4ad2bcad74f98fec028cf21ce5b1e5020dd",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e518d4ad2bcad74f98fec028cf21ce5b1e5020dd",
"type": "github"
}
},
"root": {
"inputs": {
"darwin": "darwin",
@@ -291,7 +275,6 @@
"jail-nix": "jail-nix",
"nix-homebrew": "nix-homebrew",
"nixpkgs": "nixpkgs",
"nixpkgs-screen": "nixpkgs-screen",
"systems": "systems_2",
"vscode-server": "vscode-server"
}

View File

@@ -3,11 +3,6 @@
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
# too many issues with screen 5.0
# - load average in status broken
# - background colors in programs (eg less) not showing
# - caption and hardstatus color lacks intensity
nixpkgs-screen.url = "github:NixOS/nixpkgs/e518d4ad2bcad74f98fec028cf21ce5b1e5020dd";
systems.url = "github:nix-systems/default";
home-manager = {
url = "github:nix-community/home-manager";
@@ -44,13 +39,7 @@
...
}@inputs:
let
trustedSSHKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBxRBsFGa8OFbviYDGSAKLgfm/K2XUxvCo+31FW37yab artem"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIPAtIXXHm58julnr7S0xzBTM1jN5JkKxOL4JpuWDOa2jAAAABHNzaDo= office-dock-usb-a"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHY1xx0huqV6Mcc2WngYDabITeNUbGamJ8//206MxxVTAAAABHNzaDo= keychain-usb-c"
"sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHzY2eOz+JdaKOpIgZbF5FsZzQy0l8vPJjAQdTpBFGsoAAAABHNzaDo= safe"
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJg7zQ4H0LQeQcILZBwCzQ+MYKtCgKm7HPe9oFeoyprKZXAvpm+HDHtaYdU39JF9f+nvRztzXuMhgETAQMAQCkc= fingerprint@macbook"
];
homeManagerUser = "artem";
eachSystem = nixpkgs.lib.genAttrs (import systems);
in
{
@@ -70,24 +59,35 @@
darwinModules = {
mac-portable = import ./modules/darwin/mac-portable.nix;
};
nixosModules = {
linux-headless = import ./modules/nixos/linux-headless.nix;
linux-lxc = import ./modules/nixos/linux-lxc.nix;
jailed-agy = import ./modules/nixos/jailed-agy.nix;
};
homeConfigurations."artem@deimos" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-linux;
extraSpecialArgs.primaryUser = "artem";
homeConfigurations."${homeManagerUser}@deimos" = home-manager.lib.homeManagerConfiguration {
pkgs = import nixpkgs {
system = "x86_64-linux";
};
extraSpecialArgs.primaryUser = homeManagerUser;
modules = [
inputs.fw_nix.nixosModules.identities
vscode-server.homeModules.default
self.homeModules.linux-headless
./hosts/deimos/home.nix
];
};
homeConfigurations."artem@mars" = home-manager.lib.homeManagerConfiguration {
pkgs = nixpkgs.legacyPackages.x86_64-darwin;
homeConfigurations."${homeManagerUser}@mars" = home-manager.lib.homeManagerConfiguration {
pkgs = import nixpkgs {
system = "x86_64-darwin";
config.allowDeprecatedx86_64Darwin = true;
};
extraSpecialArgs = {
primaryUser = "artem";
inherit trustedSSHKeys;
primaryUser = homeManagerUser;
};
modules = [
inputs.fw_nix.nixosModules.identities
self.homeModules.mac-portable
./hosts/mars/home.nix
];
@@ -95,39 +95,41 @@
darwinConfigurations.mars = darwin.lib.darwinSystem {
system = "x86_64-darwin";
specialArgs.primaryUser = "artem";
specialArgs.primaryUser = homeManagerUser;
modules = [
inputs.fw_nix.nixosModules.identities
self.darwinModules.mac-portable
inputs.fw_nix.nixosModules.tools
inputs.fw_nix.nixosModules.nix-gc
inputs.fw_nix.nixosModules.nix-settings
inputs.fw_nix.nixosModules.tools
inputs.fw_nix.nixosModules.futureware
inputs.nix-homebrew.darwinModules.nix-homebrew
./hosts/mars/darwin.nix
{
nixpkgs.config.allowDeprecatedx86_64Darwin = true;
}
];
};
nixosConfigurations.deimos =
let
system = "x86_64-linux";
in
nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = {
inherit trustedSSHKeys;
inherit (inputs) jail-nix;
pkgs-screen = import inputs.nixpkgs-screen {
inherit system;
};
};
modules = [
inputs.fw_nix.nixosModules.nix-gc
inputs.fw_nix.nixosModules.nix-settings
inputs.fw_nix.nixosModules.tools
inputs.fw_nix.nixosModules.sshd
inputs.fw_nix.nixosModules.futureware
./hosts/deimos/nixos.nix
];
nixosConfigurations.deimos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {
primaryUser = homeManagerUser;
inherit (inputs) jail-nix;
};
modules = [
inputs.fw_nix.nixosModules.identities
self.nixosModules.linux-headless
self.nixosModules.linux-lxc
self.nixosModules.jailed-agy
inputs.fw_nix.nixosModules.nix-gc
inputs.fw_nix.nixosModules.nix-settings
inputs.fw_nix.nixosModules.tools
inputs.fw_nix.nixosModules.sshd
inputs.fw_nix.nixosModules.futureware
./hosts/deimos/nixos.nix
];
};
devShells = eachSystem (
system:

22
hosts/common/home.nix Normal file
View File

@@ -0,0 +1,22 @@
{
identities,
primaryUser,
...
}:
let
user = identities.users.${primaryUser};
in
{
programs.git = {
signing = {
# Will be available on remote machines via SSH agent (Secretive).
key = "key::" + user.sign."sign@mars".publicKey;
signByDefault = true;
};
settings.user = {
name = "Artem Sheremet";
inherit (user) email;
};
};
}

View File

@@ -1,5 +1,18 @@
_: {
home.homeDirectory = "/home/artem";
{
config,
lib,
pkgs,
...
}:
let
utils = import "${pkgs.path}/nixos/lib/utils.nix" { inherit lib pkgs config; };
haremote-path = "${config.home.homeDirectory}/src/haremote";
haremote-unit = utils.escapeSystemdPath haremote-path;
in
{
imports = [
../common/home.nix
];
services.vscode-server.enable = true;
services.vscode-server.installPath = [
@@ -7,17 +20,17 @@ _: {
"$HOME/.antigravity-server"
];
systemd.user.mounts.home-artem-src-haremote = {
systemd.user.mounts."${haremote-unit}" = {
Unit = {
Description = "Mount ~/src/haremote";
Description = "Mount ${haremote-path}";
After = [ "network-online.target" ];
Wants = [ "network-online.target" ];
};
Mount = {
What = "root@homeassistant.home.arpa:/homeassistant";
Where = "/home/artem/src/haremote";
Where = haremote-path;
Type = "fuse.sshfs";
Options = "reconnect,ServerAliveInterval=15,uid=1000,gid=1000,IdentityAgent=/home/artem/.ssh/ssh_auth_sock";
Options = "reconnect,ServerAliveInterval=15,uid=1000,gid=1000,IdentityAgent=${config.home.homeDirectory}/.ssh/ssh_auth_sock";
};
Install = {
WantedBy = [ "default.target" ];
@@ -26,8 +39,8 @@ _: {
programs.zsh.loginExtra = ''
if [ -n "$SSH_AUTH_SOCK" ]; then
mkdir -p ~/src/haremote
[ -z "$(ls -A ~/src/haremote 2>/dev/null)" ] && systemctl --user restart home-artem-src-haremote.mount
mkdir -p ${haremote-path}
[ -z "$(ls -A ${haremote-path} 2>/dev/null)" ] && systemctl --user restart ${haremote-unit}.mount
fi
'';
}

View File

@@ -1,184 +1,35 @@
{
modulesPath,
pkgs,
pkgs-screen,
trustedSSHKeys,
jail-nix,
identities,
primaryUser,
...
}:
let
jail = jail-nix.lib.init pkgs;
in
{
imports = [
"${modulesPath}/virtualisation/lxc-container.nix"
];
# Disable legacy channel behavior that lxc-container brings in via installer/cd-dvd/channel.nix.
system.installer.channel.enable = false;
# Impermanence setup:
# 1. There's no initrd/stage 1 in LXC container; /sbin/init is invoked after
# LXC finishes setting up special and user-configured filesystems. Any
# options in boot.initrd, as well as neededForBoot fileSystems won't be
# respected.
# 2. Non-boot fileSystems (aka systemd) mount too late for systemd or nixos
# persistence to be instantiated, so we have to create this script below.
# 3. The expectation from host is to mount /home and /nix. Root filesystem
# will also be a disk, as that's Incus requirement; the host should clean
# it up periodically using: "incus rebuild --empty <vm>".
# 4. Since rootfs will be empty after rebuild, you have to point LXC at the
# current init (instead of /sbin/init), by adding to the "config:" section
# in "incus config edit <vm>":
# raw.lxc: lxc.init.cmd = /nix/var/nix/profiles/system/init
system.activationScripts.persistence = {
deps = [ "specialfs" ];
text = ''
persist() {
local item="$1"
local constructor="''${item%%:*}"
local target="''${item#*:}"
mkdir -p "$(dirname "$target")"
$constructor "$target"
if ! mountpoint -q "$target"; then
local source="/home/persistent/$target"
mkdir -p "$(dirname "$source")"
$constructor "$source"
mount --bind "$source" "$target"
fi
}
for item in \
"mkdir -p:/var/lib/nixos" \
"mkdir -p:/var/lib/systemd" \
"touch:/etc/machine-id" \
"touch:/etc/ssh/ssh_host_ed25519_key" \
; do
persist "$item"
done
chmod 0600 /etc/ssh/ssh_host_ed25519_key
# lxc-container.nix installBootloader/installInitScript will attempt to
# symlink /sbin/init, so we have to create the parent directory.
mkdir -p /sbin
'';
};
system.activationScripts.users.deps = [ "persistence" ];
# This is supposed to persist machine-id, but fails.
systemd.services.systemd-machine-id-commit.enable = false;
users.users.artem = {
users.users.${primaryUser} = {
uid = 1000;
isNormalUser = true;
extraGroups = [
"wheel"
"docker"
"kvm"
];
openssh.authorizedKeys.keys = trustedSSHKeys;
openssh.authorizedKeys.keys = identities.getAccessKeys { user = primaryUser; };
shell = pkgs.zsh;
linger = true; # Keep sshfs mounted even on logout.
};
# Create /etc/zshrc that loads the nix-darwin environment.
programs.zsh.enable = true;
security.sudo.wheelNeedsPassword = false;
virtualisation.docker.enable = true;
documentation.man.enable = true;
nixpkgs.config.allowUnfree = true;
environment.systemPackages = with pkgs; [
# TODO: clean this up against artem@deimos
git
pkgs-screen.screen
# TODO: move below into hosts/deimos/home.nix
sshfs
# https://unix.stackexchange.com/questions/651165/using-systemd-to-mount-remote-filesystems-in-user-bus
# Have to run the wrapper due to SUID.
(pkgs.writeShellScriptBin "umount.fuse.sshfs" ''
exec /run/wrappers/bin/fusermount -u "$1"
'')
file
nixfmt
nixd
home-assistant-cli
yt-dlp
# From hosts/common/tools.nix:
# Software debug
iotop
dool # dool --time --disk -D /dev/sde,/dev/sdf --top-bio --top-cpu --zfs-arc
strace
ltrace
smem # smem -tkP nginx
# Hardware info and tunables
parted
hdparm
efivar
efibootmgr
sg3_utils # sg_unmap
lm_sensors # sensors
nvme-cli
dmidecode
ethtool
# jailed-gemini --yolo
(jail "jailed-gemini" pkgs.gemini-cli (
with jail.combinators;
[
network
time-zone
no-new-session
mount-cwd
(readwrite (noescape "~/.gemini"))
# The above is a stow-controlled symlink to the following.
(readwrite (noescape "~/dotfiles/legacy/.gemini"))
(add-pkg-deps (
with pkgs;
[
bashInteractive
curl
wget
jq
git
which
ripgrep
gnugrep
gnused
gawkInteractive
ps
findutils
gzip
unzip
gnutar
diffutils
coreutils
procps
python3
nix
]
))
]
))
];
# unprivileged LXCs can't set net.ipv4.ping_group_range
security.wrappers.ping = {
owner = "root";
group = "root";
capabilities = "cap_net_raw+p";
source = "${pkgs.iputils.out}/bin/ping";
};
# For building RPi configs. Extra steps are handled by the host (nas).
# https://discuss.linuxcontainers.org/t/systemd-binfmt-service-is-masked/21566/4
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
@@ -187,6 +38,4 @@ in
hostName = "deimos";
domain = "home.arpa";
};
system.stateVersion = "25.11"; # Never change this.
}

View File

@@ -2,10 +2,15 @@
pkgs,
lib,
config,
trustedSSHKeys,
identities,
primaryUser,
...
}:
{
imports = [
../common/home.nix
];
home.packages = with pkgs; [
dosbox-staging # dosbox appears broken on darwin
@@ -19,7 +24,11 @@
home.activation.setupAuthorizedKeys = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
run install -m 0600 -D \
${pkgs.writeText "keys" (builtins.concatStringsSep "\n" trustedSSHKeys)} \
${
pkgs.writeText "keys" (
builtins.concatStringsSep "\n" (identities.getAccessKeys { user = primaryUser; })
)
} \
${config.home.homeDirectory}/.ssh/ephemeral_sshd/authorized_keys
'';

View File

@@ -0,0 +1,29 @@
{
"mcpServers": {
"nix": {
"command": "nix",
"args": [
"run",
"github:utensils/mcp-nixos",
"--"
]
},
"ha": {
"command": "nix",
"args": [
"shell",
"nixpkgs#uv",
"nixpkgs#python3",
"--command",
"uv",
"tool",
"run",
"ha-mcp"
],
"env": {
"UV_PYTHON_DOWNLOADS": "never",
"UV_PYTHON_PREFERENCE": "system"
}
}
}
}

View File

@@ -1,35 +0,0 @@
{
"mcpServers": {
"nix": {
"command": "nix",
"args": [
"run",
"github:utensils/mcp-nixos",
"--"
]
},
"ha": {
"url": "${HASS_SERVER}/mcp_server/sse",
"headers": {
"Authorization": "Bearer ${HASS_TOKEN}"
},
"timeout": 5000
}
},
"security": {
"auth": {
"selectedType": "oauth-personal"
}
},
"general": {
"sessionRetention": {
"warningAcknowledged": true,
"enabled": true,
"maxAge": "30d"
},
"preferredEditor": "vim"
},
"model": {
"name": "auto-gemini-3"
}
}

View File

@@ -1,44 +0,0 @@
[color]
ui = auto
[alias]
co = checkout
st = status
di = diff -w --no-prefix
df = diff
dc = diff --cached
ci = commit
br = branch
lg = log -p --decorate=full --show-signature
lol = log --graph --decorate=full --pretty=oneline --abbrev-commit
lola = log --graph --decorate=full --pretty=oneline --abbrev-commit --all
ls = ls-files
# Show files ignored by git:
ign = ls-files -o -i --exclude-standard
[apply]
whitespace = nowarn
[push]
default = tracking
[rebase]
stat = yes
[format]
pretty = fuller
[fetch]
prune = yes
[credential "https://source.developers.google.com"]
helper = gcloud.sh
[core]
autocrlf = input
[branch]
# 0 times I wanted this when doing "git checkout".
autoSetupMerge = false
# Set up new branches in a way that "git pull" does a rebase by default.
autoSetupRebase = always
[gpg]
format = ssh
[commit]
gpgsign = true
# Must always go last, to be able to override the settings above.
[include]
path = ~/.config/gitconfig_local

View File

@@ -1,34 +0,0 @@
# http://aperiodic.net/screen/commands:start
# see accompanying file ~/.ssh/rc
setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
# no screen blinking on bell
vbell off
startup_message off
# disable "New screen..." message
msgwait 0
defscrollback 10240
# hostname, timestamp, LA in status bar
caption always "%{+b}%H | %c %d.%m.%Y | Load: %l"
# colored window list
hardstatus alwayslastline "%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<"
# Launch login shells
shell -${SHELL}
# 256color support
#termcapinfo xterm 'Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm'
term screen-256color
#defbce "on"
# beep on activity monitor alert (C-a M)
# ex.: 12:37 activity -> 7$ zsh
activity "%c activity -> %n%f %t^G"
# Alt Left/Right = switch windows
bindkey "^[[1;3D" prev
bindkey "^[[1;3C" next
bindkey "^[b" prev
bindkey "^[f" next
# Alt N = new window
bindkey "^[n" screen
shelltitle '% |zsh'

View File

@@ -1,25 +0,0 @@
Host *
# Share SSH connection.
# If disabling, consider impact on ssh agent forwarding in screen
# sessions (see .ssh/rc file).
ControlMaster auto
ControlPath ~/.ssh/ctl/%r@%h:%p
ControlPersist 10m
# When a shared connection is broken (remote reboot), detect it faster.
ServerAliveInterval 11
ServerAliveCountMax 2
ConnectTimeout 10
AddKeysToAgent yes
#Host custom-host-with-xorg
# HostName custom-hostname
# User crate
# ForwardX11 yes
# ForwardX11Trusted yes
#Host always-changing-keys-dont-care
# StrictHostKeyChecking no
# UserKnownHostsFile=/dev/null
Include config.d/*

View File

@@ -1,11 +0,0 @@
#!/bin/sh
# When SSH-ing with agent forwarding enabled, this variable is set by sshd
# itself. However, an existing screen session that we attach to will not have
# its SSH_AUTH_SOCK environment variable updated, so we hardcode this path in
# .screenrc and create a symlink to keep it alive.
#
# It WILL break if two sessions are opened to a machine, and a newer one is
# terminated. ControlMaster in .ssh/config solves this problem by sharing the
# connection (and as a result, sharing SSH agent socket).
[ -n "$SSH_AUTH_SOCK" ] && ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock

View File

@@ -35,6 +35,9 @@ if exists("+undofile")
" Enable the persistent undo file(s)
set undodir=~/.vim/undo
set undofile
if !isdirectory(expand(&undodir))
call mkdir(expand(&undodir), "p")
endif
endif
set switchbuf+=usetab " Switch to existing tab; open a new tab for the new buf

View File

@@ -8,9 +8,9 @@ export PATH="${HOME}/bin:${PATH}"
# Since we exec right afterwards, there's no point in setting this shell up.
if [[ -o login ]]; then
[ -n "$SSH_CLIENT" ] || [ -n "$SSH_TTY" ] && \
[ -z "$STY" ] && \
which screen 2>/dev/null && \
exec screen -URR
[ -z "$TMUX" ] && \
command -v tmux >/dev/null && \
exec tmux new -A -D -s main
fi
HISTFILE=~/.zsh_history
@@ -62,7 +62,6 @@ alias grep='grep --line-buffered --color=auto'
alias ipt='iptables -nvL --line-numbers'
alias ip6t='ip6tables -nvL --line-numbers'
alias tcpdump='tcpdump -l'
alias ag='ag -C 2 --pager="$PAGER" --smart-case'
alias mysql='mysql --select_limit=1000'
alias logcat='adb logcat -v "color printable usec year zone" -T 10'
alias readelf='readelf -W'
@@ -81,6 +80,10 @@ starttransfer: %{time_starttransfer} | \
total: %{time_total} | \
size: %{size_download}\n"'
rg() {
command rg -C 2 --smart-case --pretty "$@" | pager
}
# nix-deploy # current host
# nix-deploy nas # deploy nas
# nix-deploy test secondary # deploy secondary but do not add to boot
@@ -125,7 +128,22 @@ nix-deploy() {
cmd=(nixos-rebuild)
command -v nixos-rebuild >/dev/null 2>&1 || cmd=(nix run "nixpkgs#nixos-rebuild" --)
"${cmd[@]}" "$action" --flake ".#$config" --target-host "$target" --sudo "$@" |& nom
nix build ".#nixosConfigurations.$config.config.system.build.toplevel" \
--out-link "result.$config" |& nom
local build_status=$pipestatus[1]
if (( build_status != 0 )); then
return $build_status
fi
if [[ "$action" != "build" ]]; then
# Bypass nixos-rebuild self-update check which errors in
# flake-only setups when --store-path is used.
_NIXOS_REBUILD_REEXEC=1 "${cmd[@]}" "$action" \
--store-path "$(readlink -f "result.$config")" \
--target-host "$target" \
--sudo \
"$@"
fi
}
myip() {

View File

@@ -1,24 +1,75 @@
{
pkgs,
lib,
identities,
primaryUser,
...
}:
{
home.username = primaryUser;
nixpkgs.config.allowUnfree = true;
home.packages = with pkgs; [
stow
wget
gemini-cli
silver-searcher
antigravity-cli
yubikey-manager
];
home.activation.stowLegacy = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
if [ -d "$HOME/dotfiles" ]; then
if [ -d "$HOME/dotfiles/legacy" ]; then
run ${pkgs.stow}/bin/stow -d $HOME/dotfiles -t $HOME legacy
fi
'';
home.activation.report-changes = lib.hm.dag.entryAnywhere ''
# oldGenPath can be undefined with home-manager used as part of NixOS config
if [ -n "''${oldGenPath+x}" ]; then
${pkgs.nvd}/bin/nvd diff $oldGenPath $newGenPath
fi
'';
programs.git = {
enable = true;
settings = {
alias = {
co = "checkout";
st = "status";
di = "diff -w --no-prefix";
df = "diff";
dc = "diff --cached";
ci = "commit";
br = "branch";
lg = "log -p --decorate=full --show-signature";
lol = "log --graph --decorate=full --pretty=oneline --abbrev-commit";
lola = "log --graph --decorate=full --pretty=oneline --abbrev-commit --all";
ls = "ls-files";
# Show files ignored by git:
ign = "ls-files -o -i --exclude-standard";
};
color.ui = "auto";
apply.whitespace = "nowarn";
push.default = "tracking";
rebase.stat = "yes";
format.pretty = "fuller";
fetch.prune = "yes";
core.autocrlf = "input";
branch = {
# 0 times I wanted this when doing "git checkout".
autoSetupMerge = false;
# Set up new branches in a way that "git pull" does a rebase by default.
autoSetupRebase = "always";
};
gpg.format = "ssh";
gpg.ssh.allowedSignersFile = "${pkgs.writeText "allowed_signers" (
lib.concatStringsSep "\n" (identities.getSigningEntries { })
)}";
credential."https://source.developers.google.com".helper = "gcloud.sh";
};
};
programs.zsh = {
enable = true;
initContent = ''
@@ -29,9 +80,9 @@
fi
if [ -r ~/dotfiles/migrated/.zshrc ]; then
# Hack for faster iterations
. ~/dotfiles/migrated/.zshrc
else
# If no custom override is available, use the one bundled with flake.
. ${../../migrated/.zshrc}
fi
'';
@@ -82,5 +133,104 @@
};
};
programs.tmux = {
enable = true;
shortcut = "a"; # ^a
escapeTime = 0;
historyLimit = 10240;
# hjkl HJKL and mouse to switch between and resize panels.
mouse = true;
keyMode = "vi";
customPaneNavigationAndResize = true;
extraConfig = ''
set-environment -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
set-option -g update-environment "DISPLAY SSH_ASKPASS SSH_AGENT_PID SSH_CONNECTION"
# Instead of flashing or beeping, blink the window in status.
set -g visual-bell off
set -g monitor-activity on
set -g bell-action none
set -g window-status-activity-style "fg=yellow,blink"
# Requires support from terminal (e.g. iTerm2).
set -s set-clipboard on
# For scrolling through logs.
bind y set-window-option synchronize-panes
# Panel configuration.
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind Enter resize-pane -Z
# Navigation.
bind -n M-Up new-window -c "#{pane_current_path}"
bind -n M-Down confirm-before -p "kill-window #W? (y/n)" kill-window
bind -n M-Left previous-window
bind -n M-Right next-window
# Status bar.
set -g status-interval 5
set -g status-position bottom
set -g status-style "bg=default,fg=white"
set -g status-left-length 20
set -g status-left "#[fg=green,bold]#H #[fg=white]| "
set -g status-right-length 60
set -g status-right "#[fg=cyan]%H:%M%Z %d.%m.%Y #[fg=white]| #[fg=yellow]Load: #(cut -d ' ' -f 1-3 /proc/loadavg)"
set -g status-justify left
set -g window-status-format "#[fg=white,dim]#I:#W#F"
set -g window-status-current-format "#[fg=white,bold,bg=blue] #I:#W#F "
'';
};
programs.ssh = {
enable = true;
enableDefaultConfig = false;
includes = [ "config.d/*" ];
settings = {
"*" = {
# Share SSH connection.
# If disabling, consider impact on ssh agent forwarding in screen
# sessions (see .ssh/rc file).
ControlMaster = "auto";
ControlPath = "~/.ssh/ctl/%r@%h:%p";
ControlPersist = "10m";
# When a shared connection is broken (remote reboot), detect it faster.
ServerAliveInterval = 11;
ServerAliveCountMax = 2;
ConnectTimeout = 10;
AddKeysToAgent = "yes";
};
};
};
home.file = {
".ssh/rc" = {
executable = true;
text = ''
#!/bin/sh
# When SSH-ing with agent forwarding enabled, this variable is set by sshd
# itself. However, an existing screen session that we attach to will not have
# its SSH_AUTH_SOCK environment variable updated, so we hardcode this path in
# .screenrc and create a symlink to keep it alive.
#
# It WILL break if two sessions are opened to a machine, and a newer one is
# terminated. ControlMaster in .ssh/config solves this problem by sharing the
# connection (and as a result, sharing SSH agent socket).
[ -n "$SSH_AUTH_SOCK" ] && ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
'';
};
".ssh/ctl/.keep".text = "";
};
home.stateVersion = "25.11"; # never modify
}

View File

@@ -1,8 +1,8 @@
{ primaryUser, ... }:
{ lib, primaryUser, ... }:
{
imports = [
./common.nix
];
home.homeDirectory = "/home/${primaryUser}";
home.homeDirectory = lib.mkDefault "/home/${primaryUser}";
}

View File

@@ -1,16 +1,22 @@
{ pkgs, primaryUser, ... }:
{
pkgs,
lib,
primaryUser,
...
}:
{
imports = [
./common.nix
];
home.homeDirectory = "/Users/${primaryUser}";
home.homeDirectory = lib.mkDefault "/Users/${primaryUser}";
home.packages = with pkgs; [
secretive
vlc-bin
# Faster and more feature-rich than Terminal.
# TODO: https://iterm2.com/shell_integration/zsh
iterm2
# Newer OpenSSH client to support FIDO2 keys.
@@ -29,6 +35,10 @@
TripleClickSelectsFullWrappedLines = true;
WordChars = "/-._~";
PromptOnQuit = false;
# Use system browser to open links.
NoSyncBrowserUpsell = 1;
NoSyncBrowserUpsell_selection = 1;
};
home.file."Library/Application Support/iTerm2/DynamicProfiles/nix-profile.json".text =
builtins.toJSON
@@ -41,6 +51,7 @@
Columns = 160;
Rows = 45;
"Scrollback Lines" = 1000000;
# For tmux selection and moving borders.
"Mouse Reporting" = true;
@@ -67,6 +78,10 @@
export SSH_AUTH_SOCK=~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh
'';
nixpkgs.config.allowUnfree = true;
# TODO: defaults read NSGlobalDomain
# https://nix-darwin.github.io/nix-darwin/manual/index.html
# -> set system.defaults.NSGlobalDomain
# or system.defaults.CustomSystemPreferences
programs.vscode.enable = true;
}

View File

@@ -0,0 +1,148 @@
{
config,
lib,
pkgs,
jail-nix,
primaryUser,
...
}:
let
jail = jail-nix.lib.init pkgs;
allPackages =
with pkgs;
[
bashInteractive
curl
wget
jq
git
which
ripgrep
gnugrep
gnused
gawkInteractive
ps
findutils
gzip
unzip
gnutar
diffutils
coreutils
procps
python3
python3Packages.pip
esphome
ruby
go
gcc
gnumake
pkg-config
nix
]
++ config.programs.jailed-agy.extraPackages;
in
{
options.programs.jailed-agy = {
extraPackages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
description = "Extra packages to append to the jailed-agy environment.";
};
};
config = {
environment.systemPackages = [
(jail "jailed-agy" pkgs.antigravity-cli (
with jail.combinators;
[
network
time-zone
no-new-session
mount-cwd
# Enforce that the wrapper is not run as root/privileged user
(add-runtime ''
if [ "$(id -u)" -eq 0 ]; then
echo "Error: jailed-agy must not be run as root/privileged user!" >&2
exit 1
fi
'')
# Automatically append --dangerously-skip-permissions to agy invocation
(set-argv [
"--dangerously-skip-permissions"
(noescape "\"$@\"")
])
(readwrite (noescape "~/.gemini"))
# The above is a stow-controlled symlink to the following.
(readwrite (noescape "~/dotfiles/legacy/.gemini"))
# Enable easy installation of pip packages in the current directory.
(set-env "PYTHONPATH" (noescape "\"$PWD/.pip-packages\""))
(set-env "PIP_TARGET" (noescape "\"$PWD/.pip-packages\""))
(set-env "PIP_CACHE_DIR" (noescape "\"$PWD/.pip-cache\""))
(set-env "PIP_BREAK_SYSTEM_PACKAGES" "1")
# Enable easy installation and persistence of RubyGems in the current directory.
(set-env "GEM_HOME" (noescape "\"$PWD/.gem\""))
# Enable easy installation and persistence of Go modules and caches in the current directory.
(set-env "GOPATH" (noescape "\"$PWD/.go\""))
(set-env "GOCACHE" (noescape "\"$PWD/.go-cache\""))
# Preconfigure compiler and linker flags dynamically for all jail packages.
# This allows compiling Ruby gems (e.g. ffi, which requires libffi) and Go packages
# (e.g. YubiKey plugins, which require pcsclite) out-of-the-box.
(set-env "PKG_CONFIG_PATH" (
lib.concatStringsSep ":" (map (pkg: "${pkg.dev or pkg}/lib/pkgconfig") allPackages)
))
(set-env "NIX_CFLAGS_COMPILE" (
lib.concatStringsSep " " (map (pkg: "-isystem ${pkg.dev or pkg}/include") allPackages)
))
(set-env "NIX_LDFLAGS" (
lib.concatStringsSep " " (map (pkg: "-L${pkg.out or pkg}/lib") allPackages)
))
# Mount system and user profiles so their packages are automatically available at runtime
(try-ro-bind "/run/current-system/sw" "/run/current-system/sw")
(try-ro-bind "/etc/profiles/per-user/${primaryUser}" "/etc/profiles/per-user/${primaryUser}")
# Mount Nix files and directories to support nix-shell and Nix operations in jail
(try-ro-bind "/nix/store" "/nix/store")
(try-ro-bind "/nix/var/nix/daemon-socket" "/nix/var/nix/daemon-socket")
(try-ro-bind "/nix/var/nix/profiles" "/nix/var/nix/profiles")
(try-ro-bind "/etc/nix" "/etc/nix")
(try-ro-bind "/etc/static" "/etc/static")
# Forward Nix environment variables
(try-fwd-env "NIX_REMOTE")
(try-fwd-env "NIX_PATH")
(try-fwd-env "NIX_SSL_CERT_FILE")
(add-pkg-deps allPackages)
# Prepend local project binary directories, system, and user bin paths to the jail's PATH.
# Note: We place this after `add-pkg-deps` so that local paths take highest precedence.
# We use explicit double quotes to allow bash to expand $PWD at runtime and handle spaces.
(
state:
state
// {
env = state.env // {
PATH =
if state.env ? PATH && state.env.PATH != "" then
"\"\$PWD/.gem/bin:\$PWD/.go/bin:\$PWD/.pip-packages/bin:/run/current-system/sw/bin:/etc/profiles/per-user/${primaryUser}/bin:${state.env.PATH}\""
else
"\"\$PWD/.gem/bin:\$PWD/.go/bin:\$PWD/.pip-packages/bin:/run/current-system/sw/bin:/etc/profiles/per-user/${primaryUser}/bin\"";
};
}
)
]
))
];
};
}

View File

@@ -0,0 +1,23 @@
{
pkgs,
...
}:
{
# Create /etc/zshrc that loads the nix-darwin environment.
programs.zsh.enable = true;
security.sudo.wheelNeedsPassword = false;
programs.mosh.enable = true;
documentation.man.enable = true;
environment.systemPackages = with pkgs; [
# https://unix.stackexchange.com/questions/651165/using-systemd-to-mount-remote-filesystems-in-user-bus
# Have to run the wrapper due to SUID.
(pkgs.writeShellScriptBin "umount.fuse.sshfs" ''
exec /run/wrappers/bin/fusermount -u "$1"
'')
];
system.stateVersion = "25.11"; # Never change this.
}

View File

@@ -0,0 +1,76 @@
{
modulesPath,
pkgs,
...
}:
{
imports = [
"${modulesPath}/virtualisation/lxc-container.nix"
];
# Disable legacy channel behavior that lxc-container brings in via installer/cd-dvd/channel.nix.
system.installer.channel.enable = false;
# Impermanence setup:
# 1. There's no initrd/stage 1 in LXC container; /sbin/init is invoked after
# LXC finishes setting up special and user-configured filesystems. Any
# options in boot.initrd, as well as neededForBoot fileSystems won't be
# respected.
# 2. Non-boot fileSystems (aka systemd) mount too late for systemd or nixos
# persistence to be instantiated, so we have to create this script below.
# 3. The expectation from host is to mount /home and /nix. Root filesystem
# will also be a disk, as that's Incus requirement; the host should clean
# it up periodically using: "incus rebuild --empty <vm>".
# 4. Since rootfs will be empty after rebuild, you have to point LXC at the
# current init (instead of /sbin/init), by adding to the "config:" section
# in "incus config edit <vm>":
# raw.lxc: lxc.init.cmd = /nix/var/nix/profiles/system/init
system.activationScripts.persistence = {
deps = [ "specialfs" ];
text = ''
persist() {
local item="$1"
local constructor="''${item%%:*}"
local target="''${item#*:}"
mkdir -p "$(dirname "$target")"
$constructor "$target"
if ! mountpoint -q "$target"; then
local source="/home/persistent/$target"
mkdir -p "$(dirname "$source")"
$constructor "$source"
mount --bind "$source" "$target"
fi
}
for item in \
"mkdir -p:/var/lib/nixos" \
"mkdir -p:/var/lib/systemd" \
"mkdir -p:/var/lib/docker" \
"touch:/etc/machine-id" \
"touch:/etc/ssh/ssh_host_ed25519_key" \
; do
persist "$item"
done
chmod 0600 /etc/ssh/ssh_host_ed25519_key
# lxc-container.nix installBootloader/installInitScript will attempt to
# symlink /sbin/init, so we have to create the parent directory.
mkdir -p /sbin
'';
};
system.activationScripts.users.deps = [ "persistence" ];
# This is supposed to persist machine-id, but fails.
systemd.services.systemd-machine-id-commit.enable = false;
# unprivileged LXCs can't set net.ipv4.ping_group_range
security.wrappers.ping = {
owner = "root";
group = "root";
capabilities = "cap_net_raw+p";
source = "${pkgs.iputils.out}/bin/ping";
};
}