ssh-keyup
Set up passwordless SSH on Raspberry Pi, NVIDIA Jetson or any Linux device in one command.
Tired of juggling ssh-keygen, ssh-copy-id (missing on Windows) and ~/.ssh/config edits every time you set up a new device?
ssh-keyup handles all three in one interactive session.
Quickstart
Install globally with pip:
pip install ssh-keyup
ssh-keyup # ready to use anywhere
Tip: If
ssh-keyupis missing or runs an old version after install, new script sits in a folder outside PATH (pip warns about this). Add that folder to PATH, or install with pipx instead:
pipx install ssh-keyup
Or run directly without installing:
git clone https://github.com/Kurokesu/ssh-keyup.git
cd ssh-keyup
python ssh_keyup.py # Windows
python3 ssh_keyup.py # Linux
Follow prompts, enter remote password once and you're done. Alias now works in anything that reads ~/.ssh/config:
Terminal:
ssh mypi # no password, ever again
VSCode: Remote - SSH works out of the box. Press Ctrl+Shift+P, select Remote-SSH: Connect to Host and pick your alias for a full IDE on the device, no password:
Usage
Skip prompts
ssh-keyup pi@192.168.1.23 mypi # user, host and alias in one go
Flags (--host, --user, --alias) work too, see ssh-keyup --help.
Set up a fleet
for host in 192.168.1.10 192.168.1.11 192.168.1.12; do
ssh-keyup pi@$host
done
Manage entries
List or remove entries ssh-keyup manages:
ssh-keyup --list
ssh-keyup --remove mypi # deletes its key pair too
Prerequisites
Python 3.8+ and OpenSSH tools (ssh, ssh-keygen) in PATH.
- Windows 10/11: Python from python.org or Microsoft Store. OpenSSH Client via Settings > Optional Features or Git for Windows.
- Linux:
sudo apt install python3 openssh-client(usually pre-installed).
How it works
flowchart LR
run["ssh-keyup"] --> check["check connection"]
check --> gen["generate ed25519 key<br/>~/.ssh/id_ed25519_mypi"]
gen --> deploy["deploy public key<br/>target: ~/.ssh/authorized_keys"]
deploy --> config["update ssh config<br/>~/.ssh/config"]
Features
- Works on Windows OpenSSH, where
ssh-copy-iddoes not exist - Never touches your password. Only the public key is piped over SSH and OpenSSH prompts for the password itself
- One Ed25519 key per device (
~/.ssh/id_ed25519_<alias>), not one key reused everywhere - Deploys in a single SSH session, one password prompt total
- Adds a named entry to
~/.ssh/config, works instantly withssh <alias>and VSCode Remote SSH - Checks host is reachable first, so typos surface before keys exist
- Recovers from host key mismatches after a reflash
- Entry management, list or retire devices without leaving stale keys behind
- Zero dependencies, standard library plus system OpenSSH
FAQ
Why not do it by hand?
Usual commands for passwordless SSH from Windows:
ssh-keygen -t ed25519
type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh pi@raspberrypi.local "cat >> ~/.ssh/authorized_keys"
notepad $env:USERPROFILE\.ssh\config # then add a Host block by hand
Works once. Same key lands on every device, ~/.ssh keeps default permissions that sshd may reject and each new device means another config edit.
Why not ssh-copy-id?
ssh-copy-id appends a key to authorized_keys and stops there. Windows OpenSSH does not ship it at all.
| ssh-keyup | ssh-copy-id | |
|---|---|---|
| Works on Windows OpenSSH | yes | no |
| Ed25519 key per device | yes | no |
Sets authorized_keys permissions |
yes | yes |
Writes ~/.ssh/config alias |
yes | no |
| Recovers from changed host key | yes | no |
| Entry management | yes | no |
How do I fix "REMOTE HOST IDENTIFICATION HAS CHANGED"?
Reflashing creates a new host key, so next ssh refuses to connect:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
...
Offending ECDSA key in ~/.ssh/known_hosts:3
Host key verification failed.
Run ssh-keyup again. It detects a changed key, shows new fingerprint for confirmation, clears stale known_hosts entry with ssh-keygen -R and redeploys. Usually a reflash is behind it, but this warning can also mean a real man-in-the-middle, so ssh-keyup asks instead of trusting silently.
Does --remove clean up entries on the device?
No. It deletes local key pair and ~/.ssh/config entry. Line in the device's authorized_keys stays until removed there.
What devices are supported?
Anything reachable over SSH: Raspberry Pi, NVIDIA Jetson, Orange Pi, VMs, servers.
Release files for ssh-keyup 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ssh_keyup-1.2.0.tar.gz | 25.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ssh_keyup-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.9 kB
Release files / ssh_keyup-1.2.0.tar.gz
| Download URL | ssh_keyup-1.2.0.tar.gz |
|---|---|
| Size | 25.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4fce9680e1d3893e95f5ad5532257660cb38ff7f6c6f89414c43b09eb2321d96
|
|
BLAKE2b-256 checksum How to use checksums |
dcc1403fc0af7486a427728d28ae97d91be03c8993d806f4e90d33363c3aeb5f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency logRelease files / ssh_keyup-1.2.0-py3-none-any.whl
| Download URL | ssh_keyup-1.2.0-py3-none-any.whl |
|---|---|
| Size | 26.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0e3e6428ea629f3d37b0a47501875d31a03d81da67e3c72c7a16cb1c6cf795e1
|
|
BLAKE2b-256 checksum How to use checksums |
c0ce1788805e2f9e4424e3e71171da1e70698b93937a7b468606712c65277945
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 3, 2026.
Transparency log