Skip to main content

max / mountaineer

11.6 KB · 275 lines History Blame Raw
1 # Mountaineer Profiles
2
3 This document is the concrete manifest of what each Mountaineer build contains. `MANIFESTO.md` states the principles, `STACK.md` defends each pick. This file is the inventory.
4
5 There are two builds, with a strict subset relationship per principle 13:
6
7 - **Mountaineer Server** — the foundational system. Headless, service-oriented, everything an operator needs on a VPS, a homelab box, or any machine that does not need a graphical layer.
8 - **Mountaineer Sysadmin** — Server plus the Wayland graphical layer and laptop integration. The build a sysadmin installs on the workstation they use every day.
9
10 **Sysadmin = Server ∪ Graphical.** No package in Server is omitted from or replaced in Sysadmin. A Sysadmin install on a server is a Server install with idle graphical packages; a Server install on a workstation is a perfectly functional headless system. This is the constraint that keeps the two builds one mental model.
11
12 Roles within a profile — `bastion`, `homelab`, `dev-workstation`, etc. — are planned for a later iteration (see the final section) and layer additional package sets and config on top of a chosen profile. They are not separate profiles.
13
14 ---
15
16 ## Mountaineer Server
17
18 The full set of packages and configuration overlays Server adds on top of a minimal Alpine installation.
19
20 ### Packages
21
22 Grouped by role for readability. Versions follow Alpine's `linux-lts` release; any package not in Alpine's repositories is not in Mountaineer.
23
24 **Foundation**
25
26 - `alpine-base`, `alpine-conf` (Alpine baseline)
27 - `apk-tools` (package manager — already present)
28 - `busybox`, `busybox-suid` (already present; `/bin/sh` stays ash)
29 - `openssh-server`, `openssh-client`
30 - `chrony`
31 - `unbound`
32
33 **Init and supervision**
34
35 - `s6`, `s6-rc`, `s6-linux-init`, `execline`
36 - `mountaineer-s6-services` (Mountaineer-authored: the canonical s6-rc service definitions for every shipped daemon)
37
38 **Interactive userland (defaults, not aliases)**
39
40 - `nushell`
41 - `helix`
42 - `zellij`
43 - `starship`
44 - `ripgrep`, `fd`, `sd`, `bat`, `eza`, `dust`, `procs`, `bottom`, `zoxide`, `lnav`
45
46 **Containers**
47
48 - `podman`, `buildah`, `crun`
49 - `mountaineer-podman-s6` (Mountaineer-authored: s6-rc templates for supervised containers — the quadlet analog)
50
51 **Filesystem**
52
53 - `zfs`, `zfs-lts`, `zfs-scripts`
54 - `zfsbootmenu`
55
56 **Networking**
57
58 - `ifupdown-ng`, `ifupdown-ng-wireguard` (plugin for wireguard interfaces)
59 - `dhcpcd`
60 - `nftables`
61
62 **Web ingress and TLS**
63
64 - `caddy`
65
66 **Secrets and backup**
67
68 - `age`
69 - `sops`
70 - `restic`
71
72 **Mail (send-only)**
73
74 - `msmtp`, `msmtp-mta` (provides `/usr/sbin/sendmail`)
75
76 **Log routing**
77
78 - `vector`
79
80 **Mountaineer tools**
81
82 - `mountaineer-sysop` (the `sysop` CLI itself — ratatui frontends, swap-friendly backends, role-based vocabulary)
83 - `mountaineer-base-config` (the configuration overlay — see next section)
84 - `mountaineer-manifest` (ships `/etc/mountaineer/manifest.toml`)
85
86 ### Configuration overlay
87
88 Mountaineer ships defaults in these files. Each one is heavily commented; reading the file teaches what it does (principle 2). Operators edit these files directly; nothing wraps them.
89
90 ```
91 /etc/mountaineer/
92 manifest.toml # role → package mapping, source of truth for `sysop info`
93 profile # "server" or "sysadmin"
94
95 /etc/ssh/sshd_config # hardened: no password auth, no root, modern KEX/cipher/MAC
96 /etc/chrony/chrony.conf # iburst, public NTP pool, documented swap pattern
97 /etc/unbound/unbound.conf # local recursive resolver, DoT upstream, DNSSEC
98 /etc/caddy/Caddyfile # commented example: reverse proxy, static, podman backend
99 /etc/nftables.d/ # default-deny, ICMP/ICMPv6 filtering, SSH rate-limited
100 /etc/vector/vector.toml # routes container + system logs to /var/log/{containers,system}
101 /etc/msmtprc # configured-but-failing default (operator must point at SMTP)
102 /etc/network/interfaces.d/ # example stanzas for static, dhcp, bridge, wireguard
103 /etc/restic/ # stub repository config; commented scheduled-job example
104
105 /etc/s6/ # s6-rc compiled service database
106 /etc/s6-rc.d/ # Mountaineer-canonical service definitions (source)
107
108 /etc/nushell/ # global nushell environment + default aliases
109 /etc/profile.d/ # interactive shell setup (PATH, zoxide init, starship init)
110 /etc/helix/ # global helix config (themes, LSP defaults)
111
112 /etc/zfs/
113 zpool.cache # generated at install
114 mountaineer-arc.conf # tuned zfs_arc_max default (sized at install)
115 ```
116
117 ### Default services (running on a fresh Server install)
118
119 Supervised by s6-rc:
120
121 - `sshd`
122 - `chronyd`
123 - `unbound`
124 - `nftables-load` (one-shot at boot, loads ruleset)
125 - `caddy` (off by default; enable via `sysop service enable caddy` once Caddyfile is configured)
126 - `vector`
127
128 Not running by default; available to enable:
129
130 - `podman` (lazy — no daemon, but `sysop podman-s6` templates supervise individual containers as needed)
131 - `restic-backup` (one-shot scheduled; off until `/etc/restic/` is configured)
132
133 ### Explicitly not in Server
134
135 - No graphical anything (no Wayland, no X, no compositor, no fonts beyond terminal essentials)
136 - No web browser
137 - No NetworkManager, no systemd-anything, no Docker, no OpenRC
138 - No full MTA (msmtp is send-only)
139 - No bash as interactive shell (`apk add bash` if you insist)
140
141 ---
142
143 ## Mountaineer Sysadmin
144
145 Sysadmin = Server + the additions below. Everything in the Server section above applies; this section is purely the delta.
146
147 ### Additional packages
148
149 **Wayland and compositor**
150
151 - `river`
152 - `wlroots` (pulled in by river)
153 - `xdg-desktop-portal`, `xdg-desktop-portal-wlr` (for application portals — screen share, file picker)
154
155 **Graphical userland**
156
157 - `foot` (terminal)
158 - `yambar` (status bar)
159 - `fuzzel` (launcher)
160 - `cliphist` (clipboard history)
161 - `fnott` (notifications)
162 - `grim`, `slurp`, `swappy` (screenshots and annotation)
163 - `swaylock`, `swayidle`, `swaybg` (lock, idle, background)
164 - `wl-clipboard` (clipboard CLI integration)
165
166 **Audio**
167
168 - `pipewire`, `pipewire-pulse`, `pipewire-jack`
169 - `wireplumber`
170
171 **Wireless and laptop integration**
172
173 - `iwd`
174 - `seatd`
175 - `brightnessctl`
176 - `tlp`, `tlp-rdw`
177
178 **Browser fallback**
179
180 - `w3m` (emergency text browser only; first-boot install flow prompts for a real browser)
181
182 **Fonts**
183
184 - `font-jetbrains-mono-nerd` (terminal, editor)
185 - `font-inter` (UI text)
186 - `font-noto`, `font-noto-emoji` (broad Unicode coverage)
187
188 ### Additional configuration overlay
189
190 ```
191 /etc/mountaineer/
192 profile # "sysadmin"
193
194 ~/.config/river/init # shipped default; tiling layout, keybinds documented inline
195 ~/.config/foot/foot.ini # font, colors, scrollback
196 ~/.config/yambar/config.yml # the ~30-line default status bar
197 ~/.config/fuzzel/fuzzel.ini # launcher styling
198 ~/.config/fnott/fnott.ini # notification styling
199 ~/.config/swaylock/config # lock screen styling
200 ~/.config/swayidle/config # dim, lock, suspend timeouts
201
202 /etc/iwd/main.conf # iwd defaults
203 /etc/seatd.conf
204 /etc/tlp.conf # battery-favoring tuned defaults
205 ```
206
207 Per-user configs ship as `/etc/skel/.config/...` and are copied into new users' home directories at account creation.
208
209 ### Additional services (Sysadmin-only)
210
211 Supervised by s6-rc (system) or river's session manager (user):
212
213 - `seatd`
214 - `iwd`
215 - `pipewire`, `wireplumber` (user session)
216 - `tlp`
217
218 ### First-boot Sysadmin flow
219
220 On first login to a Sysadmin install, the Mountaineer setup script:
221
222 1. Prompts for hostname, user account, SSH key import (if any).
223 2. Asks if the user wants to import a wifi profile (or defers to `sysop wifi` later).
224 3. Presents the `apk` browser packages and runs `apk add` on the user's choice (or "skip — use w3m for now").
225 4. Drops the user into a river session with the default layout.
226
227 Subsequent runs of any of these steps are available as `sysop` subcommands.
228
229 ### Explicitly not in Sysadmin
230
231 Sysadmin adds exactly the packages above and nothing else. Anything not in this delta is either in Server (and therefore in Sysadmin) or not in Mountaineer at all.
232
233 In particular, Sysadmin does **not** add:
234
235 - A display manager. River is launched from a TTY login via a small shell script (`/usr/local/bin/start-river`) — no greetd, no SDDM, no gdm. The login prompt is the kernel's, the way it has always been.
236 - A file manager. The terminal is the file manager. `yazi` (or `ranger`, or any other TUI file manager) is one `apk add` away for operators who want one.
237 - A mail client. `aerc` is the natural Mountaineer-flavored pick if we ship one in a later iteration; for now, operators install what they want.
238 - An office suite, a media player, a chat client, a calendar, or any of the consumer-desktop expectations. Sysadmin is not a consumer desktop (manifesto: "What this isn't").
239
240 ---
241
242 ## Roles (planned, v0.2+)
243
244 Roles are *additive overlays* on top of a chosen profile. They are not separate profiles, do not break the subset relationship, and exist to bundle common operator setups so a fresh Mountaineer machine can become "the bastion" or "the homelab box" with one command.
245
246 Each role is a small `sysop` subcommand that installs a specific package set and drops in a specific configuration overlay. The mechanism is identical to a manual `apk add ... ; cp config files` sequence — the role just curates the list.
247
248 Planned roles (none of these are built yet; this list anchors the design conversation):
249
250 - **`bastion`** — hardened SSH jump host. Tightens sshd, installs fail2ban-equivalent (probably `sshguard`), configures audit logging, enables port-knocking via nftables sets. Implies Server.
251 - **`homelab`** — single-machine self-hosted services host. Adds caddy as default-on, ships an example Caddyfile for `*.home.arpa` routing, pre-seeds a podman-s6 setup for common containers (gitea, nextcloud, etc., user picks at role-init time).
252 - **`dev-workstation`** — Sysadmin plus language toolchains for the operator's stated languages and development tooling (`git`, `gh`, `direnv`, `mise` or equivalent). The `docker → podman` shell alias is already shipped system-wide; the role does not redo it. Implies Sysadmin.
253 - **`vps`** — Server with a focus on minimal install size, default-deny aggressively tuned for an internet-exposed machine, wireguard pre-configured for inbound from a known endpoint. Implies Server.
254 - **`relay-mail`** — Server with msmtp replaced by OpenSMTPD configured as an outbound relay (the documented upgrade from msmtp). Implies Server.
255
256 The role mechanism deliberately mirrors the profile mechanism: additive, documented, no parallel forks, swappable underlying tools per principle 14. A role that adds Caddy and one that adds OpenSMTPD compose; a role that *replaces* an init system does not exist and never will.
257
258 ---
259
260 ## How profiles are built
261
262 (Implementation notes — separable from the inventory above.)
263
264 Both profiles ship as `apkovl` overlays applied to Alpine's minimal install image, plus an ISO variant that runs the Mountaineer installer as its only first-boot action. The installer handles:
265
266 1. Disk partitioning and zpool creation (canonical dataset layout).
267 2. Base Alpine bootstrap via `apk add --root /mnt`.
268 3. Mountaineer package set install (Server set always; Sysadmin set additionally if the install was started from the Sysadmin ISO).
269 4. Configuration overlay deployment.
270 5. s6-rc service database compilation and enablement.
271 6. zfsbootmenu installation and the initial snapshot creation.
272 7. First user account creation and the first-boot flow (Sysadmin only).
273
274 The package sets are maintained as plain text files in the Mountaineer repository — `profiles/server.world`, `profiles/sysadmin.world` — and the strict-subset invariant is checked in CI: every package in `server.world` must appear in `sysadmin.world`, and CI fails otherwise. The invariant is enforced mechanically, not by discipline.
275