deviant/Parameters/SSHkeyServer
Local Dev ced2eda48d @
chore: checkpoint in-flight work across domains

Sweep of accumulated uncommitted work on design/dex-p2p-architecture into
one checkpoint (multiple sessions share this tree). Main areas:

- anthemus: covenant-wiring follow-ups (engine, ExchangePanel), AgoraScreen seam
- spv: ServerPool + p2p header transport (pool.ts, core/spv/*), wallet.ts wiring
- walletconnect: responder/useConnect updates + connect-responder-compat test
- wallet: send-tier-a rework + swap.ts, plus send-tier-a unit tests
- asm: chipnet throughput/stress harness (scripts/chipnet-asm-*) + ASM_Native docs
- app UI: screens/* and shell.css touch-ups; sat -> bits copy migration
- docs: new snapshots (INDEX regenerated), Parameters (WalletConnect/SSH/ASM),
  KnowledgeBase, WALLET-COORDINATION changelog

Checkpoint only; not a release. Secrets (Keys/, .chipnet-keys*, .env) remain
gitignored and were verified absent from the staged set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@
2026-08-14 02:00:43 +02:00
..
README.md style(docs): migrate sat/sats → bit/bits across wiki + Parameters 2026-08-09 01:09:06 +02:00
silentmode-navigate.md @ 2026-08-14 02:00:43 +02:00

SSH key access to a new server — runbook

Copy-paste procedure for getting passwordless SSH onto a fresh VPS from a Windows/PowerShell workstation. Written from the commands that actually worked (CoinSpectrum server bootstrap, Ubuntu 24.04) — including the traps that turned a 2-minute job into a 20-minute one. Read §4 before improvising.

Convention in this project: one key per server / project, not one global key — so a key can be revoked without breaking every other deployment. Existing: p2pexchange_ed25519, checkers_deploy, coinspectrum_ed25519.


1. TL;DR — the whole thing, 3 commands

Replace <name> (e.g. coinspectrum) and <ip>.

# 1. generate a passphrase-less key   ← note -N '' (see §4.1, this is the #1 trap)
ssh-keygen -t ed25519 -f "$env:USERPROFILE\.ssh\<name>_ed25519" -C "<name>-deploy" -N ''

# 2. print the PUBLIC key (safe to show/paste anywhere)
Get-Content "$env:USERPROFILE\.ssh\<name>_ed25519.pub"

# 3. install it on the server — paste the key inline, DO NOT pipe (see §4.2)
#    prompts for the root password once; must be run in YOUR OWN terminal
ssh root@<ip> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '<PASTE-PUBLIC-KEY-LINE>' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && echo KEY_ADDED"

Expect KEY_ADDED. Then verify (§3). Done.


2. Step by step

2.1 Generate the key

ssh-keygen -t ed25519 -f "$env:USERPROFILE\.ssh\<name>_ed25519" -C "<name>-deploy" -N ''
  • ed25519 — small, fast, modern. Don't use RSA for new keys.
  • -N '' — empty passphrase, required for unattended deploy scripts.
  • Creates two files: the private key (never leaves your machine, never paste it anywhere) and .pub (safe to paste into chat, tickets, panels).

2.2 Install the public key on the server

The server must already accept either a root password or some existing access. Run this in your own terminal — it prompts for the password interactively, so it can't be run by an agent/script:

ssh root@<ip> "mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo 'ssh-ed25519 AAAA...comment' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && echo KEY_ADDED"

Already sitting at a root shell (provider web console)? Skip the ssh wrapper and paste just the inner part:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo 'ssh-ed25519 AAAA...comment' >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys && echo KEY_ADDED

Permissions matter: sshd silently refuses keys if ~/.ssh isn't 700 or authorized_keys isn't 600.

2.3 Optional — SSH config alias

So you can type ssh <name> and scripts stay clean:

# %USERPROFILE%\.ssh\config
Host <name>
    HostName <ip>
    User root
    IdentityFile ~/.ssh/<name>_ed25519
    IdentitiesOnly yes

3. Verify (non-interactive — the correct test)

ssh -i "$env:USERPROFILE\.ssh\<name>_ed25519" -o BatchMode=yes -o ConnectTimeout=10 -o IdentitiesOnly=yes root@<ip> 'echo CONNECTED; grep PRETTY_NAME /etc/os-release; nproc; free -h | head -2; df -h / | tail -1'
  • BatchMode=yes — never hangs on a prompt; fails fast instead. Always use it when testing, otherwise a broken key just sits waiting for a password forever.
  • IdentitiesOnly=yes — offer only this key. Without it ssh walks every key in ~/.ssh and you can't tell which one actually worked.
  • First connection to a new host: add -o StrictHostKeyChecking=accept-new to auto-accept the host key instead of prompting.

4. Traps (all four cost real time — read these)

4.1 -N '""' creates a key with a LITERAL "" passphrase ← worst one

On PowerShell, -N '""' does not mean "empty passphrase" — it passes the two characters " " as the passphrase. The key then works interactively but fails under BatchMode/automation, with a very misleading symptom (see §5).

Detect:

ssh-keygen -y -f "$env:USERPROFILE\.ssh\<name>_ed25519" -P ''      # empty?  prints pubkey
ssh-keygen -y -f "$env:USERPROFILE\.ssh\<name>_ed25519" -P '""'    # literal? prints pubkey

Fix without regenerating — ssh-keygen -p changes only the passphrase, the keypair is unchanged, so a public key already installed on servers stays valid:

ssh-keygen -p -f "$env:USERPROFILE\.ssh\<name>_ed25519" -P '""' -N ''

Use -N '' when generating. Verify with -P '' before installing anywhere.

4.2 Never pipe the public key into ssh on Windows

# BROKEN — the pipe consumes stdin, so ssh can't prompt for the password;
# fails with a "Permission denied" that looks like a server problem but isn't
Get-Content ...\key.pub | ssh root@<ip> "cat >> ~/.ssh/authorized_keys"

Put the key inline in the remote command instead (§2.2), leaving stdin free for the password prompt.

4.3 Provider-panel "SSH keys" often only apply at (re)build

Pasting a key into the hosting panel of an already-running server frequently does nothing — many providers only inject keys during provisioning. Symptom: key is listed in the UI, but every user still gets Permission denied.

Options: install it over SSH/console yourself (§2.2), or rebuild the server from the panel with the key selected (fine for an empty box, destroys data otherwise).

4.4 An agent can't type passwords

Any step needing an interactive password (ssh-copy-id, first key install) must be run by a human in their own terminal. Automate only after key auth works.


5. Decoding failures

Run ssh -v and read the last few lines:

ssh -v -i "$env:USERPROFILE\.ssh\<name>_ed25519" -o BatchMode=yes -o IdentitiesOnly=yes root@<ip> 'echo ok' 2>&1 | Select-String 'Offering|Server accepts|Authentications that can|denied|Load key'
What you see What it means Fix
Server accepts key: … then Permission denied Server side is CORRECT — the key IS in authorized_keys. ssh then failed to use the private key locally, i.e. it's passphrase-protected §4.1 — strip the passphrase
Offering public key… then Authentications that can continue: publickey,password, no "accepts" Key is not in authorized_keys on the server §2.2 — install it
Load key … incorrect passphrase supplied Wrong/unknown passphrase §4.1
Permission denied (publickey) only — no password Password auth is disabled server-side; you need console/rebuild §4.3
Hangs with no output You forgot BatchMode=yes; it's waiting on a hidden prompt §3
UNPROTECTED PRIVATE KEY FILE Windows ACLs too open on the private key icacls — restrict to your user only

Useful check — is the auth method even offered? publickey,password in Authentications that can continue lists what the server allows.


6. Inventory

Project Key Host User
CoinSpectrum + Silent Mode / navigate.st (layout) coinspectrum_ed25519 195.184.247.106 (Ubuntu 24.04, 1 core / 2.9 GB / 48 GB) root
P2PExchange (telegram order-book bot) p2pexchange_ed25519 81.31.210.65 (/opt/p2pexchange, systemd p2pexchange) root
Checkers checkers_deploy — —

Per-project keys mean revoking one (delete its line from that server's authorized_keys) doesn't touch the others.


7. Hardening (after it works — optional)

  1. Dedicated non-root deploy user instead of root:
    adduser --disabled-password --gecos "" deploy
    mkdir -p /home/deploy/.ssh && cp ~/.ssh/authorized_keys /home/deploy/.ssh/
    chown -R deploy:deploy /home/deploy/.ssh && chmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys
    usermod -aG sudo deploy
    
  2. Disable password auth once keys work — /etc/ssh/sshd_config: PasswordAuthentication no, PermitRootLogin prohibit-password, then systemctl restart ssh. Test key login in a second terminal BEFORE closing your current session, or you can lock yourself out.
  3. Firewall — ufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable.
  4. fail2ban — apt install fail2ban for brute-force protection.