Files
dotfiles/systems/portal-1/README.md
T
2026-08-26 07:33:31 -04:00

2.7 KiB

portal_1

Minimal NixOS target for a Vultr VM, installed with nixos-anywhere. The Nix flake target is portal_1; the machine hostname is portal-1 because DNS hostnames cannot contain underscores.

Before deploying

  1. Confirm the VM's system disk is /dev/vda. If it is not, update both references in disk-config.nix.
  2. Confirm the SSH public key in default.nix is the key that should have administrator access.
  3. Boot the VM into a NixOS installer or another nixos-anywhere-compatible Linux rescue environment with root SSH access. Keep this environment running while completing the SOPS bootstrap below.

Bootstrap SOPS

Use the rescue environment's SSH host key as the permanent portal identity. Replace VM_IP below:

ssh root@VM_IP 'cat /etc/ssh/ssh_host_ed25519_key.pub' | \
  nix shell nixpkgs#ssh-to-age --command ssh-to-age

This prints an age1... recipient; it does not copy the private key. Add the recipient to .sops.yaml:

- &system_portal_1 age1...

Then add *system_portal_1 to the age recipients for users/secrets.yaml. Re-encrypt the existing file for the new recipient and add the Tailscale key:

nix shell nixpkgs#sops --command sops updatekeys users/secrets.yaml
nix shell nixpkgs#sops --command sops users/secrets.yaml

Add the OAuth client secret from the Auth Keys: Write credential in the SOPS editor and save it:

tailscale_auth_key: tskey-client-...

Deploy

From the repository root, replace VM_IP with the VM's public IP:

nix run github:nix-community/nixos-anywhere -- \
  --copy-host-keys --flake .#portal_1 root@VM_IP

This repartitions /dev/vda, so anything already on that disk is erased. The layout reserves 8 GiB for swap and assigns the remaining space to the root filesystem.

--copy-host-keys preserves the same private SSH host key at /etc/ssh/ssh_host_ed25519_key on the installed system. SOPS-Nix converts that key to an age identity during activation. After the reboot, connect as richie and verify that automatic Tailscale enrollment succeeded:

ssh -p 278 richie@VM_IP
sudo tailscale status

The installed OpenSSH service listens on port 278. Port 22 is served by Endlessh and will not provide an SSH login.

HAProxy uses the same frontend, routing, and rate-limiting configuration as Jeeves. Portal manages the ACME certificates for the existing public domains; their DNS records must resolve to Portal for HTTP-01 issuance and renewal.

The application backends still use Jeeves' original 127.0.0.1 addresses. Replace them with the corresponding Tailscale addresses before directing application traffic through Portal. Ports 80 and 443 are allowed through the firewall.