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
- Confirm the VM's system disk is
/dev/vda. If it is not, update both references indisk-config.nix. - Confirm the SSH public key in
default.nixis the key that should have administrator access. - 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.