Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c7392f2dd9 | |||
| f5f8e88966 | |||
| bf874d962a |
@@ -1,105 +0,0 @@
|
|||||||
# mibook: choose terminal-only vs desktop at boot
|
|
||||||
|
|
||||||
## Goal
|
|
||||||
|
|
||||||
Let mibook offer a choice, each time it boots, between the normal KDE desktop
|
|
||||||
and a terminal-only ("server") mode with no graphical session — decided at
|
|
||||||
boot, without rebuilding the system.
|
|
||||||
|
|
||||||
## Background: why the first attempt failed
|
|
||||||
|
|
||||||
The first implementation booted mibook to a text console by default
|
|
||||||
(`systemd.defaultUnit = "multi-user.target"`, display manager not started) and
|
|
||||||
provided a `desktop` command to start KDE on demand. On real hardware this
|
|
||||||
locked the machine out:
|
|
||||||
|
|
||||||
- **No SSH.** mibook is WiFi-only and its WiFi credentials are stored per-user
|
|
||||||
in KWallet ("agent-owned"). NetworkManager only receives the password once a
|
|
||||||
desktop session is running, so a headless boot never joins the network and
|
|
||||||
the machine has no IP — nothing to SSH into.
|
|
||||||
- **No usable console.** The boot appeared to "hang" with no login prompt:
|
|
||||||
`NetworkManager-wait-online` stalled waiting for a network that never came
|
|
||||||
up, and the `getty` login prompt on tty1 was buried under later service
|
|
||||||
messages.
|
|
||||||
|
|
||||||
Conclusion: a headless WiFi laptop cannot be reached remotely, and the plain
|
|
||||||
console was hard to use. The design must (a) keep the desktop as the reliable
|
|
||||||
default, (b) make the terminal path a deliberate, self-sufficient choice, and
|
|
||||||
(c) not depend on the network being up.
|
|
||||||
|
|
||||||
## Behavior
|
|
||||||
|
|
||||||
- The **default GRUB entry** boots straight into KDE — unchanged from the
|
|
||||||
known-working baseline.
|
|
||||||
- A **separate GRUB entry, `mibook (terminal)`** (a NixOS *specialisation*),
|
|
||||||
boots to a text console with **autologin** for `finn`. From there the user
|
|
||||||
can work in the shell or run `desktop` to bring KDE up (via SDDM).
|
|
||||||
- The choice is made in the GRUB menu at boot — matching the original request
|
|
||||||
to "decide each time I boot."
|
|
||||||
- Booting never stalls on the network.
|
|
||||||
|
|
||||||
### Known limitation (documented, not fixed in config)
|
|
||||||
|
|
||||||
In terminal mode WiFi will not connect on its own, because the password is
|
|
||||||
stored per-user in KWallet. To reach mibook over SSH from terminal mode, the
|
|
||||||
user must first save the WiFi as a **system** connection in KDE:
|
|
||||||
network settings → the WiFi network → "All users may connect to this network".
|
|
||||||
Until then, terminal mode is local-console-only. This is a one-time manual
|
|
||||||
step outside the scope of the Nix config.
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
### `machines/mibook/configuration.nix`
|
|
||||||
|
|
||||||
- Add a NixOS specialisation `specialisation.terminal.configuration`:
|
|
||||||
- `system.nixos.tags = [ "terminal" ];` — labels the generated boot entry.
|
|
||||||
- `systemd.defaultUnit = lib.mkForce "multi-user.target";` — boots to the
|
|
||||||
text console. `graphical.target` is what pulls in the display manager (via
|
|
||||||
its embedded `Wants=display-manager.service`), so defaulting to
|
|
||||||
`multi-user.target` leaves SDDM installed but not started at boot.
|
|
||||||
- `services.getty.autologinUser = "finn";` — guarantees a usable shell on
|
|
||||||
the console instead of a login prompt that can scroll off screen.
|
|
||||||
- A `desktop` command via
|
|
||||||
`pkgs.writeShellScriptBin "desktop" "exec sudo systemctl start display-manager.service"`
|
|
||||||
in `environment.systemPackages`, to start KDE on demand.
|
|
||||||
- Add `systemd.services.NetworkManager-wait-online.enable = false;` (applies to
|
|
||||||
both the default and terminal boots) so boot never stalls waiting for the
|
|
||||||
network.
|
|
||||||
|
|
||||||
### Reverted from the first attempt
|
|
||||||
|
|
||||||
- `modules/environments/kde-desktop/default.nix` — remove the `startOnBoot`
|
|
||||||
option and its `mkMerge`/`mkIf` machinery; back to the original profile that
|
|
||||||
simply enables SDDM + Plasma 6.
|
|
||||||
- `machines/mibook/environments.nix` — remove `kde-desktop.startOnBoot = false;`
|
|
||||||
(back to just `kde-desktop.enable = true;`).
|
|
||||||
|
|
||||||
## Why a specialisation
|
|
||||||
|
|
||||||
A specialisation generates a second boot-menu entry automatically from a
|
|
||||||
modified copy of the configuration. It is the idiomatic NixOS mechanism for a
|
|
||||||
boot-time choice and avoids fragile hand-written GRUB `extraEntries` that would
|
|
||||||
need to track kernel/initrd paths across generations. The default entry remains
|
|
||||||
byte-for-byte the working desktop configuration.
|
|
||||||
|
|
||||||
## Testing / verification
|
|
||||||
|
|
||||||
- `nix build '.#nixosConfigurations.mibook.config.system.build.toplevel'`
|
|
||||||
builds both `nixos-system-mibook` and `nixos-system-mibook-terminal`.
|
|
||||||
- Verified on the built closures:
|
|
||||||
- Parent `default.target` → `graphical.target`; no console autologin
|
|
||||||
(identical to the pre-change baseline).
|
|
||||||
- Specialisation `default.target` → `multi-user.target`; tty1 getty wrapper
|
|
||||||
contains `--autologin finn`; `desktop` present in the system profile.
|
|
||||||
- `NetworkManager-wait-online` disabled in both.
|
|
||||||
- Post-`switch` manual check on mibook: default GRUB entry boots to KDE; the
|
|
||||||
`terminal` entry boots to an autologged-in console; running `desktop` there
|
|
||||||
starts SDDM and a working Plasma session.
|
|
||||||
|
|
||||||
## Trade-offs
|
|
||||||
|
|
||||||
- Autologin on the terminal console means physical access grants a shell
|
|
||||||
without a password. Acceptable for a personal laptop the user controls; the
|
|
||||||
desktop (default) boot is unaffected.
|
|
||||||
- `desktop` relies on `sudo`; the user has sudo access, so no extra config is
|
|
||||||
required.
|
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
./disks.nix
|
./disks.nix
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
./environments.nix
|
./environments.nix
|
||||||
|
./network.nix
|
||||||
# ./system.nix use docker here
|
# ./system.nix use docker here
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
useOSProber = true;
|
useOSProber = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
# Configure keymap in X11
|
# Configure keymap in X11
|
||||||
services.xserver.xkb = {
|
services.xserver.xkb = {
|
||||||
layout = "de";
|
layout = "de";
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
services.printing.enable = true;
|
services.printing.enable = true;
|
||||||
nixpkgs.config.allowUnfree = true;
|
nixpkgs.config.allowUnfree = true;
|
||||||
|
|
||||||
|
|
||||||
hardware.nvidia.prime = {
|
hardware.nvidia.prime = {
|
||||||
sync.enable = false;
|
sync.enable = false;
|
||||||
|
|
||||||
@@ -42,37 +45,6 @@
|
|||||||
|
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
# Don't let boot stall waiting for a network that may never come up
|
|
||||||
# (WiFi credentials live in KWallet and need a desktop session), which
|
|
||||||
# otherwise hangs the terminal boot before the login prompt appears.
|
|
||||||
systemd.services.NetworkManager-wait-online.enable = false;
|
|
||||||
|
|
||||||
# Boot-time choice: the default GRUB entry boots straight into KDE.
|
|
||||||
# A separate "terminal" entry (a NixOS specialisation) boots to a text
|
|
||||||
# console with autologin, where you can work or run `desktop` to bring
|
|
||||||
# KDE up. Pick the entry you want in the GRUB menu at boot.
|
|
||||||
#
|
|
||||||
# NOTE: in terminal mode WiFi will not connect on its own (the password
|
|
||||||
# is stored per-user in KWallet). To reach the machine over SSH from
|
|
||||||
# terminal mode, first save the WiFi as a system connection in KDE:
|
|
||||||
# network settings -> your WiFi -> "All users may connect to this network".
|
|
||||||
specialisation.terminal.configuration = {
|
|
||||||
system.nixos.tags = [ "terminal" ];
|
|
||||||
|
|
||||||
# Boot to a text console. graphical.target is what pulls in the display
|
|
||||||
# manager (via its embedded Wants=display-manager.service), so defaulting
|
|
||||||
# to multi-user.target leaves SDDM installed but not started at boot.
|
|
||||||
systemd.defaultUnit = lib.mkForce "multi-user.target";
|
|
||||||
|
|
||||||
# Guarantee a usable shell on the console (no login prompt to hunt for).
|
|
||||||
services.getty.autologinUser = "finn";
|
|
||||||
|
|
||||||
# Bring the desktop up on demand from the terminal.
|
|
||||||
environment.systemPackages = [
|
|
||||||
(pkgs.writeShellScriptBin "desktop" "exec sudo systemctl start display-manager.service")
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# KDE (PowerDevil) power settings: do nothing on lid close while on AC power.
|
# KDE (PowerDevil) power settings: do nothing on lid close while on AC power.
|
||||||
# Shipped as a system-wide default; KConfig cascades so a user's own
|
# Shipped as a system-wide default; KConfig cascades so a user's own
|
||||||
# ~/.config/powerdevilrc will override this if present.
|
# ~/.config/powerdevilrc will override this if present.
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
_: {
|
||||||
|
# Athena (local AI): allow LAN access to the Hermes web dashboard.
|
||||||
|
# Bound to 0.0.0.0:9119 in the athena docker stack; NixOS default-deny
|
||||||
|
# firewall otherwise blocks inbound connections from other devices.
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
9119 # athena hermes dashboard
|
||||||
|
];
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user