halkyon/deploy/host/README.md

133 lines
6.2 KiB
Markdown
Raw Normal View History

# The instance's host at home
halkyon.li runs at home on balthasar (ADR 0039) and is published through ramiel
(`../forward/README.md`). This folder holds what the host needs beyond Docker: SSH for
melchior, the root disk unlocked over SSH at boot, Docker's data on the HDD, and home's
end of the tunnel.
| File | On the host | What for |
|---|---|---|
| `sshd-halkyon.conf` | `/etc/ssh/sshd_config.d/10-halkyon.conf` | keys alone, two users (D17) |
| `dropbear.conf` | `/etc/dropbear/initramfs/dropbear.conf` | the passphrase over SSH at boot (D20) |
| `initramfs-modules` | appended to `/etc/initramfs-tools/modules` | the USB network adapter at boot (D20) |
| `fstab-docker` | appended to `/etc/fstab` | Docker's and containerd's data on the HDD (D12) |
| `docker-after-data.conf` | `docker.service.d/` and `containerd.service.d/` | both wait for it (D12) |
| `wg-halkyon.conf` | `/etc/wireguard/wg-halkyon.conf` | home's end of the tunnel (D8) |
| `wg-halkyon.nft` | `/etc/wireguard/wg-halkyon.nft` | what the tunnel may carry (D9, D17) |
| `wg-quick-before-docker.conf` | `wg-quick@wg-halkyon.service.d/` | the tunnel before Docker (D12) |
`test/deploy/halkyon_li_forward_test.dart` holds these files to ADR 0039's rules.
## Steps
As the developer at the iMac (`sudo`), from this checkout (`~/project-halkyon/halkyon`),
in this order: each step leaves the machine working, and the early ones keep a way in
for the later.
1. **sshd for melchior** (D17). On balthasar, then from melchior, then on balthasar:
```sh
sudo apt install openssh-server
```
```sh
ssh-copy-id raisondetredev@192.168.178.53 # on melchior, with balthasar's password
```
```sh
sudo install -m 644 deploy/host/sshd-halkyon.conf /etc/ssh/sshd_config.d/10-halkyon.conf
sudo sshd -t && sudo systemctl reload ssh
```
Then, before closing anything, from melchior: `ssh raisondetredev@192.168.178.53`
must still get in, and `ssh -o PubkeyAuthentication=no raisondetredev@192.168.178.53`
must be refused. In the FRITZ!Box, give balthasar always the same address
(*Heimnetz › Netzwerk › balthasar › Diesem Netzwerkgerät immer die gleiche
IPv4-Adresse zuweisen*), so that 192.168.178.53 stays its address.
2. **The passphrase over SSH at boot** (D20):
```sh
sudo apt install dropbear-initramfs
sudo install -m 644 deploy/host/dropbear.conf /etc/dropbear/initramfs/dropbear.conf
# melchior's public key alone (from ~/.ssh/authorized_keys, step 1), restricted:
printf 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding,command="/usr/bin/cryptroot-unlock" %s\n' \
"$(cat ~/.ssh/authorized_keys)" | sudo tee /etc/dropbear/initramfs/authorized_keys
grep -v '^#' deploy/host/initramfs-modules | sudo tee -a /etc/initramfs-tools/modules
echo 'IP=::::balthasar:enx0050b6bffcff:dhcp' | sudo tee -a /etc/initramfs-tools/initramfs.conf
sudo update-initramfs -u
```
At the next boot, at home: `ssh -p 2222 root@192.168.178.53` from melchior asks for the
root disk's passphrase, and the boot goes on. The keyboard at the iMac still works as
before, so a mistake here costs no more than the walk to it.
3. **No desktop** (D12): it stops starting at boot, and Docker Desktop, which runs a VM of
its own beside Docker, goes. Multipass only if it isn't used:
```sh
sudo systemctl set-default multi-user.target # back: graphical.target
sudo apt remove docker-desktop
sudo snap disable multipass
```
4. **Docker's data on the HDD** (D12). Everything Docker holds now (the home Jellyfin's
images and containers) moves with it. ADR 0032's home Jellyfin stops here for good;
its configuration and library stay where they are and move into the instance later
(`../sidecars/README.md`, *Jellyfin on halkyon.li*):
```sh
sudo docker compose -p home-jellyfin down
sudo systemctl stop docker docker.socket containerd
sudo mkdir -p /data/docker /data/containerd
sudo rsync -aHAX --numeric-ids /var/lib/docker/ /data/docker/
sudo rsync -aHAX --numeric-ids /var/lib/containerd/ /data/containerd/
sudo mv /var/lib/docker /var/lib/docker.old
sudo mv /var/lib/containerd /var/lib/containerd.old
sudo mkdir /var/lib/docker /var/lib/containerd
grep -v '^#' deploy/host/fstab-docker | sudo tee -a /etc/fstab
for unit in docker containerd; do
sudo install -D -m 644 deploy/host/docker-after-data.conf \
/etc/systemd/system/$unit.service.d/after-data.conf
done
sudo systemctl daemon-reload
sudo mount /var/lib/docker && sudo mount /var/lib/containerd
sudo systemctl start containerd docker
sudo docker images # as before
```
Once Docker runs as before: `sudo rm -rf /var/lib/docker.old /var/lib/containerd.old`.
5. **Home's end of the tunnel** (D8, D9, D12). Home's key, made here and never leaving
but into Proton Pass (vault *Infra*, an item *balthasar wg-halkyon*):
```sh
sudo apt install wireguard-tools
sudo install -d -m 700 /etc/wireguard
sudo sh -c 'umask 077; wg genkey > /etc/wireguard/wg-halkyon.key'
sudo cat /etc/wireguard/wg-halkyon.key # into Proton Pass
sudo wg pubkey < /etc/wireguard/wg-halkyon.key # home's public key: ramiel's config
```
Then the files, with ramiel's public key (`../forward/README.md`, step 3) in place of
`<ramiel's public key>`:
```sh
sudo install -m 600 deploy/host/wg-halkyon.conf deploy/host/wg-halkyon.nft /etc/wireguard/
sudoedit /etc/wireguard/wg-halkyon.conf
sudo nft -c -f /etc/wireguard/wg-halkyon.nft # checks the rules, loads nothing
sudo install -D -m 644 deploy/host/wg-quick-before-docker.conf \
/etc/systemd/system/wg-quick@wg-halkyon.service.d/before-docker.conf
sudo systemctl daemon-reload
sudo systemctl enable --now wg-quick@wg-halkyon
sudo wg show wg-halkyon # a handshake once ramiel is up too
ping -c 1 10.61.97.1 # refused by home's own rules: nothing new goes to ramiel
```
From melchior, away from home: `ssh -J ramiel raisondetredev@10.61.97.2`.
6. **Reboot**, at home, to see each step hold: the passphrase over SSH (step 2), no
desktop (step 3), Docker on the HDD (step 4), the tunnel up before Docker (step 5).
The instance itself follows (its users, checkout, `.env` and first deploy), once its
compose files for Meditate and Jellyfin are built.