1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
---
title: "Launching SSH during early boot with mkinitfs"
blurb: "Replacing the early init with our own script to launch SSH, killing it in early userspace, and allowing remote disk decryption in the mean time"
author: "7222e800"
slug: "alpine-ssh-early-initfs-disk-decryption"
id: 1768406136
# Timestamps are in ISO8601 UTC (`date -u +%Y-%m-%dT%H:%M:%SZ`)
created: "2026-01-14T15:53:57Z"
updated: "2026-01-14T15:53:57Z"
published: false
---
<blockquote class="default-blockquote blockquote-red-400">
**Warning**<br/>
This post talks about operations that may lead the reader's system
unbootable, including modifying it's initramfs.
Do not follow along if the reader is not prepared to fix it's own
systems from potentially infuriating bugs.
<p><small class="text-sm opacity-50 hover:opacity-70 transition-opacity">Maybe avoid following along on the friday
before the reader's vacation.</small></p>
</blockquote>
For a while, this one's been meaning to setup an early-boot SSH environment for
Alpine Linux on systems that are using a
[System Disk](https://wiki.alpinelinux.org/wiki/System_Disk_Mode) installation
mode.
<!-- TODO: APKOVL boot article -->
In [Data Disk](https://wiki.alpinelinux.org/wiki/Data_Disk_Mode) mode, it can
be handled in `boot` or `sysinit`. This can even be nicely netbooted via a
netbooted apkovl - article on that eventually. (for now, if you're interested
in that, here's a good starting point:
[alpine/mkinitfs#cc4954b/initramfs-init.in](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/initramfs-init.in#L647))
On System Disk installations, with tooling like [dracut](https://wiki.gentoo.org/wiki/Dracut),
this would also be trivial. Unfortunately, this one's a masochist and like
staying close to the intended upstream Alpine installation
> **Note**<br/>
> Alpine does have
> [a package](https://pkgs.alpinelinux.org/package/v3.23/community/x86_64/dracut)
> for dracut, and the reader may want to look into using it instead.
## mkinitfs and it's challenges
Alpine's [mkinitfs](https://gitlab.alpinelinux.org/alpine/mkinitfs/) allows us
to do things like including files or kernel modules in the image, via their
[features.d](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/tree/master/features.d).
This is nice and all, but on it's own, we can only really give the kernel a
module, or a file we manually call by spamming enter through the encryption
password prompts and running via the 'Emergency Shell'.
### approach 1: patching
The easiest solution this one thought of was to just directly modify
`/usr/share/mkinitfs/initramfs-init` and be happy, then deal with it when
upstream modifies things.
This is, however, very not "set, make a blog post, and forget". So we skipped
that idea.
### approach 2: fork the upstream
The second, and nicest to upstream solution it thought of was modify
[initramfs-init.in](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/initramfs-init.in)
- which gets built into `/init` in the initfs.
This would've worked very well, but would require maintaining one's own
`/init`, for which the distro provides few guarantees that the rest of the
tooling will forever accomodate an old version forked off.
#### upstreaming
It also thought about upstreaming this, for which this would've been the only
viable approach. However, with this, comes the challenge of cleaning up the
sshd during early openrc, cleanly, without any use-case edge-cases.
> **For Alpine Maintainers**<br/>
> If beings involved in the mkinitfs project want something like this, this
> one's willing to, with some guidance on avoiding user edge-cases, contribute
> this.
### approach 3: third approach's the charm
The third approach was wrapping
[nlplug-findfs](https://gitlab.alpinelinux.org/alpine/mkinitfs/-/blob/cc4954bc73cf55833b48624232b9c42ca3abc390/nlplug-findfs.1.in),
replacing the system-wide binary, regenerating the initramfs, and then spawning
SSH from there and directly interacting via libssh.
Whilst this would be sensible in theory, this has a high maintenance burden if
nlplug-findfs is modified substantially (or, worse, entirely removed). This is
heavily in no guarantees provided land.
So this one opted against it.
### approach 4: a kernel module
A kernel module could start a userspace process early, which would not involve
touching any of the existing tooling's code (and just needs one file added).
But also, no.
## starting ssh before `initramfs-init.in`
> "it's like LogoFAIL for your initfs" - somebeing, probably
|