Independent marketplace for cloud provider accounts across 22 providers

Developer Workflows

SSH Keys for Cloud Servers: Generating, Adding and Rotating

Cloud providers expect an SSH public key before they create a Linux server. This guide generates a modern Ed25519 key pair, shows where the key is stored at DigitalOcean, Hetzner, AWS, Vultr, Google Cloud and Azure, sets up the agent and config file, and rotates keys safely.

Terminal showing ssh-keygen output next to a list of cloud provider key management screens

Why Cloud Servers Expect a Key, Not a Password

Almost every cloud provider asks for an SSH public key before it will create a Linux server. DigitalOcean, Hetzner, Vultr and Linode all show a key picker in the create dialog, and AWS EC2 will not launch most Linux images without a key pair attached. The reason is simple: a password can be guessed by a bot hammering port 22, while a private key that exists only on your laptop cannot.

The workflow itself is short. You generate a key pair once, upload the public half to each provider, and the provider drops it into ~/.ssh/authorized_keys on every server you create. From that point the private half on your machine is the only thing that opens the door.

This guide walks through that sequence with real commands, shows where the key lives at the providers you are most likely to use, and covers the part most tutorials skip: rotating a key without locking yourself out.

Generating a Modern Key Pair

Use the Ed25519 algorithm unless you have a specific reason not to. Its keys are short, fast to verify and supported by every current OpenSSH release on Linux, macOS and Windows 10 or later.

ssh-keygen -t ed25519 -a 100 -C "you@example.com laptop 2026" -f ~/.ssh/id_ed25519_cloud

Three flags matter here. -t ed25519 picks the algorithm. -a 100 raises the number of key derivation rounds protecting the passphrase, which slows an offline brute-force attempt if the private file is ever copied. -C sets a comment that shows up in authorized_keys, so label it with the device and year rather than leaving the default hostname.

Always set a passphrase when prompted. A passphrase means a stolen file is still useless on its own, and the SSH agent described below means you only type it once per session.

If an older appliance or a legacy provider image rejects Ed25519, fall back to RSA with a 4096-bit modulus: ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_legacy. Keep that key separate and delete it when the last old target is gone.

The command writes two files. id_ed25519_cloud is the private key and must never leave the machine. id_ed25519_cloud.pub is the public key, and it is safe to paste into any provider console. Check permissions once with chmod 600 ~/.ssh/id_ed25519_cloud; OpenSSH refuses to use a private key that other users can read.

Adding the Public Key at Each Provider

Print the public key with cat ~/.ssh/id_ed25519_cloud.pub and copy the single line it outputs. Every console below accepts that line verbatim. Where a CLI exists, the third column shows the equivalent command, which is handy when you manage several accounts.

ProviderWhere the key is storedConsole path or CLI
DigitalOceanAccount-wide, selectable per DropletSettings, Security, Add SSH Key; or doctl compute ssh-key import laptop --public-key-file ~/.ssh/id_ed25519_cloud.pub
Hetzner CloudPer projectSecurity, SSH Keys; or hcloud ssh-key create --name laptop --public-key-from-file ~/.ssh/id_ed25519_cloud.pub
AWS EC2Per region, as a named key pairEC2, Key Pairs, Import; or aws ec2 import-key-pair --key-name laptop --public-key-material fileb://~/.ssh/id_ed25519_cloud.pub
VultrAccount-wideAccount, SSH Keys; or vultr-cli ssh-key create --name laptop --key "$(cat ~/.ssh/id_ed25519_cloud.pub)"
Google Compute EngineProject metadata or OS Logingcloud compute os-login ssh-keys add --key-file ~/.ssh/id_ed25519_cloud.pub
AzurePassed at VM creation or stored as an SSH key resourceaz vm create ... --ssh-key-values ~/.ssh/id_ed25519_cloud.pub

Two details trip people up. AWS key pairs are regional, so a key imported in eu-central-1 does not appear in us-east-1; import it again there. Hetzner keys belong to a project, so a second project needs its own upload. DigitalOcean and Vultr keys are account-wide and can be ticked for any new server. The EC2 key pair documentation and the DigitalOcean SSH key guide describe the console flows in detail.

For a server that already exists, skip the console and push the key over an existing connection:

ssh-copy-id -i ~/.ssh/id_ed25519_cloud.pub deploy@203.0.113.10

That appends the public key to the remote user's authorized_keys and fixes the file permissions. Test it in a second terminal before closing the first one.

If you are bringing several servers online after picking up a DigitalOcean account through AllCloudShop or a Hetzner Cloud account, upload the key to the account first. Every server you create afterward inherits it and you never touch a password at all. The two providers organize keys differently, which the DigitalOcean vs Hetzner comparison touches on when it covers account structure.

Making Daily Use Painless: ssh-agent and the Config File

A passphrase-protected key would be tedious if you typed the passphrase for every connection. The SSH agent holds the decrypted key in memory for the length of your session.

eval "$(ssh-agent -s)" followed by ssh-add ~/.ssh/id_ed25519_cloud

On macOS, ssh-add --apple-use-keychain stores the passphrase in Keychain so it survives reboots. On Windows, enable the built-in OpenSSH Authentication Agent service and ssh-add works the same way. Linux desktops usually start an agent automatically through GNOME Keyring or KDE Wallet.

Next, stop typing IP addresses. Add a block per server or per provider to ~/.ssh/config:

Host web-fra1
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_cloud
IdentitiesOnly yes

Now ssh web-fra1 does the right thing, and so do scp, rsync and any editor that speaks SSH. IdentitiesOnly yes is worth keeping: without it the client offers every key in the agent, and a server that limits authentication attempts may reject you before it reaches the right one.

Prefer one key per device over one key copied everywhere. When a laptop is lost you remove exactly one line from each server and nothing else changes.

Rotating a Key Without Locking Yourself Out

Keys should be replaced when a device is retired, when a person leaves the team, or on a schedule you can actually keep. The order of operations matters because the one mistake you cannot undo remotely is removing the last working key.

  1. Generate the new pair with a fresh filename and comment, for example id_ed25519_2026.
  2. Add the new public key to every server with ssh-copy-id -i ~/.ssh/id_ed25519_2026.pub host, still authenticating with the old key.
  3. Upload the new public key to each provider console so future servers receive it.
  4. Open a new terminal and connect with ssh -i ~/.ssh/id_ed25519_2026 -o IdentitiesOnly=yes host. Do this for every host before continuing.
  5. Remove the old line from ~/.ssh/authorized_keys on each server. A quick way is sed -i '/laptop 2024/d' ~/.ssh/authorized_keys, matching on the comment you set at creation time.
  6. Delete the old key from the provider consoles, then destroy the old private file locally with shred -u ~/.ssh/id_ed25519_old.

Configuration management makes this repeatable. Ansible's ansible.posix.authorized_key module can add the new key and remove the old one across an inventory in a single play, and cloud-init can seed the right key on first boot. The Ansible walkthrough shows the module syntax.

Keep in mind that replacing the key in a provider console changes nothing on servers that already exist. The console only affects the initial provisioning step; running servers keep whatever is in their authorized_keys file.

Mistakes That Cause Lockouts

  • Disabling password login in sshd_config before confirming the key works from a fresh terminal. Test first, then set PasswordAuthentication no and run sudo systemctl reload ssh.
  • Copying a private key into a repository, a Docker image or a shared drive. Only the .pub file should ever travel.
  • Wrong permissions on the server side: ~/.ssh must be 700 and authorized_keys must be 600, otherwise sshd silently ignores the file.
  • Attaching the key to the wrong user. Provider images log you in as root, ubuntu, ec2-user or admin depending on the distribution, and the key only lands in that account's home directory.
  • Forgetting that a firewall change can block port 22 for everyone, including you. The first hour checklist covers the safe order for tightening a new machine.

Common Questions About SSH Keys

Can I use the same key for GitHub and my cloud servers?

Technically yes, because both simply store your public key. Many engineers still prefer a separate key for code hosting so that revoking server access does not interrupt pushes, and vice versa. Keys are cheap to make, and the config file keeps them organized.

What is the difference between an AWS key pair and a normal SSH key?

Nothing at the protocol level. AWS stores the public half as a named, regional resource and injects it into the instance at first boot. You can import a key you generated yourself, which is preferable to downloading a .pem file that AWS generated, because the private half then never passes through a browser.

Does a passphrase get in the way of automation?

Interactive keys should have one. For CI runners and deployment scripts, create a dedicated key without a passphrase, restrict it to a single low-privilege user on the target, and store it in the pipeline's secret store rather than in the repository. The secrets guide explains the storage side.

How do I see which keys a server currently trusts?

Run cat ~/.ssh/authorized_keys as the login user. Each line is one public key, and the trailing comment tells you which device it came from, which is exactly why a descriptive -C value at generation time pays off later.

Questions about a cloud account?

Ask about products, variants, availability or purchasing on either channel.