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> @ |
||
|---|---|---|
| .. | ||
| README.md | ||
| silentmode-navigate.md | ||
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~/.sshand you can't tell which one actually worked.- First connection to a new host: add
-o StrictHostKeyChecking=accept-newto 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)
- 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 - Disable password auth once keys work —
/etc/ssh/sshd_config:PasswordAuthentication no,PermitRootLogin prohibit-password, thensystemctl restart ssh. Test key login in a second terminal BEFORE closing your current session, or you can lock yourself out. - Firewall —
ufw allow OpenSSH && ufw allow 80,443/tcp && ufw enable. - fail2ban —
apt install fail2banfor brute-force protection.