Adding a public node
This guide walks through adding a VM/VPS/root server/Droplet with a static IP from your Mac: create the VM, prepare SSH, fill the environment inventory, and open firewall rules.
The example uses the dev environment (yours might be prod, staging, or another name) and host name static-1.
Where you see ENV=<env>, replace with your environment name (for example prod).
Before you start
Section titled “Before you start”Know which environment and inventory file you are completing, and have an external Postgres instance ready for that environment (configured in the vault before the first deploy).
You must be arriving here from Get started locally or Deploy to production.
Read project from inventories/<env>/hosts.yml → all.vars.project (currently example). In examples below, <project> is that value and <env> is the environment name you pass as ENV= (for example dev, prod).
Our objective is to complete inventories/<env>/hosts.yml — for dev, that is inventories/dev/hosts.yml:
all: vars: project: example hostname: example.com
nodes: hosts: static-1: public_ip: "xxx.xxx.xxx.xxx" ssh_ed25519_sha256: "SHA256:0f37...2ed230" private_address: 10.217.80.11all: vars: project: <project> hostname: <your-prefix>.<project>.com
nodes: hosts: static-1: public_ip: "REPLACE_WITH_STATIC_1_PUBLIC_IPV4" ssh_ed25519_sha256: "SHA256:REPLACE_WITH_COMPLETE_FINGERPRINT_STATIC_1" private_address: 10.217.80.11For a Lima guest or a home-lab roaming node, see the other start-here and roaming guides — this page is public static nodes only.
Step 1: Operator SSH key
Section titled “Step 1: Operator SSH key”Create the Ed25519 key Ansible will use from your Mac.
On your Mac, create an Ed25519 key with an empty passphrase. Store both files in your password manager.
ssh-keygen -t ed25519 -a 100 \ -f ~/.ssh/example-dev \ -C "example dev"
ssh-add ~/.ssh/example-devpbcopy < ~/.ssh/example-dev.pubssh-keygen -t ed25519 -a 100 \ -f ~/.ssh/<project>-<env> \ -C "<project> <env>"
ssh-add ~/.ssh/<project>-<env>pbcopy < ~/.ssh/<project>-<env>.pubInventory will reference this key as ~/.ssh/example-dev via ssh_private_key_file in group vars.
Important: We will need the public key from Step 1 in Step 3.
Step 2: Create the VM
Section titled “Step 2: Create the VM”Provision an Ubuntu amd64 VM with a public IPv4 address.
In your cloud provider console:
- Create a Ubuntu Server 26.04 amd64 (
x86_64) on your favourite cloud provider. arm64 may/may not work, but we have not tested it. - Attach a public IPv4 (or a stable DNS name you will put in
hosts.yml). - Do not rely on this automation to create the server or provider firewall rules—you configure those yourself.
Note the public IP (example format xxx.xxx.xxx.xxx).
Step 3: Prepare the node (console or provider SSH)
Section titled “Step 3: Prepare the node (console or provider SSH)”Create the ops user, install your public key, and grant passwordless sudo.
On the new VM, create the inventory SSH user (example ops), install the Mac public key, and grant passwordless sudo:
sudo adduser --disabled-password --gecos '' opssudo install -d -o ops -g ops -m 0700 /home/ops/.sshsudo tee /home/ops/.ssh/authorized_keys >/dev/nullPaste the public key from the clipboard (from Step 1), press
sudo chown ops:ops /home/ops/.ssh/authorized_keyssudo chmod 600 /home/ops/.ssh/authorized_keysprintf '%s\n' 'ops ALL=(ALL) NOPASSWD:ALL' | \ sudo tee /etc/sudoers.d/90-sc-ops >/dev/nullsudo chmod 440 /etc/sudoers.d/90-sc-opssudo visudo -cf /etc/sudoers.d/90-sc-opssudo -u ops sudo -n truevisudo -cf should report parsed OK.
Step 4: Verify the operator key
Section titled “Step 4: Verify the operator key”Confirm the authorized key on the VM matches your Mac key.
On your Mac:
ssh-keygen -lf ~/.ssh/example-dev.pubOn the new VM:
sudo ssh-keygen -lf /home/ops/.ssh/authorized_keysThe SHA256:… lines must match.
Step 5: Record the VM/server fingerprint
Section titled “Step 5: Record the VM/server fingerprint”Copy the VM host-key fingerprint for inventory pinning.
On the VM:
sudo ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
# Sample output: 256 SHA256:pRR2cezc6UOTGq+vTrVwPFCFKlHRKuuV/OL/9/c3e+M root@whatever-server (ED25519)Copy the full SHA256:pRR...e+M value into your password manager. You will paste it into hosts.yml as ssh_ed25519_sha256 (this is the VM/server’s fingerprint).
Step 6: Fill the environment inventory
Section titled “Step 6: Fill the environment inventory”Add the node’s public IP and fingerprint to your hosts inventory.
Edit inventories/<env>/hosts.yml. Under nodes.hosts, set static-1 (or add a new static-2, …):
static-1: public_ip: "159.203.27.69" ssh_ed25519_sha256: "SHA256:pRR...e+M" private_address: 10.217.80.11static-1: public_ip: "REPLACE_WITH_STATIC_1_PUBLIC_IPV4" ssh_ed25519_sha256: "SHA256:REPLACE_WITH_COMPLETE_FINGERPRINT_STATIC_1" private_address: 10.217.80.11To add another public node, duplicate the block as static-2, assign the next mesh IP (e.g. .12), add an A record for ns.<hostname> pointing at that node’s public IPv4, and run task up ENV=<env> again. If the DNS is hosted on Cloudflare, do not enable the proxy orange icons.
Step 7: Cloud provider firewall
Section titled “Step 7: Cloud provider firewall”Open TCP 22 for bootstrap and UDP 51830 if roaming peers will dial in later.
On the cloud provider (or host) firewall for this VM:
| Phase | Rule |
|---|---|
| Before setup | Allow inbound TCP 22 from your Mac’s current public /32 |
| After setup | Allow inbound UDP 51830 from peers that will dial this hub (if roaming nodes are added later, open UDP 51830 broadly—not only the Mac /32) |
| After setup | Allow inbound TCP 80 and TCP 443 |
Your Mac does not need further configuration for this step.
Step 8: Prove bootstrap SSH
Section titled “Step 8: Prove bootstrap SSH”Confirm direct SSH from your Mac works before continuing.
From the Mac, enter the following command with the path to the private key you created in Step 1 and the public IP of the VM:
It will ask for “Are you sure you want to continue connecting (yes/no)?” — type yes and press
If this fails, fix user, keys, or firewall before continuing.
Next steps
Section titled “Next steps”Go back to Get started locally or Deploy to production from where you started this guide.
To add a home-lab roaming node later, see Adding a roaming node.